如何用Frida钩子CURLNetRequest结构体的user与password成员
Frida钩子C++结构体成员获取username和password
问题背景
用户基于RhodeMobile构建的应用,需要通过Frida钩子librhodes.so中CURLNetRequest类下两个结构体的user、password等成员,但当前代码仅能获取到AuthMethod值,需调整实现逻辑。
目标C++代码片段
class CURLNetRequest : public CNetRequestBase { DEFINE_LOGCLASS; struct ProxySettings { void initFromConfig(); String host; int port; String username; String password; }; struct AuthSettings { AuthSettings( AuthMethod m, const String& u, const String& p ) : method(m) , user(u) , password(p) {} const AuthMethod method; const String user; const String password; }; ...
当前Frida代码
const some_func_pointer = Module.getExportByName('librhodes.so', '_ZN3rho3net14CURLNetRequest10CURLHolder11set_optionsEPKcRKNSt6__ndk112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEESD_PNS0_11IRhoSessionEPNS_9HashtableISB_SB_EERKNS1_13ProxySettingsERKNS1_12AuthSettingsE'); const some_func = new NativeFunction(some_func_pointer, "void", ["int", "pointer"]); Interceptor.replace(some_func_pointer, new NativeCallback(function (size, data) { console.log(size) console.log(data.readUtf8String()) some_func(size, data); }, "void", ["int", "pointer"]));
解决方案
核心问题是函数签名不匹配和结构体成员内存偏移计算错误,以下是修正后的实现:
1. 修正函数参数签名
原函数的demangled名称对应的参数列表需严格匹配,64位架构下参数类型定义如下(32位需将指针长度改为4字节):
const some_func = new NativeFunction(some_func_pointer, 'void', [ 'pointer', // const char* 'pointer', // std::string& 'pointer', // std::string& 'pointer', // IRhoSession* 'pointer', // Hashtable& 'pointer', // ProxySettings& 'pointer' // AuthSettings& ]);
2. 编写字符串读取辅助函数
Rhodes中String对应NDK的std::__ndk1::basic_string,内部布局为[data_ptr, size, capacity],封装读取逻辑:
function readStdString(strPtr) { const dataPtr = strPtr.readPointer(); return dataPtr ? dataPtr.readUtf8String() : ''; }
3. 钩子函数读取结构体成员
根据结构体内存对齐规则,计算成员偏移并读取:
Interceptor.replace(some_func_pointer, new NativeCallback(function (url, str1, str2, session, hashtable, proxySettings, authSettings) { // 读取AuthSettings成员(64位架构示例) const authMethod = authSettings.readInt(); const userStrPtr = authSettings.add(8); // 偏移8字节到user成员 const passwordStrPtr = authSettings.add(24); // 偏移24字节到password成员 console.log(`AuthMethod: ${authMethod}`); console.log(`Username: ${readStdString(userStrPtr)}`); console.log(`Password: ${readStdString(passwordStrPtr)}`); // 读取ProxySettings成员(64位架构示例) const proxyHostPtr = proxySettings.readPointer(); const proxyPort = proxySettings.add(8).readInt(); const proxyUserPtr = proxySettings.add(16); const proxyPassPtr = proxySettings.add(32); console.log(`Proxy Host: ${readStdString(proxyHostPtr)}`); console.log(`Proxy Port: ${proxyPort}`); console.log(`Proxy Username: ${readStdString(proxyUserPtr)}`); console.log(`Proxy Password: ${readStdString(proxyPassPtr)}`); // 调用原函数 some_func(url, str1, str2, session, hashtable, proxySettings, authSettings); }, 'void', [ 'pointer', 'pointer', 'pointer', 'pointer', 'pointer', 'pointer', 'pointer' ]));
4. 32位架构适配
若为32位ARM,指针长度为4字节,结构体偏移需调整:
AuthSettings:method占4字节,user偏移4字节,password偏移16字节ProxySettings:host偏移0,port偏移4,username偏移16,password偏移28
注意事项
- 结构体偏移需结合反编译
librhodes.so的结果确认,不同编译器的对齐规则可能导致偏移变化 - 若Rhodes使用自定义
String类,需根据其内部布局修改readStdString函数逻辑
内容的提问来源于stack exchange,提问作者hanan
相关产品推荐
相关产品推荐

