安卓逆向 - 某东sign(基于unidbg主动调用)

本文仅供学习交流,只提供关键思路不会给出完整代码,严禁用于非法用途,拒绝转载,若有侵权请联系我删除!

目标app:5Lqs5LicYXBwMTEuMy4y

目标接口:aHR0cHM6Ly9hcGkubS5qZC5jb20vY2xpZW50LmFjdGlvbj9mdW5jdGlvbklkPXNlYXJjaA==
一、引言

接上篇安卓逆向 - 某东body参数算法还原_小馒头yy的博客-CSDN博客 我们抓到了关键字搜索的包,并且成功还原了body参数,今天我们来看看请求url中的sign是如何生成的。

二、分析Java层代码

1、熟练打开Jadx,搜索sign参数发现搜出来的结果太多了15179条,不好分析。过来人的经验是搜索put("sign" "sign"等关键字减小范围。

安卓逆向 - 某东sign(基于unidbg主动调用)_第1张图片

2、调整搜索策略后,明显少了很多条信息,我们依次点开查看上下文,使用Frida辅助动态分析

安卓逆向 - 某东sign(基于unidbg主动调用)_第2张图片

最终定位到如下关键行,使用Frida hook发现跟我们抓到的包一模一样。

 String signature = a.a().w().signature(a.a().c(), queryParameter, str, deviceUUID, b, versionName);

hook到结果:

st=1694351779782&sign=989c40fed76cc5b05b47825524b34e14&sv=122

安卓逆向 - 某东sign(基于unidbg主动调用)_第3张图片

跟进该方法,发现是个接口

安卓逆向 - 某东sign(基于unidbg主动调用)_第4张图片选中该接口,查看其引用。继续跟进去分析代码,最后我们找到该native方法。说明该算法时调用so层的代码生成,我们后面将尝试使用Unidbg主动调用生成该sign。

  public static native String getSignFromJni(Context context, String str, String str2, String str3, String str4, String str5);

安卓逆向 - 某东sign(基于unidbg主动调用)_第5张图片

三、unidbg入门

1、unidbg介绍:允许您模拟 Android 本机库和实验性 iOS 模拟。unidbg 是一款基于 unicorn 和 dynarmic 的逆向工具, 可以直接调用 Android 和 IOS 的 so 文件,无论是黑盒调用 so 层算法,还是白盒 trace 输出 so 层寄存器值变化都是一把利器。官方github: GitHub - zhkl0228/unidbg: Allows you to emulate an Android native library, and an experimental iOS emulation

2、使用前置:需要有一定的Java基础

配置Java环境:推荐Java8

配置maven环境:https://maven.apache.org/download.cgi

开发工具IDEA:IntelliJ IDEA – 领先的 Java 和 Kotlin IDE

3、unidbg官方github有充足的例子,足够我们了解学习它。建议安装官方的流程都学习一遍,这对我们学习unidbg有极大好处。

安卓逆向 - 某东sign(基于unidbg主动调用)_第6张图片

四、基于unidbg主动调用生成sign

1、配置unidbg基础环境,clone官方代码,找到生成sign方法的so, 就是下方的libjdbitmapkit.so

2、编写基础代码,路径需要改成自己的,重点是 vm.callJNI_OnLoad(emulator, module);这步,我们期望能打印出动态注册方法的地址偏移

public class JdSignTest extends AbstractJni {

    private final AndroidEmulator emulator;
    private final VM vm;
    private PKCS7 pkcs7;
    private DvmClass dvmClass = null;

    public JdSignTest(){
        emulator = AndroidEmulatorBuilder.for32Bit().build();
        Memory memory = emulator.getMemory();
        memory.setLibraryResolver(new AndroidResolver(23));
        // 加载 apk
        vm = emulator.createDalvikVM(new File("D:\\resource\\reverse\\jd\\jd_11.3.2.apk"));
        vm.setVerbose(true);
        vm.setJni(this);
        // 加载 so
        DalvikModule dalvikModule = vm.loadLibrary(new File("D:\\resource\\reverse\\jd\\so\\libjdbitmapkit.so"), false);
        Module module = dalvikModule.getModule();
        // 调用 onload
        vm.callJNI_OnLoad(emulator, module);
    }
}

3、运行以上代码,报错了不要慌,这种一般都是so调用了Java层的方法,我们根据提示补充即可。

安卓逆向 - 某东sign(基于unidbg主动调用)_第7张图片

如,以上报错需要补充代码:

    @Override
    public DvmObject getStaticObjectField(BaseVM vm, DvmClass dvmClass, String signature) {
        if ("com/jingdong/common/utils/BitmapkitUtils->a:Landroid/app/Application;".equals(signature)){
            DvmClass dvmClass1 = vm.resolveClass("android/app/Activity");
            return vm.resolveClass("android/app/Application", dvmClass1).newObject(null);
        }
        return super.getStaticObjectField(vm, dvmClass, signature);
    }

unidbg的缺点就是这个,so层可以调用了很多地方,最多的是通过Jni调用Java方法,我们都需要补充上去,特别的费时间。缺的环境可能是:目标函数中通过 JNI 调用到了某个自己的 JAVA 方法、对linux虚拟文件的读写、对资源文件的读写、系统调用、Android系统库SO。

4、将所有缺的环境补全,成功打印出动态注册信息,注意 RegisterNative关键字,这个指的就是注册Java层的native方法,往后翻看到getSignFromJni(),分析其参数,和我们Java层的分析对应上了。

安卓逆向 - 某东sign(基于unidbg主动调用)_第8张图片

5、接下来模拟调用该方法,填充参数。

getSignFromJni(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;

 直接以全类名调用,传的几个参数就是我们在Java层hook到的,都是明文,例:

StringObject str5 = new StringObject(vm,"11.3.2");       
DvmClass obj = vm.resolveClass("com/jingdong/common/utils/BitmapkitUtils");
DvmObject context = vm.resolveClass("android/content/Context").newObject(null);
// 通过方法名称去调用
DvmObject dvmObject = obj.callStaticJniMethodObject(emulator, "getSignFromJni(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
                context, str, str2,
                str3, str4, str5);

调用该方法,再次报错

    public static void main(String[] args) {
        JdSignTest test = new JdSignTest();
        test.getSignFromJni();
    }

安卓逆向 - 某东sign(基于unidbg主动调用)_第9张图片

我们根据报错,继续漫长的补环境。例:

    @Override
    public DvmObject newObjectV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
        if ("java/lang/StringBuffer->()V".equals(signature)){
            return vm.resolveClass("java/lang/StringBuffer").newObject(new StringBuffer());
        }
        if ("java/lang/Integer->(I)V".equals(signature)){
            Integer integer = vaList.getIntArg(0);
            return vm.resolveClass("java/lang/Integer").newObject(integer);
        }
        return super.newObjectV(vm, dvmClass, signature, vaList);
    }

 补环境的过程是漫长且痛苦的,最后跑出结果时也是真的爽

安卓逆向 - 某东sign(基于unidbg主动调用)_第10张图片

收工!

你可能感兴趣的:(爬虫,android,java,爬虫,网络爬虫)