zoukankan      html  css  js  c++  java
  • 爬虫工程师的unidbg入门教程

    • 现在很多的app使用了so加密,以后会越来越多。爬虫工程师可能会直接逆向app,看java代码,完成java层的算法破解,但是如果遇到so该怎么办呢?可能你会直接破解so,但是真的会有很多爬虫工程师会去并且会破解so吗?有时候我们可以不用破解so,利用很多大佬写好的轮子即可完成so的调用。
    • 说到调用,就有很多方法了,比如用frida的rpc、xposed+andserver、再者就是unicorn+web框架等等,今天要说的并不是这些,而是unidbg,这框架有什么好的地方呢?看看介绍。

    介绍(来自逸飞)

    unidbg 是一个基于 unicorn 的逆向工具,可以黑盒调用安卓和 iOS 中的 so 文件。unidbg 是一个标准的 java 项目。

    由于现在的大多数 app 把签名算法已经放到了 so 文件中,所以要想破解签名算法,必须能够破解 so 文件。但是我们知道,C++ 的逆向远比 Java 的逆向要难得多了,所以好多时候是没法破解的,那么这个时候还可以采用 hook 的方法,直接读取程序中算出来的签名,但是这样的话,需要实际运行这个应用,需要模拟器或者真机,效率又不是很高。

    unidbg 就是一个很巧妙地解决方案,他不需要直接运行 app,也无需逆向 so 文件,而是通过在 app 中找到对应的 JNI 接口,然后用 unicorn 引擎直接执行这个 so 文件,所以效率也比较高。

    • 这里重要的是目前利用unidbg+springboot做成了web服务。

    食用

    案例来自JXU2QkQyYXBwJTIwdjQuMTYuMA==
    对于该app而言,是非常适合入门的一个app,未加固、算法简单、很容易找到so的jni。
    先去凯神的github上下载https://github.com/zhkl0228/unidbg
    下载完毕用idea打开,等待maven下载完毕。我这里已经创建好du的文件。


    上个代码看着比较方便,代码中有很多注释

    public class du extends AbstractJni {
    
        //ARM模拟器
        private final ARMEmulator emulator;
        //vm
        private final VM vm;
        //载入的模块
        private final Module module;
    
        private final DvmClass TTEncryptUtils;
    
        //初始化
        public du() throws IOException {
            //创建app进程,这里其实可以不用写的,我这里是随便写的,使用app本身的进程就可以绕过进程检测
            emulator = new AndroidARMEmulator("com.du.du");
            Memory memory = emulator.getMemory();
            //作者支持19和23两个sdk
            memory.setLibraryResolver(new AndroidResolver(23));
            memory.setCallInitFunction();
            //创建DalvikVM,利用apk本身,可以为null
            //如果用apk文件加载so的话,会自动处理签名方面的jni,具体可看AbstractJni,利用apk加载的好处,
    //        vm = emulator.createDalvikVM(new File("src/test/resources/du/du4160.apk"));
    我这里没有用到apk,主要是没有检测其他因素。
            vm = emulator.createDalvikVM(null);
            //加载so,使用armv8-64速度会快很多,这里是so的文件路径,其实也可以利用apk自身的。
            DalvikModule dm = vm.loadLibrary(new File("src/test/resources/du/libJNIEncrypt.so"), false);
            //调用jni
            dm.callJNI_OnLoad(emulator);
            module = dm.getModule();
            //加载so的那个类
            TTEncryptUtils = vm.resolveClass("com/duapp/aesjni/AESEncrypt");
        }
    
    
        //关闭模拟器
        private void destroy() throws IOException {
            emulator.close();
            System.out.println("destroy");
        }
    
        public static void main(String[] args) throws IOException {
            du t = new du();
            t.encodeByte();
            t.destroy();
        }
    
        private String encodeByte() {
            //调试
            // 这里还支持gdb调试,
            //emulator.attach(DebuggerType.GDB_SERVER);
            //附加调试器
    //        emulator.attach(DebuggerType.SIMPLE);
    //        emulator.traceCode();
            //这里是打断点,原地址0x00005028->新地址0x40005028 新地址需要改成0x4 
    //        emulator.attach().addBreakPoint(null, 0x40001188);//encode地址
    //        emulator.attach().addBreakPoint(null, 0x40000D10);
            Number ret = TTEncryptUtils.callStaticJniMethod(emulator, "getByteValues()Ljava/lang/String;");
            long hash = ret.intValue() & 0xffffffffL;
            StringObject st1 = vm.getObject(hash);
            //*这里要处理下字符串
            String byteString = st1.getValue();
            StringBuilder builder = new StringBuilder(byteString.length());
            for (int i = 0; i < byteString.length(); i++) {
                if (byteString.charAt(i) == '0') {
                    builder.append('1');
                } else {
                    builder.append('0');
                }
            }
            //获取encodeByte地址
            ret = TTEncryptUtils.callStaticJniMethod(emulator, "encodeByte(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
                    //传参,这里需要两个字符串,所以就传入两个参数
                    vm.addLocalObject(new StringObject(vm, "要加密的值")),
                    vm.addLocalObject(new StringObject(vm, builder.toString())));
            //ret 返回的是地址,
            hash = ret.intValue() & 0xffffffffL;
            //获得其值
            StringObject str = vm.getObject(hash);
            System.out.println(str.getValue());
            return str.getValue();
        }
    }
    

    上边代码有jni的类是哪一个需要知道,就是下面这个类,这个其实是和加载so有关系的。

    TTEncryptUtils = vm.resolveClass("com/*/aesjni/AESEncrypt");
    我们需要逆向app,这里不细说如何在app中寻找加载so的类。如下图,encodeByte是该app调用native层加密的入口,loadLibrary是java加载so的方法,这个类就是上述代码中填写的。


    然后再看"encodeByte(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"这里,这是smali写法,不补基础,后面跟上需要传的参数,
    getByteValues 这个方法是毒获取的一个01字符串,并且在java层进行了处理,然后再传进encodeByte里面,encodeByte这个方法最后获取的其实并不是最终需要的,需要md5才是最后的newSign。可以验证一下下。


    测试结果通过。

    最后

    启动java文件时候注意这个改成自己的平台!!!

    VM options: -Djava.library.path=prebuilt/os -Djna.library.path=prebuilt/os
    Where os may: linux64, win32, win64, osx64
    

    在这里插入图片描述

    最后这个文件放在https://github.com/zhaoboy9692/dailyanalysis喜欢的可以star,谢谢。

  • 相关阅读:
    oracle的安装与plsql的环境配置
    Working with MSDTC
    soapui-java.lang.Exception Failed to load url
    Oracle 一个owner访问另一个owner的table,不加owner
    Call API relation to TLS 1.2
    Call API HTTP header Authorization: Basic
    VS2008 .csproj cannot be opened.The project type is not supported by this installat
    The changes couldn't be completed.Please reboot your computer and try again.
    Create DB Table View Procedure
    DB Change
  • 原文地址:https://www.cnblogs.com/xbjss/p/13326639.html
Copyright © 2011-2022 走看看