Android Xposed 模块实战:MaskWechat 微信聊天记录隐藏方案的架构设计与技术实现
Android Xposed 模块实战:MaskWechat 微信聊天记录隐藏方案的架构设计与技术实现
给微信一点隐私
前言
在移动端隐私保护领域,如何在不修改目标应用数据的前提下,实现敏感聊天记录的视觉隐藏,是一个兼具技术深度和实用价值的课题。本文以开源项目 MaskWechat 为例,从架构设计、Hook 策略、SQL 拦截、授权体系等维度,深入解析一个完整 Xposed 模块的工程实践。
项目基于 LSPosed / Xposed 框架,使用 Kotlin + Java 混合开发,适配微信 8.0.22 至 8.0.58 共计 20+ 个版本,核心思路是 “只遮不改”------仅在 UI 层拦截和隐藏,不对微信的用户数据做任何写入或删除操作。
一、整体架构
1.1 模块入口与插件注册
模块入口类 MainHook 实现了 Xposed 的三大接口:
public class MainHook implements IXposedHookLoadPackage,
IXposedHookZygoteInit,
IXposedHookInitPackageResources {
// ...
}
在 handleLoadPackage 中,通过 Hook Application.onCreate 和 Instrumentation.callApplicationOnCreate 两个入口点来确保初始化时机可靠。插件体系采用 注册表模式,将功能解耦为独立插件:
PluginRegistry.register(
new CommonPlugin(), // SQL 级拦截(聊天列表、搜索)
new WXDbPlugin(), // 数据库相关
new WXConfigPlugin(), // 配置管理
new WXMaskPlugin() // 主隐藏逻辑调度器
);
1.2 插件分层设计
WXMaskPlugin 作为核心调度器,内部按功能拆分为多个 PluginPart:
| PluginPart | 职责 |
|---|---|
HideMainUIListPluginPart |
主页聊天列表隐藏(ListView / RecyclerView) |
EnterChattingUIPluginPart |
聊天页面进入时的记录隐藏 |
HideSearchListUIPluginPart |
搜索结果中的用户过滤 |
EmptySingChatHistoryGalleryPluginPart |
单聊历史图片/视频过滤 |
HiddenChatEntryPluginPart |
隐藏会话入口 |
SearchMagicPluginPart |
搜索关键词拦截 |
每个 Part 独立实现 IPlugin 接口,拥有自己的 Hook 逻辑,互不干扰。
二、核心 Hook 策略
2.1 主页聊天列表:双层拦截
隐藏聊天列表条目是模块最核心的功能,采用了 数据层 + 视图层 的双重拦截策略。
数据层:Hook getItem
微信的聊天列表 Adapter 有一个获取条目数据的方法(经混淆后名称因版本而异),模块通过版本映射表定位并 Hook 该方法:
val GetItemMethodName = when (AppVersionUtil.getVersionCode()) {
Constrant.WX_CODE_8_0_22 -> "aCW"
in Constrant.WX_CODE_8_0_22..Constrant.WX_CODE_8_0_43 -> "k"
Constrant.WX_CODE_8_0_58, Constrant.WX_CODE_8_0_66 -> "m"
else -> "m"
}
在 afterHookedMethod 中,读取条目的 field_username 字段,若命中隐藏列表,则清空 field_content、field_digest 等关键显示字段,并将 field_conversationTime 设为 0 使其沉底。
视图层:Hook onBindViewHolder
对于使用 RecyclerView 的新版微信,还需额外 Hook onBindViewHolder,通过 XposedHelpers.getAdditionalInstanceField 读取数据层打上的 _wxmask_hidden 标记,将对应 itemView 设为 View.GONE 并将高度置零:
if (isHidden) {
itemView.visibility = View.GONE
itemView.layoutParams?.let { lp ->
lp.height = 0
itemView.layoutParams = lp
}
return
}
同时处理了 RecyclerView 的视图复用问题------对非隐藏项恢复 VISIBLE 和 WRAP_CONTENT。
2.2 SQL 级拦截:从数据库层面过滤
仅在 UI 层拦截存在一个问题:当新消息到达时,微信会执行 SQL 查询来刷新列表,可能导致隐藏用户被短暂显示。CommonPlugin 通过 Hook SQLiteDatabase 的多个方法,在 SQL 层面彻底解决:
SELECT 查询拦截:
// 聊天列表批量查询 -> 注入 NOT IN 条件
"AND rconversation.username NOT IN ($hideValueText) "
// 单条查询拦截 -> 返回空结果
param.args[1] = sql.replaceFirst("WHERE", "WHERE 1=0 AND")
UPDATE / INSERT 拦截:
当微信收到新消息更新 rconversation 表时,模块检查 ContentValues 或 whereArgs 中的 username,若命中隐藏列表则阻止写入:
// UPDATE 拦截:让 WHERE 条件永远不成立
param.args[2] = "1=0"
// INSERT 拦截:直接返回失败
param.result = -1L
// execSQL 拦截:替换为空操作
param.args[0] = "SELECT 1"
这套 SQL 层面的拦截确保了即使有新消息推送,隐藏用户也不会出现在列表中。
2.3 搜索结果过滤
微信的全局搜索涉及多张 FTS5 虚拟表,模块通过正则匹配识别搜索 SQL:
private val regex by lazy {
Regex("^SELECT (FTS5MetaContact|FTS5MetaTopHits|...)\.docid, ...")
}
匹配后将原始 SQL 包装为子查询,追加 aux_index NOT IN (...) 过滤条件,从搜索结果中剔除指定用户。
三、聊天页面隐藏与临时解除
3.1 进入聊天页的拦截
通过 Hook BaseChattingUIFragment.onActivityCreated,从 Fragment 的 arguments 中提取 Chat_User,与隐藏列表比对。命中后,将聊天内容区域 (MMChattingListView) 设为 View.INVISIBLE。
3.2 临时解除机制
模块支持两种临时解除方式:
快速点击解除: 在聊天记录空白处连续快速点击(默认 5 次以上,间隔不超过 150ms),通过 QuickCountClickListenerUtil 实现点击计数和时间窗口判断。
输入框口令: 在聊天输入框输入特定指令:
| 口令 | 功能 |
|---|---|
#show |
临时显示聊天记录 |
#hide |
临时隐藏 |
#add |
将当前用户加入隐藏列表 |
#del |
从隐藏列表移除 |
#copyId |
复制当前用户的 wxid |
四、版本适配策略
微信每次更新都可能导致类名、方法名、资源 ID 发生变化。项目采用 版本号常量映射 的方式应对:
// 20+ 个版本常量
const val WX_CODE_8_0_22 = 2140
const val WX_CODE_8_0_32 = 2300
// ...
const val WX_CODE_8_0_58 = 2841
关键 Hook 点都通过 when 表达式按版本分发:
val adapterClazzName = when (AppVersionUtil.getVersionCode()) {
Constrant.WX_CODE_8_0_22 -> "com.tencent.mm.ui.g"
in Constrant.WX_CODE_8_0_32..Constrant.WX_CODE_8_0_34 -> "com.tencent.mm.ui.y"
// ... 逐版本适配
else -> null // 未知版本走猜测逻辑
}
对于未适配的版本,模块还实现了 自动猜测机制:通过 Hook RecyclerView.setAdapter 动态发现 Adapter 类,再根据方法签名特征(参数类型、返回值、修饰符)自动定位 getItem 方法。
五、授权与试用体系
5.1 双层授权架构
项目实现了一套完整的授权体系,分为两个检查层:
- AuthManager(主应用进程):负责网络登录、Token 管理、Profile 拉取,写入签名文件
- AuthChecker(微信进程):纯本地文件读取,零网络请求,通过 HMAC-SHA256 校验数据完整性
这种设计确保了在微信进程中的授权检查不依赖网络,不影响微信的启动速度。
5.2 防篡改机制
授权数据文件 auth_status.dat 采用 JSON | HMAC 的格式存储:
// 写入
val hmac = AuthChecker.computeHmac(jsonStr)
val content = "$jsonStr|$hmac"
// 读取验证
val expectedSignature = computeHmac(jsonStr)
if (signature == expectedSignature) { /* 通过 */ }
同时引入了 服务器时间估算 和 时间倒退检测:
// 用服务器时间 + 本地经过时间来估算当前真实时间
val estimatedServerNow = serverTime + (now - cachedAt)
// 检测系统时钟被回拨
if (now < cachedAt) {
return false // 拒绝授权
}
5.3 授权检查的性能优化
AuthChecker 使用了 5 分钟 TTL 的内存缓存,避免每次 Hook 回调都进行磁盘 IO:
private const val CACHE_TTL = 5 * 60 * 1000L
fun readAndVerifyAuth(): Boolean {
val now = System.currentTimeMillis()
if (now - lastCheckTime < CACHE_TTL) {
return cachedResult // 命中缓存
}
val result = doCheck() // 读文件 + HMAC 校验
cachedResult = result
lastCheckTime = now
return result
}
每个 Hook 点的授权检查调用链为:readAndVerifyAuth() -> 缓存命中则直接返回 -> 未命中则读取文件 + HMAC 验证 + VIP/试用期判断。
六、配置管理与观察者模式
隐藏列表的配置通过 ConfigUtil 管理,支持动态变更。当用户在微信内通过口令或配置中心修改隐藏列表时,通过观察者模式通知所有相关组件:
interface ConfigSetObserver {
fun onConfigChange()
}
// WXMaskPlugin 监听配置变化,重新加载隐藏列表
override fun onConfigChange() {
loadConfigData()
}
// HideMainUIListPluginPart 监听配置变化,刷新列表 Adapter
override fun onConfigChange() {
refreshAllAdapters()
}
Adapter 刷新使用弱引用列表避免内存泄漏:
private val adapterRefs = mutableListOf<WeakReference<Any>>()
七、构建与版本管理
项目使用 Gradle 构建,在编译时自动将 Git 分支、提交哈希、构建时间注入 BuildConfig:
buildConfigField "String", "buildInfoJson64",
"\"${buildInfoJson.bytes.encodeBase64()}\""
APK 输出文件名自动包含版本号和 Git 信息:
windcarMaskWechat-v1.0.1-a3b2c1-release.apk
Release 构建启用了 R8 混淆和资源压缩:
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
'proguard-rules.pro'
}
八、设计亮点总结
| 设计点 | 方案 | 好处 |
|---|---|---|
| 双层拦截 | 数据层(getItem)+ 视图层(onBindViewHolder) | 确保 ListView 和 RecyclerView 都能正确隐藏 |
| SQL 注入过滤 | Hook rawQuery / update / insert / execSQL | 从数据库层面彻底防止隐藏用户出现 |
| 版本适配 | 常量映射表 + 自动猜测兜底 | 已知版本精确适配,未知版本也有一定概率可用 |
| 授权分层 | AuthManager(网络)+ AuthChecker(本地文件) | 微信进程零网络开销,不影响启动性能 |
| 配置热更新 | 观察者模式 + 弱引用 Adapter 列表 | 修改配置后即时生效,无需重启微信 |
| 数据安全 | 只隐藏不修改,HMAC 签名,时间倒退检测 | 不破坏微信数据,授权文件防篡改 |
九、写在最后
MaskWechat 的核心设计理念是 “最小侵入”:不修改任何微信数据,不注入任何持久化内容,所有隐藏操作都发生在内存中的 UI 层和 SQL 查询层。这种设计既保证了功能的可靠性,也将对微信的影响降到了最低。
对于 Xposed 模块开发者而言,这个项目在以下方面提供了可借鉴的实践:
- 插件化架构:将功能拆分为独立 PluginPart,降低耦合
- 多层级 Hook:UI Hook + SQL Hook 互为补充,确保无遗漏
- 版本兼容策略:精确映射 + 智能猜测的降级方案
- 跨进程授权:文件 + HMAC 的轻量级方案,避免微信进程中的网络请求
项目地址:[https://https://xoxome.online/?page_id=2861)
声明:本项目仅供学习和个人测试使用,请勿用于任何商业或非法用途。使用模块的风险由用户自行承担。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)