mirror of
https://github.com/yincongcyincong/wechat_chatter.git
synced 2026-07-15 10:26:52 +08:00
finish 8.28
This commit is contained in:
+9
-9
@@ -1,19 +1,19 @@
|
||||
let module;
|
||||
Process.enumerateModules().forEach(function (m) {
|
||||
if (m.name.toLowerCase().includes("wechat.dylib")) {
|
||||
module = m;
|
||||
}
|
||||
});
|
||||
console.log("module:", module.name, module.base, module.size);
|
||||
var moduleName = "wechat.dylib";
|
||||
var module = Process.findModuleByName(moduleName);
|
||||
var baseAddr = module.base;
|
||||
if (!baseAddr) {
|
||||
console.error("[!] 找不到 WeChat 模块基址,请检查进程名。");
|
||||
}
|
||||
console.log("[+] WeChat base address: " + baseAddr);
|
||||
|
||||
function scanPatterns() {
|
||||
myPatterns.forEach((item, index) => {
|
||||
const { name, pattern } = item;
|
||||
|
||||
Memory.scan(module.base, module.size, pattern, {
|
||||
Memory.scan(baseAddr, module.size, pattern, {
|
||||
onMatch: function(address, size) {
|
||||
// 计算相对偏移 (RVA)
|
||||
const offset = address.sub(module.base);
|
||||
const offset = address.sub(baseAddr);
|
||||
console.log(`"${name}": "${offset}", 绝对地址: ${address}`);
|
||||
},
|
||||
onError: function(reason) {
|
||||
|
||||
+23
-19
@@ -1,16 +1,11 @@
|
||||
// 1. 获取微信主模块的基地址
|
||||
var baseAddr = ptr(0);
|
||||
Process.enumerateModules().forEach(function (m) {
|
||||
if (m.name.toLowerCase().includes("wechat.dylib")) {
|
||||
baseAddr = m.base;
|
||||
}
|
||||
});
|
||||
|
||||
if (baseAddr === 0x0) {
|
||||
console.log("wechat.dylib not found");
|
||||
var moduleName = "wechat.dylib";
|
||||
var baseAddr = Process.findModuleByName(moduleName).base;
|
||||
if (!baseAddr) {
|
||||
console.error("[!] 找不到 WeChat 模块基址,请检查进程名。");
|
||||
}
|
||||
console.log("[+] WeChat base address: " + baseAddr);
|
||||
|
||||
console.log("baseAddr: " + baseAddr);
|
||||
|
||||
// -------------------------基础函数分区-------------------------
|
||||
function toVarint(n) {
|
||||
@@ -108,15 +103,15 @@ function generateBytes(n) {
|
||||
// 双方公共使用的地址
|
||||
var triggerX1Payload;
|
||||
var triggerX0;
|
||||
var req2bufEnterAddr = baseAddr.add(0x3806b30);
|
||||
var req2bufExitAddr = baseAddr.add(0x3807C48);
|
||||
var req2bufEnterAddr = baseAddr.add(`0x3806b30`);
|
||||
var req2bufExitAddr = baseAddr.add(0x3807C44);
|
||||
var sendFuncAddr = baseAddr.add(0x498D2E0);
|
||||
var insertMsgAddr = ptr(0);
|
||||
var sendMsgType = "";
|
||||
|
||||
// 图片消息全局变量
|
||||
var imageCallbackFuncAddr = baseAddr.add(0x251AD40);
|
||||
var imgProtobufAddr = imageCallbackFuncAddr.add(0x54);
|
||||
var imgProtobufAddr = imageCallbackFuncAddr.add(0x50);
|
||||
var patchImgProtobufFunc1 = imageCallbackFuncAddr.add(0x10);
|
||||
var patchImgProtobufFunc1Byte;
|
||||
var patchImgProtobufFunc2 = imageCallbackFuncAddr.add(0x30);
|
||||
@@ -126,7 +121,7 @@ var imgProtobufDeleteAddrByte;
|
||||
|
||||
// 视频消息全局变量
|
||||
var videoCallbackFuncAddr = baseAddr.add(0x2587FD0);
|
||||
var videoProtobufAddr = videoCallbackFuncAddr.add(0x54);
|
||||
var videoProtobufAddr = videoCallbackFuncAddr.add(0x50);
|
||||
var patchVideoProtobufFunc1 = videoCallbackFuncAddr.add(0x10);
|
||||
var patchVideoProtobufFunc1Byte;
|
||||
var patchVideoProtobufFunc2 = videoCallbackFuncAddr.add(0x30);
|
||||
@@ -139,6 +134,11 @@ var cndOnCompleteAddr = baseAddr.add(0x37C40E0);
|
||||
var imgMessageCallbackFunc1 = baseAddr.add(0x89159F0);
|
||||
var videoMessageCallbackFunc1 = baseAddr.add(0x8918790);
|
||||
|
||||
var uploadGetCallbackWrapperAddr = baseAddr.add(0x4aa2324);
|
||||
var uploadGetCallbackWrapperFuncAddr = baseAddr.add(0x37C392C);
|
||||
var uploadOnCompleteAddr = baseAddr.add(0x4AA2920);
|
||||
var uploadOnCompleteFuncAddr = baseAddr.add(0x37C4B10);
|
||||
|
||||
var uploadImageX1 = ptr(0);
|
||||
var imgCgiAddr = ptr(0);
|
||||
var sendImgMessageAddr = ptr(0);
|
||||
@@ -767,7 +767,11 @@ function attachProto() {
|
||||
}));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
setImmediate(attachProto);
|
||||
|
||||
function attachVideoProto() {
|
||||
Interceptor.attach(videoProtobufAddr, {
|
||||
onEnter: function (args) {
|
||||
|
||||
@@ -899,7 +903,7 @@ function attachProto() {
|
||||
});
|
||||
}
|
||||
|
||||
setImmediate(attachProto);
|
||||
setImmediate(attachVideoProto());
|
||||
|
||||
|
||||
function triggerUploadImg(receiver, md5, imagePath) {
|
||||
@@ -1242,7 +1246,7 @@ function patchCdnOnComplete() {
|
||||
setImmediate(patchCdnOnComplete)
|
||||
|
||||
function attachGetCallbackFromWrapper() {
|
||||
Interceptor.attach(baseAddr.add(0x4aa2324), {
|
||||
Interceptor.attach(uploadGetCallbackWrapperAddr, {
|
||||
onEnter: function (args) {
|
||||
const tmpFileId = this.context.x1.readPointer().readUtf8String();
|
||||
const imageFileId = imageIdAddr.readUtf8String();
|
||||
@@ -1252,13 +1256,13 @@ function attachGetCallbackFromWrapper() {
|
||||
return
|
||||
}
|
||||
|
||||
uploadCallback.add(0x10).writePointer(baseAddr.add(0x37C392C));
|
||||
uploadCallback.add(0x10).writePointer(uploadGetCallbackWrapperFuncAddr);
|
||||
this.context.x8 = uploadCallback;
|
||||
console.log("[+] GetCallbackFromWrapper x8: " + this.context.x8);
|
||||
}
|
||||
})
|
||||
|
||||
Interceptor.attach(baseAddr.add(0x4AA2920), {
|
||||
Interceptor.attach(uploadOnCompleteAddr, {
|
||||
onEnter: function (args) {
|
||||
const tmpFileId = this.context.x1.readPointer().readUtf8String();
|
||||
const imageFileId = imageIdAddr.readUtf8String();
|
||||
@@ -1268,7 +1272,7 @@ function attachGetCallbackFromWrapper() {
|
||||
return
|
||||
}
|
||||
|
||||
uploadCallback.add(0x30).writePointer(baseAddr.add(0x37C4B10));
|
||||
uploadCallback.add(0x30).writePointer(uploadOnCompleteFuncAddr);
|
||||
this.context.x8 = uploadCallback;
|
||||
console.log("[+] OnComplete x8: " + this.context.x8);
|
||||
}
|
||||
|
||||
+7
-7
@@ -1,7 +1,7 @@
|
||||
var baseAddr = ptr(0);
|
||||
Process.enumerateModules().forEach(function (m) {
|
||||
if (m.name.toLowerCase().includes("wechat.dylib")) {
|
||||
baseAddr = m.base;
|
||||
}
|
||||
});
|
||||
console.log("Base address of wechat.dylib: " + baseAddr);
|
||||
// 1. 获取微信主模块的基地址
|
||||
var moduleName = "wechat.dylib";
|
||||
var baseAddr = Process.findModuleByName(moduleName).base;
|
||||
if (!baseAddr) {
|
||||
console.error("[!] 找不到 WeChat 模块基址,请检查进程名。");
|
||||
}
|
||||
console.log("[+] WeChat base address: " + baseAddr);
|
||||
|
||||
+15
-20
@@ -1,19 +1,14 @@
|
||||
var baseAddr = ptr(0);
|
||||
Process.enumerateModules().forEach(function (m) {
|
||||
if (m.name.toLowerCase().includes("wechat.dylib")) {
|
||||
baseAddr = m.base;
|
||||
}
|
||||
});
|
||||
|
||||
if (baseAddr === 0x0) {
|
||||
console.log("wechat.dylib not found");
|
||||
var moduleName = "wechat.dylib";
|
||||
var baseAddr = Process.findModuleByName(moduleName).base;
|
||||
if (!baseAddr) {
|
||||
console.error("[!] 找不到 WeChat 模块基址,请检查进程名。");
|
||||
}
|
||||
console.log("baseAddr: " + baseAddr);
|
||||
console.log("[+] WeChat base address: " + baseAddr);
|
||||
|
||||
var buf2RespAddr = baseAddr.add(0x382c1b4)
|
||||
var downloadImagAddr = baseAddr.add(0x4bf8608) // image_download
|
||||
var downloadFileAddr = baseAddr.add(0x4B97384) // c2c_download
|
||||
var downloadVideoAddr = baseAddr.add(0x4bb9100) // hdvideo_streaming
|
||||
var buf2RespAddr = baseAddr.add(0x382C1A8)
|
||||
var downloadImagAddr = baseAddr.add(0x4BF85F0) // image_download
|
||||
var downloadFileAddr = baseAddr.add(0x4B97378) // c2c_download
|
||||
var downloadVideoAddr = baseAddr.add(0x4bb90fc) // hdvideo_streaming
|
||||
var startDownloadMedia = baseAddr.add(0x4AD54D4)
|
||||
|
||||
var downloadGlobalX0;
|
||||
@@ -40,12 +35,12 @@ setImmediate(setupDownloadFileDynamic)
|
||||
function setReceiver() {
|
||||
Interceptor.attach(buf2RespAddr, {
|
||||
onEnter: function (args) {
|
||||
const currentPtr = this.context.x1;
|
||||
const currentPtr = this.context.x20;
|
||||
if (currentPtr.add(0).readU8() !== 0x08) {
|
||||
return
|
||||
}
|
||||
|
||||
const x2 = this.context.x2.toInt32();
|
||||
const x2 = this.context.x0.toInt32();
|
||||
const fields = getProtobufRawBytes(currentPtr, x2)
|
||||
|
||||
const sender = fields[0]
|
||||
@@ -154,8 +149,8 @@ function setReceiver() {
|
||||
|
||||
Interceptor.attach(downloadFileAddr, {
|
||||
onEnter: function (args) {
|
||||
var dataPtr = this.context.x1;
|
||||
var dataLen = this.context.x2.toInt32();
|
||||
var dataPtr = this.context.x22;
|
||||
var dataLen = this.context.x0.toInt32();
|
||||
var fileId = this.context.sp.add(0x30).readPointer().readUtf8String();
|
||||
var cdnUrl = this.context.x19.add(0x2F8).readPointer().readUtf8String();
|
||||
|
||||
@@ -170,7 +165,7 @@ function setReceiver() {
|
||||
|
||||
Interceptor.attach(downloadImagAddr, {
|
||||
onEnter: function (args) {
|
||||
var dataPtr = this.context.x1;
|
||||
var dataPtr = this.context.x22;
|
||||
var dataLen = this.context.x2.toInt32();
|
||||
var fileId = this.context.x19.add(0x2E0).readPointer().readUtf8String();
|
||||
var cdnUrl = this.context.x19.add(0x2F8).readPointer().readUtf8String();
|
||||
@@ -187,7 +182,7 @@ function setReceiver() {
|
||||
Interceptor.attach(downloadVideoAddr, {
|
||||
onEnter: function (args) {
|
||||
var dataPtr = this.context.x1;
|
||||
var dataLen = this.context.x2.toInt32();
|
||||
var dataLen = this.context.x24.toInt32();
|
||||
var fileId = this.context.x22.add(0x40).readPointer().readUtf8String();
|
||||
var cdnUrl = this.context.x22.add(0x58).readPointer().readUtf8String();
|
||||
|
||||
|
||||
+12
-18
@@ -1,15 +1,9 @@
|
||||
var baseAddr = ptr(0);
|
||||
Process.enumerateModules().forEach(function (m) {
|
||||
if (m.name.toLowerCase().includes("wechat.dylib")) {
|
||||
baseAddr = m.base;
|
||||
}
|
||||
});
|
||||
|
||||
if (baseAddr === 0x0) {
|
||||
console.log("wechat.dylib not found");
|
||||
var moduleName = "wechat.dylib";
|
||||
var baseAddr = Process.findModuleByName(moduleName).base;
|
||||
if (!baseAddr) {
|
||||
console.error("[!] 找不到 WeChat 模块基址,请检查进程名。");
|
||||
}
|
||||
console.log("baseAddr: " + baseAddr);
|
||||
|
||||
console.log("[+] WeChat base address: " + baseAddr);
|
||||
|
||||
// -------------------------基础函数分区-------------------------
|
||||
function toVarint(n) {
|
||||
@@ -95,15 +89,15 @@ var textCgiAddr = ptr(0);
|
||||
var sendTextMessageAddr = ptr(0);
|
||||
var textMessageAddr = ptr(0);
|
||||
var textProtoX1PayloadAddr = ptr(0);
|
||||
var sendMessageCallbackFunc = ptr(0);
|
||||
var messageCallbackFunc1 = baseAddr.add(0x8915F28);
|
||||
|
||||
var sendMessageCallbackFunc = baseAddr.add(0x8915F28);
|
||||
|
||||
|
||||
// 双方公共使用的地址
|
||||
var triggerX1Payload;
|
||||
var triggerX0;
|
||||
var req2bufEnterAddr = baseAddr.add(0x3806b30);
|
||||
var req2bufExitAddr = baseAddr.add(0x3807C48);
|
||||
var req2bufExitAddr = baseAddr.add(0x3807C44);
|
||||
var sendFuncAddr = baseAddr.add(0x498D2E0);
|
||||
var insertMsgAddr = ptr(0);
|
||||
var sendMsgType = "";
|
||||
@@ -137,7 +131,7 @@ function setupSendTextMessageDynamic() {
|
||||
// B. 构建 sendTextMessageAddr 结构体 (X24 基址位置)
|
||||
sendTextMessageAddr.add(0x00).writeU64(0);
|
||||
sendTextMessageAddr.add(0x08).writeU64(0);
|
||||
sendTextMessageAddr.add(0x10).writePointer(sendMessageCallbackFunc);
|
||||
sendTextMessageAddr.add(0x10).writeU64(0);
|
||||
sendTextMessageAddr.add(0x18).writeU64(1);
|
||||
sendTextMessageAddr.add(0x20).writeU32(taskIdGlobal);
|
||||
sendTextMessageAddr.add(0x28).writePointer(textMessageAddr); // 指向动态分配的 Message
|
||||
@@ -150,7 +144,7 @@ function setupSendTextMessageDynamic() {
|
||||
}));
|
||||
|
||||
// C. 构建 Message 结构体
|
||||
textMessageAddr.add(0x00).writePointer(messageCallbackFunc1);
|
||||
textMessageAddr.add(0x00).writePointer(sendMessageCallbackFunc);
|
||||
textMessageAddr.add(0x08).writeU32(taskIdGlobal);
|
||||
textMessageAddr.add(0x0c).writeU32(0x20a);
|
||||
textMessageAddr.add(0x10).writeU64(0x3);
|
||||
@@ -309,7 +303,7 @@ function triggerSendTextMessage(taskId, receiver, content, atUser) {
|
||||
}
|
||||
|
||||
function AttachSendTextProto() {
|
||||
Interceptor.attach(sendFuncAddr, {
|
||||
Interceptor.attach(sendFuncAddr.add(0x10), {
|
||||
onEnter: function (args) {
|
||||
if (triggerX1Payload) {
|
||||
return
|
||||
@@ -448,4 +442,4 @@ function attachReq2buf() {
|
||||
|
||||
setImmediate(attachReq2buf);
|
||||
|
||||
// -------------------------Req2Buf公共部分分区-------------------------
|
||||
// -------------------------Req2Buf公共部分分区-------------------------
|
||||
|
||||
-143
@@ -1,143 +0,0 @@
|
||||
const FUNCTION_RVA = 0x10250D878; // 目标函数 sendMsg_10250D878 的 RVA
|
||||
|
||||
const STRUCT_SIZE = 0x50;
|
||||
|
||||
const module = Process.getModuleByName("WeChat");
|
||||
const baseAddress = module.base;
|
||||
console.log(`Base: ${baseAddress}, size: ${module.base.add(module.size)}`)
|
||||
|
||||
const targetAddress = baseAddress.add(FUNCTION_RVA - 0x100000000);
|
||||
console.log(`Target Address: ${targetAddress}`)
|
||||
|
||||
let resent = true;
|
||||
let arg0;
|
||||
|
||||
function sendMessageWechat() {
|
||||
const funcAddr_1 = baseAddress.add(0x10817DF48 - 0x100000000); // 示例计算
|
||||
const funcAddr_2 = baseAddress.add(0x108177ED0 - 0x100000000); // 示例计算
|
||||
const funcAddr_3 = baseAddress.add(0x10816AFD8 - 0x100000000); // 示例计算
|
||||
const funcAddr_4 = baseAddress.add(0x10817C298 - 0x100000000); // 示例计算
|
||||
|
||||
|
||||
// --- 2. 构造数据结构体的内存 ---
|
||||
const structPointer = Memory.alloc(STRUCT_SIZE);
|
||||
|
||||
// --- 3. 构造 wxid 字符串 (参数 5) ---
|
||||
const WXID_STRING = "wxid_7wd1ece99f7i21";
|
||||
|
||||
structPointer.writePointer(funcAddr_1);
|
||||
console.log(`Function 1 Address: ${funcAddr_1}`);
|
||||
|
||||
// 结构体偏移 0x08: 参数 2 的第一级指针 (0x60000151F948)
|
||||
// 这里需要构造二级指针。由于无法分配静态地址 0x6000...,我们只能构造一个新链。
|
||||
|
||||
// 构造二级指针的目标函数 sub_1023D8204
|
||||
const funcPtr_2_tmp1 = Memory.alloc(Process.pointerSize);
|
||||
const funcPtr_2_tmp2 = Memory.alloc(Process.pointerSize);
|
||||
funcPtr_2_tmp1.writePointer(funcPtr_2_tmp2);
|
||||
funcPtr_2_tmp2.writePointer(funcAddr_2);
|
||||
structPointer.add(0x08).writePointer(funcPtr_2_tmp1);
|
||||
console.log(`Function 2 Address: ${funcAddr_2}, tmp1: ${funcPtr_2_tmp1}, tmp2: ${funcPtr_2_tmp2}`);
|
||||
|
||||
// 结构体偏移 0x10: 参数 3 的第一级指针 (0x600003F41C20 -> sub_1021D5E48)
|
||||
const funcPtr_3 = Memory.alloc(Process.pointerSize);
|
||||
funcPtr_3.writePointer(funcAddr_3);
|
||||
structPointer.add(0x10).writePointer(funcPtr_3);
|
||||
console.log(`Function 3 Address: ${funcAddr_3}, tmp: ${funcPtr_3}`);
|
||||
|
||||
const funcPtr_4 = Memory.alloc(Process.pointerSize);
|
||||
funcPtr_4.writePointer(funcAddr_4);
|
||||
structPointer.add(0x18).writePointer(funcPtr_4);
|
||||
console.log(`Function 4 Address: ${funcAddr_3}, tmp: ${funcPtr_4}`);
|
||||
|
||||
// 结构体偏移 0x20: 参数 5 (wxid_7wd1ece99f7i21)
|
||||
structPointer.add(0x20).writeUtf8String(WXID_STRING);
|
||||
console.log(`WXID String Address: ${WXID_STRING}`);
|
||||
|
||||
// 填充剩余部分(假设为 NULL 或 0)
|
||||
structPointer.add(0x28).writePointer(NULL);
|
||||
structPointer.add(0x30).writePointer(NULL);
|
||||
|
||||
console.log(`Structure constructed at: ${structPointer}`);
|
||||
|
||||
|
||||
// --- 5. 定义函数签名并调用 ---
|
||||
try {
|
||||
|
||||
const sendMsgFunc = new NativeFunction(
|
||||
targetAddress,
|
||||
'void',
|
||||
['pointer'] // 参数类型为 'pointer'
|
||||
);
|
||||
|
||||
console.log(`Attempting to call the function with constructed structure...: ${targetAddress}`);
|
||||
|
||||
// 调用函数,传入主结构体的地址
|
||||
sendMsgFunc(structPointer);
|
||||
|
||||
console.log(`Function called successfully!`);
|
||||
|
||||
} catch (e) {
|
||||
console.error(`Error calling function: ${e.message}`);
|
||||
console.error(`Error details: ${e.stack}`);
|
||||
}
|
||||
}
|
||||
|
||||
Interceptor.attach(targetAddress, {
|
||||
onEnter: function (args) {
|
||||
console.log(`[ENTER] sendMsg called with a1 = ${args[0]}`);
|
||||
// 检查传入的结构
|
||||
const a1 = args[0]
|
||||
console.log(` a1: ${a1.readPointer()}`);
|
||||
console.log(` a1+8: ${a1.add(0x08).readPointer()}`);
|
||||
console.log(` a1+16: ${a1.add(0x10).readPointer()}`);
|
||||
console.log(` a1+24: ${a1.add(0x18).readPointer()}`);
|
||||
console.log(` a1+32: ${a1.add(0x20).readPointer()}`);
|
||||
|
||||
},
|
||||
onLeave: function (retval) {
|
||||
console.log(`[LEAVE] sendMsg returned`);
|
||||
}
|
||||
});
|
||||
|
||||
function resend() {
|
||||
console.log(`Resending structure...`);
|
||||
console.log(` resend a1: ${arg0.readPointer()}`);
|
||||
console.log(` resend a1+8: ${arg0.add(0x08).readPointer()}`);
|
||||
console.log(` resend a1+16: ${arg0.add(0x10).readPointer()}`);
|
||||
console.log(` resend a1+24: ${arg0.add(0x18).readPointer()}`);
|
||||
console.log(` resend a1+32: ${arg0.add(0x20).readPointer()}`);
|
||||
const structPointer = Memory.alloc(STRUCT_SIZE);
|
||||
|
||||
// --- 3. 构造 wxid 字符串 (参数 5) ---
|
||||
const WXID_STRING = "wxid_7wd1ece99f7i21";
|
||||
|
||||
structPointer.writePointer(arg0.readPointer());
|
||||
structPointer.add(0x08).writePointer(arg0.add(0x08).readPointer());
|
||||
structPointer.add(0x10).writePointer(arg0.add(0x10).readPointer());
|
||||
structPointer.add(0x18).writePointer(arg0.add(0x18).readPointer());
|
||||
structPointer.add(0x20).writeUtf8String(WXID_STRING);
|
||||
structPointer.add(0x28).writePointer(NULL);
|
||||
structPointer.add(0x30).writePointer(NULL);
|
||||
console.log(`Resent structure constructed at: ${structPointer}`);
|
||||
|
||||
try {
|
||||
|
||||
const sendMsgFunc = new NativeFunction(
|
||||
targetAddress,
|
||||
'void',
|
||||
['pointer'] // 参数类型为 'pointer'
|
||||
);
|
||||
|
||||
console.log(`Attempting to call the function with constructed structure...: ${targetAddress}`);
|
||||
|
||||
// 调用函数,传入主结构体的地址
|
||||
sendMsgFunc(structPointer);
|
||||
|
||||
console.log(`Function called successfully!`);
|
||||
|
||||
} catch (e) {
|
||||
console.error(`Error calling function: ${e.message}`);
|
||||
console.error(`Error details: ${e.stack}`);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
### 问题
|
||||
解决不存在frida-core.h: https://github.com/frida/frida-go/issues/4
|
||||
|
||||
1 参数 10817DF48 是一个函数 sub_10250D544
|
||||
2 参数 60000151F948->600003F41C38 -> 108177ED0 是一个函数 sub_1023D8204
|
||||
3 参数 600003F41C20 -> 10816AFD8 是一个函数 sub_1021D5E48
|
||||
4 参数 1371FD018-> 10817C298 是一个函数 sub_10247C008
|
||||
5 参数 wxid_7wd1ece99f7i21
|
||||
+28
-28
@@ -26,16 +26,16 @@ func main() {
|
||||
initFrida()
|
||||
}
|
||||
go SendWorker()
|
||||
|
||||
|
||||
http.HandleFunc("/send_private_msg", sendHandler)
|
||||
http.HandleFunc("/send_group_msg", sendHandler)
|
||||
|
||||
|
||||
http.HandleFunc("/ws", handleWebSocket)
|
||||
http.HandleFunc("/test_ws", testWebSocket)
|
||||
|
||||
|
||||
stop := make(chan os.Signal, 1)
|
||||
signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
|
||||
|
||||
|
||||
go func() {
|
||||
<-stop
|
||||
fridaScript.Clean()
|
||||
@@ -43,13 +43,13 @@ func main() {
|
||||
device.Clean()
|
||||
Fatal("正在释放 Frida 资源并退出...")
|
||||
}()
|
||||
|
||||
|
||||
// 3. 启动服务
|
||||
Info("HTTP 服务启动在", "host", config.ReceiveHost)
|
||||
if err := http.ListenAndServe(config.ReceiveHost, nil); err != nil {
|
||||
Error("服务启动失败", "err", err)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
func initFlag() {
|
||||
@@ -59,13 +59,13 @@ func initFlag() {
|
||||
flag.StringVar(&config.FridaGadgetAddr, "gadget_addr", "127.0.0.1:27042", "Gadget 地址: 127.0.0.1:27042 仅当 type 为 gadget 时有效")
|
||||
flag.StringVar(&config.OnebotToken, "token", "MuseBot", "OneBot Token: MuseBot")
|
||||
flag.StringVar(&config.ImagePath, "image_path", "", "图片路径: /Users/xxx/Library/Containers/com.tencent.xinWeChat/Data/Documents/xwechat_files/xxx/temp/xxx/2026-01/Img/")
|
||||
flag.StringVar(&config.WechatConf, "wechat_conf", "../wechat_version/4_1_7_57_mac.json", "微信配置文件路径: ../wechat_version/4_1_6_12_mac.json")
|
||||
flag.StringVar(&config.WechatConf, "wechat_conf", "../wechat_version/4_1_8_28_mac.json", "微信配置文件路径: ../wechat_version/4_1_6_12_mac.json")
|
||||
flag.StringVar(&config.ConnType, "conn_type", "http", "连接类型: http | websocket")
|
||||
flag.IntVar(&config.SendInterval, "send_interval", 1000, "发送间隔: ms")
|
||||
flag.StringVar(&logLevel, "log_level", "info", "log level")
|
||||
|
||||
|
||||
flag.Parse()
|
||||
|
||||
|
||||
fmt.Println("FridaType", config.FridaType)
|
||||
fmt.Println("SendURL", config.SendURL)
|
||||
fmt.Println("ReceiveHost", config.ReceiveHost)
|
||||
@@ -86,39 +86,39 @@ func initFridaGadget() {
|
||||
if err != nil {
|
||||
Fatal("❌ 无法连接 Gadget", err)
|
||||
}
|
||||
|
||||
|
||||
session, err = device.Attach("Gadget", nil)
|
||||
if err != nil {
|
||||
Fatal("❌ 附加失败", err)
|
||||
}
|
||||
|
||||
|
||||
loadJs()
|
||||
|
||||
|
||||
}
|
||||
|
||||
func initFrida() {
|
||||
var err error
|
||||
// 1. 获取本地设备管理器
|
||||
mgr := frida.NewDeviceManager()
|
||||
|
||||
|
||||
// 2. 枚举并获取本地设备 (TypeLocal)
|
||||
device, err = mgr.DeviceByType(frida.DeviceTypeLocal)
|
||||
if err != nil {
|
||||
Fatal("无法获取本地设备", "err", err)
|
||||
}
|
||||
|
||||
|
||||
pid, err := GetWeChatPID()
|
||||
if err != nil {
|
||||
Fatal("未发现正在运行的微信进程")
|
||||
}
|
||||
Info("微信进程 PID", "PID", pid)
|
||||
MonitorProcessExit(pid)
|
||||
|
||||
|
||||
session, err = device.Attach(pid, nil)
|
||||
if err != nil {
|
||||
Fatal("Attach 失败 (请检查 SIP 状态或权限)", "err", err)
|
||||
}
|
||||
|
||||
|
||||
loadJs()
|
||||
}
|
||||
|
||||
@@ -127,35 +127,35 @@ func loadJs() {
|
||||
if err != nil {
|
||||
Fatal("读取文件失败", "err", err)
|
||||
}
|
||||
|
||||
|
||||
// 2. 将 JSON 解析为 Map
|
||||
var wechatHookConf map[string]interface{}
|
||||
if err = json.Unmarshal(jsonData, &wechatHookConf); err != nil {
|
||||
Fatal("解析 JSON 失败", "err", err)
|
||||
}
|
||||
|
||||
|
||||
codeTemplate, err := os.ReadFile("./script.js")
|
||||
if err != nil {
|
||||
Fatal("读取脚本失败", "err", err)
|
||||
}
|
||||
|
||||
|
||||
tmpl, err := template.New("fridaScript").Parse(string(codeTemplate))
|
||||
if err != nil {
|
||||
Fatal("解析模板失败", "err", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
var buf bytes.Buffer
|
||||
err = tmpl.Execute(&buf, wechatHookConf)
|
||||
if err != nil {
|
||||
Fatal("执行模板失败", "err", err)
|
||||
}
|
||||
|
||||
|
||||
script, err := session.CreateScript(buf.String())
|
||||
if err != nil {
|
||||
Fatal("创建脚本失败", "err", err)
|
||||
}
|
||||
|
||||
|
||||
// 打印 JS 里的 console.log
|
||||
script.On("message", func(rawMsg string) {
|
||||
defer func() {
|
||||
@@ -163,16 +163,16 @@ func loadJs() {
|
||||
Error("message panic", "err", r, "stack", string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
var msg map[string]interface{}
|
||||
err = json.Unmarshal([]byte(rawMsg), &msg)
|
||||
if err != nil {
|
||||
Error("JSON解析失败", "err", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
msgType := msg["type"].(string)
|
||||
|
||||
|
||||
switch msgType {
|
||||
case "send":
|
||||
if p, ok := msg["payload"]; ok {
|
||||
@@ -224,7 +224,7 @@ func loadJs() {
|
||||
Error("下载失败", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -234,11 +234,11 @@ func loadJs() {
|
||||
Error("[JS日志报错]", "err", msg["description"], "stack", msg["stack"])
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
if err := script.Load(); err != nil {
|
||||
Fatal("❌ 加载脚本失败", err)
|
||||
}
|
||||
|
||||
|
||||
fridaScript = script
|
||||
Info("✅ Frida 已就绪,微信控制通道已打通")
|
||||
}
|
||||
|
||||
+15
-15
@@ -1,5 +1,5 @@
|
||||
// 1. 获取微信主模块的基地址
|
||||
var baseAddr = Process.getModuleByName("WeChat").base;
|
||||
var moduleName = "wechat.dylib";
|
||||
var baseAddr = Process.findModuleByName(moduleName).base;
|
||||
if (!baseAddr) {
|
||||
console.error("[!] 找不到 WeChat 模块基址,请检查进程名。");
|
||||
}
|
||||
@@ -260,7 +260,7 @@ function generateBytes(n) {
|
||||
// 文本消息全局变量
|
||||
// 文本消息全局变量
|
||||
var textCallbackFuncAddr = baseAddr.add({{.textCallbackFuncAddr}});
|
||||
var protobufAddr = textCallbackFuncAddr.add(0x44);
|
||||
var protobufAddr = textCallbackFuncAddr.add(0x40);
|
||||
var patchTextProtobufAddr = textCallbackFuncAddr.add(0x20);
|
||||
var patchTextProtobufByte
|
||||
var patchTextProtobufDeleteAddr = textCallbackFuncAddr.add(0x5C);
|
||||
@@ -284,7 +284,7 @@ var buf2RespAddr = baseAddr.add({{.buf2RespAddr}});
|
||||
|
||||
// 图片消息全局变量
|
||||
var imageCallbackFuncAddr = baseAddr.add({{.imageCallbackFuncAddr}});
|
||||
var imgProtobufAddr = imageCallbackFuncAddr.add(0x54);
|
||||
var imgProtobufAddr = imageCallbackFuncAddr.add(0x50);
|
||||
var patchImgProtobufFunc1 = imageCallbackFuncAddr.add(0x10);
|
||||
var patchImgProtobufFunc1Byte;
|
||||
var patchImgProtobufFunc2 = imageCallbackFuncAddr.add(0x30);
|
||||
@@ -294,7 +294,7 @@ var imgProtobufDeleteAddrByte;
|
||||
|
||||
// 视频消息全局变量
|
||||
var videoCallbackFuncAddr = baseAddr.add({{.videoCallbackFuncAddr}});
|
||||
var videoProtobufAddr = videoCallbackFuncAddr.add(0x54);
|
||||
var videoProtobufAddr = videoCallbackFuncAddr.add(0x50);
|
||||
var patchVideoProtobufFunc1 = videoCallbackFuncAddr.add(0x10);
|
||||
var patchVideoProtobufFunc1Byte;
|
||||
var patchVideoProtobufFunc2 = videoCallbackFuncAddr.add(0x30);
|
||||
@@ -577,8 +577,8 @@ function triggerSendTextMessage(taskId, receiver, content, atUser) {
|
||||
}
|
||||
}
|
||||
|
||||
function AttachSendTextProto() {
|
||||
Interceptor.attach(sendFuncAddr, {
|
||||
function AttachSendFunc() {
|
||||
Interceptor.attach(sendFuncAddr.add(0x10), {
|
||||
onEnter: function (args) {
|
||||
|
||||
if (triggerX1Payload) {
|
||||
@@ -592,7 +592,7 @@ function AttachSendTextProto() {
|
||||
})
|
||||
}
|
||||
|
||||
setImmediate(AttachSendTextProto);
|
||||
setImmediate(AttachSendFunc);
|
||||
|
||||
// 拦截 SendTextProto 编码逻辑,注入自定义 Payload
|
||||
function attachSendTextProto() {
|
||||
@@ -1707,12 +1707,12 @@ setImmediate(setupDownloadFileDynamic)
|
||||
function setReceiver() {
|
||||
Interceptor.attach(buf2RespAddr, {
|
||||
onEnter: function (args) {
|
||||
const currentPtr = this.context.x1;
|
||||
const currentPtr = this.context.x20;
|
||||
if (currentPtr.add(0).readU8() !== 0x08) {
|
||||
return
|
||||
}
|
||||
|
||||
const x2 = this.context.x2.toInt32();
|
||||
const x2 = this.context.x0.toInt32();
|
||||
// console.log(" [+] currentPtr: ", hexdump(currentPtr, {
|
||||
// offset: 0,
|
||||
// length: x2,
|
||||
@@ -1820,8 +1820,8 @@ function setReceiver() {
|
||||
|
||||
Interceptor.attach(downloadFileAddr, {
|
||||
onEnter: function (args) {
|
||||
var dataPtr = this.context.x1;
|
||||
var dataLen = this.context.x2.toInt32();
|
||||
var dataPtr = this.context.x22;
|
||||
var dataLen = this.context.x20.toInt32();
|
||||
var fileId = this.context.sp.add(0x30).readPointer().readUtf8String();
|
||||
var cdnUrl = this.context.x19.add(0x2F8).readPointer().readUtf8String();
|
||||
|
||||
@@ -1841,7 +1841,7 @@ function setReceiver() {
|
||||
|
||||
Interceptor.attach(downloadImagAddr, {
|
||||
onEnter: function (args) {
|
||||
var dataPtr = this.context.x1;
|
||||
var dataPtr = this.context.x22;
|
||||
var dataLen = this.context.x2.toInt32();
|
||||
var fileId = this.context.x19.add(0x2E0).readPointer().readUtf8String();
|
||||
var cdnUrl = this.context.x19.add(0x2F8).readPointer().readUtf8String();
|
||||
@@ -1863,7 +1863,7 @@ function setReceiver() {
|
||||
Interceptor.attach(downloadVideoAddr, {
|
||||
onEnter: function (args) {
|
||||
var dataPtr = this.context.x1;
|
||||
var dataLen = this.context.x2.toInt32();
|
||||
var dataLen = this.context.x24.toInt32();
|
||||
var fileId = this.context.x22.add(0x40).readPointer().readUtf8String();
|
||||
var cdnUrl = this.context.x22.add(0x58).readPointer().readUtf8String();
|
||||
|
||||
@@ -2107,4 +2107,4 @@ function getMessages(content, sender, mediaContent) {
|
||||
return messages;
|
||||
}
|
||||
|
||||
// -------------------------接收消息分区-------------------------
|
||||
// -------------------------接收消息分区-------------------------
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
{
|
||||
"textCallbackFuncAddr": "",
|
||||
"sendMessageCallbackFunc": "",
|
||||
"sendFuncAddr": "",
|
||||
"req2bufEnterAddr": "",
|
||||
"req2bufExitAddr": "",
|
||||
"imageCallbackFuncAddr": "",
|
||||
"imgMessageCallbackFunc": "",
|
||||
"uploadImageAddr": "",
|
||||
"cndOnCompleteAddr": "",
|
||||
"buf2RespAddr": "",
|
||||
"uploadGetCallbackWrapperAddr": "",
|
||||
"uploadGetCallbackWrapperFuncAddr": "",
|
||||
"uploadOnCompleteAddr": "",
|
||||
"uploadOnCompleteFuncAddr": "",
|
||||
"downloadImagAddr": "",
|
||||
"startDownloadMedia": "",
|
||||
"downloadFileAddr": "",
|
||||
"downloadVideoAddr": "",
|
||||
"videoCallbackFuncAddr": "",
|
||||
"videoMessageCallbackFunc": ""
|
||||
}
|
||||
"textCallbackFuncAddr": "0x2524140",
|
||||
"sendMessageCallbackFunc": "0x8915F28",
|
||||
"sendFuncAddr": "0x498D2E0",
|
||||
"req2bufEnterAddr": "0x3806b30",
|
||||
"req2bufExitAddr": "0x3807C44",
|
||||
"imageCallbackFuncAddr": "0x251AD40",
|
||||
"imgMessageCallbackFunc": "0x89159F0",
|
||||
"uploadImageAddr": "0x4ad4860",
|
||||
"cndOnCompleteAddr": "0x37C40E0",
|
||||
"buf2RespAddr": "0x382C1A8",
|
||||
"uploadGetCallbackWrapperAddr": "0x4aa2324",
|
||||
"uploadGetCallbackWrapperFuncAddr": "0x37C392C",
|
||||
"uploadOnCompleteAddr": "0x4AA2920",
|
||||
"uploadOnCompleteFuncAddr": "0x37C4B10",
|
||||
"downloadImagAddr": "0x4BF85F0",
|
||||
"startDownloadMedia": "0x4AD54D4",
|
||||
"downloadFileAddr": "0x4B97378",
|
||||
"downloadVideoAddr": "0x4bb90fc",
|
||||
"videoCallbackFuncAddr": "0x2587FD0",
|
||||
"videoMessageCallbackFunc": "0x8918790"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user