前言
之前研究了安卓root环境下内存读写的方案,今天分享一下安卓的绘制方法.
环境
1.雷电模拟器3
2.Android5.1真机
3.Android Studio 2020.3.1 Patch4
4.ndk (22.1.7171670)
原理
1.app向WindowManager添加一个具有悬浮窗属性的view,并且设置为透明不可点击.这个view主要用来绘制.
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
getLayoutType(),
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
PixelFormat.TRANSLUCENT);
if (Build.VERSION.SDK_INT >= 28) {
params.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES ;
}
//添加悬浮窗
windowManager.addView(overlayView, params);
2.app使用root权限启动一个root进程,该进程负责读取游戏内数据并用udp发送到app中.
public void StartSuProcess() throws Exception{
Process p = Runtime.getRuntime().exec("su");
OutputStream os = p.getOutputStream();
p.getErrorStream();
String str =getBaseContext().getApplicationInfo().nativeLibraryDir+"/libjni_draw.so";
os.write((str + "\n").getBytes());
os.write("exit\n".getBytes());
os.flush();
os.close();
}
3.app接收到进程发来的数据,在onDraw方法中调用drawRect函数进行绘制.
@Override
protected void onDraw(Canvas canvas) {
// super.onDraw(canvas);
// DrawRect(canvas,255, 255, 255, 255,1,80,80,550,600);
Draw(this,canvas);
invalidate();
}
具体步骤
1.首先用ce搜出僵尸的坐标,搜未知的初始值,然后依次搜索减少的数值,最后搜索到僵尸的坐标地址特征码
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF
用之前内存读取的方法,结合udp,将读取到的地址坐标转为结构体发送给app端.
2.新建OverlayView类,该类继承View类并重写onDraw方法,之后调用windowManager的addView方法添加到系统中,然后在onDraw中调用native方法绘制方框,并调用invalidate方法反复刷新.
3.在native中建立起udp连接,新建一个线程接收root进程发送过来的数据,onDraw线程进入native后反射调用OverlayView类中的DrawRect方法绘制矩形.
有几个需要注意的地方
1.因为使用了udp,所以要在AndroidManifest.xml中添加权限
<uses-permission android:name="android.permission.INTERNET"/>
悬浮窗为
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
2.绘制的时候最好一次绘制所有的矩形,否则会出现绘制闪烁的情况.
3.悬浮窗创建的时候需要默认为横屏,否则竖屏模式创建的悬浮窗在转换到横屏后会出现显示问题.
需要在AndroidManifest.xml的activity中添加属性,横屏显示.
android:screenOrientation="landscape"
4.root进程用ndk-build编译,放在jni目录里,编译后需要将名字改为libjni_draw.so,配置build.gradle打包进app里,并在app启动时由StartSuProcess方法启动.
5.关闭app后root进程不会随之关闭,需要在root进程中不断检测app存活从而判断是否需要关闭.
void *checkApp(void *)
{
while (true)
{
if (find_pid(APP_PACKAGE_NAME) == -1)
{
exit(0);
}
sleep(5);
}
}
6.由于是用特征码进行搜索,因此会搜出许多非真实的数据.大家也可以进一步排查.
写在最后
除了使用udp传输数据外,还可以用mmap方式的共享内存进行数据传输.
绘制方面除了用悬浮窗外,还可以借助android源码和skia编译可执行文件绘制.
Andorid5.1测试通过(雷电模拟器3和安卓真机),
其余版本未知.
github地址:
https://github.com/PShocker/Android_float_view_draw
植物大战僵尸网盘地址:
链接:https://pan.baidu.com/s/15N_GaoDQBGPfIfXwfvA9dA
提取码:zd68
最后附上截图