android app so sig 加密参数 unidbg

android 逆向 30 / 38

前言

继续上一篇分享,本文主要分享下怎么使用 unidbg 跑起来。话不多说直接开干

unidbg

老规矩,先搭架子

package com.xiayu.meituxiuxiu;

import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Emulator;
import com.github.unidbg.Module;
import com.github.unidbg.debugger.BreakPointCallback;
import com.github.unidbg.debugger.Debugger;
import com.github.unidbg.debugger.DebuggerType;
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.linux.android.dvm.array.ArrayObject;
import com.github.unidbg.linux.android.dvm.array.ByteArray;
import com.github.unidbg.memory.Memory;
import unicorn.ArmConst;

import java.io.File;
import java.io.IOException;
import java.security.MessageDigest;

public class GetSig_v9080Test extends AbstractJni {
    private final AndroidEmulator emulator;
    private final Module module;
    private final VM vm;

    public String apkPath = "/Volumes/T7/android/android-file/meituxiuxiu-9.0.8.0.apk";
    public String soPath2 = "unidbg-android/src/test/resources/test_so/meituxiuxiu/librelease_sig-9.0.8.0.so";

    GetSig_v9080Test() {
        emulator = AndroidEmulatorBuilder.for32Bit().build();
        final Memory memory = emulator.getMemory();
        memory.setLibraryResolver(new AndroidResolver(23));
        vm = emulator.createDalvikVM(new File(apkPath));
        vm.setVerbose(true);
        vm.setJni(this);

        DalvikModule dm2 = vm.loadLibrary(new File(soPath2), true);
        dm2.callJNI_OnLoad(emulator);
        module = dm2.getModule();

    }

    public static void main(String[] args) {
        GetSig_v9080Test getSig = new GetSig_v9080Test();
        getSig.destroy();
    }

    private void destroy() {
        try {
            emulator.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

又是熟悉的 bug,这里依赖了 libgnustl_shared.so 我们给他加上

跑起来,发现啥都没有输出,这没啥事,只要没报错就是好事。下面直接 call 函数

注意这里的 byte[][] 类型,千万不要直接 vm.resolveClass("[[B") 这样在后面取值会报错,需要使用 ArrayObject + ByteArray 构建(龙哥指点)

public ArrayObject getByteByte() {
    String[] arg5 = {这里大家自行填充 frida hook 出来的参数即可};

    DvmObject<?>[] dvm = new DvmObject<?>[arg5.length];
    for (int v1 = 0; v1 < arg5.length; ++v1) {
        if (arg5[v1] == null) {
            arg5[v1] = "";
        }
        dvm[v1] = new ByteArray(vm, arg5[v1].getBytes());
    }

    return new ArrayObject(dvm);
}

public void call() {
    String methodId = "nativeGeneratorSig(Ljava/lang/String;[[BLjava/lang/String;Ljava/lang/Object;)Lcom/meitu/secret/SigEntity;";
    DvmClass SigEntity = vm.resolveClass("com/meitu/secret/SigEntity");

    SigEntity.callStaticJniMethodObject(
            emulator, methodId,
            new StringObject(vm, "search/feeds.json"),
            getByteByte(),
            new StringObject(vm, "6184556633574670337"),
            vm.resolveClass("android/content/Context").newObject(null)
    );
}

报错,正常补环境

又报错,但是看不出来啥问题,日志全开看看

发现这里是调用 GetSuperClass JNI 函数报错的。不知道啥问题点进源码看看 DalvikVM.java:150

这里调用了 dvmClass.getSuperclass 函数,返回空,才报错的。跟进去看看

这个函数返回 superClass 字段,该字段的值来源于初始化的时候。在哪里初始化的呢。这个跟一下源码就可以了,我这里就不再继续分析了。是在 vm.resolveClass 的时候

这里可以传递多个参数,正常都是传递一个,如果有两个第二个参数就是 superClass

咱们加上试试

跑起来,成功了,没有报 superClass 错误了,但是又出现其他的了,不慌点进源码一探究竟

发现这里是个未实现的 JNI 函数,这里为了简单,就直接返回需要的值就行了。使用 jnitrace 看看返回值是啥

这里是个 0 直接返回

上面正常补环境即可

这里需要注意下,android base64java base64 还是有点区别的(龙哥的精讲课程里也说到过),这里为了不出问题,就直接复制了 android base64 的代码,大家自行复制就行

环境补完,但是出奇的是结果尽然为空就很奇怪。不慌继续分析

复制最后一次 NewStringUTF 的地址,ida 里跳过去

是在这里操作的,x 查看该函数的交叉引用

跟到了这里 LABEL_8 代码块,很明显是在 ValidateKey::getValidateResult 函数之后的 if 判断里调用的,在分析该函数逻辑

这里有多地方会返回 -1 那就应该是该函数出了问题

Tips: 这里应该是单步调试或者 hook 排除,博主就不去一步步分析了,大家可以自行尝试(具体啥原因也是没分析出来,直接使用 patch 大法搞定它)

还记得上一篇的 frida hook 里面就有 hook while 循环里 v11 的值,来看一下

这里循环了三次,最后一次结果为 0,刚好前面的 if 判断不成立就可以继续了

这里直接使用 unidbg hook 强制修改函数返回值为 0,最后也是成功运行出了结果

暂无评论
本文作者:
本文链接: https://www.qinless.com/?p=1432
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 qinless 的博客!
100

发表评论

返回顶部