`
runfeel
  • 浏览: 935882 次
文章分类
社区版块
存档分类
最新评论

android应用程序fps meter[帧数显示]的分析 —— 浅谈root的风险 (2)

 
阅读更多

上一节已经分析应用程序启动后,会通过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系统的话,是很难被注入代码的。



分享到:
评论

相关推荐

    显示帧数Fraps

    4. **性能测试**:通过长时间运行游戏,Fraps可以记录并分析帧数变化,帮助玩家了解硬件在长时间负载下的表现,找出可能的瓶颈。 5. **兼容性广泛**:Fraps支持大量的DirectX和OpenGL游戏,几乎涵盖了市面上所有的...

    游戏帧数自定义工具FPS_Limiter_0.2

    (按下 OSD 按钮可以 在游戏画面显示帧数) 点击 create bat 按钮 此时会自动创建批处理bat文件: “游戏启动程序名.limited.bat” 双击上面创建的bat文件 此时会打开一个命令提示符窗口并 以你自定义的游戏帧数运行...

    GTA4显示帧数工具

    通过使用帧数显示工具,玩家可以实时查看游戏运行的帧率,找出可能导致性能瓶颈的因素,如CPU、GPU的负荷,或是内存使用情况等,从而进行相应的优化。 3. **如何使用GTA4显示帧数工具** 包含的"setup.exe"文件是...

    FPS帧数读取

    测FPS FPS帧数读取

    Android测量每秒帧数Frames Per Second (FPS)的方法

    在Android开发中,测量应用程序或游戏的性能是一个重要的任务,特别是在涉及到动画和视频播放时。帧率(Frames Per Second,FPS)是衡量这种性能的关键指标,它表示每秒钟屏幕上显示图像的数量。高FPS意味着更流畅的...

    FPS查看软件FPS查看软件

    FPS(Frames Per Second)是衡量计算机图形显示性能的重要指标,特别是在游戏领域,它代表每秒屏幕上显示的图像帧数。高FPS通常意味着更流畅的游戏体验,而低FPS可能导致画面卡顿或延迟。FPS查看软件可以帮助玩家...

    Android camera 预览帧数和视频通话图片缓存

    在Android平台上,摄像头预览帧数和视频通话中的图片缓存是两个紧密相关的概念,它们对应用程序的性能和用户体验有着重要影响。这篇文章将深入探讨这两个主题,并基于给出的`AndroidVideo.java`文件来分析相关技术。...

    显示unity帧数

    可以显示游戏中的帧数FPS

    提升Android应用程序性能

    在Android应用开发中,每一帧的处理时间需要控制在合适的范围内,通常为了达到60fps(每秒帧数),开发者只有16.67毫秒来完成每一帧的处理,而要达到24fps则有41.67毫秒。这意味着任何的UI线程阻塞都将导致应用运行...

    (Mac/Linux版)Android实时显示帧率(GameBench)

    2. **连接设备**:使用USB数据线将Android设备连接到电脑,并确保ADB驱动已正确安装,设备处于调试模式并允许USB调试。 3. **运行GameBench**:在终端中,导航到.jar文件所在的目录,然后输入`java -jar GameBench....

    用VFW捕捉视频的帧数显示

    - 开启定时器,定时调用捕获帧的函数,并更新帧数显示。 - 实现捕获帧的回调函数,计算并更新帧数。 - 记得在适当的时候释放资源,关闭捕获设备。 7. **注意事项**: - 确保正确处理VFW错误,例如设备未连接或...

    在屏幕上显示 FPS,CPU 使用率,更好的监控应用性能.zip

    标题提到的"在屏幕上显示 FPS,CPU 使用率,更好的监控应用性能",这是一个旨在提升用户体验和系统监控能力的工具或技术。这种技术通常用于实时监测应用运行时的系统资源消耗情况,帮助开发者定位性能瓶颈,以实现更...

    Android-Android性能监控检测工具FPSCPUPSSPrivateDirty

    在Android应用开发中,性能监控是至关重要的环节,它能够帮助开发者发现并优化应用程序的性能问题,提升用户体验。本文将详细介绍Android性能监控检测工具——FPSCPUPSSPrivateDirty,并探讨这些指标在Android系统中...

    可以看游戏帧数的程序Frags

    Frags是一款专为游戏玩家设计的实用工具,它能够实时显示游戏中的帧数(FPS),帮助玩家了解游戏运行的性能状态。帧数是衡量游戏流畅度的重要指标,通常来说,帧数越高,游戏画面就越流畅。Fraps的使用非常简单,...

    程序4_视频帧数提取_

    帧率(Frame Rate)是指每秒钟显示的帧数,常见的有24fps、30fps和60fps,帧率越高,视频流畅性越好,但数据量也越大。视频帧数提取就是从视频中识别并提取出每一帧的顺序和数量,以便对单个帧进行分析或操作。 在...

    Android实时投屏软件.此应用程序提供USB(或通过TCP/IP)连接的Android设备的显示和控制 它不需要任何root

    QtScrcpy 可以通过 USB / 网络连接Android设备,并进行显示和控制。无需root权限。 同时支持 GNU/Linux ,Windows 和 MacOS 三大主流桌面平台。 它专注于: 精致 (仅显示设备屏幕) 性能 (30~60fps) 质量 (1920×1080...

    fraps一款游戏帧数测试软件

    值得注意的是,虽然Fraps提供了直观的帧数显示,但其自身也会占用一定的系统资源。因此,在进行测试时,可能会对游戏性能产生微小的影响。此外,Fraps主要用于桌面游戏,对于一些使用内置性能监控的现代游戏或者VR...

    [Unity3D]查看与设置游戏帧数FPS

    ### Unity3D中游戏帧数FPS的查看与设置 在Unity3D开发过程中,了解如何有效地查看和设置游戏帧数FPS对于优化游戏性能至关重要。本文将详细介绍如何在Unity3D中实现这一目标,并提供相关的代码示例。 #### 1. Unity...

    python 读取视频,处理后,实时计算帧数fps的方法

    实时计算每秒的帧数 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(*'...

Global site tag (gtag.js) - Google Analytics