/** * Frida debug script v2 — auto-test multiple send message call chains * Usage: frida -U -f com.tencent.mm --no-pause -l debug_wechat_send2.js */ var testResults = []; function log(tag, msg) { console.log("[" + tag + "] " + msg); } // ── Test 1: builder.a() -> m1.a() (current path, returns boolean) ── function testChain1(toUser, content) { log("TEST1", "builder.a() -> m1.a()"); try { var r1 = Java.use("u01.r1"); var builder = r1.a(toUser); log("TEST1", "builder class=" + builder.getClass().getName()); var q1 = Java.use("u01.q1"); q1.e.call(builder, content); q1.h.call(builder, 0); var m1 = q1.a.call(builder); log("TEST1", "result class=" + m1.getClass().getName()); var m1cls = Java.use("u01.m1"); var ret = m1cls.a.call(m1); log("TEST1", "m1.a() returned=" + ret); return { chain: "builder.a()->m1.a()", result: ret }; } catch (e) { log("TEST1", "ERROR: " + e); return { chain: "builder.a()->m1.a()", error: e.toString() }; } } // ── Test 2: builder.b() (returns void, maybe real submit) ── function testChain2(toUser, content) { log("TEST2", "builder.b() direct submit"); try { var r1 = Java.use("u01.r1"); var builder = r1.a(toUser); var q1 = Java.use("u01.q1"); q1.e.call(builder, content); q1.h.call(builder, 0); q1.b.call(builder); // void return log("TEST2", "builder.b() called successfully (void)"); return { chain: "builder.b()", result: "void-ok" }; } catch (e) { log("TEST2", "ERROR: " + e); return { chain: "builder.b()", error: e.toString() }; } } // ── Test 3: builder.a() then call m1.a() with different args ── function testChain3(toUser, content) { log("TEST3", "Try m1 other methods"); try { var r1 = Java.use("u01.r1"); var builder = r1.a(toUser); var q1 = Java.use("u01.q1"); q1.e.call(builder, content); q1.h.call(builder, 0); var m1 = q1.a.call(builder); var m1cls = Java.use("u01.m1"); // List all public methods on m1 var methods = m1cls.class.getDeclaredMethods(); for (var i = 0; i < methods.length; i++) { var m = methods[i]; if ((m.getModifiers() & 0x0001) && m.getParameterTypes().length === 0) { log("TEST3", "m1 method: " + m.getName() + "() -> " + m.getReturnType().getName()); } } // Try calling a() again to see if it's idempotent var ret = m1cls.a.call(m1); log("TEST3", "m1.a() = " + ret); return { chain: "m1.inspect", result: ret }; } catch (e) { log("TEST3", "ERROR: " + e); return { chain: "m1.inspect", error: e.toString() }; } } // ── Test 4: Try g(String) setter instead of e(String) ── function testChain4(toUser, content) { log("TEST4", "builder.g() instead of e()"); try { var r1 = Java.use("u01.r1"); var builder = r1.a(toUser); var q1 = Java.use("u01.q1"); q1.g.call(builder, content); // g(String) returns q1 q1.h.call(builder, 0); var m1 = q1.a.call(builder); var m1cls = Java.use("u01.m1"); var ret = m1cls.a.call(m1); log("TEST4", "m1.a() = " + ret); return { chain: "builder.g()->m1.a()", result: ret }; } catch (e) { log("TEST4", "ERROR: " + e); return { chain: "builder.g()->m1.a()", error: e.toString() }; } } // ── Test 5: Try f(az0.h7) ── function testChain5(toUser, content) { log("TEST5", "Skip f() - requires az0.h7 object"); return { chain: "builder.f()", skipped: true }; } // ── Test 6: Hook WCDB to see which chain triggers INSERT ── function hookWCDB() { try { var SQLiteDatabase = Java.use("com.tencent.wcdb.database.SQLiteDatabase"); SQLiteDatabase.insert.overload('java.lang.String', 'java.lang.String', 'android.content.ContentValues').implementation = function(table, nullCol, values) { if (table && table.indexOf("message") !== -1) { var talker = values.getAsString("talker"); var content = values.getAsString("content"); var isSend = values.getAsInteger("isSend"); log("WCDB", "INSERT talker=" + talker + " isSend=" + isSend + " content=" + (content ? content.substring(0, 40) : "null")); } return this.insert(table, nullCol, values); }; log("WCDB", "Hook installed"); } catch (e) { log("WCDB", "Hook failed: " + e); } } // ── Main ── Java.perform(function() { log("MAIN", "Waiting 5s for WeChat to initialize..."); hookWCDB(); setTimeout(function() { log("MAIN", "Running tests..."); var toUser = "filehelper"; var content = "FridaTest_" + Date.now(); testChain1(toUser, content); setTimeout(function() { testChain2(toUser, content + "_B"); }, 2000); setTimeout(function() { testChain3(toUser, content + "_C"); }, 4000); setTimeout(function() { testChain4(toUser, content + "_D"); }, 6000); setTimeout(function() { log("MAIN", "All tests done. Check WeChat chat for messages."); }, 8000); }, 5000); });