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

Frida拦截HermesRuntimeImpl::call触发访问违例错误求助

拦截HermesRuntimeImpl::call时调用valueToString触发访问违例的解决方案

问题概述

用Frida拦截React Native安卓应用的HermesRuntimeImpl::call方法,意图提取参数并执行额外操作,但调用jsi::Value::toString时出现访问违例:

Error: access violation accessing 0x500000cf0

现有代码问题分析

核心错误点

  1. Runtime实例误用:当前代码把makeHermesRuntime的函数地址直接当作Runtime实例传入valueToString,但makeHermesRuntime是创建Runtime的工厂函数,并非实例本身,直接传递必然触发非法内存访问。
  2. 成员函数调用逻辑错误:jsi::Value::toString是C++成员函数,第一个参数应为jsi::Value的this指针,第二个是Runtime实例指针,且返回的jsi::String不能直接读取内存,需要调用其utf8()方法获取可读取的字符串。
  3. Runtime实例获取方式无效:当前环境中makeHermesRuntime未被调用,说明Runtime是通过Native层直接传递等其他途径创建的。

原始拦截代码(带错误调用)

let libhermesBaseAddress = Module.findBaseAddress("libhermes.so");
let hermesRuntimeImplCallAddress = libhermesBaseAddress.add(0x1f3931 - 0x00100000);
let runtimePtr = Module.findExportByName("libhermes.so", "_ZN8facebook6hermes17makeHermesRuntimeERKN6hermes2vm13RuntimeConfigE");
let valueToStringAddr = Module.findExportByName("libjsi.so", "_ZNK8facebook3jsi5Value8toStringERNS0_7RuntimeE");

Interceptor.attach(hermesRuntimeImplCallAddress, {
    onEnter: function (args) {
        console.log("HermesRuntimeImpl::call intercepted");

        let func = args[1];
        let jsThis = args[2];
        let jsArgs = args[3];
        let count = args[4];
        
        console.log(`Function: ${func}`);
        console.log(`jsThis: ${jsThis}`);
        console.log(`jsArgs: ${jsArgs}`);
        console.log(`Count: ${count}`);
        console.log(`runtimePtr: ${runtimePtr}`);
        console.log(`valueToStringAddr: ${valueToStringAddr}`);

        let valueToString = new NativeFunction(valueToStringAddr, 'pointer', ['pointer', 'pointer']);
        let resultPtr = valueToString(jsThis, runtimePtr);
        let resultString = Memory.readUtf8String(resultPtr);
        
        console.log("Value to String Result:", resultString);
    }
}); 

修正方案

1. 从拦截上下文获取正确的Runtime实例

HermesRuntimeImpl::call是成员函数,args[0]就是HermesRuntimeImpl的this指针,而HermesRuntimeImpl继承自jsi::Runtime,直接用args[0]作为Runtime实例即可。

2. 修正valueToString的调用逻辑

jsi::Value::toString返回的是jsi::String指针,需要调用jsi::String::utf8()方法才能获取C风格字符串,不能直接读取指针内存。

3. 批量Hook两个HermesRuntimeImpl::call方法

存在两个同名方法(分别处理普通调用和构造函数调用),需同时Hook避免遗漏。

修正后的完整代码

// 加载依赖库基地址
const libhermesBase = Module.findBaseAddress("libhermes.so");
const libjsiBase = Module.findBaseAddress("libjsi.so");

// 替换为你分析得到的两个HermesRuntimeImpl::call偏移(相对于libhermes基地址)
const callOffsets = [
    0x1f3931 - 0x00100000, // 普通调用偏移
    0xXXXXXX - 0x00100000  // 构造函数调用偏移,自行补充
];

// 获取jsi相关函数地址
const valueToStringAddr = Module.findExportByName("libjsi.so", "_ZNK8facebook3jsi5Value8toStringERNS0_7RuntimeE");
const stringUtf8Addr = Module.findExportByName("libjsi.so", "_ZNK8facebook3jsi6String4utf8ERNS0_7RuntimeE");

// 定义Native函数
const valueToString = new NativeFunction(valueToStringAddr, 'pointer', ['pointer', 'pointer']);
const getStringUtf8 = new NativeFunction(stringUtf8Addr, 'pointer', ['pointer', 'pointer']);

// 批量Hook两个call方法
callOffsets.forEach(offset => {
    const callAddr = libhermesBase.add(offset);
    Interceptor.attach(callAddr, {
        onEnter(args) {
            console.log(`[+] Intercepted HermesRuntimeImpl::call at ${callAddr}`);
            
            // args[0]就是HermesRuntime实例
            const runtime = args[0];
            const jsThis = args[2];
            const jsArgs = args[3];
            const argCount = args[4].toUInt32();

            // 转换jsThis为字符串
            try {
                const strPtr = valueToString(jsThis, runtime);
                if (strPtr) {
                    const utf8Ptr = getStringUtf8(strPtr, runtime);
                    const jsThisStr = Memory.readUtf8String(utf8Ptr);
                    console.log(`[jsThis] ${jsThisStr}`);
                }
            } catch (e) {
                console.log(`[-] Failed to convert jsThis: ${e.message}`);
            }

            // 遍历所有参数并转换
            for (let i = 0; i < argCount; i++) {
                const argPtr = jsArgs.add(i * Process.pointerSize);
                const argValue = argPtr.readPointer();
                try {
                    const strPtr = valueToString(argValue, runtime);
                    if (strPtr) {
                        const utf8Ptr = getStringUtf8(strPtr, runtime);
                        const argStr = Memory.readUtf8String(utf8Ptr);
                        console.log(`[Arg ${i}] ${argStr}`);
                    }
                } catch (e) {
                    console.log(`[-] Failed to convert arg ${i}: ${e.message}`);
                }
            }
        }
    });
});

注意事项

  • 偏移地址适配:不同版本的libhermes.so偏移不同,需用IDA/Ghidra重新分析获取正确的HermesRuntimeImpl::call偏移。
  • 异常处理:添加try-catch防止单个参数转换失败导致拦截逻辑崩溃。
  • jsi对象生命周期:不要长时间持有jsi对象指针,避免内存回收导致的访问错误。

内容的提问来源于stack exchange,提问作者Thuwarakan Mohanraj

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 12:54:57