这两天看到有部分人称微信大规模封号,主要被封的是Xposed和各类微信插件的使用者,部分人说自己只是安装了Xposed,但并未使用微信相关的任何插件也被封了。由此有人开始说微信侵犯用户隐私,随意扫描用户的手机等等。

本人一直是Xposed的使用者,主要是用来使用自己写的扒Android8.1上“吉字节”等单位改回“GB”的插件。另外也有使用修改微信UI以及防撤回的与微信相关的插件,但并未受到此次封号的影响。普通用户不太清楚开发方面的事,以为检测Xposed框架是件很复杂的事,今天就来聊聊Xposed的简单检测方法。

检测

Xposed重写了zygote,zygote启动时会加载Xposed相关组件,因此由zygote孵化出来的每个进程都会有Xposed的相关代码。根据这一原理,我们可以通过以下几种方式检测。

Xposed Installer

Xposed利用Xposed Installer这一App安装Xposed和管理模块,其包名为de.robv.android.xposed.installer,检测这一包名是最简单直观的对Xposed检测的方法。

堆栈信息

抛出一个异常并捕获,将堆栈信息打印出来。

1
2
3
4
5
6
7
8
// .....省略部分
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:440)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:108)

可以看到每个App是先执行的XposedBridge.jar的main方法,之后再调用的Zygote的main方法。通过检测堆栈中是否包含Xposed等字样即可知道是否安装了Xposed。

maps

Xposed的组件需要被加载,必然在内存空间留下痕迹。通过遍历/proc/<pid>/maps/proc/self/maps)的内容可以发现如下内容。因此也可以据此来判断。

1
7de6c41000-7de6c42000 r--s 00019000 b3:18 139265 /system/framework/XposedBridge.jar

更精准的检测

以上方法只能检测用户是否安装使用了Xposed,这是一个风险点,但我们并不能因为用户使用了Xposed就将其封禁。通过Xposed的实现方式,我们可以采取更精准的方式去检测。

de.robv.android.xposed.XposedBridge中有一个disableHooks字段用于标记对于当前应用是否要进行hook。通过获取这个字段的值就可以知道是否在我们App上启用hook了,甚至可以通过将其设置为true停掉Xposed。

1
2
3
4
5
6
Field disableHooksFiled = ClassLoader.getSystemClassLoader()
.loadClass("de.robv.android.xposed.XposedBridge")
.getDeclaredField("disableHooks");
disableHooksFiled.setAccessible(true);
Object enable = disableHooksFiled.get(null); // 当前状态
disableHooksFiled.set(null, true); // 设置为关闭

另一个更为精准的方式见这篇文章,Xposed将需要hook的字段、方法、构造函数等缓存在了几个HashMap中,通过遍历这几个看是否有与自己相关的内容就可知道自己是否有被hook了,具体的原理和方法可以看一下这篇文章。

反检测与反反检测

上面提到的那些检测方法实际上都可以被绕过的,hook掉调用的那些检测方法并返回虚假的信息就可以轻松绕过。例如上文提到检测maps文件,那么我们可以需要类似下面这样的伪代码遍历maps文件的每一行并判断是否包含Xposed的相关组件。

1
line.contains("Xposed")

那么可以hookString.contains方法,如果发现你想判断的内容包含Xposed等关键字就直接返回false即可。

面对这些反检测的手段,第一我们可以增加检测的维度,加大绕过检测的难度,从Java层和C层进行多方面的检测。第二我们可以设置一些蜜罐,例如面对上面这种反检测的手段,如果我们调用"Xposed".contains("Xposed")的返回值是false,那必然说明其使用了这种反检测手段。

结语

攻防真的很无聊。