从0到1编写一个Xposed Module :Anti Screenshot
最近开始接触app测试,发现坑有些多,赤手空拳搞不定,决定开始学习xposed module的相关的操作。
毕竟“root==god”,要好好利用 root 来对app进行降维打击!
今天先解决某些app不能截图的问题,实测可bypass 某im的闪图功能、某支付软件的付款码界面、还有某银行app。
代码已开源到GitHub,并且还有现成的Release等你下载!
Github Repo:
https://github.com/lushann/Anti-Screenshot
Release:
https://github.com/lushann/Anti-Screenshot/releases
正文Start
毕竟是从0到1的一篇文章,基本流程还得走走。
一、环境准备
已经配置好xposed环境的测试机一枚
准备好一份XposedBridge API jar:
https://forum.xda-developers.com/xposed/xposed-api-changelog-developer-news-t2714067
二、项目初始化
1.Android Studio 新建项目
这里新建一个 Empty Activity的项目
说明:
如果选择No Activity 的话,在studio里边没办法直接安装到测试机上进行测试,因为没有actvity。模块开发结束后,可以把activity删掉,然后生成签名的apk,这样安装后,模块不会在桌面生成图标,完美。 我寻思了一下,我会用到的测试机,Android版本最低也是8.1,所以就把Minimum SDK设置成 8.0 了。
2.编写xposed module 基本信息
在src/main/res/values/strings.xml中添加如下:
<string name="xposed_description">强制截屏 @lushan</string>
在AndroidManifest.xml文件中,标签内部添加以下代码
<meta-data android:name="xposedmodule" android:value="true" /> <meta-data android:name="xposeddescription" android:value="@string/xposed_description" /> <meta-data android:name="xposedminversion" android:value="54" />
如图:
3.加载 XposedBridge API 包
将XposedBridgeApi包拷贝到libs下,然后右键 Add As Library:
在app文件夹下的build.gradle中检查 dependencies块中的内容
说明:网上的教程大多数写的是用 provided,该关键字已被 compileOnly 取代。
如果本步骤设置不当,xposed框架会打印如下log:
4.新建Xposed module 入口函数
函数体:
public class HookMain implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
}
}
咱们在这一步呢,先写个空的入口函数,内部逻辑以后再写。
5.指定 Xposed module 入口函数
在src/main下,新建 assets/xposed_init , 文件内容为包名+入口函数名
到这儿,一个xposed module的雏形就差不多完成了,接下来我们需要完善相关的Hook逻辑,不过我们现在可以执行一下,看一下啥效果
xposed 框架能够正确识别到这是个 module,并且能够显示之前设置好的 module 基本信息。
三、分析Android禁止截屏相关函数
总的来说,经过我的细致观察,Android提供的禁止截屏的方法,最终都是给“Display“这个类,增加“FLAG_SECURE”属性
下边是官方文档关于如何设定 “FLAG_SECURE“的方法:
An application creates a window with a secure surface by specifying the WindowManager.LayoutParams#FLAG_SECUREwindow flag. Likewise, an application creates a SurfaceView with a secure surface by calling SurfaceView#setSecure before attaching the secure view to its containing window.
文档:
https://developer.android.com/reference/android/view/Display#FLAG_SECURE
很明显,上边这段文档介绍了两种方法来设定 Display.FLAG_SECURE,一个呢是通过指定 window类的flag:WindowManager.LayoutParams#FLAG_SECURE, 另一个就是使用 SurfaceView#setSecure 方法。
接下来好好看一下相关的函数,以备Hook之用。
1. 指定window flag
可以通过以下两个方法实现:
window.setFlag(WindowManager.LayoutParams.FLAG_SECURE)
文档:
https://developer.android.com/reference/android/view/Window#setFlags(int,%20int))
window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
https://developer.android.com/reference/android/view/Window#addFlags(int))
2.SurfaceView.setSecure
https://developer.android.com/reference/android/view/SurfaceView#setSecure(boolean))
综上所述,咱们需要hook三个函数。
四、完成 module 编写
其实逻辑还挺简单的,hook函数调用、改参数,一气呵成
public class HookMain implements IXposedHookLoadPackage {
String packageName = new String();
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
packageName = loadPackageParam.packageName;
// Hook "window.setFlag(WindowManager.LayoutParams.FLAG_SECURE)"
XposedHelpers.findAndHookMethod(Window.class, "setFlags", int.class, int.class,
removeSecureFlagHook);
// Hook "window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)"
XposedHelpers.findAndHookMethod(Window.class, "addFlags", int.class,
removeSecureFlagHook);
// Hook "SurfaceView.setSecure"
XposedHelpers.findAndHookMethod(SurfaceView.class, "setSecure", boolean.class,
removeSetSecureHook);
}
private final XC_MethodHook removeSecureFlagHook = new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
if ((Integer) param.args[0] == WindowManager.LayoutParams.FLAG_SECURE){
param.args[0] = 0;
XposedBridge.log("Anti Screenshot : 已阻止" + packageName);
}
}
};
private final XC_MethodHook removeSetSecureHook = new XC_MethodHook() {
@Override
protected void beforeHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable {
param.args[0] = false;
XposedBridge.log("Anti Screenshot : 已阻止" + packageName);
}
};
}
五、测试
保证在Xposed框架中启用这个模块之后,咱们简单测试一下闪图
Yes!成功看到了茄子!
此时,在Xposed的 log 界面我们可以看到:
Yes!本文结束,模块相关问题请提issus,告辞
参考:
Xposed模块开发指南 https://yuanfentiank789.github.io/2017/04/01/xposeddev/ DisableFlagSecure https://github.com/veeti/DisableFlagSecure
- WebComponent魔法堂:深究Custom Element 之 面向痛点编程
- 修复bootstrap daterangepicker中的3个问题
- 搭建AngualarJS开发环境
- CSS魔法堂:重拾Border之——更广阔的遐想
- Jboss EAP:native management API学习
- linux:手动校准系统时间和硬件CMOS时间
- CSS3魔法堂:说说Multi-column Layout
- 数据可视化-EChart2.0使用总结2
- rpc框架之 thrift 学习 2 - 基本概念
- rpc框架之avro 学习 1 - hello world
- 探讨Android中的内置浏览器和Chrome
- java并发编程学习: 阻塞队列 使用 及 实现原理
- CSS魔法堂:说说Float那个被埋没的志向
- Netbeans配置Xdebug
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Nginx系列:安全下载模块
- 5分钟入门GANS:原理解释和keras代码实现
- 使用ML 和 DNN 建模的技巧总结
- 医学图像分割模型U-Net介绍和Kaggle的Top1解决方案源码解析
- 机器学习中的音频特征:理解Mel频谱图
- 兄弟,如何淡定地渡过七夕?
- Spring 源码第 9 篇,深入分析 FactoryBean
- PowerBI 动态数据格式 高级版 以及重要通知
- 气哭老板的顶级密钥存放方案,又做了一件蠢事
- 构建没有数据集的辣辣椒分类器,准确性达到96%
- 由 Redis 分布式锁造成的重大事故
- 10分钟搞定 Java 并发队列好吗?好的
- MySQL 案例:关于程序端的连接池与数据库的连接数
- spark和kafka jar包冲突NoSuchMethodError: net.jpountz.lz4.LZ4BlockInputStream
- 聊聊claudb的scripting command