You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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()无效且崩溃的原因

核心原因

  1. 原函数是noreturn类型:Uncrackable3中的goodbye()实际功能是直接终止进程(比如调用exit()或abort()),调用它的代码默认程序会在此处退出,完全没有处理函数返回的逻辑。当你强行让它返回后,调用者的执行流程被打乱,后续代码会访问已释放资源或执行非法操作,最终导致栈帧混乱(EIP为0就是栈中返回地址被破坏的典型表现)。
  2. 检测逻辑不止依赖goodbye():Root/插桩检测是多分支的,即使阻止了goodbye()的退出,检测代码可能还有其他触发崩溃的逻辑(比如直接修改栈指针、调用其他终止函数)。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 19:04:59