文章总结: 记录使用FridaHook动态注册函数RegisterNatives的实战经历。在静态确认调用关系后Hook失败,排查发现libart.so中存在CheckJNI与非CheckJNI两个版本符号导致拦截失效。通过分析符号地址并指定正确目标进行拦截,最终成功捕获方法信息,解决了多符号环境下的Hook难题。 综合评分: 85 文章分类: 移动安全,逆向分析,实战经验
【APP测试】某次hook动态注册的踩坑经历
原创
d0n9x1e d0n9x1e
蝉SEC
2026年1月15日 14:16 江苏
frida首先,上一段hook_RegisterNatives代码
function hook_RegisterNatives() {
var RegisterNatives_addr = null;
var symbols = Process.findModuleByName("libart.so").enumerateSymbols();
for (var i = 0; i < symbols.length; i++) {
var symbol = symbols[i].name;
if ((symbol.indexOf("CheckJNI") == -1) && (symbol.indexOf("JNI") >= 0)) {
if (symbol.indexOf("RegisterNatives") >= 0) {
RegisterNatives_addr = symbols[i].address;
console.log("RegisterNatives_addr: ", RegisterNatives_addr);
}
}
}
Interceptor.attach(RegisterNatives_addr, {
onEnter: function (args) {
var env = args[0];
var jclass = args[1];
var class_name = Java.vm.tryGetEnv().getClassName(jclass);
var methods_ptr = ptr(args[2]);
var method_count = args[3].toInt32();
console.log("RegisterNatives method counts: ", method_count);
for (var i = 0; i < method_count; i++) {
var name = methods_ptr.add(i * Process.pointerSize * 3).readPointer().readCString();
var sig = methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize).readPointer().readCString();
var fnPtr_ptr = methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize * 2).readPointer();
var find_module = Process.findModuleByAddress(fnPtr_ptr);
console.log("类: ", class_name, "方法: ", name, "签名: ", sig, "函数地址: ", fnPtr_ptr, "模块名: ", find_module.name, "函数偏移: ", ptr(fnPtr_ptr).sub(find_module.base));
}
},
onLeave: function (retval) {}
});
}
hook_RegisterNatives()
通过ida可以很明确的看到调用了动态注册函数
但是怎么都hook不到
很奇怪,不可能的啊,明明静态看的时候调用了
打印出addr_RegisterNatives地址查看
function hook_dlopen(so_name) {
Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"), {
onEnter: function (args) {
var pathptr = args[0];
if (pathptr !== undefined && pathptr != null) {
var path = ptr(pathptr).readCString();
// console.log(path)
if (path.indexOf(so_name) !== -1) {
this.match = true
}
}
},
onLeave: function (retval) {
if (this.match) {
console.log(so_name, "加载成功")
// var base = Module.findBaseAddress("libhello-jni.so")
// console.log(hexdump(base.add(0x37070),{
// length: 200,
// header: true,
// ansi: true
// }))
}
}
});
}
function hook_RegisterNatives() {
var addr_RegisterNatives = null;
var symbols = Process.findModuleByName("libart.so").enumerateSymbols();
for (var i = 0; i < symbols.length; i++) {
var symbol = symbols[i].name;
if ((symbol.indexOf("CheckJNI") == -1) && (symbol.indexOf("JNI") >= 0)) {
if (symbol.indexOf("RegisterNatives") >= 0) {
addr_RegisterNatives = symbols[i].address;
console.log("addr_RegisterNatives: ", addr_RegisterNatives);
}
}
}
//赋值addr_RegisterNatives1地址0x71676be210
// var addr_RegisterNatives1 = ptr("0x71676be210");
console.log("addr_RegisterNatives==",addr_RegisterNatives)
if (addr_RegisterNatives) {
Interceptor.attach(addr_RegisterNatives, {
onEnter: function (args) {
var java_class = Java.vm.tryGetEnv().getClassName(args[1]);
var methods = args[2];
var method_count = parseInt(args[3]);
console.log("addr_RegisterNatives java_class:", java_class, "method_count:", method_count);
for (var i = 0; i < method_count; i++) {
console.log(methods.add(i * Process.pointerSize * 3).readPointer().readCString());
console.log(methods.add(i * Process.pointerSize * 3 + Process.pointerSize).readPointer().readCString());
var fnPtr = methods.add(i * Process.pointerSize * 3 + Process.pointerSize * 2).readPointer();
var module_so = Process.findModuleByAddress(fnPtr);
console.log("=====================")
console.log(module_so.name + "!" + fnPtr.sub(module_so.base));
console.log("=====================")
}
}, onLeave: function (retval) {
}
})
}
}
function main(){
Java.perform(function () {
hook_RegisterNatives();
hook_dlopen("libhello-jni.so");
});
}
setImmediate(main)
怎么有两个addr_RegisterNatives
询问gpt
RegisterNatives的地址问题
你通过 Module.enumerateSymbolsSync("libart.so") 找到了两个 RegisterNatives 的地址,分别是:
复制
0x71676be210 _ZN3art3JNIILb0EE15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi
0x716771ece8 _ZN3art3JNIILb1EE15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi
这两个地址分别对应于 非 CheckJNI 模式 和 CheckJNI 模式 的 RegisterNatives 实现。通常情况下,实际使用的地址取决于应用是否启用了 CheckJNI 模式。
- CheckJNI 模式:用于调试目的,会进行额外的检查以确保 JNI 调用的正确性。
- 非 CheckJNI 模式:用于生产环境,性能更好。
如果你的应用启用了 CheckJNI 模式,那么应该拦截的是第二个地址(0x716771ece8)。否则,应该拦截第一个地址(0x71676be210)。你需要确认应用是否启用了 CheckJNI 模式,并选择正确的地址进行拦截。
好吧我们来hook另一个addr_RegisterNatives
function hook_dlopen(so_name) {
Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"), {
onEnter: function (args) {
var pathptr = args[0];
if (pathptr !== undefined && pathptr != null) {
var path = ptr(pathptr).readCString();
// console.log(path)
if (path.indexOf(so_name) !== -1) {
this.match = true
}
}
},
onLeave: function (retval) {
if (this.match) {
console.log(so_name, "加载成功")
// var base = Module.findBaseAddress("libhello-jni.so")
// console.log(hexdump(base.add(0x37070),{
// length: 200,
// header: true,
// ansi: true
// }))
}
}
});
}
function hook_RegisterNatives() {
var addr_RegisterNatives = null;
var symbols = Process.findModuleByName("libart.so").enumerateSymbols();
for (var i = 0; i < symbols.length; i++) {
var symbol = symbols[i].name;
if ((symbol.indexOf("CheckJNI") == -1) && (symbol.indexOf("JNI") >= 0)) {
if (symbol.indexOf("RegisterNatives") >= 0) {
addr_RegisterNatives = symbols[i].address;
console.log("addr_RegisterNatives: ", addr_RegisterNatives);
}
}
}
//赋值addr_RegisterNatives1地址0x71676be210
var addr_RegisterNatives1 = ptr("0x71676be210");
console.log("addr_RegisterNatives==",addr_RegisterNatives)
if (addr_RegisterNatives) {
Interceptor.attach(addr_RegisterNatives1, {
onEnter: function (args) {
var env = args[0];
var jclass = args[1];
var class_name = Java.vm.tryGetEnv().getClassName(jclass);
var methods_ptr = ptr(args[2]);
var method_count = args[3].toInt32();
console.log("RegisterNatives method counts: ", method_count);
for (var i = 0; i < method_count; i++) {
var name = methods_ptr.add(i * Process.pointerSize * 3).readPointer().readCString();
var sig = methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize).readPointer().readCString();
var fnPtr_ptr = methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize * 2).readPointer();
var find_module = Process.findModuleByAddress(fnPtr_ptr);
console.log("类: ", class_name, "方法: ", name, "签名: ", sig, "函数地址: ", fnPtr_ptr, "模块名: ", find_module.name, "函数偏移: ", ptr(fnPtr_ptr).sub(find_module.base));
}
},
onLeave: function (retval) {}
})
}
}
function main(){
Java.perform(function () {
hook_RegisterNatives();
hook_dlopen("libhello-jni.so");
});
}
setImmediate(main)
终于得到了┭┮﹏┭┮
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:蝉SEC d0n9x1e d0n9x1e《【APP测试】某次hook动态注册的踩坑经历》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。








评论