xhs某书shield逆向破解(二) | unidbg

186次阅读
没有评论

上一篇文章中我们已经找到了生成shiled参数的Native函数,以及函数的偏移位置,这篇会讲一下如何搭建unidbg环境,如何补缺失环境,最终生成shield参数。

一、搭建unidbg环境

首先把unidbg项目拉下来(项目地址:https://github.com/zhkl0228/unidbg)。

在test中新建一个类,然后把小红书apk和对应的libshiled.so文件放到resources资源目录下。

然后把最基本的unidbg框架搭下,代码如下:

public class ShieldTest extends AbstractJni {

    //ARM模拟器
    private final AndroidEmulator emulator;

    //vm
    private final VM vm;

    //载入的模块
    private final Module module;

    public ShieldTest() {
        // 创建模拟器实例
        emulator = AndroidEmulatorBuilder.for32Bit().setProcessName("com.xhs").build();
        Memory memory = emulator.getMemory();
        memory.setLibraryResolver(new AndroidResolver(23));

        // 创建Android虚拟机
        vm = emulator.createDalvikVM(new File("unidbg-android/src/test/resources/xhs/xhs_v6.97.0.apk"));
        vm.setJni(this);
        vm.setVerbose(true);

        //加载so
        DalvikModule dm = vm.loadLibrary(new File("unidbg-android/src/test/resources/xhs/libshield_v6.97.0.so"), true);
        dm.callJNI_OnLoad(emulator);
        module = dm.getModule();
    }
}

二、分析Native函数

xhs某书shield逆向破解(二)

我们分析下这块代码:

  1. 首先需要调initializeNative这个初始化函数;
  2. 第二步调initialize函数,获取cPtr;
  3. 最终生成shield是调用intercept函数,需传入一个“okhttp3/Interceptor$Chain”,paramLong就是第二步获取的cPtr值。

三、补缺失环境

先把初始化函数initializeNative的代码逻辑写上(偏移位置怎么找可以看我的上篇文章)。

public void initializeNative() {
    List<Object> params = new ArrayList<>();
    params.add(vm.getJNIEnv());
    params.add(0);
    module.callFunction(emulator, 0x6c11d, params.toArray());
}

public static void main(String[] args) {
    ShieldTest shieldTest = new ShieldTest();
    shieldTest.initializeNative();
}

直接运行下,会发现报错了。

xhs某书shield逆向破解(二)

这个报错一般就说明要补环境了。

这里先解释下这个:“java/nio/charset/Charset->defaultCharset()Ljava/nio/charset/Charset;”

这句话的意思是调用java/nio/charset/Charset这个类下的defaultCharset函数,返回值是Ljava/nio/charset/Charset,unidbg缺少这一块的处理逻辑,我们需要手动补上。

我们可以直接点“com.github.unidbg.linux.android.dvm.AbstractJni.callStaticObjectMethodV(AbstractJni.java:388)”这个位置,进去后会看到一个方法,我们需要重写callStaticObjectMethodV方法,然后把Charset对象return回去就好。

@Override
public DvmObject<?> callStaticObjectMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
    switch (signature) {
        case "java/nio/charset/Charset->defaultCharset()Ljava/nio/charset/Charset;":
            return vm.resolveClass("java/nio/charset/Charset").newObject(Charset.defaultCharset());
    }
    throw new UnsupportedOperationException(signature);
}

继续运行,发现又报错了

xhs某书shield逆向破解(二)

这次是缺少一个versionCode参数,这个参数可以在AndroidManifest.xml文件中找到,我这个版本是6970181,直接返回即可。

@Override
public int getIntField(BaseVM vm, DvmObject<?> dvmObject, String signature) {
    switch (signature) {
        case "android/content/pm/PackageInfo->versionCode:I": {
            return 6970181;
        }
    }
    return super.getIntField(vm, dvmObject, signature);
}

然后继续运行,报错了就补环境,我就不把所有的都写出来了,比较多,挑几个讲一下。

sDeviceId:

xhs某书shield逆向破解(二)

这里是缺少一个sDeviceId参数,我这里是通过IDA分析这块代码,然后打印GetStringUTFChars函数结果找到的。

xhs某书shield逆向破解(二)
xhs某书shield逆向破解(二)

ps:

这里分析IDA代码有个技巧,像这块代码,v1大概率就是env,可以在v1上右键“set lvar type”,把类型改为JNIEnv*,然后确定,会发现很多函数能显示出来了,看起来会直观很多。

xhs某书shield逆向破解(二)
xhs某书shield逆向破解(二)

main_hmac:

这个参数可以直接adb连上去,在s.xml文件下找到。

然后依次把三个函数的所有环境补完,就可以运行生成shield了。

下面是三个Native函数的代码逻辑:

public void initializeNative() {
    List<Object> params = new ArrayList<>();
    params.add(vm.getJNIEnv());
    params.add(0);
    module.callFunction(emulator, 0x6c11d, params.toArray());
}

public long initialize() {
    List<Object> params = new ArrayList<>();
    params.add(vm.getJNIEnv());
    params.add(0);

    params.add(vm.addLocalObject(new StringObject(vm, "main")));
    Number number = module.callFunction(emulator, 0x6b801, params.toArray());
    return number.longValue();
}

public void intercept(long cPtr) {
    List<Object> params = new ArrayList<>();
    params.add(vm.getJNIEnv());
    params.add(0);

    DvmObject<?> chain = vm.resolveClass("okhttp3/Interceptor$Chain").newObject(null);
    params.add(vm.addLocalObject(chain));
    params.add(cPtr);
    Number number = module.callFunction(emulator, 0x6b9e9, params.toArray());
    Object result = vm.getObject(number.intValue()).getValue();
}

public static void main(String[] args) {
    ShieldTest shieldTest = new ShieldTest();
    shieldTest.initializeNative();

    long cPtr = shieldTest.initialize();
    System.out.println(cPtr);

    shieldTest.intercept(cPtr);
}

三、最终效果

xhs某书shield逆向破解(二)

评论(没有评论)
载入中...