之前看到有人发了关于使用xposed屏蔽抖音检测xposed的思路(https://www.52pojie.cn/thread-684757-1-1.html),贴出了部分伪代码,
但觉抖音写的蛮有意思的,自己对这方面也不是很清楚,毕竟Android我没怎么学习。借这个机会,了解一下。写的不是很清楚,大家多多抱哈啊!~~
整理了一下文档,我发现抖音主要使用了以下的手段检测xposed。


环境:      win10 x64
使用的工具:apkdb & jeb 2.2.7

1.尝试加载xposed的类,如果能加载则表示已经安装了。

XposedHelpers类中存在fieldCache methodCache constructorCache 这三个静态成员,都是hashmap类型,凡是需要被hook的且已经被找到的对象都会被缓存到这三个map里面。
我们通过便利这三个map来找到相关hook信息。
备注:方法a是检测xposed到底改了什么东西存放到a中。抖音似乎会收集相关信息并上报。

    public void b()
{
try
{
Object localObject = ClassLoader.getSystemClassLoader()
.loadClass("de.robv.android.xposed.XposedHelpers").newInstance();
// 如果加载类失败 则表示当前环境没有xposed
if (localObject != null)
{
a(localObject, "fieldCache");
a(localObject, "methodCache");
a(localObject, "constructorCache");
}
return;
}
catch (Throwable localThrowable) {}
} private void a(Object arg5, String arg6) {
try {
// 从XposedHelpers中读取相关的hook信息
Field v0_1 = arg5.getClass().getDeclaredField(arg6);
v0_1.setAccessible(true);
Set v0_2 = v0_1.get(arg5).keySet();
if(v0_2 == null) {
return;
}
if(v0_2.isEmpty()) {
return;
}
Iterator v1 = v0_2.iterator();
// 排除无关紧要的类
while(v1.hasNext()) {
Object v0_3 = v1.next();
if(v0_3 == null) {
continue;
}
if(((String)v0_3).length() <= 0) {
continue;
}
if(((String)v0_3).toLowerCase().startsWith("android.support")) {
continue;
}
if(((String)v0_3).toLowerCase().startsWith("javax.")) {
continue;
}
if(((String)v0_3).toLowerCase().startsWith("android.webkit")) {
continue;
}
if(((String)v0_3).toLowerCase().startsWith("java.util")) {
continue;
}
if(((String)v0_3).toLowerCase().startsWith("android.widget")) {
continue;
}
if(((String)v0_3).toLowerCase().startsWith("sun.")) {
continue;
}
this.a.add(v0_3);
}
}
catch(Throwable v0) {
v0.printStackTrace();
}
}

2.检测xposed相关文件

检测XposedBridge.jar这个文件和de.robv.android.xposed.XposedBridge
XposedBridge.jar存放在framework里面,de.robv.android.xposed.XposedBridge是开发xposed框架使用的主要接口。
在这个方法里读取了maps这个文件,在linux内核中,这个文件存储了进程映射了的内存区域和访问权限。在这里我们可以看到这个进程加载了那些文件。
如果进程加载了xposed相关的so库或者jar则表示xposed框架已注入。

 public static boolean a(String paramString)
{
try
{
Object localObject = new HashSet();
// 读取maps文件信息
BufferedReader localBufferedReader =
new BufferedReader(new FileReader("/proc/" + Process.myPid() + "/maps"));
for (;;)
{
// 遍历查询关键词
String str = localBufferedReader.readLine();
if (str == null) {
break;
}
if ((str.endsWith(".so")) || (str.endsWith(".jar"))) {
((Set)localObject).add(str.substring(str.lastIndexOf(" ") + 1));
}
}
localBufferedReader.close();
localObject = ((Set)localObject).iterator();
while (((Iterator)localObject).hasNext())
{
boolean bool = ((String)((Iterator)localObject).next()).contains(paramString);
if (bool) {
return true;
}
}
}
catch (Exception paramString) {}
return false;
}

3.检测堆栈信息

如果你的手机安装了xposed框架,那么你在查看app崩溃时候的堆栈信息,一定能在顶层找到xposed的类信息,
既然xposed想改你的信息,那么在调用栈里面肯定是有它的身影的。比如出现de.robv.android.xposed.XposedBridge这个类,方法被hook的时候调用栈里会出现de.robv.android.xposed.XposedBridge.handleHookedMethod 和de.robv.android.xposed.XposedBridge.invokeOriginalMethodNative这些xposed的方法,在dalvik.system.NativeStart.main方法后出现de.robv.android.xposed.XposedBridge.main调用

    try {
throw new Exception("");
} catch (Exception localException) {
StackTraceElement[] arrayOfStackTraceElement = localException.getStackTrace();
int m = arrayOfStackTraceElement.length;
int i = 0;
int j;
// 遍历整个堆栈查询xposed相关信息 检测 ZygoteInit 是否出现了2次
for (int k = 0; i < m; k = j) {
StackTraceElement localStackTraceElement = arrayOfStackTraceElement[i];
j = k;
if (localStackTraceElement.getClassName()
.equals("com.android.internal.os.ZygoteInit")) {
k += 1;
j = k;
if (k == 2) {
return true;
}
}
if (localStackTraceElement.getClassName().equals(e)) {
return true;
}
i += 1;
}
}
return false;
} try {
throw new Exception("");
}
catch(
Exception localException) {
arrayOfStackTraceElement = localException.getStackTrace();
j = arrayOfStackTraceElement.length;
i = 0;
}
for(;;) {
boolean bool1 = bool2;
if (i < j) {
if (arrayOfStackTraceElement[i].getClassName()
.equals("de.robv.android.xposed.XposedBridge")) {
bool1 = true;
}
} else {
return bool1;
}
i += 1;
}

