【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.如何判断是静态注册还是动态注册?
- 两种方法都试一下,哪个好用就是哪个


浙公网安备 33010602011771号