update wechat

This commit is contained in:
yincong
2025-12-26 11:12:49 +08:00
parent f0acbb6713
commit 8c915ed8d4
4 changed files with 256 additions and 175 deletions
+83 -63
View File
@@ -5,12 +5,24 @@ if (!baseAddr) {
}
console.log("[*] WeChat base address: " + baseAddr);
// 假设 0x10444A99C 是相对于 0x100000000 的地址
const triggerFuncAddr = baseAddr.add(0x444A99C);
// 触发函数地址,不同版本的地址看wechat_version 中的json文件复制过来
var triggerFuncAddr = baseAddr.add(0x444A99C);
var sendMessageCallbackFunc = baseAddr.add(0xEDB4678);
var messageCallbackFunc1 = baseAddr.add(0x7f04f70);
var messageCallbackFunc2 = baseAddr.add(0x7f04fc8);
var messageCallbackFunc3 = baseAddr.add(0x7f96918);
var messageCallbackFunc4 = baseAddr.add(0x7f96a08);
var messageCallbackFunc5 = baseAddr.add(0x7f968a0);
// 这个必须是绝对位置
var triggerX1Payload = ptr(0x175ED6600);
var req2bufEnterAddr = baseAddr.add(0x33EE8E8);
var req2bufExitAddr = baseAddr.add(0x33EFA00);
var protobufAddr = baseAddr.add(0x223EF58);
// 定义一个全局变量用于保存 X0 的指针
// 触发函数X0参数地址
var globalMessagePtr = ptr(0);
// 消息体的一些指针地址
var cgiAddr = ptr(0);
var callBackFuncAddr = ptr(0);
var sendMessageAddr = ptr(0);
@@ -18,11 +30,13 @@ var messageAddr = ptr(0);
var messageContentAddr = ptr(0);
var messageAddrAddr = ptr(0);
var contentAddr = ptr(0);
var insertMsgAddr = ptr(0);
// 消息的taskId
var taskId = 0x20000090
var receiver = "wxid_7wd1ece99f7i21"
var content = "hello world";
// 打印消息的地址,便于查询问题
function printAddr() {
console.log("[*] Addresses:");
console.log(" - cgiAddr: " + cgiAddr);
@@ -33,6 +47,7 @@ function printAddr() {
console.log(" - messageAddrAddr: " + messageAddrAddr);
console.log(" - contentAddr: " + contentAddr);
console.log(" - globalMessagePtr: " + globalMessagePtr);
console.log(" - triggerX1Payload: " + triggerX1Payload);
}
// 辅助函数:写入 Hex 字符串
@@ -42,6 +57,7 @@ function patchHex(addr, hexStr) {
addr.add(bytes.length).writeU8(0); // 终止符
}
// 初始化进行内存的分配
function setupSendMessageDynamic() {
console.log("[*] Starting Dynamic Message Patching...");
@@ -63,7 +79,7 @@ function setupSendMessageDynamic() {
// B. 构建 SendMessage 结构体 (X24 基址位置)
sendMessageAddr.add(0x00).writeU64(0);
sendMessageAddr.add(0x08).writeU64(0);
sendMessageAddr.add(0x10).writePointer(baseAddr.add(0xEDB4678)); // 虚表地址通常仍需硬编码或从模块基址计算
sendMessageAddr.add(0x10).writePointer(sendMessageCallbackFunc); // 虚表地址通常仍需硬编码或从模块基址计算
sendMessageAddr.add(0x18).writeU64(1);
sendMessageAddr.add(0x20).writeU32(taskId);
sendMessageAddr.add(0x28).writePointer(messageAddr); // 指向动态分配的 Message
@@ -76,7 +92,7 @@ function setupSendMessageDynamic() {
}));
// C. 构建 Message 结构体
messageAddr.add(0x00).writePointer(baseAddr.add(0x7f04f70));
messageAddr.add(0x00).writePointer(messageCallbackFunc1);
messageAddr.add(0x08).writeU32(taskId);
messageAddr.add(0x0c).writeU32(0x20a);
messageAddr.add(0x10).writeU64(0x3);
@@ -89,26 +105,26 @@ function setupSendMessageDynamic() {
messageAddr.add(0x58).writeU64(uint64("0x0101010100000001"));
// 处理回调地址
callBackFuncAddr.writePointer(baseAddr.add(0x7f04fc8));
callBackFuncAddr.writePointer(messageCallbackFunc2);
messageAddr.add(0x98).writePointer(callBackFuncAddr);
// 设置内容指针
messageAddr.add(0xb8).writePointer(baseAddr.add(0x7f96918));
messageAddr.add(0xb8).writePointer(messageCallbackFunc3);
messageAddr.add(0xc0).writePointer(messageContentAddr);
messageAddr.add(0xc8).writeU64(uint64("0x0000000100000001"));
messageAddr.add(0xd0).writeU64(0x4);
messageAddr.add(0xd8).writeU64(0x1);
messageAddr.add(0xe0).writeU64(0x1);
messageAddr.add(0xe8).writePointer(baseAddr.add(0x7f96a08));
messageAddr.add(0xe8).writePointer(messageCallbackFunc4);
messageContentAddr.writePointer(messageAddrAddr);
messageAddrAddr.writePointer(baseAddr.add(0x7f968a0));
messageAddrAddr.writePointer(messageCallbackFunc5);
messageAddrAddr.add(0x08).writePointer(contentAddr);
console.log(" [+] messageAddr Object: ", hexdump(messageAddr, {
offset: 0,
length: 200,
length: 128,
header: true,
ansi: true
}));
@@ -118,14 +134,12 @@ function setupSendMessageDynamic() {
setImmediate(setupSendMessageDynamic);
// 设置trigger函数的x0参数
function setTriggerAttach() {
var targetAddr = baseAddr.add(0x444A99C);
console.log("[*] WeChat Base: " + baseAddr + "[*] Attaching to: " + targetAddr);
console.log("[*] WeChat Base: " + baseAddr + "[*] Attaching to: " + triggerFuncAddr);
// 3. 开始拦截
Interceptor.attach(targetAddr, {
Interceptor.attach(triggerFuncAddr, {
onEnter: function (args) {
console.log("[*] Entered Function: 0x10444A99C");
@@ -145,25 +159,21 @@ function setTriggerAttach() {
setImmediate(setTriggerAttach);
/**
* 手动触发函数调用:模拟 IDA Appcall 逻辑
*/
function manualTrigger() {
console.log("[*] Manual Trigger Started...");
const payloadBase = ptr("0x175ED6600");
if (globalMessagePtr.isNull()) {
console.log("[!] globalMessagePtr is NULL, cannot trigger!");
return;
}
// 获取当前时间戳 (秒)
const timestamp = Math.floor(Date.now() / 1000);
// 2. 执行基础的 Patch (Dword/Qword)
messageAddr.add(0x08).writeU32(taskId);
sendMessageAddr.add(0x20).writeU32(taskId);
messageAddrAddr.add(0x18).writeU32(timestamp);
// 3. 构造并填充 Payload
// 注意:Frida 的 writeByteArray 不会自动处理长度,需确保数据完整
const payloadData = [
0x0A, 0x02, 0x00, 0x00, // 0x00
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x08
@@ -220,17 +230,16 @@ function manualTrigger() {
];
// 从 0x175ED6604 开始写入 Payload
payloadBase.writeU32(taskId);
payloadBase.add(0x04).writeByteArray(payloadData);
payloadBase.add(0x18).writePointer(cgiAddr);
console.log("[+] Payload trigger function written to memory.");
triggerX1Payload.writeU32(taskId);
triggerX1Payload.add(0x04).writeByteArray(payloadData);
triggerX1Payload.add(0x18).writePointer(cgiAddr);
const sub_10444A99C = new NativeFunction(triggerFuncAddr, 'uint64', ['pointer', 'pointer']);
// 5. 调用函数
try {
const arg1 = globalMessagePtr; // 第一个指针参数
const arg2 = payloadBase; // 第二个参数 0x175ED6600
const arg2 = triggerX1Payload; // 第二个参数 0x175ED6600
console.log(`[*] Calling trigger function at ${triggerFuncAddr} with args: (${arg1}, ${arg2})`);
@@ -243,18 +252,13 @@ function manualTrigger() {
}
/**
* 拦截特定地址并重定向结构体指针
*/
// ReqBuf 进行拦截,替换入参数的消息指针
function attachReq2buf() {
// 1. 计算运行时地址
// 假设 IDA 地址 1033EE8E8 对应的偏移是 0x33EE8E8 (基于基址 0x100000000)
const targetAddr = baseAddr.add(0x33EE8E8);
console.log("[*] Target Req2buf enter Address: " + targetAddr);
console.log("[*] Target Req2buf enter Address: " + req2bufEnterAddr);
// 2. 开始拦截
Interceptor.attach(targetAddr, {
Interceptor.attach(req2bufEnterAddr, {
onEnter: function(args) {
if (!this.context.x1.equals(taskId)) {
return;
@@ -289,10 +293,9 @@ function attachReq2buf() {
}
});
const returnAddr = baseAddr.add(0x33EFA00);
console.log("[*] Target Req2buf leave Address: " + targetAddr);
Interceptor.attach(returnAddr, {
// 在出口处拦截req2buf,把insertMsgAddr设置为0,避免被垃圾回收导致整个程序崩溃
console.log("[*] Target Req2buf leave Address: " + req2bufExitAddr);
Interceptor.attach(req2bufExitAddr, {
onEnter: function(args) {
if (!this.context.x25.equals(taskId)) {
return;
@@ -302,8 +305,6 @@ function attachReq2buf() {
}
});
}
// 确保在初始化后执行
setImmediate(attachReq2buf);
// 辅助函数:Protobuf Varint 编码 (对应 get_varint_timestamp_bytes)
@@ -325,33 +326,53 @@ function getVarintTimestampBytes() {
return encodedBytes;
}
/**
* 模拟 run_patch_script 逻辑的 Frida 脚本
* 当命中 10223EF58 时触发内存写入和寄存器修改
*/
function stringToHexArray(str) {
var arr = [];
for (var i = 0; i < str.length; i++) {
arr.push(str.charCodeAt(i)); // 获取字符的 ASCII 码 (即十六进制值)
}
return arr;
}
function generateRandom5ByteVarint() {
let res = [];
// 前 4 个字节:最高位(bit 7)必须是 1,低 7 位随机
for (let i = 0; i < 4; i++) {
let random7Bit = Math.floor(Math.random() * 128);
res.push(random7Bit | 0x80); // 强制设置最高位为 1
}
// 第 5 个字节:最高位必须是 0,为了确保不变成 4 字节,低 7 位不能全为 0
let lastByte = Math.floor(Math.random() * 127) + 1;
res.push(lastByte & 0x7F); // 确保最高位为 0
return res;
}
// 拦截 Protobuf 编码逻辑,注入自定义 Payload
function attachProto() {
const targetHookAddr = baseAddr.add(0x223EF58);
console.log("[*] proto注入拦截目标地址: " + targetHookAddr);
// 2. 预先分配一块持久内存用于存放 Payload (对应 x1_addr)
// Memory.alloc 会返回一个在脚本运行期间有效的地址
console.log("[*] proto注入拦截目标地址: " + protobufAddr);
const x1_custom_addr = Memory.alloc(256);
console.log("[*] Frida 分配的 Payload 地址: " + x1_custom_addr);
Interceptor.attach(targetHookAddr, {
Interceptor.attach(protobufAddr, {
onEnter: function(args) {
// --- 构造动态 Payload ---
const prefix = [
0x08, 0x01, 0x12, 0x5E, 0x0A, 0x15, 0x0A, 0x13, // 0x00
0x77, 0x78, 0x69, 0x64, 0x5F, 0x37, 0x77, 0x64, // 0x08
0x31, 0x65, 0x63, 0x65, 0x39, 0x39, 0x66, 0x37, // 0x10
0x69, 0x32, 0x31, 0x12, 0x03, 0x38, 0x38, 0x38, // 0x18
0x18, 0x01, 0x20 // 0x20
];
const receiverProto = stringToHexArray(receiver);
const contentHeader = [0x12, content.length];
const contentProto = stringToHexArray(content);
const tsHeader = [0x18, 0x01, 0x20];
const tsBytes = getVarintTimestampBytes();
const msgIdHeader = [0x28]
const msgId = generateRandom5ByteVarint()
const suffix = [
0x28, 0xD1, 0xF7, 0xA6, 0xE6, 0x0C, // 某个id头部
0x32, 0x32, 0x3C, // 0x28 头部
0x6D, 0x73, 0x67, 0x73, 0x6F, 0x73, 0x75, 0x72, // 0x30 msgsour
0x63, 0x65, 0x3E, 0x3C, 0x61, 0x6C, 0x6E, 0x6F, // 0x38 ce><alno
@@ -363,9 +384,9 @@ function attachProto() {
];
// 合并数组
const finalPayload = prefix.concat(tsBytes).concat(suffix);
const finalPayload = prefix.concat(receiverProto).concat(contentHeader).
concat(contentProto).concat(tsHeader).concat(tsBytes).concat(msgIdHeader).concat(msgId).concat(suffix);
// --- 写入内存 ---
x1_custom_addr.writeByteArray(finalPayload);
console.log("[*] Payload 已写入,长度: " + finalPayload.length);
@@ -382,5 +403,4 @@ function attachProto() {
});
}
// 启动
setImmediate(attachProto);
+159 -111
View File
@@ -1,15 +1,28 @@
// 1. 获取微信主模块的基地址
var baseAddr = Module.findBaseAddress("WeChat");
var baseAddr = Process.getModuleByName("WeChat").base;
if (!baseAddr) {
console.log("[!] 找不到 WeChat 模块基址,请检查进程名。");
}
console.log("[*] WeChat base address: " + baseAddr);
// 假设 0x10444A99C 是相对于 0x100000000 的地址
const triggerFuncAddr = baseAddr.add(0x444A99C);
// 触发函数地址,不同版本的地址看wechat_version 中的json文件复制过来
var triggerFuncAddr = baseAddr.add(0x444A99C);
var sendMessageCallbackFunc = baseAddr.add(0xEDB4678);
var messageCallbackFunc1 = baseAddr.add(0x7f04f70);
var messageCallbackFunc2 = baseAddr.add(0x7f04fc8);
var messageCallbackFunc3 = baseAddr.add(0x7f96918);
var messageCallbackFunc4 = baseAddr.add(0x7f96a08);
var messageCallbackFunc5 = baseAddr.add(0x7f968a0);
// 这个必须是绝对位置
var triggerX1Payload = ptr(0x175ED6600);
var req2bufEnterAddr = baseAddr.add(0x33EE8E8);
var req2bufExitAddr = baseAddr.add(0x33EFA00);
var protobufAddr = baseAddr.add(0x223EF58);
// 定义一个全局变量用于保存 X0 的指针
// 触发函数X0参数地址
var globalMessagePtr = ptr(0);
// 消息体的一些指针地址
var cgiAddr = ptr(0);
var callBackFuncAddr = ptr(0);
var sendMessageAddr = ptr(0);
@@ -17,11 +30,13 @@ var messageAddr = ptr(0);
var messageContentAddr = ptr(0);
var messageAddrAddr = ptr(0);
var contentAddr = ptr(0);
var insertMsgAddr = ptr(0);
// 消息的taskId
var taskId = 0x20000090
var receiver = "wxid_7wd1ece99f7i21"
var content = "hello world";
// 打印消息的地址,便于查询问题
function printAddr() {
console.log("[*] Addresses:");
console.log(" - cgiAddr: " + cgiAddr);
@@ -32,6 +47,7 @@ function printAddr() {
console.log(" - messageAddrAddr: " + messageAddrAddr);
console.log(" - contentAddr: " + contentAddr);
console.log(" - globalMessagePtr: " + globalMessagePtr);
console.log(" - triggerX1Payload: " + triggerX1Payload);
}
// 辅助函数:写入 Hex 字符串
@@ -41,6 +57,7 @@ function patchHex(addr, hexStr) {
addr.add(bytes.length).writeU8(0); // 终止符
}
// 初始化进行内存的分配
function setupSendMessageDynamic() {
console.log("[*] Starting Dynamic Message Patching...");
@@ -57,60 +74,81 @@ function setupSendMessageDynamic() {
// A. 写入字符串内容
patchHex(cgiAddr, "2F 63 67 69 2D 62 69 6E 2F 6D 69 63 72 6F 6D 73 67 2D 62 69 6E 2F 6E 65 77 73 65 6E 64 6D 73 67");
patchHex(contentAddr, "77 77 77"); // "www"
patchHex(contentAddr, " ");
// B. 构建 SendMessage 结构体 (X24 基址位置)
sendMessageAddr.add(0x00).writeU64(0);
sendMessageAddr.add(0x08).writeU64(0);
sendMessageAddr.add(0x10).writeU64(uint64("0x10EDB4678")); // 虚表地址通常仍需硬编码或从模块基址计算
sendMessageAddr.add(0x10).writePointer(sendMessageCallbackFunc); // 虚表地址通常仍需硬编码或从模块基址计算
sendMessageAddr.add(0x18).writeU64(1);
sendMessageAddr.add(0x20).writeU32(taskId);
sendMessageAddr.add(0x28).writePointer(messageAddr); // 指向动态分配的 Message
console.log(" [+] sendMessageAddr Object: ", hexdump(sendMessageAddr, {
offset: 0,
length: 48,
header: true,
ansi: true
}));
// C. 构建 Message 结构体
messageAddr.add(0x00).writeU64(uint64("0x107f04f70"));
messageAddr.add(0x00).writePointer(messageCallbackFunc1);
messageAddr.add(0x08).writeU32(taskId);
messageAddr.add(0x0c).writeU32(0x20a);
messageAddr.add(0x10).writeU64(3);
messageAddr.add(0x18).writePointer(cgiAddr); // 指向动态分配的 CGI 字符串
messageAddr.add(0x10).writeU64(0x3);
messageAddr.add(0x18).writePointer(cgiAddr);
// 设置一些固定值
messageAddr.add(0x20).writeU64(uint64("0x20"));
messageAddr.add(0x28).writeU64(uint64("0x8000000000000030"));
messageAddr.add(0x30).writeU64(uint64("0x0000000001010100"));
messageAddr.add(0x58).writeU64(uint64("0x0101010100000001"));
// 处理回调地址
callBackFuncAddr.writeU64(uint64("0x107f04fc8"));
messageAddr.add(0x98).writePointer(callBackFuncAddress);
callBackFuncAddr.writePointer(messageCallbackFunc2);
messageAddr.add(0x98).writePointer(callBackFuncAddr);
// 设置内容指针
messageAddr.add(0xb8).writePointer(messageCallbackFunc3);
messageAddr.add(0xc0).writePointer(messageContentAddr);
messageAddr.add(0xc8).writeU64(uint64("0x0000000100000001"));
messageAddr.add(0xd0).writeU64(0x4);
messageAddr.add(0xd8).writeU64(0x1);
messageAddr.add(0xe0).writeU64(0x1);
messageAddr.add(0xe8).writePointer(messageCallbackFunc4);
messageContentAddr.writePointer(messageAddrAddr);
messageAddrAddr.writeU64(uint64("0x107f968a0"));
messageAddrAddr.writePointer(messageCallbackFunc5);
messageAddrAddr.add(0x08).writePointer(contentAddr);
console.log(" [+] messageAddr Object: ", hexdump(messageAddr, {
offset: 0,
length: 128,
header: true,
ansi: true
}));
console.log("[+] Dynamic Memory Setup Complete.");
console.log(" - Message Object: " + messageAddr);
console.log(" [+] Dynamic Memory Setup Complete. - Message Object: " + messageAddr);
}
setImmediate(setupSendMessageDynamic);
function doAttach() {
var targetAddr = baseAddr.add(0x444A99C);
console.log("[*] WeChat Base: " + baseAddr + "[*] Attaching to: " + targetAddr);
// 设置trigger函数的x0参数
function setTriggerAttach() {
console.log("[*] WeChat Base: " + baseAddr + "[*] Attaching to: " + triggerFuncAddr);
// 3. 开始拦截
Interceptor.attach(targetAddr, {
Interceptor.attach(triggerFuncAddr, {
onEnter: function (args) {
if (globalMessagePtr) {
console.log("[*] Entered Function: 0x10444A99C");
if (!globalMessagePtr.isNull()) {
return;
}
globalMessagePtr = this.context.x0;
console.log("[+] 当前 X0 的指针值: " + globalMessagePtr);
console.log("[+] globalMessagePtr 当前 X0 的指针值: " + globalMessagePtr);
},
onLeave: function (retval) {
}
@@ -118,28 +156,24 @@ function doAttach() {
}
// 使用 setImmediate 确保在模块加载后执行
setImmediate(doAttach);
setImmediate(setTriggerAttach);
/**
* 手动触发函数调用:模拟 IDA Appcall 逻辑
*/
function manualTrigger() {
console.log("[*] Manual Trigger Started...");
const payloadBase = ptr("0x175ED6600");
if (globalMessagePtr.isNull()) {
console.log("[!] globalMessagePtr is NULL, cannot trigger!");
return;
}
// 获取当前时间戳 (秒)
const timestamp = Math.floor(Date.now() / 1000);
// 2. 执行基础的 Patch (Dword/Qword)
messageAddr.add(0x08).writeU32(taskId);
sendMessageAddr.add(0x20).writeU32(taskId);
messageAddrAddr.add(0x18).writeU32(timestamp);
// 3. 构造并填充 Payload
// 注意:Frida 的 writeByteArray 不会自动处理长度,需确保数据完整
const payloadData = [
0x0A, 0x02, 0x00, 0x00, // 0x00
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x08
@@ -196,139 +230,149 @@ function manualTrigger() {
];
// 从 0x175ED6604 开始写入 Payload
payloadBase.writeU32(taskId);
payloadBase.add(0x04).writeByteArray(payloadData);
payloadBase.add(0x18).writeU32(cgiAddr);
console.log("[+] Payload written to memory.");
triggerX1Payload.writeU32(taskId);
triggerX1Payload.add(0x04).writeByteArray(payloadData);
triggerX1Payload.add(0x18).writePointer(cgiAddr);
const sub_10444A99C = new NativeFunction(triggerFuncAddr, 'uint64', ['pointer', 'uint64']);
const sub_10444A99C = new NativeFunction(triggerFuncAddr, 'uint64', ['pointer', 'pointer']);
// 5. 调用函数
try {
const arg1 = globalMessagePtr; // 第一个指针参数
const arg2 = payloadBase; // 第二个参数 0x175ED6600
const arg2 = triggerX1Payload; // 第二个参数 0x175ED6600
console.log(`[*] Calling function at ${triggerFuncAddr} with args: (${arg1}, ${arg2})`);
console.log(`[*] Calling trigger function at ${triggerFuncAddr} with args: (${arg1}, ${arg2})`);
const result = sub_10444A99C(arg1, arg2);
console.log("[+] Execution Success. Return value: " + result);
console.log("[+] Execution trigger function Success. Return value: " + result);
} catch (e) {
console.log("[!] Error during execution: " + e);
console.log("[!] Error trigger function during execution: " + e);
}
}
/**
* 拦截特定地址并重定向结构体指针
*/
// ReqBuf 进行拦截,替换入参数的消息指针
function attachReq2buf() {
// 1. 计算运行时地址
// 假设 IDA 地址 1033EE8E8 对应的偏移是 0x33EE8E8 (基于基址 0x100000000)
const targetAddr = baseAddr.add(0x33EE8E8);
console.log("[*] Target Req2buf enter Address: " + targetAddr);
console.log("[*] Target Req2buf enter Address: " + req2bufEnterAddr);
// 2. 开始拦截
Interceptor.attach(targetAddr, {
Interceptor.attach(req2bufEnterAddr, {
onEnter: function(args) {
if (args.context.x1 !== taskId) {
if (!this.context.x1.equals(taskId)) {
return;
}
console.log("[+] 已命中目标地址: " + targetAddr);
console.log("[+] 已命中目标Req2Buf地址:0x1033EE8E8 taskId:" + taskId + "base:" + baseAddr);
// 3. 获取 X24 寄存器的值
const x24_base = this.context.x24;
insertMsgAddr = x24_base.add(0x60);
console.log("[*] 当前 X24 基址: " + x24_base);
console.log("[*] 准备修改位置 (X24 + 0x60): " + insertMsgAddr);
console.log("[*] 当前 Req2Buf X24 基址: " + x24_base);
console.log("[*] 准备修改位置 Req2Buf (X24 + 0x60): " + insertMsgAddr , hexdump(insertMsgAddr, {
offset: 0,
length: 16,
header: true,
ansi: true
}));
if (typeof sendMessageAddr !== 'undefined') {
// 写入 8 字节指针
insertMsgAddr.writePointer(sendMessageAddr);
console.log("[!] 成功! 已将 X24+0x60 指向新地址: " + sendMessageAddr);
console.log("[+] 写入后内存预览: " + insertMsgAddr.readPointer());
insertMsgAddr = ptr(0x0);
console.log("[!] 成功! Req2Buf 已将 X24+0x60 指向新地址: " + sendMessageAddr +
"[+] Req2Buf 写入后内存预览: " + insertMsgAddr, hexdump(insertMsgAddr, {
offset: 0,
length: 16,
header: true,
ansi: true
}));
} else {
console.log("[?] 错误: 变量 sendMessageAddr 未定义,请确保已运行分配逻辑。");
}
}
});
returnAddr = baseAddr.add(0x33EFA00);
console.log("[*] Target Req2buf leave Address: " + targetAddr);
Interceptor.attach(returnAddr, {
// 在出口处拦截req2buf,把insertMsgAddr设置为0,避免被垃圾回收导致整个程序崩溃
console.log("[*] Target Req2buf leave Address: " + req2bufExitAddr);
Interceptor.attach(req2bufExitAddr, {
onEnter: function(args) {
if (args.context.x25 !== taskId) {
if (!this.context.x25.equals(taskId)) {
return;
}
insertMsgAddr.writePointer(0x0);
console.log("[+] 清空写入后内存预览: " + insertMsgAddr.readPointer());
insertMsgAddr.writeU64(0x0);
console.log("[+] 0x1033EFA00 清空写入后内存预览: " + insertMsgAddr.readPointer());
}
});
}
// 确保在初始化后执行
setImmediate(attachReq2buf);
// 辅助函数:Protobuf Varint 编码 (对应 get_varint_timestamp_bytes)
function getVarintTimestampBytes() {
let ts = Math.floor(Date.now() / 1000);
let encodedBytes = [];
let tempTs = ts >>> 0; // 强制转为 32位 无符号整数
/**
* 模拟 run_patch_script 逻辑的 Frida 脚本
* 当命中 10223EF58 时触发内存写入和寄存器修改
*/
while (true) {
let byte = tempTs & 0x7F;
tempTs >>>= 7;
if (tempTs !== 0) {
encodedBytes.push(byte | 0x80);
} else {
encodedBytes.push(byte);
break;
}
}
return encodedBytes;
}
function stringToHexArray(str) {
var arr = [];
for (var i = 0; i < str.length; i++) {
arr.push(str.charCodeAt(i)); // 获取字符的 ASCII 码 (即十六进制值)
}
return arr;
}
function generateRandom5ByteVarint() {
let res = [];
// 前 4 个字节:最高位(bit 7)必须是 1,低 7 位随机
for (let i = 0; i < 4; i++) {
let random7Bit = Math.floor(Math.random() * 128);
res.push(random7Bit | 0x80); // 强制设置最高位为 1
}
// 第 5 个字节:最高位必须是 0,为了确保不变成 4 字节,低 7 位不能全为 0
let lastByte = Math.floor(Math.random() * 127) + 1;
res.push(lastByte & 0x7F); // 确保最高位为 0
return res;
}
// 拦截 Protobuf 编码逻辑,注入自定义 Payload
function attachProto() {
// 1. 计算运行时地址 (假设 IDA 基址 0x100000000)
const targetHookAddr = baseAddr.add(0x223EF58);
console.log("[*] proto注入拦截目标地址: " + protobufAddr);
// 2. 预先分配一块持久内存用于存放 Payload (对应 x1_addr)
// Memory.alloc 会返回一个在脚本运行期间有效的地址
const x1_custom_addr = Memory.alloc(256);
console.log("[*] Frida 分配的 Payload 地址: " + x1_custom_addr);
// 辅助函数:Protobuf Varint 编码 (对应 get_varint_timestamp_bytes)
function getVarintTimestampBytes() {
let ts = Math.floor(Date.now() / 1000);
let encodedBytes = [];
let tempTs = ts >>> 0; // 强制转为 32位 无符号整数
while (true) {
let byte = tempTs & 0x7F;
tempTs >>>= 7;
if (tempTs !== 0) {
encodedBytes.push(byte | 0x80);
} else {
encodedBytes.push(byte);
break;
}
}
return encodedBytes;
}
// 3. 开始 Attach
Interceptor.attach(targetHookAddr, {
Interceptor.attach(protobufAddr, {
onEnter: function(args) {
console.log("------------------------------------------");
console.log("[+] 命中 Hook 地址: " + targetHookAddr);
// --- 构造动态 Payload ---
const prefix = [
0x08, 0x01, 0x12, 0x5E, 0x0A, 0x15, 0x0A, 0x13, // 0x00
0x77, 0x78, 0x69, 0x64, 0x5F, 0x37, 0x77, 0x64, // 0x08
0x31, 0x65, 0x63, 0x65, 0x39, 0x39, 0x66, 0x37, // 0x10
0x69, 0x32, 0x31, 0x12, 0x03, 0x38, 0x38, 0x38, // 0x18
0x18, 0x01, 0x20 // 0x20
];
const receiverProto = stringToHexArray(receiver);
const contentHeader = [0x12, content.length];
const contentProto = stringToHexArray(content);
const tsHeader = [0x18, 0x01, 0x20];
const tsBytes = getVarintTimestampBytes();
const msgIdHeader = [0x28]
const msgId = generateRandom5ByteVarint()
const suffix = [
0x28, 0xD1, 0xF7, 0xA6, 0xE6, 0x0C, // 某个id头部
0x32, 0x32, 0x3C, // 0x28 头部
0x6D, 0x73, 0x67, 0x73, 0x6F, 0x73, 0x75, 0x72, // 0x30 msgsour
0x63, 0x65, 0x3E, 0x3C, 0x61, 0x6C, 0x6E, 0x6F, // 0x38 ce><alno
@@ -340,19 +384,23 @@ function attachProto() {
];
// 合并数组
const finalPayload = prefix.concat(tsBytes).concat(suffix);
const finalPayload = prefix.concat(receiverProto).concat(contentHeader).
concat(contentProto).concat(tsHeader).concat(tsBytes).concat(msgIdHeader).concat(msgId).concat(suffix);
// --- 写入内存 ---
x1_custom_addr.writeByteArray(finalPayload);
console.log("[*] Payload 已写入,长度: " + finalPayload.length);
this.context.x1 = x1_custom_addr;
this.context.x2 = ptr(0x62);
console.log("[+] 寄存器修改完成: X1=" + this.context.x1 + ", X2=" + this.context.x2);
console.log("[+] 寄存器修改完成: X1=" + this.context.x1 + ", X2=" + this.context.x2, hexdump(x1_custom_addr, {
offset: 0,
length: 160,
header: true,
ansi: true
}));
}
});
}
// 启动
setImmediate(attachProto);
+1 -1
View File
@@ -33,7 +33,7 @@ def run_patch_script():
b"\x08\x01\x12\x5E\x0A\x15\x0A\x13" # 0x00 第一个字段头部 + 接收人id头部
b"\x77\x78\x69\x64\x5F\x37\x77\x64" # 0x08 (接收人id wxid_xxxx)
b"\x31\x65\x63\x65\x39\x39\x66\x37" # 0x10 (接收人id wxid_xxxx)
b"\x69\x32\x31\x12\x03\x38\x38\x38" # 0x18 (接收人id wxid_xxxx + 第二个字段头部 + 字符串长度+字符串内容)
b"\x32\x31\x12\x03\x38\x38\x38" # 0x18 (接收人id wxid_xxxx + 第二个字段头部 + 字符串长度+字符串内容)
b"\x18\x01\x20" # 0x20 (第三个字段时间戳头部+时间戳)
)
+13
View File
@@ -0,0 +1,13 @@
{
"triggerFuncAddr": "0x444A99C",
"sendMessageCallbackFunc": "0xEDB4678",
"messageCallbackFunc1": "0x7f04f70",
"messageCallbackFunc2": "0x7f04fc8",
"messageCallbackFunc3": "0x7f96918",
"messageCallbackFunc4": "0x7f96a08",
"messageCallbackFunc5": "0x7f968a0",
"triggerX1Payload": "0x175ED6600",
"req2bufEnterAddr": "0x33EE8E8",
"req2bufExitAddr": "0x33EFA00",
"protobufAddr": "0x223EF58"
}