debug_wechat_send4.js
5.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/**
* Frida debug script v4 — comprehensive WCDB hook
* Hooks insert, insertWithOnConflict, replace, replaceOrThrow, execSQL, rawQuery
* Usage: frida -U -p PID -l debug_wechat_send4.js
*/
function log(tag, msg) {
console.log("[" + tag + "] " + msg);
}
function printStack(tag) {
var Exception = Java.use("java.lang.Exception");
var Log = Java.use("android.util.Log");
var trace = Log.getStackTraceString(Exception.$new());
console.log("[" + tag + " STACK]\n" + trace + "\n[END STACK]");
}
function hookAllWcdbMethods(clsName) {
try {
var cls = Java.use(clsName);
log("HOOK", "Hooking " + clsName);
// insert
try {
cls.insert.overload('java.lang.String', 'java.lang.String', 'android.content.ContentValues').implementation = function(table, nullCol, values) {
if (table && table.toLowerCase().indexOf("message") !== -1) {
var isSend = values ? values.getAsInteger("isSend") : null;
var talker = values ? values.getAsString("talker") : null;
var content = values ? values.getAsString("content") : null;
log("INSERT", "table=" + table + " isSend=" + isSend + " talker=" + talker + " content=" + (content ? content.substring(0, 40) : "null"));
if (isSend && isSend == 1) printStack("INSERT_SEND");
}
return this.insert(table, nullCol, values);
};
} catch(e) {}
// insertWithOnConflict
try {
cls.insertWithOnConflict.overload('java.lang.String', 'java.lang.String', 'android.content.ContentValues', 'int').implementation = function(table, nullCol, values, conflict) {
if (table && table.toLowerCase().indexOf("message") !== -1) {
var isSend = values ? values.getAsInteger("isSend") : null;
log("INSERT2", "table=" + table + " isSend=" + isSend);
if (isSend && isSend == 1) printStack("INSERT2_SEND");
}
return this.insertWithOnConflict(table, nullCol, values, conflict);
};
} catch(e) {}
// replace
try {
cls.replace.overload('java.lang.String', 'java.lang.String', 'android.content.ContentValues').implementation = function(table, nullCol, values) {
if (table && table.toLowerCase().indexOf("message") !== -1) {
log("REPLACE", "table=" + table);
printStack("REPLACE");
}
return this.replace(table, nullCol, values);
};
} catch(e) {}
// execSQL(String)
try {
cls.execSQL.overload('java.lang.String').implementation = function(sql) {
var lowerSql = sql ? sql.toLowerCase() : "";
if (lowerSql.indexOf("message") !== -1 && (lowerSql.indexOf("insert") !== -1 || lowerSql.indexOf("replace") !== -1)) {
log("EXECSQL", sql.substring(0, 200));
printStack("EXECSQL");
}
return this.execSQL(sql);
};
} catch(e) {}
// execSQL(String, Object[])
try {
cls.execSQL.overload('java.lang.String', '[Ljava.lang.Object;').implementation = function(sql, args) {
var lowerSql = sql ? sql.toLowerCase() : "";
if (lowerSql.indexOf("message") !== -1 && (lowerSql.indexOf("insert") !== -1 || lowerSql.indexOf("replace") !== -1)) {
log("EXECSQL2", sql.substring(0, 200));
printStack("EXECSQL2");
}
return this.execSQL(sql, args);
};
} catch(e) {}
// rawQuery
try {
cls.rawQuery.overload('java.lang.String', '[Ljava.lang.String;').implementation = function(sql, args) {
var lowerSql = sql ? sql.toLowerCase() : "";
if (lowerSql.indexOf("message") !== -1 && lowerSql.indexOf("insert") !== -1) {
log("RAWQUERY", sql.substring(0, 200));
printStack("RAWQUERY");
}
return this.rawQuery(sql, args);
};
} catch(e) {}
log("HOOK", clsName + " hooks installed");
} catch (e) {
log("HOOK", "Failed to hook " + clsName + ": " + e);
}
}
Java.perform(function () {
log("MAIN", "Installing comprehensive WCDB hooks...");
// Hook WCDB
hookAllWcdbMethods("com.tencent.wcdb.database.SQLiteDatabase");
// Also hook standard Android SQLite
hookAllWcdbMethods("android.database.sqlite.SQLiteDatabase");
// Hook SQLiteStatement for prepared statement execution
try {
var Stmt = Java.use("com.tencent.wcdb.database.SQLiteStatement");
Stmt.execute.overload().implementation = function() {
var sql = this.mSql ? this.mSql.value : "unknown";
if (sql.toLowerCase().indexOf("message") !== -1) {
log("STMT", "execute: " + sql.substring(0, 100));
printStack("STMT");
}
return this.execute();
};
log("HOOK", "SQLiteStatement hooked");
} catch(e) {
log("HOOK", "SQLiteStatement hook failed: " + e);
}
log("MAIN", "All hooks installed. Send a message manually now.");
});