当前位置: 首页 > news >正文

frida对qt5(32位)实现简单HOOK

frida对qt5(32位)实现简单HOOK

注意

关于在使用getExportByName是要根据实际情况来修改,可以使用ida或者x32dbg来搜索函数,例如QJsonDocument::fromJson,如下图则就是他的签名
在这里插入图片描述

https抓包

function findExportByNameAddress(targetDLL, funcName) {// 查找指定模块const module = Process.findModuleByName(targetDLL);if (!module) {console.error(`[!] 找不到模块: ${targetDLL}`);return;}// 获取模块的所有导出函数const exports = module.enumerateExports();for (let i = 0; i < exports.length; i++) {// console.log(`[+] 找到 ${targetDLL} 的 ${exports[i].name} 地址: ${exports[i].address}`);if (exports[i].name === funcName) {return exports[i].address;}}return null;
}const sslBufferMap = {}; // 保存请求缓存(按连接)
const sslRespMap = {}; // 保存响应缓存(按连接)function parseHttpMessagesFromBuffer(buffer, isRequest = true) {const messages = [];let offset = 0;const totalLen = buffer.byteLength;const uint8 = new Uint8Array(buffer);while (offset < totalLen) {const remaining = totalLen - offset;const dataSlice = uint8.slice(offset);const str = String.fromCharCode.apply(null, dataSlice);const headerEnd = str.indexOf("\r\n\r\n");if (headerEnd === -1) break;const headerPart = str.slice(0, headerEnd);const lines = headerPart.split("\r\n");if (!lines[0]) break;const statusLine = lines[0];const headers = [];let contentLength = 0;for (let i = 1; i < lines.length; i++) {const line = lines[i];const [key, value] = line.split(/:\s*/);if (!key || !value) continue;headers.push({ key, value });if (key.toLowerCase() === "content-length") {contentLength = parseInt(value);}}const bodyStart = headerEnd + 4;const totalMsgLength = bodyStart + contentLength;if (remaining < totalMsgLength) break;const body = String.fromCharCode.apply(null,uint8.slice(offset + bodyStart, offset + totalMsgLength));messages.push({startLine: statusLine,headers,body,});offset += totalMsgLength;}const leftover = uint8.slice(offset);return {messages,remaining: leftover,};
}function printHttpRequest(req) {console.log("\n========== HTTP Request ==========");const [method, path] = req.startLine.split(" ");let host = "";for (const { key, value } of req.headers) {if (key.toLowerCase() === "host") host = value;}const url = host ? `https://${host}${path}` : path;console.log("URL:", url);console.log("Method:", method);for (const { key, value } of req.headers) {console.log(`${key}: ${value}`);}console.log("");console.log(req.body);
}function printHttpResponse(resp) {console.log("\n========== HTTP Response ==========");console.log(resp.startLine);for (const { key, value } of resp.headers) {console.log(`${key}: ${value}`);}console.log("");console.log(resp.body);
}const ssl_write_ptr = findExportByNameAddress("libssl-1_1.dll", "SSL_write");
const ssl_read_ptr = findExportByNameAddress("libssl-1_1.dll", "SSL_read");if (ssl_write_ptr !== null) {Interceptor.attach(ssl_write_ptr, {onEnter: function (args) {const ssl = args[0];const buf = args[1];const len = args[2].toInt32();const sslId = ssl.toString();const chunk = Memory.readByteArray(buf, len);if (!chunk) return;if (!sslBufferMap[sslId]) sslBufferMap[sslId] = new Uint8Array();const prevBuf = sslBufferMap[sslId];const newBuf = new Uint8Array(prevBuf.length + chunk.byteLength);newBuf.set(prevBuf, 0);newBuf.set(new Uint8Array(chunk), prevBuf.length);const { messages, remaining } = parseHttpMessagesFromBuffer(newBuf.buffer,true);for (const req of messages) {printHttpRequest(req);}sslBufferMap[sslId] = remaining;},});
}if (ssl_read_ptr !== null) {Interceptor.attach(ssl_read_ptr, {onEnter: function (args) {this.ssl = args[0];  // 保存 SSL* 指针this.buf = args[1];  // 读取缓冲区指针},onLeave: function (retval) {const len = retval.toInt32();if (len <= 0) return;const sslId = this.ssl.toString();const chunk = Memory.readByteArray(this.buf, len);if (!chunk) return;if (!sslRespMap[sslId]) sslRespMap[sslId] = new Uint8Array();const prevBuf = sslRespMap[sslId];const newBuf = new Uint8Array(prevBuf.length + chunk.byteLength);newBuf.set(prevBuf, 0);newBuf.set(new Uint8Array(chunk), prevBuf.length);const { messages, remaining } = parseHttpMessagesFromBuffer(newBuf.buffer, false);for (const resp of messages) {printHttpResponse(resp);}sslRespMap[sslId] = remaining;}});
}

QString抓包

// 获取模块及导出函数地址
const qtCore = Process.getModuleByName("Qt5Core.dll");
const toUtf8Addr = qtCore.getExportByName("?toUtf8@QString@@QBE?AVQByteArray@@XZ"
);
const byteArrayDataAddr = qtCore.getExportByName("?data@QByteArray@@QBEPBDXZ");
const QStringCtorAddr = qtCore.getExportByName("??0QString@@QAE@XZ");
const fromUtf8Addr = qtCore.getExportByName("?fromUtf8@QString@@SA?AV1@PBDH@Z");// 创建 NativeFunction,指定 ABI 和 exceptions
const toUtf8 = new NativeFunction(toUtf8Addr, "void", ["pointer", "pointer"], {abi: "thiscall",
});const byteArrayData = new NativeFunction(byteArrayDataAddr,"pointer",["pointer"],{abi: "thiscall",}
);const QStringCtor = new NativeFunction(QStringCtorAddr,"pointer",["pointer"],{ abi: "thiscall" }
);const fromUtf8 = new NativeFunction(fromUtf8Addr, "void", ["pointer","pointer","int",
]);// 测试函数:创建 QString、转成 QByteArray、读取 UTF8
// create QString
function convertStringToQString(stringInput) {var cStrPointer = Memory.allocUtf8String(stringInput);var retQString = Memory.alloc(Process.pointerSize * 3);fromUtf8(retQString, cStrPointer, -1);return retQString;
}
function convertQStringToString(qstrPtr) {const ba = Memory.alloc(0x30);toUtf8(qstrPtr, ba);console.log("QString 转成 QByteArray 已调用", ba);const utf8p = byteArrayData(ba);return utf8p.readUtf8String();
}// 🚀 测试过程
const qstr = convertStringToQString("nihao");
console.log("转换结果:", convertQStringToString(qstr));

QJsonObject.Insert

const qtCore = Process.getModuleByName("Qt5Core.dll");const fromUtf8Addr = qtCore.getExportByName("?fromUtf8@QString@@SA?AV1@PBDH@Z");
const fromUtf8 = new NativeFunction(fromUtf8Addr, "void", ["pointer","pointer","int",
]);const toUtf8Addr = qtCore.getExportByName("?toUtf8@QString@@QBE?AVQByteArray@@XZ"
);
const toUtf8 = new NativeFunction(toUtf8Addr, "void", ["pointer", "pointer"], {abi: "thiscall",
});const byteArrayDataAddr = qtCore.getExportByName("?data@QByteArray@@QBEPBDXZ");
const dataFunc = new NativeFunction(byteArrayDataAddr, "pointer", ["pointer"], {abi: "thiscall",
});
const QJSONValuetoStringAddr = qtCore.getExportByName("?toString@QJsonValue@@QBE?AVQString@@XZ"
);
const QJSONValuetoString = new NativeFunction(QJSONValuetoStringAddr,"void",["pointer", "pointer"],{abi: "thiscall",}
);
const QJsonObjectInsertAddr = qtCore.getExportByName("?insert@QJsonObject@@QAE?AViterator@1@ABVQString@@ABVQJsonValue@@@Z"
);
let sub_671D04C0Addr = qtCore.base.add(0x1d04c0);
//获取double
let sub_671D04C0 = new NativeFunction(sub_671D04C0Addr, "int", ["int64"]);
function convertQStringToString(qStringInput) {const qByteArrayBuf = Memory.alloc(0x30);toUtf8(qStringInput, qByteArrayBuf);const utf8Ptr = dataFunc(qByteArrayBuf);return utf8Ptr.readUtf8String();
}
function convertQStringToString2(qStringInput) {const ptrArrayDataBuf = Memory.alloc(0x30); // 通常 QArrayData 结构体至少 0x30 字节ptrArrayDataBuf.writeU8(4);let result = test(qStringInput, ptrArrayDataBuf);console.log(result);console.log(hexdump(ptrArrayDataBuf, { length: 0x40 }));return ptrArrayDataBuf;
}
function convertStringToQString(stringInput) {const cStrPointer = Memory.allocUtf8String(stringInput);const QStringSize = 0x30;var retQString = Memory.alloc(QStringSize);// qstringCtor(retQString,cStrPointer);fromUtf8(retQString, cStrPointer, -1);return retQString;
}
function convertQJsonValueToString(qjsonValuePtr) {const qstringBuf = Memory.alloc(Process.pointerSize * 3); // QString resultconst qbyteArrayBuf = Memory.alloc(Process.pointerSize * 3); // QByteArray tempQJSONValuetoString(qjsonValuePtr, qstringBuf); // 调用 QJsonValue::toString()toUtf8(qstringBuf, qbyteArrayBuf); // 转 QByteArrayconst utf8StrPtr = dataFunc(qbyteArrayBuf); // 得到 char* 指针return utf8StrPtr.readUtf8String(); // 返回 JS 字符串
}function toString(qStringPtr) {let size = qStringPtr.add(0x04).readU32();let offset = qStringPtr.add(0x0c).readU32();let result = qStringPtr.add(offset).readUtf16String(size);return result;
}
Interceptor.attach(QJsonObjectInsertAddr, {onEnter: function (args) {const keyQString = args[1];const valuePtr = args[2];const keyStr = convertQStringToString(keyQString);const typeOffset = 0x0c;const valueType = valuePtr.add(typeOffset).readU32();if (valueType === 3) {console.log("key:",keyStr,"value:",convertQJsonValueToString(valuePtr));} else if (valueType === 2) {// Frida 读取低 32 位和高 32let low = Memory.readU32(valuePtr); // *(DWORD*)a1let high = Memory.readU32(valuePtr.add(4)); // *((DWORD*)a1 + 1)// 组装成 int64let full = (BigInt(high) << 32n) | BigInt(low);let result = sub_671D04C0(full);console.log("key:", keyStr, "value:", result);}},onLeave: function (retval) {},
});

json

const qtCore = Process.getModuleByName("Qt5Core.dll");const fromUtf8Addr = qtCore.getExportByName("?fromUtf8@QString@@SA?AV1@PBDH@Z");
const fromUtf8 = new NativeFunction(fromUtf8Addr, "void", ["pointer","pointer","int",
]);const toUtf8Addr = qtCore.getExportByName("?toUtf8@QString@@QBE?AVQByteArray@@XZ"
);
const toUtf8 = new NativeFunction(toUtf8Addr, "void", ["pointer", "pointer"], {abi: "thiscall",
});const byteArrayDataAddr = qtCore.getExportByName("?data@QByteArray@@QBEPBDXZ");
const dataFunc = new NativeFunction(byteArrayDataAddr, "pointer", ["pointer"], {abi: "thiscall",
});
const QJSONValuetoStringAddr = qtCore.getExportByName("?toString@QJsonValue@@QBE?AVQString@@XZ"
);
const QJSONValuetoString = new NativeFunction(QJSONValuetoStringAddr,"void",["pointer", "pointer"],{abi: "thiscall",}
);
const fromJsonPtr = qtCore.getExportByName("?fromJson@QJsonDocument@@SA?AV1@ABVQByteArray@@PAUQJsonParseError@@@Z"
);
let fromJson = new NativeFunction(fromJsonPtr, "pointer", ["pointer","pointer",
]);
const toJsonPtr = qtCore.getExportByName("?toJson@QJsonDocument@@QBE?AVQByteArray@@W4JsonFormat@1@@Z"
);
let toJson = new NativeFunction(toJsonPtr, "void", ["pointer", "pointer"], {abi: "thiscall",
});
let sub_671D04C0Addr = qtCore.base.add(0x1d04c0);
//获取double
let sub_671D04C0 = new NativeFunction(sub_671D04C0Addr, "int", ["int64"]);
function convertQStringToString(qStringInput) {const qByteArrayBuf = Memory.alloc(0x30);toUtf8(qStringInput, qByteArrayBuf);const utf8Ptr = dataFunc(qByteArrayBuf);return utf8Ptr.readUtf8String();
}function convertStringToQString(stringInput) {const cStrPointer = Memory.allocUtf8String(stringInput);const QStringSize = 0x30;var retQString = Memory.alloc(QStringSize);// qstringCtor(retQString,cStrPointer);fromUtf8(retQString, cStrPointer, -1);return retQString;
}
function convertQJsonValueToString(qjsonValuePtr) {const qstringBuf = Memory.alloc(Process.pointerSize * 3); // QString resultconst qbyteArrayBuf = Memory.alloc(Process.pointerSize * 3); // QByteArray tempQJSONValuetoString(qjsonValuePtr, qstringBuf); // 调用 QJsonValue::toString()toUtf8(qstringBuf, qbyteArrayBuf); // 转 QByteArrayconst utf8StrPtr = dataFunc(qbyteArrayBuf); // 得到 char* 指针return utf8StrPtr.readUtf8String(); // 返回 JS 字符串
}function toString(qStringPtr) {let size = qStringPtr.add(0x04).readU32();let offset = qStringPtr.add(0x0c).readU32();let result = qStringPtr.add(offset).readUtf16String(size);return result;
}
Interceptor.attach(fromJsonPtr, {onEnter: function (args) {this.inputDataPtr = args[0]; // QByteArray*},onLeave: function (retval) {// retval 是 QJsonDocument*if (retval.isNull()) {console.log("fromJson returned null");return;}const resultQByteArrayPtr = Memory.alloc(0x30);// 调用 QJsonDocument::toJson(this)toJson(retval, resultQByteArrayPtr); // QByteArray*const utf8StrPtr = dataFunc(resultQByteArrayPtr); // 得到 char* 指针let result = utf8StrPtr.readUtf8String();console.log("拦截到数据", result);},
});
http://www.xdnf.cn/news/1024201.html

相关文章:

  • java中的类与对象
  • 文件系统1(Linux中)
  • 纪念2024.10-2025.6飞牛os的6次系统崩溃
  • 大矩阵可以分解为低秩矩阵的乘积
  • 什么是音频?
  • Git 分支管理规范
  • 【Python训练营打卡】day52 @浙大疏锦行
  • 《并查集》题集
  • AndroidManifest里面的lable标签
  • Flutter:加减乘除,科学计数法转换
  • 《第二章-内功筑基》 C++修炼生涯笔记(基础篇)数据类型与运算符
  • 前端给一行文字不设置宽度 ,不拆分 ,又能让某几个字在视觉下方居中显示
  • LeetCode 2529.正整数和负整数的最大计数
  • Appium + Java 测试全流程
  • Spring boot 的 maven 打包过程
  • Fiori 初学记录----怎么调用后端系统odata 服务实现简单的CURD
  • 使用特征线法求解一阶线性齐次偏微分方程组
  • 多模态大语言模型arxiv论文略读(121)
  • html+css+js趣味小游戏~(附源码)
  • 数据库分库分表情况下数据统计的相关问题详解(面试问答)
  • C++面试(9)-----反转链表
  • 2025年渗透测试面试题总结-字节跳动[实习]安全研发员(题目+回答)
  • CoLMDriver:基于LLM的协同自动驾驶
  • LangChain面试内容整理-知识点10:文本嵌入模型(Embeddings)使用
  • 如何安装使用qmt脚本跟单聚宽策略
  • C++四大默认成员函数:构造、析构、拷贝构造与赋值重载
  • 利用pycharm搭建模型步骤
  • Sqoop进阶之路:解锁数据迁移新姿势
  • 2025.6.12 【校内 NOI 训练赛】记录(集训队互测选做)
  • 使用OceanBase的Oblogminer进行日志挖掘的实践