Android Uncrackable3中Hook goodbye()函数崩溃及函数名差异问题
关于OWASP Uncrackable3逆向分析的问题解答
问题1:函数名差异的原因
_Z7goodbyev是C++**名字修饰(Name Mangling)**的产物:
- C++支持函数重载,编译器会把函数名、参数类型等信息编码成唯一字符串,避免同名函数冲突。
_Z7goodbyev的解码规则:_Z是修饰标识,7代表原函数名长度,goodbye是函数原名,v表示参数为void。 - Ghidra会自动对导出符号做名字还原(Demangling),将编译器生成的修饰名转换回可读的原函数名,所以显示为
goodbye();而Frida默认直接读取模块导出表中的原始修饰名,不会自动还原。
问题2:Hook goodbye()无效且崩溃的原因
核心原因
- 原函数是noreturn类型:Uncrackable3中的
goodbye()实际功能是直接终止进程(比如调用exit()或abort()),调用它的代码默认程序会在此处退出,完全没有处理函数返回的逻辑。当你强行让它返回后,调用者的执行流程被打乱,后续代码会访问已释放资源或执行非法操作,最终导致栈帧混乱(EIP为0就是栈中返回地址被破坏的典型表现)。 - 检测逻辑不止依赖goodbye():Root/插桩检测是多分支的,即使阻止了
goodbye()的退出,检测代码可能还有其他触发崩溃的逻辑(比如直接修改栈指针、调用其他终止函数)。 - Hook时机滞后:你的脚本在
libc.so的open函数触发时才Hookgoodbye(),但goodbye()可能在open调用前就已执行,导致Hook未生效就触发了检测。
优化建议
- 改用
Interceptor.attach而非Interceptor.replace:只拦截调用不替换函数实现,通过this.return()让函数提前返回,避免破坏原栈帧:
let once_only = 0; Java.perform(function(){ const libfoo = Process.findModuleByName('libfoo.so'); if (libfoo && once_only === 0) { const goodbyeAddr = libfoo.findExportByName('_Z7goodbyev'); if (goodbyeAddr) { Interceptor.attach(goodbyeAddr, { onEnter: function() { console.log('Blocked goodbye() call'); this.return(); // 直接返回,跳过原函数逻辑 } }); once_only = 1; } } });
- 提前Hook时机:不要等到
open调用,脚本启动后直接查找libfoo.so并Hook目标函数,避免错过调用时机。 - 优先Hook检测逻辑本身:确认
check_instrumentation的正确地址(需考虑ASLR偏移、函数入口对齐),如果是布尔型检测函数,用Interceptor.attach修改其返回值,而非替换整个函数。
内容的提问来源于stack exchange,提问作者Reflected Name
相关产品推荐
相关产品推荐

