add succ script

This commit is contained in:
yincong
2025-12-25 18:41:33 +08:00
parent e880d816d4
commit 99017df8d9
7 changed files with 760 additions and 43 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* wechat_method_finder.js
* _method_finder.js
* 目标: 批量挂钩微信主程序 (WeChat.app) 中所有与消息/加密相关的 Objective-C 方法。
* 作用: 找到微信内部封装的消息发送、接收、加解密逻辑的“入口”类和方法。
*/
+374 -33
View File
@@ -1,44 +1,385 @@
/**
* 构造内存数据并调用 sub_10481C304
*/
function callTargetFunction() {
const mod = Process.getModuleByName("WeChat");
const sub_10481C304_addr = ptr("0x10481C304").sub("0x100000000").add(mod.base);
const sub_10481C304 = new NativeFunction(sub_10481C304_addr, 'void', ['pointer']);
// 1. 获取微信主模块的基地址
var baseAddr = Process.getModuleByName("WeChat").base;
if (!baseAddr) {
console.log("[!] 找不到 WeChat 模块基址,请检查进程名。");
}
console.log("[*] WeChat base address: " + baseAddr);
// 2. 准备原始字节数据 (Hex 形式)
// 注意:0x18 偏移处的 8 字节(原数据 60 E1 39 78 05 00 00 00)会被动态生成的指针覆盖
const rawData = [
0x00, 0x00, 0x00, 0x00, 0x0A, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x18 指针位置
0x05, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x80, 0x00, 0x01, 0x11, 0x01, 0x00, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xFF, 0xFF, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0A, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
// 假设 0x10444A99C 是相对于 0x100000000 的地址
const triggerFuncAddr = baseAddr.add(0x444A99C);
// 定义一个全局变量用于保存 X0 的指针
var globalMessagePtr = ptr(0);
var cgiAddr = ptr(0);
var callBackFuncAddr = ptr(0);
var sendMessageAddr = ptr(0);
var messageAddr = ptr(0);
var messageContentAddr = ptr(0);
var messageAddrAddr = ptr(0);
var contentAddr = ptr(0);
var insertMsgAddr = ptr(0);
var taskId = 0x20000090
function printAddr() {
console.log("[*] Addresses:");
console.log(" - cgiAddr: " + cgiAddr);
console.log(" - callBackFuncAddr: " + callBackFuncAddr);
console.log(" - sendMessageAddr: " + sendMessageAddr);
console.log(" - messageAddr: " + messageAddr);
console.log(" - messageContentAddr: " + messageContentAddr);
console.log(" - messageAddrAddr: " + messageAddrAddr);
console.log(" - contentAddr: " + contentAddr);
console.log(" - globalMessagePtr: " + globalMessagePtr);
}
// 辅助函数:写入 Hex 字符串
function patchHex(addr, hexStr) {
const bytes = hexStr.split(' ').map(h => parseInt(h, 16));
addr.writeByteArray(bytes);
addr.add(bytes.length).writeU8(0); // 终止符
}
function setupSendMessageDynamic() {
console.log("[*] Starting Dynamic Message Patching...");
// 1. 动态分配内存块(按需分配大小)
// 分配原则:字符串给 64-128 字节,结构体按实际大小分配
cgiAddr = Memory.alloc(128);
callBackFuncAddr = Memory.alloc(16);
sendMessageAddr = Memory.alloc(256);
messageAddr = Memory.alloc(512);
messageContentAddr = Memory.alloc(32);
messageAddrAddr = Memory.alloc(32);
contentAddr = Memory.alloc(255);
// 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, " ");
// B. 构建 SendMessage 结构体 (X24 基址位置)
sendMessageAddr.add(0x00).writeU64(0);
sendMessageAddr.add(0x08).writeU64(0);
sendMessageAddr.add(0x10).writePointer(baseAddr.add(0xEDB4678)); // 虚表地址通常仍需硬编码或从模块基址计算
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).writePointer(baseAddr.add(0x7f04f70));
messageAddr.add(0x08).writeU32(taskId);
messageAddr.add(0x0c).writeU32(0x20a);
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.writePointer(baseAddr.add(0x7f04fc8));
messageAddr.add(0x98).writePointer(callBackFuncAddr);
// 设置内容指针
messageAddr.add(0xb8).writePointer(baseAddr.add(0x7f96918));
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).writeU64(0x107f96a08);
messageContentAddr.writePointer(messageAddrAddr);
messageAddrAddr.writePointer(baseAddr.add(0x7f968a0));
messageAddrAddr.add(0x08).writePointer(contentAddr);
console.log(" [+] messageAddr Object: ", hexdump(messageAddr, {
offset: 0,
length: 200,
header: true,
ansi: true
}));
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);
// 3. 开始拦截
Interceptor.attach(targetAddr, {
onEnter: function (args) {
console.log("[*] Entered Function: 0x10444A99C");
if (!globalMessagePtr.isNull()) {
return;
}
globalMessagePtr = this.context.x0;
console.log("[+] globalMessagePtr 当前 X0 的指针值: " + globalMessagePtr);
},
onLeave: function (retval) {
}
});
}
// 使用 setImmediate 确保在模块加载后执行
setImmediate(doAttach);
/**
* 手动触发函数调用:模拟 IDA Appcall 逻辑
*/
function manualTrigger() {
console.log("[*] Manual Trigger Started...");
const payloadBase = ptr("0x175ED6600");
// 获取当前时间戳 (秒)
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
0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // 0x10
0x40, 0xec, 0x0e, 0x12, 0x01, 0x00, 0x00, 0x00, // 0x18
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, // 0x28
0x00, 0x01, 0x01, 0x01, 0x00, 0xAA, 0xAA, 0xAA, // 0x30
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, // 0x38
0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, // 0x40
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xAA, 0xAA, 0xAA, // 0x48
0xFF, 0xFF, 0xFF, 0xFF, 0xAA, 0xAA, 0xAA, 0xAA, // 0x50
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x58
0x0A, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60
0x64, 0x65, 0x66, 0x61, 0x75, 0x6C, 0x74, 0x2D, // 0x68 default-
0x6C, 0x6F, 0x6E, 0x67, 0x6C, 0x69, 0x6E, 0x6B, // 0x70 longlink
0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x10, // 0x78
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x80
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x88
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x90
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x98
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xA0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xA8
0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, // 0xB0
0xC0, 0x66, 0xED, 0x75, 0x01, 0x00, 0x00, 0x00, // 0xB8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xC0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xC8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xD0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xD8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xE0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xE8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xF0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xF8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x100
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x108
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x110
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x118
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x120
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x128
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x130
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x138
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x140
0x01, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, // 0x148
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x150
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x158
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x160
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x168
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x170
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x178
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x180
0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, // 0x188
0x98, 0x67, 0xED, 0x75, 0x01, 0x00, 0x00, 0x00, // 0x190
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x198
];
// 3. 申请结构体内存
const structPtr = Memory.alloc(rawData.length);
structPtr.writeByteArray(rawData);
// 从 0x175ED6604 开始写入 Payload
payloadBase.writeU32(taskId);
payloadBase.add(0x04).writeByteArray(payloadData);
payloadBase.add(0x18).writePointer(cgiAddr);
console.log("[+] Payload trigger function written to memory.");
// 4. 申请字符串内存并写入指针 (偏移 0x18)
const cgiPath = "/cgi-bin/micromsg-bin/newsendmsg";
const pathPtr = Memory.allocUtf8String(cgiPath);
structPtr.add(0x18).writePointer(pathPtr);
console.log("[+] 内存结构体已准备完毕: " + structPtr + " [+] 字符串地址: " + pathPtr + " 内容: " + cgiPath);
console.log();
const sub_10444A99C = new NativeFunction(triggerFuncAddr, 'uint64', ['pointer', 'pointer']);
// 5. 调用函数
try {
console.log("[*] 结构体内存布局 (调用前):");
sub_10481C304(structPtr);
console.log("[+] sub_10481C304 调用成功!");
const arg1 = globalMessagePtr; // 第一个指针参数
const arg2 = payloadBase; // 第二个参数 0x175ED6600
console.log(hexdump(structPtr, { offset: 0, length: rawData.length, header: true, ansi: true }));
console.log(`[*] Calling trigger function at ${triggerFuncAddr} with args: (${arg1}, ${arg2})`);
const result = sub_10444A99C(arg1, arg2);
console.log("[+] Execution trigger function Success. Return value: " + result);
} catch (e) {
console.log("[-] 调用出错: " + e);
console.log("[!] Error trigger function during execution: " + e);
}
}
}
/**
* 拦截特定地址并重定向结构体指针
*/
function attachReq2buf() {
// 1. 计算运行时地址
// 假设 IDA 地址 1033EE8E8 对应的偏移是 0x33EE8E8 (基于基址 0x100000000)
const targetAddr = baseAddr.add(0x33EE8E8);
console.log("[*] Target Req2buf enter Address: " + targetAddr);
// 2. 开始拦截
Interceptor.attach(targetAddr, {
onEnter: function(args) {
if (!this.context.x1.equals(taskId)) {
return;
}
console.log("[+] 已命中目标Req2Buf地址:0x1033EE8E8 taskId:" + taskId + "base:" + baseAddr);
// 3. 获取 X24 寄存器的值
const x24_base = this.context.x24;
insertMsgAddr = x24_base.add(0x60);
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') {
insertMsgAddr.writePointer(sendMessageAddr);
console.log("[!] 成功! Req2Buf 已将 X24+0x60 指向新地址: " + sendMessageAddr +
"[+] Req2Buf 写入后内存预览: " + insertMsgAddr, hexdump(insertMsgAddr, {
offset: 0,
length: 16,
header: true,
ansi: true
}));
} else {
console.log("[?] 错误: 变量 sendMessageAddr 未定义,请确保已运行分配逻辑。");
}
}
});
const returnAddr = baseAddr.add(0x33EFA00);
console.log("[*] Target Req2buf leave Address: " + targetAddr);
Interceptor.attach(returnAddr, {
onEnter: function(args) {
if (!this.context.x25.equals(taskId)) {
return;
}
insertMsgAddr.writePointer(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位 无符号整数
while (true) {
let byte = tempTs & 0x7F;
tempTs >>>= 7;
if (tempTs !== 0) {
encodedBytes.push(byte | 0x80);
} else {
encodedBytes.push(byte);
break;
}
}
return encodedBytes;
}
/**
* 模拟 run_patch_script 逻辑的 Frida 脚本
* 当命中 10223EF58 时触发内存写入和寄存器修改
*/
function attachProto() {
// 1. 计算运行时地址 (假设 IDA 基址 0x100000000)
const targetHookAddr = baseAddr.add(0x223EF58);
console.log("[*] proto注入拦截目标地址: " + targetHookAddr);
// 3. 开始 Attach
Interceptor.attach(targetHookAddr, {
onEnter: function(args) {
// 2. 预先分配一块持久内存用于存放 Payload (对应 x1_addr)
// Memory.alloc 会返回一个在脚本运行期间有效的地址
const x1_custom_addr = Memory.alloc(512);
console.log("[*] Frida 分配的 Payload 地址: " + x1_custom_addr);
// --- 构造动态 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 tsBytes = getVarintTimestampBytes();
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
0x64, 0x65, 0x3E, 0x3C, 0x66, 0x72, 0x3E, 0x31, // 0x40 de><fr>1
0x3C, 0x2F, 0x66, 0x72, 0x3E, 0x3C, 0x2F, 0x61, // 0x48 </fr></a
0x6C, 0x6E, 0x6F, 0x64, 0x65, 0x3E, 0x3C, 0x2F, // 0x50 lnode></
0x6D, 0x73, 0x67, 0x73, 0x6F, 0x73, 0x75, 0x72, // 0x58 msgsour
0x63, 0x65, 0x3E, 0x00 // 0x60 ce>.
];
// 合并数组
const finalPayload = prefix.concat(tsBytes).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);
}
});
}
// 启动
setImmediate(attachProto);
+358
View File
@@ -0,0 +1,358 @@
// 1. 获取微信主模块的基地址
var baseAddr = Module.findBaseAddress("WeChat");
if (!baseAddr) {
console.log("[!] 找不到 WeChat 模块基址,请检查进程名。");
}
// 假设 0x10444A99C 是相对于 0x100000000 的地址
const triggerFuncAddr = baseAddr.add(0x444A99C);
// 定义一个全局变量用于保存 X0 的指针
var globalMessagePtr = ptr(0);
var cgiAddr = ptr(0);
var callBackFuncAddr = ptr(0);
var sendMessageAddr = ptr(0);
var messageAddr = ptr(0);
var messageContentAddr = ptr(0);
var messageAddrAddr = ptr(0);
var contentAddr = ptr(0);
var insertMsgAddr = ptr(0);
var taskId = 0x20000090
function printAddr() {
console.log("[*] Addresses:");
console.log(" - cgiAddr: " + cgiAddr);
console.log(" - callBackFuncAddr: " + callBackFuncAddr);
console.log(" - sendMessageAddr: " + sendMessageAddr);
console.log(" - messageAddr: " + messageAddr);
console.log(" - messageContentAddr: " + messageContentAddr);
console.log(" - messageAddrAddr: " + messageAddrAddr);
console.log(" - contentAddr: " + contentAddr);
console.log(" - globalMessagePtr: " + globalMessagePtr);
}
// 辅助函数:写入 Hex 字符串
function patchHex(addr, hexStr) {
const bytes = hexStr.split(' ').map(h => parseInt(h, 16));
addr.writeByteArray(bytes);
addr.add(bytes.length).writeU8(0); // 终止符
}
function setupSendMessageDynamic() {
console.log("[*] Starting Dynamic Message Patching...");
// 1. 动态分配内存块(按需分配大小)
// 分配原则:字符串给 64-128 字节,结构体按实际大小分配
cgiAddr = Memory.alloc(128);
callBackFuncAddr = Memory.alloc(16);
sendMessageAddr = Memory.alloc(256);
messageAddr = Memory.alloc(512);
messageContentAddr = Memory.alloc(32);
messageAddrAddr = Memory.alloc(32);
contentAddr = Memory.alloc(255);
// 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"
// B. 构建 SendMessage 结构体 (X24 基址位置)
sendMessageAddr.add(0x00).writeU64(0);
sendMessageAddr.add(0x08).writeU64(0);
sendMessageAddr.add(0x10).writeU64(uint64("0x10EDB4678")); // 虚表地址通常仍需硬编码或从模块基址计算
sendMessageAddr.add(0x18).writeU64(1);
sendMessageAddr.add(0x20).writeU32(taskId);
sendMessageAddr.add(0x28).writePointer(messageAddr); // 指向动态分配的 Message
// C. 构建 Message 结构体
messageAddr.add(0x00).writeU64(uint64("0x107f04f70"));
messageAddr.add(0x08).writeU32(taskId);
messageAddr.add(0x0c).writeU32(0x20a);
messageAddr.add(0x10).writeU64(3);
messageAddr.add(0x18).writePointer(cgiAddr); // 指向动态分配的 CGI 字符串
// 设置一些固定值
messageAddr.add(0x20).writeU64(uint64("0x20"));
messageAddr.add(0x28).writeU64(uint64("0x8000000000000030"));
messageAddr.add(0x58).writeU64(uint64("0x0101010100000001"));
// 处理回调地址
callBackFuncAddr.writeU64(uint64("0x107f04fc8"));
messageAddr.add(0x98).writePointer(callBackFuncAddress);
// 设置内容指针
messageAddr.add(0xc0).writePointer(messageContentAddr);
messageContentAddr.writePointer(messageAddrAddr);
messageAddrAddr.writeU64(uint64("0x107f968a0"));
messageAddrAddr.add(0x08).writePointer(contentAddr);
console.log("[+] Dynamic Memory Setup Complete.");
console.log(" - Message Object: " + messageAddr);
}
setImmediate(setupSendMessageDynamic);
function doAttach() {
var targetAddr = baseAddr.add(0x444A99C);
console.log("[*] WeChat Base: " + baseAddr + "[*] Attaching to: " + targetAddr);
// 3. 开始拦截
Interceptor.attach(targetAddr, {
onEnter: function (args) {
if (globalMessagePtr) {
return;
}
globalMessagePtr = this.context.x0;
console.log("[+] 当前 X0 的指针值: " + globalMessagePtr);
},
onLeave: function (retval) {
}
});
}
// 使用 setImmediate 确保在模块加载后执行
setImmediate(doAttach);
/**
* 手动触发函数调用:模拟 IDA Appcall 逻辑
*/
function manualTrigger() {
console.log("[*] Manual Trigger Started...");
const payloadBase = ptr("0x175ED6600");
// 获取当前时间戳 (秒)
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
0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // 0x10
0x40, 0xec, 0x0e, 0x12, 0x01, 0x00, 0x00, 0x00, // 0x18
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, // 0x28
0x00, 0x01, 0x01, 0x01, 0x00, 0xAA, 0xAA, 0xAA, // 0x30
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, // 0x38
0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, // 0x40
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xAA, 0xAA, 0xAA, // 0x48
0xFF, 0xFF, 0xFF, 0xFF, 0xAA, 0xAA, 0xAA, 0xAA, // 0x50
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x58
0x0A, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60
0x64, 0x65, 0x66, 0x61, 0x75, 0x6C, 0x74, 0x2D, // 0x68 default-
0x6C, 0x6F, 0x6E, 0x67, 0x6C, 0x69, 0x6E, 0x6B, // 0x70 longlink
0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x10, // 0x78
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x80
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x88
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x90
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x98
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xA0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xA8
0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, // 0xB0
0xC0, 0x66, 0xED, 0x75, 0x01, 0x00, 0x00, 0x00, // 0xB8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xC0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xC8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xD0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xD8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xE0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xE8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xF0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xF8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x100
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x108
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x110
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x118
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x120
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x128
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x130
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x138
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x140
0x01, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, // 0x148
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x150
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x158
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x160
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x168
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x170
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x178
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x180
0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, // 0x188
0x98, 0x67, 0xED, 0x75, 0x01, 0x00, 0x00, 0x00, // 0x190
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x198
];
// 从 0x175ED6604 开始写入 Payload
payloadBase.writeU32(taskId);
payloadBase.add(0x04).writeByteArray(payloadData);
payloadBase.add(0x18).writeU32(cgiAddr);
console.log("[+] Payload written to memory.");
const sub_10444A99C = new NativeFunction(triggerFuncAddr, 'uint64', ['pointer', 'uint64']);
// 5. 调用函数
try {
const arg1 = globalMessagePtr; // 第一个指针参数
const arg2 = payloadBase; // 第二个参数 0x175ED6600
console.log(`[*] Calling function at ${triggerFuncAddr} with args: (${arg1}, ${arg2})`);
const result = sub_10444A99C(arg1, arg2);
console.log("[+] Execution Success. Return value: " + result);
} catch (e) {
console.log("[!] Error during execution: " + e);
}
}
/**
* 拦截特定地址并重定向结构体指针
*/
function attachReq2buf() {
// 1. 计算运行时地址
// 假设 IDA 地址 1033EE8E8 对应的偏移是 0x33EE8E8 (基于基址 0x100000000)
const targetAddr = baseAddr.add(0x33EE8E8);
console.log("[*] Target Req2buf enter Address: " + targetAddr);
// 2. 开始拦截
Interceptor.attach(targetAddr, {
onEnter: function(args) {
if (args.context.x1 !== taskId) {
return;
}
console.log("[+] 已命中目标地址: " + targetAddr);
// 3. 获取 X24 寄存器的值
const x24_base = this.context.x24;
insertMsgAddr = x24_base.add(0x60);
console.log("[*] 当前 X24 基址: " + x24_base);
console.log("[*] 准备修改位置 (X24 + 0x60): " + insertMsgAddr);
if (typeof sendMessageAddr !== 'undefined') {
// 写入 8 字节指针
insertMsgAddr.writePointer(sendMessageAddr);
console.log("[!] 成功! 已将 X24+0x60 指向新地址: " + sendMessageAddr);
console.log("[+] 写入后内存预览: " + insertMsgAddr.readPointer());
insertMsgAddr = ptr(0x0);
} else {
console.log("[?] 错误: 变量 sendMessageAddr 未定义,请确保已运行分配逻辑。");
}
}
});
returnAddr = baseAddr.add(0x33EFA00);
console.log("[*] Target Req2buf leave Address: " + targetAddr);
Interceptor.attach(returnAddr, {
onEnter: function(args) {
if (args.context.x25 !== taskId) {
return;
}
insertMsgAddr.writePointer(0x0);
console.log("[+] 清空写入后内存预览: " + insertMsgAddr.readPointer());
}
});
}
// 确保在初始化后执行
setImmediate(attachReq2buf);
/**
* 模拟 run_patch_script 逻辑的 Frida 脚本
* 当命中 10223EF58 时触发内存写入和寄存器修改
*/
function attachProto() {
// 1. 计算运行时地址 (假设 IDA 基址 0x100000000)
const targetHookAddr = baseAddr.add(0x223EF58);
// 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, {
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 tsBytes = getVarintTimestampBytes();
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
0x64, 0x65, 0x3E, 0x3C, 0x66, 0x72, 0x3E, 0x31, // 0x40 de><fr>1
0x3C, 0x2F, 0x66, 0x72, 0x3E, 0x3C, 0x2F, 0x61, // 0x48 </fr></a
0x6C, 0x6E, 0x6F, 0x64, 0x65, 0x3E, 0x3C, 0x2F, // 0x50 lnode></
0x6D, 0x73, 0x67, 0x73, 0x6F, 0x73, 0x75, 0x72, // 0x58 msgsour
0x63, 0x65, 0x3E, 0x00 // 0x60 ce>.
];
// 合并数组
const finalPayload = prefix.concat(tsBytes).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);
}
});
}
// 启动
setImmediate(attachProto);
+7 -3
View File
@@ -1,6 +1,7 @@
import ida_idd
import ida_bytes
import idc
import time
sendMessageAddress = 0x1120eed40
MessageAddress = 0x1120eee40
@@ -10,9 +11,12 @@ idc.patch_dword(MessageAddress + 0x08, task_id)
idc.patch_dword(sendMessageAddress + 0x20, task_id)
idc.patch_dword(0x175ED6600, task_id)
MessageAddrAddr = 0x1120eed80
idc.patch_dword(MessageAddrAddr+0x18, int(time.time()))
# 改task id, 改 cgi,改第一个指针即可
payload = (
b"\x90\x00\x00\x20\x0A\x02\x00\x00" # 0x00 // task id / cmd id 175ED6600
b"\x0A\x02\x00\x00" # 0x00 // task id / cmd id 175ED6600
b"\x00\x00\x00\x00\x00\x00\x00\x00" # 0x08
b"\x03\x00\x00\x00\x10\x00\x00\x00" # 0x10
b"\x40\xec\x0e\x12\x01\x00\x00\x00" # 0x18 // cgi 1120eec40
@@ -70,7 +74,7 @@ ida_bytes.patch_bytes(0x175ED6604, payload)
my_func = ida_idd.Appcall.proto(0x10444A99C, "long long __fastcall sub_10444A99C(long long *a1, long long a2);")
try:
my_func(0x9816A9400, 0x175ED6600)
my_func(0x8E1699400, 0x175ED6600)
print("Executed with manually set X0.")
except Exception as e:
print(f"Error: {e}")
print(f"Error: {e}")
+6 -1
View File
@@ -24,7 +24,7 @@ def get_varint_timestamp_bytes():
def run_patch_script():
# --- 1. 设置目标空内存地址 ---
x1_addr = idc.get_reg_value("X1")
x1_addr = 0x1120eea40
print(f"[*] 原始 X1 指向地址: {hex(x1_addr)}")
# --- 2. 构造 Payload ---
@@ -64,6 +64,11 @@ def run_patch_script():
else:
print("[-] 错误: 无法设置 X1 寄存器,请检查寄存器名称。")
if idc.set_reg_value(0x62, "X2"):
print(f"[*] 成功: 数据已写入 {hex(x1_addr)}")
else:
print("[-] 错误: 无法设置 X2 寄存器,请检查寄存器名称。")
# 启动脚本
run_patch_script()
+13 -4
View File
@@ -4,11 +4,17 @@ cgiAddress = 0x1120eec40
callBackFuncAddress = 0x1120eec70
sendMessageAddress = 0x1120eed40 # 40 ed 0e 12 01
MessageAddress = 0x1120eee40
MessageContentAddress = 0x1120eed70
MessageContentAddress = 0x1120eed70 # 70 ed 0e 12 01
MessageAddrAddr = 0x1120eed80
ReceiverAddress = 0x1120eeb10
ReceiverAddrAddr = 0x1120eeb20
ContentAddr = 0x1120eeb50
HtmlAddr = 0x1120eeb60
HtmlAddrAddr = 0x1120eeb70
def setup_send_message():
patch_string_at_address(cgiAddress,
@@ -47,7 +53,7 @@ def setup_send_message():
idc.patch_qword(MessageAddress + 0xa0, 0)
idc.patch_qword(MessageAddress + 0xa8, 0)
idc.patch_qword(MessageAddress + 0xb0, 0)
idc.patch_qword(MessageAddress + 0xb8, 0x107f96918)
idc.patch_qword(MessageAddress + 0xb8, 0x10)
idc.patch_qword(MessageAddress + 0xc0, MessageContentAddress)
idc.patch_qword(MessageAddress + 0xc8, 0x0000000100000001)
idc.patch_qword(MessageAddress + 0xd0, 4)
@@ -57,8 +63,11 @@ def setup_send_message():
# 可能需要修改,再试一下
idc.patch_qword(MessageContentAddress, MessageAddrAddr)
idc.patch_qword(MessageAddrAddr, 0x107f968a0)
idc.patch_qword(MessageAddrAddr, cgiAddress)
idc.patch_qword(MessageAddrAddr+0x8, ContentAddr)
patch_string_at_address(ContentAddr, "77 77 77")
def patch_string_at_address(target_addr, hex_str):
data = bytes.fromhex(hex_str.replace(" ", "").replace("\n", ""))
+1 -1
View File
@@ -1,5 +1,5 @@
执行use_struct.py脚本
然后执行trigger_send.py脚本,改task id, 改 cgi,改第一个指针即可,第一个指针sub_10444A99C 函数执行的x0
在req2buf中打断点,在x0+60处,patch指针0x1120eed40
在req2buf中打断点,在x0+60处,patch指针0x1120eed40 / 40 ed 0e 12 01
更改0x1120eed40 的taskId
然后在protobuf编辑处打断点,执行脚本update_sendMsg.py