xposedhook部分记录
https://blog.coderstory.cn/?s=xposed
之前看到有人发了关于使用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) {}
未完待续。。。
文章分页
4 条评论
- ootom • 2018年5月3日 • 回复
很有参考意义
有些检测方式,有应对办法吗?
例如“检测堆栈信息”等几种不好处理的方式- coderstory • 2018年5月4日 • 回复 • 作者
getStackTrace方法直接hook 过滤掉xposed信息不就好了么
- didi • 2018年4月2日 • 回复
测试了反制xposed,没有作用呢
- bcagaybc • 2018年3月3日 • 回复
还有方法 不过暂时不会检测自身是否被hook 可以检测是否存在xposed
/proc/pid/maps 找xposed关键词
HOOK 多dex
Xposed-10-Hook动态加载的dex中方法
作者 fooree
前面Xposed-08-Hook dex加载小节演示了获取动态加载的dex文件路径的方法。
本小节演示如何Hook动态加载的dex中的方法。
温馨提示:文中包含代码,建议横屏阅读,体验更佳
没有实际操作过的话,肯定会以为这个与之前演示的方法的Hook应该没有区别。如果真是这样的话,看到这里,可以先动手去操作一下。
本小节演示还以Xposed-08-Hook dex加载小节的样本APK为例,具体地址:https://github.com/fooree/fooXposed/blob/master/files/Foox_4th_02.apk。Hook其中的解密方法,并打印参数和返回值。
0x01
我们通过查看代码,知道样本应用中解密方法是foo.ree.demos.x4th01.Base64Util#decrypt(java.lang.String)
( 解密方法源码地址:https://github.com/fooree/fooXposed/blob/master/Foox_4th_01/src/main/java/foo/ree/demos/x4th01/Base64Util.java)。
按照之前演示,对该方法进行Hook的代码应该如下:
public class FooxMain implements IXposedHookLoadPackage {@Override public void handleLoadPackage(LoadPackageParam lpp) throws Throwable {if (!"foo.ree.demos.x4th02".equals(lpp.packageName)) return; findAndHookMethod("foo.ree.demos.x4th01.Base64Util", lpp.classLoader, "decrypt", String.class, new XC_MethodHook() {@Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { XposedBridge.log(param.method + " params: " + Arrays.toString(param.args)); }@Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { XposedBridge.log(param.method + " return: " + param.getResult()); } }); }}
实际上,以上代码什么都Hook不到,而且会在findAndHookMethod
的时候,抛出异常de.robv.android.xposed.XposedHelpers.ClassNotFoundError
。
0x02
为什么以上代码会抛出异常?
因为handleLoadPackage(LoadPackageParam lpp)
方法是在应用程序进程启动时,被Xposed框架调用执行的;而此时,还没有动态加载dex,要Hook的目标方法foo.ree.demos.x4th01.Base64Util#decrypt(java.lang.String)
在当前进程中,还不存在。只有主页面上的按钮被点击时,才会加载dex,加载目标方法。所以出现ClassNotFoundError
是正常的。
那我们如何才能Hook目标方法foo.ree.demos.x4th01.Base64Util#decrypt(java.lang.String)
呢?
0x03
我们知道,在Android中,所有类的加载,都是通过java.lang.ClassLoader#loadClass(java.lang.String)
方法进行的(除非该方法被重载自定义),foo.ree.demos.x4th01.Base64Util
也不例外。
因此我们可以在DexClassLoader
调用loadClass(java.lang.String)
方法加载类foo.ree.demos.x4th01.Base64Util
时,得到该类,从而可以实现对其进行Hook。
通过分析,Hook目标方法foo.ree.demos.x4th01.Base64Util#decrypt(java.lang.String)
,需要两步:
首先Hook
java.lang.ClassLoader#loadClass(java.lang.String)
方法。然后Hook
foo.ree.demos.x4th01.Base64Util#decrypt(java.lang.String)
方法。
具体代码如下:
public class FooxMain implements IXposedHookLoadPackage {@Override public void handleLoadPackage(LoadPackageParam lpp) throws Throwable {if (!"foo.ree.demos.x4th02".equals(lpp.packageName)) return; // 第一步:Hook方法ClassLoader#loadClass(String) findAndHookMethod(ClassLoader.class, "loadClass", String.class, new XC_MethodHook() {@Override protected void afterHookedMethod(MethodHookParam param) throws Throwable {if (param.hasThrowable()) return; Class<?> cls = (Class<?>) param.getResult(); String name = cls.getName(); if ("foo.ree.demos.x4th01.Base64Util".equals(name)) {// 所有的类都是通过loadClass方法加载的 // 所以这里通过判断全限定类名,查找到目标类 // 第二步:Hook目标方法 findAndHookMethod(cls, "decrypt", String.class, new XC_MethodHook() {@Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { XposedBridge.log(param.method + " params: " + Arrays.toString(param.args)); } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { XposedBridge.log(param.method + " return: " + param.getResult()); } }); } } }); }}
若是还没有实践过,建议动动手,检验以上两种Hook方法,哪一种可行。
目前,安卓应用程序越来越大,包含的dex越来越多。只要不是主dex(classes.dex)中定义的类和方法,都可以通过以上代码进行Hook。
找个多dex的安卓应用程序,动手试一下吧。
完整代码地址:https://github.com/fooree/fooXposed/tree/master/Foox_05th
现在很多的app都有多个dex文件,因为单个dex文件顶多存放60000多个方法,如果代码太多的话必须拆分dex。如果用xposed去hook非默认dex文件的类就会发生ClassNotFoundError,要解决这个问题,我们需要拿到对应dex文件的上下文环境。
android在加载dex文件后会创建一个application类,然后会调用attach方法,attach方法的参数就是上下文context,而且attach方法是final方法,不会因为被覆盖而hook不到,拿到这个context就可以获取对应的classloader,然后可以顺利hook到你需要的类
XposedHelpers.findAndHookMethod(Application.class, "attach", Context.class, new XC_MethodHook() {@Overrideprotected void afterHookedMethod(MethodHookParam param) throws Throwable {ClassLoader cl = ((Context)param.args[0]).getClassLoader();Class<?> hookclass = null;try {hookclass = cl.loadClass("xxx.xxx.xxx");} catch (Exception e) {Log.e("DEBUG", "load class error", e);return;}Log.i("DEBUG", "load success");XposedHelpers.findAndHookMethod(hookclass, "some_method",new XC_MethodHook(){//TODO: 相关hook操作});}});
文章分页
xposedhook部分记录相关推荐
- mysql建立联合索引,mysql建立唯一键,mysql如何解决重复记录联合索引
在项目中,常常要用到联合唯一 在一些配置表中,一些列的组合成为一条记录. 比如,在游戏中,游戏的分区和用户id会形成一条记录.(比如,一个qq用户可以在艾欧尼亚.德玛西亚创建两个账号) 添加联 ...
- 实现 连续15签到记录_MySQL和Redis实现用户签到,你喜欢怎么实现?
现在的网站和app开发中,签到是一个很常见的功能 如微博签到送积分,签到排行榜 微博签到 如移动app ,签到送流量等活动, 移动app签到 用户签到是提高用户粘性的有效手段,用的好能事半功倍! 下面 ...
- 记录一次http请求失败的问题分析
问题背景 当前我有一个基于Flask编写的Restful服务,由于业务的需求,我需要将该服务打包成docker 镜像进行离线部署,原始服务的端口是在6661端口进行开启,为了区分,在docker中启动 ...
- Pytorch学习记录-torchtext和Pytorch的实例( 使用神经网络训练Seq2Seq代码)
Pytorch学习记录-torchtext和Pytorch的实例1 0. PyTorch Seq2Seq项目介绍 1. 使用神经网络训练Seq2Seq 1.1 简介,对论文中公式的解读 1.2 数据预 ...
- LeetCode简单题之学生出勤记录 I
题目 给你一个字符串 s 表示一个学生的出勤记录,其中的每个字符用来标记当天的出勤情况(缺勤.迟到.到场).记录中只含下面三种字符: 'A':Absent,缺勤 'L':Late,迟到 'P':Pre ...
- 关于TVM的点滴记录
关于TVM的点滴记录
- MySql数据库Update批量更新与批量更新多条记录的不同值实现方法
批量更新 mysql更新语句很简单,更新一条数据的某个字段,一般这样写: UPDATE mytable SET myfield = 'value' WHERE other_field = 'other ...
- 记录篇,自己在项目中使用过的。
图片选择器,6.0已经适配过,类似qq空间上传 点击打开链接_胡小牧记录 下面是效果图: PictureSelector PhotoPicker 类似qq空间发布心情. 点击打开链接 BubbleSe ...
- HTML5与CSS3权威指南之CSS3学习记录
title: HTML5与CSS3权威指南之CSS3学习记录 toc: true date: 2018-10-14 00:06:09 学习资料--<HTML5与CSS3权威指南>(第3版) ...
最新文章
- iOS进阶之页面性能优化
- HTML基础部分(2)表格
- 7-51 两个有序链表序列的合并 (20 分)(vector做法)
- 数字图像处理小练习存档1
- java中operationBox_Java使用PDFBox开发包实现对PDF文档内容编辑与保存
- SQLite_Android
- Error running ‘Unnamed‘: Unable to open debugger port (127.0.0.1:xxxx)
- Session何时创建实例
- 株洲市码高机器人编程_码高机器人教育
- 导入别的项目到我的eclipse上出现红色感叹号问题
- oracle的监听服务详解
- UCI数据集汇总及描述
- OSEK间接网络管理(NM)
- STM32通过SD卡IAP
- 魅族 系统更新服务器,Flyme
- LiveData 机制详解
- 直击本质:聊聊小程序的前世今生
- Vertica资源池
- 6.亿级流量电商详情页系统实战
- 区块链投资人李明轩:区块链通过多中心化机制解决传统互联网问题|筱静观察