推荐阅读const a = 全能的傻宝,每天都会换一种姿势来分享各种骚操作,10月份开始分享密码学;
const b = 点击加入星球;
return “无敌的龙哥”;
前言unidbg hook inline hook 使用
unidbg console debugger 使用
so 分析过程在验阶段会使用 unidbg debugger hook 功能,不熟悉的可以阅读以上文章
JD app sign so 加密算法分析还原|so 算法分析
JD app sign so 加密算法分析还原|so sub_126AC 函数算法还原
0x1前面分析了搜狗搜索 app 的 so 加解密逻辑,这次就来分析下 京东 app 的,继续学习 so 分析
app 版本 最新版 10.2.0
先来抓个包
随便点个请求,查看参数,这里有三个是 so 加密返回的
0x2反编译 apk 查看加密函数
前面 java 层的分析就不说了,最终是找到了这个类 com.jingdong.common.utilsBitmapkitUtils,调用 getSignFromJni native 函数获取加密参数,一共有六个参数,具体的加密逻辑在 BitmapkitUtils.so 文件里,frida hook 看一下
function hook() {
var BitmapkitUtils = Java.use('com.jingdong.common.utils.BitmapkitUtils');
BitmapkitUtils.getSignFromJni.implementation = function (a, b, c, d, e, f) {
console.log('b: ', b);
console.log('c: ', c);
console.log('d: ', d);
console.log('e: ', e);
console.log('f: ', f);
var res = this.getSignFromJni(a, b, c, d, e, f);
console.log('resf: ', res);
return res;
}
}
function main() {
Java.perform(function () {
hook();
})
}
setImmediate(main);
代码写完执行 frida -U -f com.jingdong.app.mall -l hook.js --no-pause | tee hook.log 命令,查看 hook.log 文件
函数的输入输出很明显,加密结果也能跟请求包对应起来,下面使用 frida 主动调用看看
frida callfunction callBitmapkitUtils() {
var BitmapkitUtils = Java.use('com.jingdong.common.utils.BitmapkitUtils');
var currentApplication = Java.use("android.app.ActivityThread").currentApplication();
var context = currentApplication.getApplicationContext();
var b = 'clientImage';
var c = '{"moduleParams":{"18":"1565611060638","19":"1565229712150","25":"1567478504636","27":"1602488415048","28":"1631069159956","30":"1567404005627","32":"1567997588476","34":"1593508185597","35":"1568708316462","37":"1630293538664","42":"1623741761542","44":"1569247647090","46":"1588839806224","47":"1571295610042","61":"1582091758495","70":"1585279774645","74":"1586781606615"}}';
var d = 'd5a585639f505b18';
var e = 'android';
var f = '10.2.0';
var res = BitmapkitUtils.getSignFromJni(context, b, c, d, e, f);
console.log('res: ', res);
}
function main() {
Java.perform(function () {
callBitmapkitUtils();
})
}
setImmediate(main);
执行 frida -UF -l call.js
查看输出每次调用都不一样,应该是跟时间戳有关系,看 sign 的结果应该是 md5 or hmac,后面既然需要用到 unidbg debugger 功能那就需要先使用 unidbg 跑起来
0x4使用 unidbg 调用 getSignFromJni 函数
这里的 so 有个坑,会调用 check_status 函数,校验 apk 的签名,有两种方式可以选择
1、直接 so patch 不执行这个函数,参考我之前的文章: JD app sign 加密参数破解 - unidbg
2、直接去补 so 的 check_status 函数,因为我们后面要去分析 so 算法还原,所以本次就选择这种方式
package com.xiayu.jingdong;
import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.LibraryResolver;
import com.github.unidbg.Module;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.*;
import com.github.unidbg.memory.Memory;
import java.io.File;
import java.io.IOException;
public class JingDong1020Test extends AbstractJni {
private final AndroidEmulator emulator;
private final VM vm;
public String apkPath = "apk 文件路径";
public String soPath = "so 文件路径";
private static LibraryResolver createLibraryResolver() {
return new AndroidResolver(23);
}
private static AndroidEmulator createARMEmulator() {
return AndroidEmulatorBuilder
.for32Bit()
.build();
}
public JingDong1020Test() {
emulator = createARMEmulator();
final Memory memory = emulator.getMemory();
memory.setLibraryResolver(createLibraryResolver());
vm = emulator.createDalvikVM(new File(apkPath));
vm.setVerbose(true);
DalvikModule dm = vm.loadLibrary(new File(soPath), false);
vm.setJni(this);
dm.callJNI_OnLoad(emulator);
Module module = dm.getModule();
}
public void callGetSignFromJni() {
DvmClass bitMapKitUtils = vm.resolveClass("com/jingdong/common/utils/BitmapkitUtils");
DvmObject> strRc = bitMapKitUtils.callStaticJniMethodObject(
emulator,
"getSignFromJni()(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
vm.addLocalObject(null),
vm.addLocalObject(new StringObject(vm, "clientImage")),
vm.addLocalObject(new StringObject(vm, "{"moduleParams":{"18":"1565611060638","19":"1565229712150","25":"1567478504636","27":"1602488415048","28":"1631069159956","30":"1567404005627","32":"1567997588476","34":"1593508185597","35":"1568708316462","37":"1630293538664","42":"1623741761542","44":"1569247647090","46":"1588839806224","47":"1571295610042","61":"1582091758495","70":"1585279774645","74":"1586781606615"}}")),
vm.addLocalObject(new StringObject(vm, "d5a585639f505b18")),
vm.addLocalObject(new StringObject(vm, "android")),
vm.addLocalObject(new StringObject(vm, "10.2.0"))
);
System.out.println("callGetSignFromJni: " + strRc.getValue());
}
public static void main(String[] args) throws IOException {
JingDong1020Test jdSign = new JingDong1020Test();
jdSign.callGetSignFromJni();
jdSign.destroy();
}
private void destroy() throws IOException {
emulator.close();
}
}
全部代码,写完跑起来
环境问题补起来,返回 Application
返回 base.apk 的文件路径
这个是调用了自定义的 com/jingdong/common/utils/BitmapkitZip->unZip 函数,目前没啥好的办法,只有去把 java 复制过来使用,第一个参数是需要解压的 apk 路径,所以我们传递的是本地的 apk 路径
一个加密参数,调用的是 java 内置函数,直接补
这里需要返回一个对象数组
接着又补了一些环境
在运行,结果就出来了,每次运行的结果不一样,下面使用 python 请求测试一下,结果是否可用
使用 java server 框架启动服务,在使用 python 调用 java 接口获取 sign 参数,测试是否可用
代码写完,结果是可以用的
最后京东 unidbg 例子就写完了,后面开始去分析 so 具体算法
更多精彩内容,源码文件下载等,原文链接,博主个人站点:https://www.qinless.com/576



