From 6b47a431741f99a79979396fd8997d886698ed9d Mon Sep 17 00:00:00 2001 From: yibo Date: Sat, 11 Jul 2026 22:33:12 +0800 Subject: [PATCH] fix(wechat-spoof): 修复副设备登录设备名泄露 Pixel — resetprop 兜 native 读 --- xhs_lsposed_a16_fix/wechat-model-spoof.sh | 19 +++++++++++++++++++ xhs_lsposed_a16_fix/wechathook_src/WeChatHook.java | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 87 insertions(+), 11 deletions(-) create mode 100644 xhs_lsposed_a16_fix/wechat-model-spoof.sh diff --git a/xhs_lsposed_a16_fix/wechat-model-spoof.sh b/xhs_lsposed_a16_fix/wechat-model-spoof.sh new file mode 100644 index 0000000..757b5ef --- /dev/null +++ b/xhs_lsposed_a16_fix/wechat-model-spoof.sh @@ -0,0 +1,19 @@ +#!/system/bin/sh +# 部署到 /data/adb/post-fs-data.d/wechat-model-spoof.sh (chmod 755)。 +# +# 微信副设备登录设备名泄露修复:微信在 native 层 __system_property_get 读 ro.product.model, +# 绕过 LSPosed Java hook(WeChatHook.hookDeviceSpoof 只改 Build.* / Java SystemProperties.get), +# 导致登录设备记录显示真机 "Pixel 10 Pro Fold",每次登录触发安全预警。 +# 这里在系统属性层把机型改成三星平板 SM-X700,native 读也会拿到伪装值 → 显示 "samsung SM-X700"。 +# 代价:全机生效(getprop 也变),非"仅微信进程内"——native prop 读无法 per-app hook, +# 只有 resetprop 兜得住。对这台专用 bot 手机可接受。详见 memory wechat-pad-login-device-spoof。 +for p in ro.product.model ro.product.product.model ro.product.vendor.model ro.product.odm.model \ + ro.product.system_ext.model ro.product.system_dlkm.model ro.product.vendor_dlkm.model \ + ro.product.bootimage.model ro.product.model_for_attestation; do + resetprop "$p" "SM-X700" +done +for p in ro.product.brand ro.product.product.brand ro.product.vendor.brand ro.product.odm.brand \ + ro.product.manufacturer ro.product.product.manufacturer; do + resetprop "$p" "samsung" +done +resetprop ro.product.marketname "Galaxy Tab S8" diff --git a/xhs_lsposed_a16_fix/wechathook_src/WeChatHook.java b/xhs_lsposed_a16_fix/wechathook_src/WeChatHook.java index 66d604e..7f2e6c3 100644 --- a/xhs_lsposed_a16_fix/wechathook_src/WeChatHook.java +++ b/xhs_lsposed_a16_fix/wechathook_src/WeChatHook.java @@ -2727,19 +2727,21 @@ public class WeChatHook implements IXposedHookLoadPackage { catch (Throwable t) { XposedBridge.log("[WeChatHook] spoof Build." + e.getKey() + " failed: " + t); } } // ro.product.* + ro.build.characteristics=tablet (the strong tablet signal). - final java.util.Map P = new java.util.HashMap<>(); - P.put("ro.product.brand", "samsung"); - P.put("ro.product.manufacturer", "samsung"); - P.put("ro.product.model", "SM-X700"); - P.put("ro.product.device", "gts8wifi"); - P.put("ro.product.name", "gts8wifixx"); - P.put("ro.build.characteristics", "tablet"); + // Pixel 有一大堆分区限定 prop(ro.product.{product,vendor,odm,system_ext,system_dlkm, + // vendor_dlkm,bootimage}.model 全 = "Pixel 10 Pro Fold")。写死白名单必漏,改**模式匹配**: + // 任何 ro.product.*.model / *marketname / *.brand 等一律盖,未来加分区也不漏。 Class sysProp = XposedHelpers.findClass("android.os.SystemProperties", cl); XC_MethodHook propHook = new XC_MethodHook() { @Override protected void afterHookedMethod(MethodHookParam p) { - if (p.args == null || p.args.length == 0) return; - Object k = p.args[0]; - if (k != null && P.containsKey(k.toString())) p.setResult(P.get(k.toString())); + if (p.args == null || p.args.length == 0 || p.args[0] == null) return; + String k = p.args[0].toString(); + String v = spoofProp(k); + if (v != null) { + // 诊断:记录微信实际读了哪个 model/name 源(找泄露源用,验证后可删) + if (k.contains("model") || k.contains("marketname") || k.contains("name")) + XposedBridge.log("[WeChatHook] spoofProp " + k + " → " + v); + p.setResult(v); + } } }; for (java.lang.reflect.Method m : sysProp.getDeclaredMethods()) { @@ -2749,13 +2751,68 @@ public class WeChatHook implements IXposedHookLoadPackage { XposedBridge.hookMethod(m, propHook); } } + // BluetoothAdapter.getName() 是设备名的另一条常见来源(走蓝牙服务 IPC,Settings hook 盖不到)。 + try { + Class bt = XposedHelpers.findClass("android.bluetooth.BluetoothAdapter", cl); + for (java.lang.reflect.Method m : bt.getDeclaredMethods()) { + if ("getName".equals(m.getName()) && m.getParameterTypes().length == 0) { + XposedBridge.hookMethod(m, new XC_MethodHook() { + @Override protected void afterHookedMethod(MethodHookParam p) { + XposedBridge.log("[WeChatHook] BluetoothAdapter.getName() intercepted"); + p.setResult("Galaxy Tab S8"); + } + }); + } + } + } catch (Throwable t) { XposedBridge.log("[WeChatHook] spoof BluetoothAdapter failed: " + t); } + // 🔑 微信副设备「设备名」= Build.MANUFACTURER + Settings.Global "device_name", + // 后者在 Pixel 上 = 真机营销名("Pixel 10 Pro Fold"),Build/prop 伪装盖不到它, + // 每次登录都以 "samsung-Pixel10 Pro Fold" 触发预警。这里把 device_name/bluetooth_name + // 一并伪装成三星平板名,让整串设备身份一致。 + final java.util.Map S = new java.util.HashMap<>(); + S.put("device_name", "Galaxy Tab S8"); + S.put("bluetooth_name", "Galaxy Tab S8"); + XC_MethodHook settingsHook = new XC_MethodHook() { + @Override protected void afterHookedMethod(MethodHookParam p) { + if (p.args == null || p.args.length < 2) return; + Object k = p.args[1]; // getString(ContentResolver, String name) + if (k != null && S.containsKey(k.toString())) p.setResult(S.get(k.toString())); + } + }; + for (String clsName : new String[]{"android.provider.Settings$Global", + "android.provider.Settings$Secure", "android.provider.Settings$System"}) { + try { + Class sc = XposedHelpers.findClass(clsName, cl); + for (java.lang.reflect.Method m : sc.getDeclaredMethods()) { + if ("getString".equals(m.getName()) + && m.getParameterTypes().length == 2 + && m.getParameterTypes()[1] == String.class) { + XposedBridge.hookMethod(m, settingsHook); + } + } + } catch (Throwable t) { XposedBridge.log("[WeChatHook] spoof " + clsName + " failed: " + t); } + } XposedBridge.log("[WeChatHook] hookDeviceSpoof: → Samsung SM-X700 tablet in " + procName - + " (Build.MODEL now=" + XposedHelpers.getStaticObjectField(build, "MODEL") + ")"); + + " (Build.MODEL now=" + XposedHelpers.getStaticObjectField(build, "MODEL") + + ", device_name spoofed=Galaxy Tab S8)"); } catch (Throwable t) { XposedBridge.log("[WeChatHook] hookDeviceSpoof failed in " + procName + ": " + t); } } + /** 模式匹配伪装 ro.* 设备身份 prop。命中返回三星平板值,未命中返回 null(放行原值)。 */ + private static String spoofProp(String k) { + if (k == null) return null; + if (k.equals("ro.build.characteristics")) return "tablet"; + if (!k.startsWith("ro.product.")) return null; + if (k.endsWith("marketname")) return "Galaxy Tab S8"; + if (k.endsWith(".model")) return "SM-X700"; + if (k.endsWith(".brand") || k.endsWith(".manufacturer")) return "samsung"; + if (k.endsWith(".device")) return "gts8wifi"; + if (k.endsWith(".name")) return "gts8wifixx"; + return null; + } + private void hookInTabletEnv(ClassLoader cl) { try { Class bkClass = XposedHelpers.findClass("com.tencent.mm.ui.bk", cl); -- libgit2 0.21.4