上一节已经分析应用程序启动后,会通过RootTools库的Shell类,获取root权限并执行/data/data/com.aatt.fpsm/files/0,也就是apk包中的res/raw/bin0这个二进制文件,此二进制文件再通过ptrace系统调用,去绑定到其他进程中,做一些动作。接下来看一下fps meter这个apk到底是做了什么动作。
Ptrace调用过程分析
ptrace是提供一个进程控制另外一个进程运行的机制,通过它可以查看和更改进程的数据,它也是linux上的调试程序gdb的基础。
ptrace调用
为查看ptrace的系统调用情况,最好的方法是在内核对应的系统调处理函数中将相关信息打印出来,修改内核的ptrace调用,加入trace,这样就可以在无源码的情况下,查看到bin0都使用了哪些ptrace操作请求,这里主要有:
ptrace: pid=76 req=16 addr=0 data=0
ptrace: pid=76 req=12 addr=0 data=be86f938
ptrace: pid=76 req=5 addr=be84fa28 data=7461642f
ptrace: pid=76 req=5 addr=be84fa2c data=61642f61
ptrace: pid=76 req=5 addr=be84fa30 data=632f6174
ptrace: pid=76 req=5 addr=be84fa34 data=612e6d6f
ptrace: pid=76 req=5 addr=be84fa38 data=2e747461
ptrace: pid=76 req=5 addr=be84fa3c data=6d737066
ptrace: pid=76 req=5 addr=be84fa40 data=6c69662f
ptrace: pid=76 req=5 addr=be84fa44 data=302f7365
ptrace: pid=76 req=5 addr=be84fa48 data=6f732e
ptrace: pid=76 req=13 addr=0 data=be86f938
ptrace: pid=76 req=7 addr=0 data=0
ptrace: pid=76 req=12 addr=0 data=be86f938
ptrace: pid=76 req=5 addr=be84f9a8 data=64616f6c
ptrace: pid=76 req=2 addr=be84f9ac data=be86f8bc
ptrace: pid=76 req=5 addr=be84f9ac data=40f30000
ptrace: pid=76 req=13 addr=0 data=be86f938
ptrace: pid=76 req=7 addr=0 data=0
ptrace: pid=76 req=12 addr=0 data=be86f938
ptrace: pid=76 req=13 addr=0 data=be86f938
ptrace: pid=76 req=7 addr=0 data=0
ptrace: pid=76 req=12 addr=0 data=be86f938
ptrace: pid=76 req=13 addr=0 data=be86f980
ptrace: pid=76 req=7 addr=0 data=0
ptrace: pid=76 req=17 addr=0 data=0
从trace出来的pid我们可以知道,ptrace是挂到surfaceflinger进程中,对其进行操作修改的,这从该apk的功能来看,确实合理。先看下surfaceflinger的maps信息(省略了一些非关键信息),这是分析的主要依据:
# cat /proc/76/maps
maps:
root@android:/proc/76 # cat maps
400a8000-400a9000 r-xp 00000000 5d:10 241 /system/bin/surfaceflinger
400a9000-400aa000 r--p 00000000 5d:10 241 /system/bin/surfaceflinger
400aa000-400ab000 rw-p 00000000 00:00 0
400ab000-400b9000 r-xp 00000000 5d:10 167 /system/bin/linker
400b9000-400ba000 r--p 00000000 00:00 0
400ba000-400bb000 r--p 0000e000 5d:10 167 /system/bin/linker
400bb000-400bc000 rw-p 0000f000 5d:10 167 /system/bin/linker
400bc000-400c6000 rw-p 00000000 00:00 0
400c6000-400f5000 r-xp 00000000 5d:10 771 /system/lib/libsurfaceflinger.so
400f5000-400fa000 r--p 0002e000 5d:10 771 /system/lib/libsurfaceflinger.so
400fa000-400fb000 rwxp 00033000 5d:10 771 /system/lib/libsurfaceflinger.so
400fb000-400fc000 rw-p 00034000 5d:10 771 /system/lib/libsurfaceflinger.so
................
40146000-40147000 ---p 00000000 00:00 0
40147000-40149000 r--p 00045000 5d:10 644 /system/lib/libc.so
40149000-4014b000 rw-p 00047000 5d:10 644 /system/lib/libc.so
4014b000-40156000 rw-p 00000000 00:00 0
................
401d3000-40210000 r-xp 00000000 5d:10 606 /system/lib/libEGL.so
40210000-40212000 r--p 0003c000 5d:10 606 /system/lib/libEGL.so
40212000-40216000 rw-p 0003e000 5d:10 606 /system/lib/libEGL.so
................
40306000-4030e000 r--s 00000000 00:0a 2126 /dev/__properties__ (deleted)
4030e000-4040c000 r--p 00000000 00:0a 2687 /dev/binder
4040c000-4040d000 ---p 00000000 00:00 0
4040d000-4050c000 rw-p 00000000 00:00 0 [stack:125]
................
40b7a000-40b80000 rw-p 00000000 00:00 0 [heap]
................
40c39000-40c3c000 r-xp 00000000 5d:10 1031 /system/vendor/lib/hw/hwcomposer.default.so
40c3c000-40c43000 ---p 00000000 00:00 0
40c43000-40c44000 r--p 00002000 5d:10 1031 /system/vendor/lib/hw/hwcomposer.default.so
40c44000-40c45000 rw-p 00003000 5d:10 1031 /system/vendor/lib/hw/hwcomposer.default.so
40c45000-40c46000 ---p 00000000 00:00 0
40c46000-40d45000 rw-p 00000000 00:00 0 [stack:184]
40d45000-40d46000 ---p 00000000 00:00 0
40d46000-40e45000 rw-p 00000000 00:00 0 [stack:187]
40e45000-40e47000 rw-p 00000000 00:00 0
................
4163c000-41641000 r-xp 00000000 5d:20 311 /data/data/com.aatt.fpsm/files/0.so
41641000-41642000 r--p 00004000 5d:20 311 /data/data/com.aatt.fpsm/files/0.so
41642000-41643000 rw-p 00005000 5d:20 311 /data/data/com.aatt.fpsm/files/0.so
................
bea46000-bea67000 rw-p 00000000 00:00 0 [stack]
ffff0000-ffff1000 r-xp 00000000 00:00 0 [vectors]
从maps信息中,其实已经能看出一些门道了:
4163c000-41641000 r-xp 00000000 5d:20 311 /data/data/com.aatt.fpsm/files/0.so
41641000-41642000 r--p 00004000 5d:20 311 /data/data/com.aatt.fpsm/files/0.so
41642000-41643000 rw-p 00005000 5d:20 311 /data/data/com.aatt.fpsm/files/0.so
这个信息可以看出,fps meter中的0.so,被注入到surfaceflinger中,这在android的安全规则中是不可能的。也就是说surfaceFlinger已经被入侵感染了,不是原来的surfaceFlinger了!
继续分析之前,首先还是看一下ptrace的操作,上述的trace中,request id就是各个ptrace请求命令。这里用到的有如下几个:
Request
|
Macro
|
Description
|
16
|
PTRACE_ATTACH
|
Attach到被调试进程,attach之后,被调试进程将暂停执行
|
12
|
PTRACE_GETREGS
|
获取被调试线程的各个寄存器值
|
5
|
PTRACE_POKEDATA
|
修改内存地址的值
|
13
|
PTRACE_SETREGS
|
设置寄存器的值
|
7
|
PTRACE_CONT
|
继续执行暂停的程序
|
2
|
PTRACE_PEEKDATA
|
从被调试进程的指定内存位置读取数据
|
17
|
PTRACE_DETACH
|
停止对进程的调试,恢复其常态运行
|
调用细节
为了解更细节的信息,需要更详尽的trace,继续将相关的输入输出参数都打印出来,结合上面的maps信息,对每一步的ptrace调用,详细分析流程如下:
ptrace_request: pid=76 req=16 addr=0 data=0
ptrace_request: pid=76 req=12 addr=0 data=beb68938
PTRACE_GETREGS:
r0 00000003 r1 c0186201 r2 bea66ac8 r3 bea66ac4
r4 40b7e020 r5 40b7dff0 r6 40b7e050 r7 00000036
r8 00000001 r9 40b7dff8 sl 00000000 fp bea66b7c
ip 402bbf24 sp bea66aa8 lr 4012b9f5 pc 40117ffc cpsr 80000010
这里是attach到surfaceflinger线程,暂停surfaceflinger线程的执行,然后获取暂停时的寄存器数据。对于这里分析的fps meter的注入入侵,需要保存surfaceflinger线程暂停点的寄存器信息,入侵完毕后再恢复现场,继续surfaceflinger的正常运行。
ptrace: pid=76 req=5 addr= bea66a28 data=7461642f
ptrace: pid=76 req=5 addr= bea66a2c data=61642f61
ptrace: pid=76 req=5 addr= bea66a30 data=632f6174
ptrace: pid=76 req=5 addr= bea66a34 data=612e6d6f
ptrace: pid=76 req=5 addr= bea66a38 data=2e747461
ptrace: pid=76 req=5 addr= bea66a3c data=6d737066
ptrace: pid=76 req=5 addr= bea66a40 data=6c69662f
ptrace: pid=76 req=5 addr= bea66a44 data=302f7365
ptrace: pid=76 req=5 addr= bea66a48 data=006f732e
这里的req=5就是PTRACE_POKEDATA,修改栈上的数据,修改的指针是addr=0xbea66a28, 则以上几个POKEDATA的调用,作用将(char )addr[]的内容修改为:“/data/data/com.aatt.fpsm/files/0.so”,这即是要注入的so的路径。
ptrace_request: pid=76 req=13 addr=0 data=beb68938
PTRACE_SETREGS:
r0 bea66a28 r1 00000000 r2 bea66ac8 r3 bea66ac4
r4 40b7e020 r5 40b7dff0 r6 40b7e050 r7 00000036
r8 00000001 r9 40b7dff8 sl 00000000 fp bea66b7c
ip 402bbf24 sp bea66a28 lr 00000000 pc 400b00ad cpsr 80000030
ptrace_request: pid=76 req=7 addr=0 data=0
调用PTRACE_SETREGS设置寄存器,然后再调用PTRACE_CONT执行。
这里面设置的寄存器,主要变动如下:
- R0:应参数,是字符串“/data/data/com.aatt.fpsm/files/0.so”的指针
- sp : 堆栈地址,也是字符串的指针位置
- lr: 函数返回地址
- pc:需要注入代码的起始地址
这里的lr是0,程序出错后跳到0去,肯定会出现异常,导致程序停止,调试端进程可以通过waitpid得知该次注入的代码已经被执行。
pc的地址 400b00ad,从上节的maps表中可以看到,这是android的动态连接器linker中的代码,PC是位于linker的代码偏移位置:400b00ad-400ab000=50ad的位置。50ad说明实际偏移是0x50AC,最低位的1表明是thumb指令。
那这个位置具体是什么呢(肯定是某个函数)?这个函数没有导出符号,我也没看出来,不过从参数和上下文分析,猜测可能是dlopen,不然用so作参数,调用linker的函数干嘛呢? 写个小程序验证了一下:
#define LOG_TAG "TEST"
#include <dlfcn.h>
#include <unistd.h>
#include <cutils/log.h>
int main(int argc, char *argv){
ALOGD("dlopen:%p dlsym:%p", (void*)dlopen, (void*)dlsym);
while(1){
sleep(100);
}
}
运行后,输出的结果:
D/TEST (27539): dlopen:0x4002d0ad dlsym:0x4002d019
对比此测试进程的maps信息:
root@android:/ # cat /proc/27539/maps
40025000-40026000 r-xp 00000000 5d:10 1304 /system/bin/test_linker
40026000-40027000 r--p 00000000 5d:10 1304 /system/bin/test_linker
40027000-40028000 rw-p 00000000 00:00 0
40028000-40036000 r-xp 00000000 5d:10 144 /system/bin/linker
40036000-40037000 r--p 00000000 00:00 0
40037000-40038000 r--p 0000e000 5d:10 144 /system/bin/linker
40038000-40039000 rw-p 0000f000 5d:10 144 /system/bin/linker
...
400d5000-400dd000 r--s 00000000 00:0a 2180 /dev/__properties__ (deleted)
beb4d000-beb6e000 rw-p 00000000 00:00 0 [stack]
ffff0000-ffff1000 r-xp 00000000 00:00 0 [vectors]
4002d0ad-40028000=50ad, 正好验证,确定这个ptrace是让surfaceflinger调用linker中的dlopen,加载/data/data/com.aatt.fpsm/files/0.so
so库加载完成后,系统waitpid返回,再看一下寄存器:
ptrace_request: pid=76 req=12 addr=0 data=beb68938
PTRACE_GETREGS:
r0 400be054 r1 00000000 r2 00000001 r3 004b4001
r4 40b7e020 r5 40b7dff0 r6 40b7e050 r7 00000036
r8 00000001 r9 40b7dff8 sl 00000000 fp bea66b7c
ip 00000000 sp bea66a28 lr 00001ffc pc 00000000 cpsr 80000010
surfaceflinger进程暂停,这里读取寄存器的值,可以看到PC是0,注入的程序执行完毕
ptrace: pid=76 req=5 addr=bea669a8 data=64616f6c
ptrace: pid=76 req=2 addr=bea669ac data=40b7e020
ptrace: pid=76 req=5 addr=bea669ac data=40b7e000
设置地址0xbea669a8的值为"load",读取的bea669ac值为0x40b7e020,然后再通过PTRACE_POKEDATA将其设置成0x40b7e00,这个地址,位于堆中,应该是malloc出来的一个指针,具体作用不明。
ptrace_request: pid=76 req=13 addr=0 data=beb68938
PTRACE_SETREGS:
r0 400be054 r1 bea669a8 r2 00000001 r3 004b4001
r4 40b7e020 r5 40b7dff0 r6 40b7e050 r7 00000036
r8 00000001 r9 40b7dff8 sl 00000000 fp bea66b7c
ip 00000000 sp bea669a8 lr 00000000 pc 400b0019 cpsr 80000030
ptrace_request: pid=75 req=7 addr=0 data=0
PTRACE_CONT执行, 这里设置的pc:400b0019,可以看到是linker中的偏移位置:0x5019,结合刚才写的测例,就是dlsym函数。这里就是查询到load函数的地址。
ptrace_request: pid=76 req=12 addr=0 data=beb68938
PTRACE_GETREGS:
r0 4163da81 r1 00000000 r2 400be054 r3 400be054
r4 40b7e020 r5 40b7dff0 r6 40b7e050 r7 00000036
r8 00000001 r9 40b7dff8 sl 00000000 fp bea66b7c
ip 00000000 sp bea669a8 lr 00001ffc pc 00000000 cpsr 80000010
ptrace_request: pid=75 req=13 addr=0 data=beb68938
PTRACE_SETREGS:
r0 4163da81 r1 00000000 r2 400be054 r3 400be054
r4 40b7e020 r5 40b7dff0 r6 40b7e050 r7 00000036
r8 00000001 r9 40b7dff8 sl 00000000 fp bea66b7c
ip 00000000 sp bea669a8 lr 00000000 pc 4163da81 cpsr 80000030
ptrace_request: pid=76 req=7 addr=0 data=0
PC为0.so中的函数,在0.so中的偏移为:4163da81-4163c000=1a81,这刚好是刚才dlsym查出来的load函数的位置,见IDA pro的反汇编信息:
这样,就在surfaceflinger中注入了用户提供的so库的代码了!
注入完成后,接下来我们需要恢复之前被暂停的surfaceflinger进程的正常执行:
ptrace_request: pid=76 req=12 addr=0 data=beb68938
PTRACE_GETREGS:
r0 00000000 r1 4272d3f3 r2 00000001 r3 40b7dff8
r4 40b7e020 r5 40b7dff0 r6 40b7e050 r7 00000036
r8 00000001 r9 40b7dff8 sl 00000000 fp bea66b7c
ip 40000002 sp bea669a8 lr 0000001e pc 00000000 cpsr 60000010
ptrace_request: pid=76 req=13 addr=0 data=beb68938
PTRACE_SETREGS:
r0 00000003 r1 c0186201 r2 bea66ac8 r3 bea66ac4
r4 40b7e020 r5 40b7dff0 r6 40b7e050 r7 00000036
r8 00000001 r9 40b7dff8 sl 00000000 fp bea66b7c
ip 402bbf24 sp bea66aa8 lr 4012b9f5 pc 40117ffc cpsr 80000010
ptrace_request: pid=76 req=7 addr=0 data=0
ptrace_request: pid=76 req=17 addr=0 data=0
寄存器恢复到暂前的样子,寄生进程从surfaceflinge分离,恢复宿主进程执行。
小结
以上我们可以简单的比喻一下:寄生进程为bin0,宿主进程为surfaceflinger,寄生进程通过ptrace绑到宿主进程上,咬一口(linker调用),下了一个卵(/data/data/com.aatt.fpsm/files/0.so及load调用)到宿主进程,然后飞走了。
通过详细分析了注入过程,应该了解了用ptrace将需要的库或代码植入宿主进程的方法。在不经意间,你运行的正常进程,已经被人为的添加进去可能有害的代码,这可能对你的信息安全或者系统稳定性有很大的影响。
不过linux系统相对来说还是很安全的,这里也并没有利用什么漏洞,如果用户不root系统的话,是很难被注入代码的。
分享到:
相关推荐
4. **性能测试**:通过长时间运行游戏,Fraps可以记录并分析帧数变化,帮助玩家了解硬件在长时间负载下的表现,找出可能的瓶颈。 5. **兼容性广泛**:Fraps支持大量的DirectX和OpenGL游戏,几乎涵盖了市面上所有的...
(按下 OSD 按钮可以 在游戏画面显示帧数) 点击 create bat 按钮 此时会自动创建批处理bat文件: “游戏启动程序名.limited.bat” 双击上面创建的bat文件 此时会打开一个命令提示符窗口并 以你自定义的游戏帧数运行...
通过使用帧数显示工具,玩家可以实时查看游戏运行的帧率,找出可能导致性能瓶颈的因素,如CPU、GPU的负荷,或是内存使用情况等,从而进行相应的优化。 3. **如何使用GTA4显示帧数工具** 包含的"setup.exe"文件是...
测FPS FPS帧数读取
在Android开发中,测量应用程序或游戏的性能是一个重要的任务,特别是在涉及到动画和视频播放时。帧率(Frames Per Second,FPS)是衡量这种性能的关键指标,它表示每秒钟屏幕上显示图像的数量。高FPS意味着更流畅的...
FPS(Frames Per Second)是衡量计算机图形显示性能的重要指标,特别是在游戏领域,它代表每秒屏幕上显示的图像帧数。高FPS通常意味着更流畅的游戏体验,而低FPS可能导致画面卡顿或延迟。FPS查看软件可以帮助玩家...
在Android平台上,摄像头预览帧数和视频通话中的图片缓存是两个紧密相关的概念,它们对应用程序的性能和用户体验有着重要影响。这篇文章将深入探讨这两个主题,并基于给出的`AndroidVideo.java`文件来分析相关技术。...
可以显示游戏中的帧数FPS
在Android应用开发中,每一帧的处理时间需要控制在合适的范围内,通常为了达到60fps(每秒帧数),开发者只有16.67毫秒来完成每一帧的处理,而要达到24fps则有41.67毫秒。这意味着任何的UI线程阻塞都将导致应用运行...
2. **连接设备**:使用USB数据线将Android设备连接到电脑,并确保ADB驱动已正确安装,设备处于调试模式并允许USB调试。 3. **运行GameBench**:在终端中,导航到.jar文件所在的目录,然后输入`java -jar GameBench....
- 开启定时器,定时调用捕获帧的函数,并更新帧数显示。 - 实现捕获帧的回调函数,计算并更新帧数。 - 记得在适当的时候释放资源,关闭捕获设备。 7. **注意事项**: - 确保正确处理VFW错误,例如设备未连接或...
标题提到的"在屏幕上显示 FPS,CPU 使用率,更好的监控应用性能",这是一个旨在提升用户体验和系统监控能力的工具或技术。这种技术通常用于实时监测应用运行时的系统资源消耗情况,帮助开发者定位性能瓶颈,以实现更...
在Android应用开发中,性能监控是至关重要的环节,它能够帮助开发者发现并优化应用程序的性能问题,提升用户体验。本文将详细介绍Android性能监控检测工具——FPSCPUPSSPrivateDirty,并探讨这些指标在Android系统中...
Frags是一款专为游戏玩家设计的实用工具,它能够实时显示游戏中的帧数(FPS),帮助玩家了解游戏运行的性能状态。帧数是衡量游戏流畅度的重要指标,通常来说,帧数越高,游戏画面就越流畅。Fraps的使用非常简单,...
帧率(Frame Rate)是指每秒钟显示的帧数,常见的有24fps、30fps和60fps,帧率越高,视频流畅性越好,但数据量也越大。视频帧数提取就是从视频中识别并提取出每一帧的顺序和数量,以便对单个帧进行分析或操作。 在...
QtScrcpy 可以通过 USB / 网络连接Android设备,并进行显示和控制。无需root权限。 同时支持 GNU/Linux ,Windows 和 MacOS 三大主流桌面平台。 它专注于: 精致 (仅显示设备屏幕) 性能 (30~60fps) 质量 (1920×1080...
值得注意的是,虽然Fraps提供了直观的帧数显示,但其自身也会占用一定的系统资源。因此,在进行测试时,可能会对游戏性能产生微小的影响。此外,Fraps主要用于桌面游戏,对于一些使用内置性能监控的现代游戏或者VR...
### Unity3D中游戏帧数FPS的查看与设置 在Unity3D开发过程中,了解如何有效地查看和设置游戏帧数FPS对于优化游戏性能至关重要。本文将详细介绍如何在Unity3D中实现这一目标,并提供相关的代码示例。 #### 1. Unity...
实时计算每秒的帧数 cap = cv2.VideoCapture(DJI_0008.MOV) #cap = cv2.VideoCapture(0) # Define the codec and create VideoWriter object #fourcc = cv2.cv.FOURCC(*'XVID') fourcc = cv2.VideoWriter_fourcc(*'...