【APP逆向40】寻找SO文件

  • 前言:当我们在寻找逆向入口时,碰到native方法,就说明加密在C语言中实现,一般来说,native方法附近会有loadlibrary告诉你,加密函数在哪个so文件中实现,但是也有比较特殊的,如下:

  • 1.碰到这种情况,我们该如何处理勒?分为两种情况,一种是静态注册,一种是动态注册

    • 1.1,如果是静态注册
Java.perform(function () {
    var dlsymadd = Module.findExportByName("libdl.so", 'dlsym');
    Interceptor.attach(dlsymadd, {
        onEnter: function (args) {
            this.info = args[1];

        }, onLeave: function (retval) {
            //那个so文件 module.name
            var module = Process.findModuleByAddress(retval);
            if (module == null) {
                return retval;
            }
            // native方法
            var funcName = this.info.readCString();

            //getHNASignature,对应的方法名称
            if (funcName.indexOf("getHNASignature") !== -1) {
                console.log(module.name);
                console.log('\t', funcName);
            }
            return retval;
        }
    })
});


// Application(identifier="com.rytong.hnair", name="海南航空", pid=14958, parameters={})
// frida -U -f  com.rytong.hnair  -l static_find_so.js

  • 1.2:动态注册
var symbols = Module.enumerateSymbolsSync("libart.so");
var addrRegisterNatives = null;
for (var i = 0; i < symbols.length; i++) {
    var symbol = symbols[i];
    if (symbol.name.indexOf("art") >= 0 &&
        symbol.name.indexOf("JNI") >= 0 &&
        symbol.name.indexOf("RegisterNatives") >= 0 &&
        symbol.name.indexOf("CheckJNI") < 0) {
        addrRegisterNatives = symbol.address;
        console.log("RegisterNatives is at ", symbol.address, symbol.name);
    }
}
console.log("addrRegisterNatives=", addrRegisterNatives);

if (addrRegisterNatives != null) {
    Interceptor.attach(addrRegisterNatives, {
        onEnter: function (args) {
            var env = args[0];
            var java_class = args[1];
            var class_name = Java.vm.tryGetEnv().getClassName(java_class);
            // 只有类名为com.bilibili.nativelibrary.LibBili,才打印输出
            
            // 对应的包名类名
            var taget_class = "com.xunmeng.pinduoduo.secure.DeviceNative";
            
            if (class_name === taget_class) {
                console.log("\n[RegisterNatives] method_count:", args[3]);
                var methods_ptr = ptr(args[2]);
                var method_count = parseInt(args[3]);

                for (var i = 0; i < method_count; i++) {
                    // Java中函数名字的
                    var name_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3));
                    // 参数和返回值类型
                    var sig_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize));
                    // C中的函数指针
                    var fnPtr_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize * 2));

                    var name = Memory.readCString(name_ptr); // 读取java中函数名
                    var sig = Memory.readCString(sig_ptr); // 参数和返回值类型
                    var find_module = Process.findModuleByAddress(fnPtr_ptr); // 根据C中函数指针获取模块

                    var offset = ptr(fnPtr_ptr).sub(find_module.base) // fnPtr_ptr - 模块基地址
                    // console.log("[RegisterNatives] java_class:", class_name);
                    console.log("name:", name, "sig:", sig, "module_name:", find_module.name, "offset:", offset);
                    //console.log("name:", name, "module_name:", find_module.name, "offset:", offset);

                }
            }
        }
    });
}

// frida -U -f  com.xunmeng.pinduoduo  -l dynamic_find_so.js
  • 2.如何判断是静态注册还是动态注册?
    • 两种方法都试一下,哪个好用就是哪个
posted @ 2025-04-18 19:33  Tony_xiao  阅读(87)  评论(0)    收藏  举报