4.修改hook方法的查询结果

数组c包含了抖音里比较重要的及各类, this.a指的是检测出的被修改的方法,字段。他执行了两者的匹配,将结果存放到了一个JSONObject里面,里面包含了是否使用模拟器,系统的详细信息,是否是双开xpp,是否适用了xp,hook了那些方法等信息上报到https://xlog.snssdk.com/do/y?ver=0.4&ts=

    private String[] c = {"android.os.Build#SERIAL",
"android.os.Build#PRODUCT",
"android.os.Build#DEVICE",
"android.os.Build#FINGERPRINT",
"android.os.Build#MODEL",
"android.os.Build#BOARD",
"android.os.Build#BRAND",
"android.os.Build.BOOTLOADER",
"android.os.Build#HARDWARE",
"android.os.SystemProperties#get(java.lang.String,java.lang.String)",
"android.os.SystemProperties#get(java.lang.String)",
"java.lang.System#getProperty(java.lang.String)",
"android.telephony.TelephonyManager#getDeviceId()",
"android.telephony.TelephonyManager#getSubscriberId()",
"android.net.wifi.WifiInfo#getMacAddress()",
"android.os.Debug#isDebuggerConnected()",
"android.app.activitymanager#isUserAMonkey()",
"com.ss."}; public ArrayList c() {
ArrayList localArrayList = new ArrayList();
Iterator localIterator = this.a.iterator();
while (localIterator.hasNext()) {
String str1 = (String) localIterator.next();
String[] arrayOfString = this.c;
int j = arrayOfString.length;
int i = 0;
while (i < j) {
if (true == str1.startsWith(arrayOfString[i])) {
String str2 = str1.replace(")#exact", ")").replace(")#bestmatch", ")").replace("#", ".");
if (str2.length() > 0) {
localArrayList.add(str2);
}
}
i += 1;
}
}
return localArrayList;
}

5.检测方法是否被篡改

Modifier.isNative方法判断是否是native修饰的方法,xposedhook方法的时候,会把方法转位native方法,我们检测native方法中不该为native的方法来达到检测的目的,比如getDeviceId,getMacAddress这些方法如果是native则表示已经被篡改了。

 public static boolean a(String paramString1, String paramString2, Class... paramVarArgs)
{
try
{
// 判断方法是不是用native修饰的
boolean bool = Modifier.isNative(Class.forName(paramString1)
.getDeclaredMethod(paramString2, paramVarArgs).getModifiers());
if (bool) {
return true;
}
}
catch (Exception paramString1)
{
paramString1.printStackTrace();
}
return false;
}

6.检测包名

这个是最简单也是最不靠谱的方法,因为只要禁止app读取应用列表就没办法了。

  if (((ApplicationInfo)localObject).packageName.equals("de.robv.android.xposed.installer"))
{
Log.wtf("HookDetection", "Xposed found on the system.");
}
}

反制xposed

1.通过反射重写xposed设置,直接禁用

这个方法是酷安里中抄来的。重写application,在onCreate中写入

  try {
Field v0_1 = ClassLoader.getSystemClassLoader()
.loadClass("de.robv.android.xposed.XposedBridge")
.getDeclaredField("disableHooks");
v0_1.setAccessible(true);
v0_1.set(null, Boolean.valueOf(true));
}
catch(Throwable v0) {
}
未完待续。。。

