update frida script

This commit is contained in:
yincong
2025-11-28 12:49:08 +08:00
parent 196213b302
commit 7a1f9e99a5
16 changed files with 798 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
Interceptor.attach(
ObjC.classes.NSEvent["- keyCode"].implementation,
{
onLeave(retval) {
try {
// 36 = Return(Enter)
if (retval.toInt32() === 36) {
console.log("\n===== ENTER PRESSED (System Level) =====");
// 打印调用栈
console.log(
Thread.backtrace(this.context, Backtracer.ACCURATE)
.map(DebugSymbol.fromAddress)
.join("\n")
);
console.log("========================================\n");
}
} catch (e) {}
}
}
);
View File
+127
View File
@@ -0,0 +1,127 @@
// ======================
// 安全参数打印
// ======================
function safePrintArg(ptr) {
try {
if (!ptr || ptr.isNull()) return "<null>";
// 如果能包装成 ObjC 对象
try {
try {
let o = new ObjC.Object(args[0]);
console.log(o.$className);
desc = o.toString();
if (desc.length > 300) desc = desc.slice(0, 300) + "...<truncated>";
return `[${cls}] ${desc}`;
} catch (_) {
console.log("raw:", args[0]);
}
} catch (_) {
// 不能包装成 OC 对象,则返回 pointer 地址
return ptr.toString();
}
} catch (e) {
return `<print-error: ${e}>`;
}
}
// ======================
// Hook 方法工具
// ======================
function hookMethod(clsName, methodName) {
try {
const cls = ObjC.classes[clsName];
if (!cls) return;
const method = cls[methodName];
if (!method || !method.implementation) return;
console.log(`\n🔥 Hooking ${clsName} ${methodName}`);
Interceptor.attach(method.implementation, {
onEnter(args) {
console.log(`\n🚀 ${clsName} ${methodName} called`);
// 打印参数 x0~x5
for (let i = 0; i < 6; i++) {
try {
console.log(`arg[${i}]: ${safePrintArg(args[i])}`);
} catch (e) {
console.log(`arg[${i}]: <error ${e}>`);
}
}
},
onLeave(retval) {
console.log(`⬅️ return: ${safePrintArg(retval)}`);
}
});
} catch (e) {
console.log(`❌ Hook ${clsName} ${methodName} failed: ${e}`);
}
}
// ======================
// WeChat 消息加密关键入口列表
// ======================
const HOOK_TARGETS = [
["WCMessageWrap", "- protobufEncode"],
["WCMessageWrap", "- serialize"],
// 发送消息必走
["WCProtoBuf", "- encodeMessage:"],
["WCProtoBuf", "- data"],
// 尝试抓取 key/data
["MMEncryptMessage", "- encryptMessage:key:"],
["WCEncryptHelper", "- encrypt:withKey:"],
["WCEncryptHelper", "- encryptData:key:"],
// 发送消息必走路径
["WCMessageMgr", "- SendAppMsg:"],
["WCMessageMgr", "- SendTextMessage:"],
["WCMessageMgr", "- SendImageMessage:"],
// 底层 protobuf builder
["PBGeneratedMessage", "- data"],
["PBGeneratedMessage", "- serialize"],
// 经常出现的 encode 函数
["MMProtoBase", "- serialize"],
["MMProtoBase", "- encode"]
];
// ======================
// 挂钩所有关键点
// ======================
function hookAll() {
console.log("🚀 WeChat 上层加密 Hook 正在启动...\n");
HOOK_TARGETS.forEach(([cls, method]) => {
hookMethod(cls, method);
});
// 额外扫描所有类名包含 Encode 或 Message 的 class
console.log("\n🔍 自动扫描 Encode / Message 类...");
for (const name in ObjC.classes) {
if (!name.includes("Encode") && !name.includes("Message")) continue;
const cls = ObjC.classes[name];
const methods = cls.$ownMethods;
methods.forEach(m => {
if (m.includes("encode") || m.includes("Encrypt") || m.includes("serialize")) {
hookMethod(name, m);
}
});
}
console.log("\n🎉 Hook 完成,开始抓取 WeChat 消息明文 / proto / encrypt 信息...\n");
}
// ======================
if (ObjC.available) {
hookAll();
} else {
setTimeout(hookAll, 1000);
}
+103
View File
@@ -0,0 +1,103 @@
// ====== 配置:你想 Hook 的 WeChat 函数偏移 ======
const WECHAT_OFFSETS = [
0x4565b2c,
0x4566f1c,
0x4564860,
0x4591ff8,
0x45d09cc,
0x45cebbc,
0x4591fa0,
0x4581834,
0x4581760,
0x4387d08,
0x4334e88,
0x4328ebc,
0x4384764,
0x43811e8
];
// ====== 统一安全打印函数 ======
function safePrintRegister(args) {
for (let i = 0; i < 8; i++) {
try {
console.log(`x${i}: ${args[i]}`);
} catch (e) {
console.log(`x${i}: <无法读取> (${e})`);
}
}
}
function safePrintBacktrace(context) {
try {
let bt = Thread.backtrace(
context,
Backtracer.FUZZY // 更稳定,遇到系统函数更不容易崩
).map(DebugSymbol.fromAddress)
.join("\n");
console.log("\n--- 调用堆栈 ---");
console.log(bt);
console.log("-----------------\n");
} catch (e) {
console.log("无法获取堆栈:" + e);
}
}
// ====== 主逻辑:Hook 偏移量函数 ======
function hook_wechat_internal_functions() {
const wechatModule = Process.findModuleByName("WeChat");
if (!wechatModule) {
console.error("❌ 找不到 WeChat 模块");
return;
}
const base = wechatModule.base;
console.log("📌 WeChat Base:", base);
WECHAT_OFFSETS.forEach(offset => {
const target = base.add(offset);
// 尝试符号化
let funcName = `WeChat!0x${offset.toString(16)}`;
try {
const sym = DebugSymbol.fromAddress(target);
if (sym && sym.name) funcName = sym.name;
} catch (_) {}
console.log(`\n🔧 准备 Hook: ${funcName} @ 0x${target}`);
try {
Interceptor.attach(target, {
onEnter(args) {
console.log("\n==============================================");
console.log(`🚀 进入函数: ${funcName}`);
console.log(`📍 地址: 0x${target}`);
console.log("\n--- 🧩 寄存器参数 x0-x7 ---");
safePrintRegister(args);
console.log("\n--- 🧵 调用堆栈 ---");
safePrintBacktrace(this.context);
console.log("==============================================\n");
},
onLeave(retval) {
// 如果需要打印返回值,可打开:
// console.log("返回值:", retval);
}
});
console.log(`✅ 已 Hook: ${funcName}`);
} catch (e) {
console.error(`❌ Hook 失败 @ 0x${target} ${e}`);
}
});
}
// ====== 入口 ======
setImmediate(() => {
hook_wechat_internal_functions();
});
+45
View File
@@ -0,0 +1,45 @@
const mod = Process.getModuleByName("WeChat");
const realAddr = ptr("0x1057ee3a8").sub("0x100000000").add(mod.base);
console.log("[+] Real Function Address:", realAddr);
Interceptor.attach(realAddr, {
onEnter(args) {
for (let i = 0; i < 10; i++) {
try {
if (args[i].isNull()) {
continue;
}
console.log(`\n[+] arg${i} ${args[i]}`);
if (args[i].compare(ptr("0x600000000000")) >= 0 && args[i].compare(ptr("0x700000000000")) < 0 && args[i].and(0x7).isNull()) {
console.log(hexdump(args[i], {
offset: 0,
length: 128
}));
}
} catch (e) {
console.log("Enter Error:", e);
}
}
console.log(
Thread.backtrace(this.context, Backtracer.ACCURATE)
.map(DebugSymbol.fromAddress).join('\n'));
},
onLeave(retval) {
console.log("===== sub_105808800 LEAVE =====");
console.log("Return value:", retval);
try {
console.log("Return hexdump:");
console.log(hexdump(retval, {
offset: 0,
length: 128
}));
} catch (_) {
}
}
});
+29
View File
@@ -0,0 +1,29 @@
// 警告:仅为演示AppKit Hooking概念,实际类名和方法可能不同
// 尝试 Hook NSResponder 的 keyDown: 方法,所有接收键盘事件的对象都会经过它
var NSResponder = ObjC.classes.NSResponder;
if (NSResponder) {
console.log("NSResponder class found.");
Interceptor.attach(NSResponder['- keyDown:'].implementation, {
onEnter: function(args) {
// args[2] 是 NSEvent* 键盘事件对象
console.log("Hooked keyDown: 方法被调用");
var event = new ObjC.Object(args[2]);
var type = event.type().toString();
console.log("捕获到键盘事件,类型: " + type);
// 检查是否为按键按下事件 (NSKeyDown = 10)
if (type === '10') {
var chars = event.charactersIgnoringModifiers().toString();
// 检查按键是否为回车 (通常chars是"\r"或"\n")
if (chars === '\r' || chars === '\n') {
console.log('>>> 🌟 捕获到 AppKit 层的回车键事件!🌟 <<<');
// 可以在这里执行您的自定义代码
}
}
}
});
console.log("AppKit NSResponder hook loaded.");
} else {
console.log("Failed to find NSResponder class.");
}
+89
View File
@@ -0,0 +1,89 @@
const keyword = "7.7";
const addrs = ["6000033DDE48"]
console.log(keyword);
console.log(addrs);
function memoGet(p) {
p = "0x" + p;
const idaAddr = ptr(p);
MemoryAccessMonitor.enable(
{
base: idaAddr,
size: 0x40 // buffer 大小
},
{
onAccess(details) {
console.log("Access by:", details.from);
attach(details.from)
console.log(hexdump(idaAddr, {length: 0x40}));
}
}
);
}
function attach(from) {
const realAddr = ptr(from);
console.log("[+] Real Function Address:", realAddr);
Interceptor.attach(realAddr, {
onEnter(args) {
for (let i = 0; i < 10; i++) {
try {
if (args[i].isNull()) {
continue;
}
console.log(`\n[+] arg${i} ${args[i]}`);
if (args[i].compare(ptr("0x600000000000")) >= 0 && args[i].compare(ptr("0x700000000000")) < 0 && args[i].and(0x7).isNull()) {
const buf = args[i].readByteArray(128)
if (!buf) {
continue;
}
let s = "";
const u8 = new Uint8Array(buf);
for (let b of u8) {
if (b >= 0x20 && b <= 0x7E) {
s += String.fromCharCode(b);
} else {
s += ".";
}
}
if (keyword === "" || s.includes(keyword)) {
console.log(`\n[+] arg${i} ${args[i]} ${s}`);
console.log(hexdump(args[i], {length: 128}));
console.log(
Thread.backtrace(this.context, Backtracer.ACCURATE)
.map(DebugSymbol.fromAddress).join('\n'));
return;
}
}
} catch (e) {
console.log("Enter Error:", e);
}
}
},
onLeave(retval) {
console.log("===== sub_105808800 LEAVE =====");
console.log("Return value:", retval);
try {
if (retval.compare(ptr("0x600000000000")) >= 0 && retval.compare(ptr("0x700000000000")) < 0 && retval.and(0x7).isNull()) {
console.log(hexdump(retval, {
offset: 0,
length: 40
}));
}
} catch (_) {
}
}
});
}
for (let addr of addrs) {
memoGet(addr);
}
+64
View File
@@ -0,0 +1,64 @@
const mod = Process.getModuleByName("WeChat");
const realAddr = ptr("0x105efadc0").sub("0x100000000").add(mod.base);
console.log("[+] Real Function Address:", realAddr);
Interceptor.attach(realAddr, {
onEnter(args) {
for (let i = 0; i < 10; i++) {
try {
if (args[i].isNull()) {
continue;
}
if (args[i].compare(ptr("0x600000000000")) >= 0 && args[i].compare(ptr("0x700000000000")) < 0 && args[i].and(0x7).isNull()) {
const buf = args[i].readByteArray(128)
if (!buf) {
continue;
}
let s = "";
const u8 = new Uint8Array(buf);
for (let b of u8) {
if (b >= 0x20 && b <= 0x7E) {
s += String.fromCharCode(b);
} else {
s += ".";
}
}
console.log(`\n[+] arg${i} ${args[i]} ${s}`);
console.log(
Thread.backtrace(this.context, Backtracer.ACCURATE)
.map(DebugSymbol.fromAddress).join('\n'));
// if (s.includes(".cc")) {
// console.log(`\n[+] arg${i} ${args[i]} ${s}`);
// console.log(hexdump(args[i], { length: 128 }));
// console.log(
// Thread.backtrace(this.context, Backtracer.ACCURATE)
// .map(DebugSymbol.fromAddress).join('\n'));
// return;
// }
}
} catch (e) {
console.log("Enter Error:", e);
}
}
},
onLeave(retval) {
// console.log("===== sub_105808800 LEAVE =====");
// console.log("Return value:", retval);
// try {
// console.log("Return hexdump:");
// console.log(hexdump(retval, {
// offset: 0,
// length: 128
// }));
// } catch (_) {
// }
}
});
+64
View File
@@ -0,0 +1,64 @@
const mod = Process.getModuleByName("WeChat");
const realAddr = ptr("0x10a1f083c");
console.log("[+] Real Function Address:", realAddr);
Interceptor.attach(realAddr, {
onEnter(args) {
for (let i = 0; i < 10; i++) {
try {
if (args[i].isNull()) {
continue;
}
if (args[i].compare(ptr("0x600000000000")) >= 0 && args[i].compare(ptr("0x700000000000")) < 0 && args[i].and(0x7).isNull()) {
const buf = args[i].readByteArray(128)
if (!buf) {
continue;
}
let s = "";
const u8 = new Uint8Array(buf);
for (let b of u8) {
if (b >= 0x20 && b <= 0x7E) {
s += String.fromCharCode(b);
} else {
s += ".";
}
}
console.log(`\n[+] arg${i} ${args[i]} ${s}`);
console.log(
Thread.backtrace(this.context, Backtracer.ACCURATE)
.map(DebugSymbol.fromAddress).join('\n'));
// if (s.includes(".cc")) {
// console.log(`\n[+] arg${i} ${args[i]} ${s}`);
// console.log(hexdump(args[i], { length: 128 }));
// console.log(
// Thread.backtrace(this.context, Backtracer.ACCURATE)
// .map(DebugSymbol.fromAddress).join('\n'));
// return;
// }
}
} catch (e) {
console.log("Enter Error:", e);
}
}
},
onLeave(retval) {
// console.log("===== sub_105808800 LEAVE =====");
// console.log("Return value:", retval);
// try {
// console.log("Return hexdump:");
// console.log(hexdump(retval, {
// offset: 0,
// length: 128
// }));
// } catch (_) {
// }
}
});
+36
View File
@@ -0,0 +1,36 @@
[
"sendmsg",
"newsendmsg",
"SendMsg",
"SendMsgFH"
].forEach(sig => {
let arr = DebugSymbol.findFunctionsMatching("*" + sig + "*");
arr.forEach(target => {
console.log("Hooking:", target);
Interceptor.attach(ptr(target), {
onEnter(args) {
console.log("🚀 Called:", target);
// 打印调用堆栈
console.log(
Thread.backtrace(this.context, Backtracer.ACCURATE)
.map(DebugSymbol.fromAddress)
.join("\n")
);
// 打印第 1 个参数,一般就是 protobuf buffer
try {
console.log("arg0:", args[0]);
console.log(hexdump(args[0], { length: 256 }));
} catch(e){}
// 打印第 2 个参数(通常是长度)
console.log("arg1:", args[1]);
},
onLeave(retval) {
console.log("⬅️ return:", retval);
}
});
});
});
+43
View File
@@ -0,0 +1,43 @@
const libc = Process.getModuleByName("libSystem.B.dylib");
// 2. 拦截 memcpy
const memcpy_ptr = libc.findExportByName("memcpy");
if (memcpy_ptr) {
console.log("[+] Hooking memcpy.");
Interceptor.attach(memcpy_ptr, {
onEnter(args) {
// args[0] = destination (目标缓冲区)
// args[1] = source (源数据)
// args[2] = length
this.src = args[1];
this.len = args[2].toInt32();
},
onLeave(retval) {
// 只检查长度适中的数据块 (防止日志爆炸)
if (this.len > 5 && this.len < 500) {
try {
// 尝试将源数据读取为 C 字符串
const message = this.src.readCString();
if (message && message.length > 1) {
console.log(`\n======================================================`);
console.log(`[+] ⚠️ 明文捕获于 memcpy!`);
console.log(`[+] 长度: ${this.len} 字节`);
console.log(`[+] 消息内容 (ASCII): ${message}`);
// 打印 Hexdump 验证
console.log(`--- Hexdump 验证 ---`);
console.log(hexdump(this.src, { length: this.len > 128 ? 128 : this.len }));
console.log(`======================================================`);
}
} catch (e) {
// 忽略读取错误
}
}
}
});
} else {
console.log("[!] memcpy symbol not found.");
}
+13
View File
@@ -0,0 +1,13 @@
MemoryAccessMonitor.enable(
{
base: ptr("0x6000034c1000"),
size: 0x40 // buffer 大小
},
{
onAccess(details) {
console.log("Access by:", details.from);
console.log("Operation:", details.operation);
console.log(hexdump(idaAddr, { length: 0x40 }));
}
}
);
+17
View File
@@ -0,0 +1,17 @@
const idaAddr = ptr("0x6000025A96DA");
console.log("start monitor");
MemoryAccessMonitor.enable(
{
base: idaAddr,
size: 0x40 // buffer 大小
},
{
onAccess(details) {
console.log("0x6000029C6DF0 Details:", JSON.stringify(details));
// console.log("0x6000029C6DF0 Access by:", DebugSymbol.fromAddress(details.from));
console.log(hexdump(idaAddr, { length: 0x40 }));
}
}
);
+63
View File
@@ -0,0 +1,63 @@
const mod = Process.getModuleByName("WeChat");
const realAddr = ptr("0x1057ee3a8").sub("0x100000000").add(mod.base);
console.log("[+] Real Function Address:", realAddr);
Interceptor.attach(realAddr, {
onEnter(args) {
for (let i = 0; i < 10; i++) {
try {
if (args[i].isNull()) {
continue;
}
// console.log(`\n[+] arg${i} ${args[i]}`);
if (args[i].compare(ptr("0x600000000000")) >= 0 && args[i].compare(ptr("0x700000000000")) < 0 && args[i].and(0x7).isNull()) {
const buf = args[i].readByteArray(128)
if (!buf) {
continue;
}
let s = "";
const u8 = new Uint8Array(buf);
for (let b of u8) {
if (b >= 0x20 && b <= 0x7E) {
s += String.fromCharCode(b);
} else {
s += ".";
}
}
if (s.includes("3.3.3.3")) {
console.log(`\n[+] arg${i} ${args[i]}`);
console.log(hexdump(args[i], { length: 64 }));
// args[i].add(0x18).writeUtf16String("5555");
// console.log(hexdump(args[i], { length: 64 }));
console.log(
Thread.backtrace(this.context, Backtracer.ACCURATE)
.map(DebugSymbol.fromAddress).join('\n'));
return;
}
}
} catch (e) {
console.log("Enter Error:", e);
}
}
},
onLeave(retval) {
// console.log("===== sub_105808800 LEAVE =====");
// console.log("Return value:", retval);
// try {
// console.log("Return hexdump:");
// console.log(hexdump(retval, {
// offset: 0,
// length: 128
// }));
// } catch (_) {
// }
}
});
+21
View File
@@ -0,0 +1,21 @@
defineHandler({
onEnter(log, args, state) {
log('ccaes_cbc_encrypt_mode() [libcorecrypto.dylib]');
try {
const bt = Thread.backtrace(
this.context,
Backtracer.ACCURATE
)
.map(DebugSymbol.fromAddress)
.join('\n');
log('--- Call Stack ---\n' + bt + '\n-------------------');
} catch (e) {
log('Error printing backtrace: ' + e);
}
},
onLeave(log, retval, state) {
}
});
+63
View File
@@ -0,0 +1,63 @@
const mod = Process.getModuleByName("WeChat");
const realAddr = ptr("0x1057ee3a8").sub("0x100000000").add(mod.base);
console.log("[+] Real Function Address:", realAddr);
Interceptor.attach(realAddr, {
onEnter(args) {
for (let i = 0; i < 10; i++) {
try {
if (args[i].isNull()) {
continue;
}
// console.log(`\n[+] arg${i} ${args[i]}`);
if (args[i].compare(ptr("0x600000000000")) >= 0 && args[i].compare(ptr("0x700000000000")) < 0 && args[i].and(0x7).isNull()) {
const buf = args[i].readByteArray(128)
if (!buf) {
continue;
}
let s = "";
const u8 = new Uint8Array(buf);
for (let b of u8) {
if (b >= 0x20 && b <= 0x7E) {
s += String.fromCharCode(b);
} else {
s += ".";
}
}
if (s.includes("3.3.3.3")) {
console.log(`\n[+] arg${i} ${args[i]}`);
console.log(hexdump(args[i], { length: 64 }));
args[i].add(0x18).writeUtf16String("5555");
console.log(hexdump(args[i], { length: 64 }));
console.log(
Thread.backtrace(this.context, Backtracer.ACCURATE)
.map(DebugSymbol.fromAddress).join('\n'));
return;
}
}
} catch (e) {
console.log("Enter Error:", e);
}
}
},
onLeave(retval) {
// console.log("===== sub_105808800 LEAVE =====");
// console.log("Return value:", retval);
// try {
// console.log("Return hexdump:");
// console.log(hexdump(retval, {
// offset: 0,
// length: 128
// }));
// } catch (_) {
// }
}
});