Xposed那些事儿 — xposed框架的检测和反制的更多相关文章

  1. Tensorflow实现Mask R-CNN实例分割通用框架,检测,分割和特征点定位一次搞定(多图)

    Mask R-CNN实例分割通用框架,检测,分割和特征点定位一次搞定(多图)   导语:Mask R-CNN是Faster R-CNN的扩展形式,能够有效地检测图像中的目标,同时还能为每个实例生成一个 ...

  2. [Xcode 实际操作]七、文件与数据-(20)CoreML机器学习框架:检测和识别图片中的物体

    目录:[Swift]Xcode实际操作 本文将演示机器学习框架的使用,实现对图片中物体的检测和识别. 首先访问苹果开发者网站关于机器学习的网址: https://developer.apple.com ...

  3. 2 _ 基本框架 _ 检测VMX环境

    VT 是先开为大,谁先开谁上层,谁上层 谁权限大. 1 判断是否支持 VMX intel 白皮书 第3卷 传入 参数eax =1, 返回值 ecx 的第5位 = 1 则 surpported VMX. ...

  4. NancyFx框架之检测任务管理器

    先建一个空的项目和之前的NancyFx系列一样的步骤 然后建三个文件夹Models,Module,Views 然后分别安装一下组件 jQuery Microsoft.AspNet.SignalR Mi ...

  5. Xposed 框架 hook 简介 原理 案例 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  6. android hook 框架 xposed 如何实现挂钩

    Android so注入-libinject2 简介.编译.运行 Android so注入-libinject2  如何实现so注入 Android so注入-Libinject 如何实现so注入 A ...

  7. 小米5安装Xposed框架——需要解锁刷机

    Xposed官网 https://forum.xda-developers.com/xposed 官方模块厂库 https://repo.xposed.info/ 中文站点 https://xpose ...

  8. 小米4 miui专用 Xposed安装器86版

    转载自 http://www.52pojie.cn/thread-516435-1-1.html 写在前面:各位用xp受到不同限制,有些机型还找不到框架包,又要刷第三方rec又要谨慎选择框架版本.官方 ...

  9. Android Hook神器:XPosed入门与登陆劫持演示

    前段时间写了一篇关于Cydia Substrate广告注入的文章,大家都直呼过瘾.但是,真正了解这一方面的同学应该知道,其实还有一个比Cydia Substrate更出名的工具:XPosed. 不是因 ...

随机推荐

  1. 【原创】你知道Oracle 10G能存多少数据吗

    昨天晚上在看Oracle 10G联机文档中关于bigfile tablespaces的描述(引用1),发现了关于Oracle存储极限的简单描述.bigfile tablespaces的存在,让Orac ...

  2. 【技术累积】【点】【编程】【13】XX式编程

    (原)函数式编程 核心概念 函数式一等公民(输入输出啥的都可以是函数): 纯函数,固定输入带来固定输出: 阅读性良好,无并发问题,但效率偏低: 大历史背景 旨在描述问题如何计算: 有两位巨擘对问题的可 ...

  3. 极客学院免费VIP

    [手快福利]用我的链接注册极客学院,你我都能免费得30天VIP!6500+编程开发视频教程随便学,还能下载资料和源码 http://e.jikexueyuan.com/invite/index.htm ...

  4. Typeclassopedia 阅读笔记:导言与 Functor

    Typeclassopedia 阅读笔记 本文是对介绍 Haskell 中类型类(type classes)的文档 Typeclassopedia 的阅读笔记和简短总结,包含此文档中重要的知识点.读者 ...

  5. C# MVC 延时

    [System.Runtime.InteropServices.DllImport("kernel32.dll")] static extern uint GetTickCount ...

  6. ApplicationLoader登录失败

    报错:Please sign in with an app-specific password. You can create one at appleid.apple.com 是因为帐号开启了双重认 ...

  7. react-draft-wysiwyg富文本

      import { EditorState, convertToRaw } from 'draft-js'; import { Editor } from 'react-draft-wysiwyg' ...

  8. 【转载】InputStreamReader和OutputStreamWriter 的区别和用法

    一.InputStreamReader 用于将一个字节流中的字节解码成字符 , 用法如下: @Test public void Test19() throws Exception { InputStr ...

  9. 在 Linux 下判断系统当前是否开启了超线程

    转自: http://www.cnblogs.com/wjoyxt/p/4804293.html #lscpu Thread(s) per core: 2 Core(s) per socket: 6 ...

  10. CentOS 7.2.1511编译安装Nginx1.10.1+MySQL5.7.15+PHP7.0.11

    准备篇 一.防火墙配置 CentOS 7.2默认使用的是firewall作为防火墙,这里改为iptables防火墙. 1.关闭firewall: systemctl stop firewalld.se ...