android应用程序fps meter[帧数显示]的分析 —— 浅谈root的风险 (3)
上节已经详细说了下注入过程,最后寄生进程在宿主进程中下了个蛋,这下完的蛋有什么作用呢?接下来再具体分析一下。
lib0的感染过程分析
对于本例注入的so动态库,首先看一下so的符号:
$ readelf -s ./lib0.so Symbol table '.dynsym' contains 136 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 FUNC GLOBAL DEFAULT UND __cxa_finalize
2: 00000000 0 FUNC GLOBAL DEFAULT UND __cxa_atexit
3: 00000000 0 FUNC GLOBAL DEFAULT UND opendir
4: 00000000 0 FUNC GLOBAL DEFAULT UND readdir
5: 00000000 0 FUNC GLOBAL DEFAULT UND strncmp
6: 00000000 0 FUNC GLOBAL DEFAULT UND closedir
7: 00003adc 8 FUNC GLOBAL DEFAULT 7 __aeabi_unwind_cpp_pr0
8: 00000000 0 FUNC GLOBAL DEFAULT UND strcmp
9: 00000000 0 FUNC GLOBAL DEFAULT UND mprotect
10: 00003ad4 8 FUNC WEAK DEFAULT 7 __aeabi_unwind_cpp_pr1
11: 000025dc 40 FUNC GLOBAL DEFAULT 7 __aeabi_i2d
12: 000026b8 620 FUNC GLOBAL DEFAULT 7 __aeabi_dmul
13: 00002924 516 FUNC GLOBAL DEFAULT 7 __aeabi_ddiv
14: 0000230c 684 FUNC GLOBAL DEFAULT 7 __aeabi_dadd
15: 00002308 688 FUNC GLOBAL DEFAULT 7 __aeabi_dsub
16: 00002c2c 20 FUNC GLOBAL DEFAULT 7 __aeabi_dcmpge
17: 00002e98 32 FUNC GLOBAL DEFAULT 7 __aeabi_i2f
18: 00002f44 408 FUNC GLOBAL DEFAULT 7 __aeabi_fmul
19: 00002c54 160 FUNC GLOBAL DEFAULT 7 __aeabi_d2f
20: 000030dc 352 FUNC GLOBAL DEFAULT 7 __aeabi_fdiv
21: 00002d00 400 FUNC GLOBAL DEFAULT 7 __aeabi_fadd
22: 0000323c 92 FUNC GLOBAL DEFAULT 7 __aeabi_f2iz
23: 00000000 0 FUNC GLOBAL DEFAULT UND clock_gettime
24: 00000000 0 FUNC GLOBAL DEFAULT UND write
25: 00006028 4 OBJECT GLOBAL DEFAULT 15 eglSwapBuffers_addr
26: 00006024 4 OBJECT GLOBAL DEFAULT 15 frames
27: 00006010 8 OBJECT GLOBAL DEFAULT 15 current_timer
28: 00006018 8 OBJECT GLOBAL DEFAULT 15 timer
29: 00006020 4 OBJECT GLOBAL DEFAULT 15 fps
30: 0000602c 4 OBJECT GLOBAL DEFAULT 15 fd
31: 00001a81 1208 FUNC GLOBAL DEFAULT 7 load
32: 00000000 0 FUNC GLOBAL DEFAULT UND strcpy
33: 00000000 0 FUNC GLOBAL DEFAULT UND strlen
34: 00000000 0 FUNC GLOBAL DEFAULT UND strcat
35: 00000000 0 FUNC GLOBAL DEFAULT UND dlsym
36: 00000000 0 FUNC GLOBAL DEFAULT UND dlopen
37: 00000000 0 FUNC GLOBAL DEFAULT UND dlclose
38: 00000000 0 FUNC GLOBAL DEFAULT UND open
39: 00000000 0 OBJECT GLOBAL DEFAULT UND __stack_chk_guard
40: 00006008 4 OBJECT GLOBAL DEFAULT 15 hwcomposer_patch
41: 00000000 0 FUNC GLOBAL DEFAULT UND __stack_chk_fail
42: 00001f39 968 FUNC GLOBAL DEFAULT 7 unload
43: 00000000 0 FUNC GLOBAL DEFAULT UND close
44: 00006004 0 NOTYPE GLOBAL DEFAULT ABS _edata
45: 00006004 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
46: 00006030 0 NOTYPE GLOBAL DEFAULT ABS _end
47: 00000000 0 FUNC WEAK DEFAULT UND __gnu_Unwind_Find_exidx
48: 00000000 0 FUNC GLOBAL DEFAULT UND abort
49: 00000000 0 FUNC GLOBAL DEFAULT UND memcpy
50: 00002300 0 FUNC GLOBAL DEFAULT 7 __aeabi_drsub
51: 00002308 688 FUNC GLOBAL DEFAULT 7 __subdf3
52: 0000230c 684 FUNC GLOBAL DEFAULT 7 __adddf3
53: 000025b8 36 FUNC GLOBAL DEFAULT 7 __floatunsidf
54: 000025b8 36 FUNC GLOBAL DEFAULT 7 __aeabi_ui2d
55: 000025dc 40 FUNC GLOBAL DEFAULT 7 __floatsidf
56: 00002604 64 FUNC GLOBAL DEFAULT 7 __extendsfdf2
57: 00002604 64 FUNC GLOBAL DEFAULT 7 __aeabi_f2d
58: 00002644 116 FUNC GLOBAL DEFAULT 7 __floatundidf
59: 00002644 116 FUNC GLOBAL DEFAULT 7 __aeabi_ul2d
60: 00002658 96 FUNC GLOBAL DEFAULT 7 __floatdidf
61: 00002658 96 FUNC GLOBAL DEFAULT 7 __aeabi_l2d
62: 000026b8 620 FUNC GLOBAL DEFAULT 7 __muldf3
63: 00002924 516 FUNC GLOBAL DEFAULT 7 __divdf3
64: 00002b28 152 FUNC GLOBAL DEFAULT 7 __gtdf2
65: 00002b28 152 FUNC GLOBAL DEFAULT 7 __gedf2
66: 00002b30 144 FUNC GLOBAL DEFAULT 7 __ltdf2
67: 00002b30 144 FUNC GLOBAL DEFAULT 7 __ledf2
68: 00002b38 136 FUNC GLOBAL DEFAULT 7 __cmpdf2
69: 00002b38 136 FUNC GLOBAL DEFAULT 7 __nedf2
70: 00002b38 136 FUNC GLOBAL DEFAULT 7 __eqdf2
71: 00002bc0 48 FUNC GLOBAL DEFAULT 7 __aeabi_cdrcmple
72: 00002bdc 20 FUNC GLOBAL DEFAULT 7 __aeabi_cdcmpeq
73: 00002bdc 20 FUNC GLOBAL DEFAULT 7 __aeabi_cdcmple
74: 00002bf0 20 FUNC GLOBAL DEFAULT 7 __aeabi_dcmpeq
75: 00002c04 20 FUNC GLOBAL DEFAULT 7 __aeabi_dcmplt
76: 00002c18 20 FUNC GLOBAL DEFAULT 7 __aeabi_dcmple
77: 00002c40 20 FUNC GLOBAL DEFAULT 7 __aeabi_dcmpgt
78: 00002c54 160 FUNC GLOBAL DEFAULT 7 __truncdfsf2
79: 00002cf4 412 FUNC GLOBAL DEFAULT 7 __aeabi_frsub
80: 00002cfc 404 FUNC GLOBAL DEFAULT 7 __subsf3
81: 00002cfc 404 FUNC GLOBAL DEFAULT 7 __aeabi_fsub
82: 00002d00 400 FUNC GLOBAL DEFAULT 7 __addsf3
83: 00002e90 40 FUNC GLOBAL DEFAULT 7 __floatunsisf
84: 00002e90 40 FUNC GLOBAL DEFAULT 7 __aeabi_ui2f
85: 00002e98 32 FUNC GLOBAL DEFAULT 7 __floatsisf
86: 00002eb8 140 FUNC GLOBAL DEFAULT 7 __floatundisf
87: 00002eb8 140 FUNC GLOBAL DEFAULT 7 __aeabi_ul2f
88: 00002ec8 124 FUNC GLOBAL DEFAULT 7 __floatdisf
89: 00002ec8 124 FUNC GLOBAL DEFAULT 7 __aeabi_l2f
90: 00002f44 408 FUNC GLOBAL DEFAULT 7 __mulsf3
91: 000030dc 352 FUNC GLOBAL DEFAULT 7 __divsf3
92: 0000323c 92 FUNC GLOBAL DEFAULT 7 __fixsfsi
93: 00003acc 8 FUNC WEAK DEFAULT 7 __aeabi_unwind_cpp_pr2
94: 00004098 0 FUNC GLOBAL DEFAULT 7 __gnu_Unwind_Restore_VFP_
95: 00004088 0 FUNC GLOBAL DEFAULT 7 __gnu_Unwind_Restore_VFP
96: 000040a8 0 FUNC GLOBAL DEFAULT 7 __gnu_Unwind_Restore_VFP_
97: 000040b8 0 FUNC GLOBAL DEFAULT 7 __gnu_Unwind_Restore_WMMX
98: 00004140 0 FUNC GLOBAL DEFAULT 7 __gnu_Unwind_Restore_WMMX
99: 00004074 20 FUNC GLOBAL DEFAULT 7 restore_core_regs
100: 0000365c 68 FUNC GLOBAL DEFAULT 7 _Unwind_VRS_Get
101: 000036c8 68 FUNC GLOBAL DEFAULT 7 _Unwind_VRS_Set
102: 00000000 0 NOTYPE WEAK DEFAULT UND __cxa_begin_cleanup
103: 00000000 0 NOTYPE WEAK DEFAULT UND __cxa_type_match
104: 00004274 916 FUNC GLOBAL DEFAULT 7 __gnu_unwind_execute
105: 00000000 0 NOTYPE WEAK DEFAULT UND __cxa_call_unexpected
106: 00003ae4 856 FUNC GLOBAL DEFAULT 7 _Unwind_VRS_Pop
107: 000040a0 0 FUNC GLOBAL DEFAULT 7 __gnu_Unwind_Save_VFP_D
108: 00004090 0 FUNC GLOBAL DEFAULT 7 __gnu_Unwind_Save_VFP
109: 000040b0 0 FUNC GLOBAL DEFAULT 7 __gnu_Unwind_Save_VFP_D_1
110: 000040fc 0 FUNC GLOBAL DEFAULT 7 __gnu_Unwind_Save_WMMXD
111: 00004154 0 FUNC GLOBAL DEFAULT 7 __gnu_Unwind_Save_WMMXC
112: 00003e3c 8 FUNC GLOBAL DEFAULT 7 _Unwind_GetCFA
113: 00003e44 164 FUNC GLOBAL DEFAULT 7 __gnu_Unwind_RaiseExcepti
114: 00003ee8 28 FUNC GLOBAL DEFAULT 7 __gnu_Unwind_ForcedUnwind
115: 00003f04 108 FUNC GLOBAL DEFAULT 7 __gnu_Unwind_Resume
116: 00003f70 32 FUNC GLOBAL DEFAULT 7 __gnu_Unwind_Resume_or_Re
117: 00003f90 4 FUNC GLOBAL DEFAULT 7 _Unwind_Complete
118: 00003f94 32 FUNC GLOBAL DEFAULT 7 _Unwind_DeleteException
119: 00003fb4 192 FUNC GLOBAL DEFAULT 7 __gnu_Unwind_Backtrace
120: 00004074 20 FUNC GLOBAL DEFAULT 7 __restore_core_regs
121: 00004168 36 FUNC GLOBAL DEFAULT 7 ___Unwind_RaiseException
122: 00004168 36 FUNC GLOBAL DEFAULT 7 _Unwind_RaiseException
123: 0000418c 36 FUNC GLOBAL DEFAULT 7 ___Unwind_Resume
124: 0000418c 36 FUNC GLOBAL DEFAULT 7 _Unwind_Resume
125: 000041b0 36 FUNC GLOBAL DEFAULT 7 ___Unwind_Resume_or_Rethr
126: 000041b0 36 FUNC GLOBAL DEFAULT 7 _Unwind_Resume_or_Rethrow
127: 000041d4 36 FUNC GLOBAL DEFAULT 7 ___Unwind_ForcedUnwind
128: 000041d4 36 FUNC GLOBAL DEFAULT 7 _Unwind_ForcedUnwind
129: 000041f8 36 FUNC GLOBAL DEFAULT 7 ___Unwind_Backtrace
130: 000041f8 36 FUNC GLOBAL DEFAULT 7 _Unwind_Backtrace
131: 00004608 64 FUNC GLOBAL DEFAULT 7 __gnu_unwind_frame
132: 00004648 44 FUNC GLOBAL DEFAULT 7 _Unwind_GetRegionStart
133: 00004674 56 FUNC GLOBAL DEFAULT 7 _Unwind_GetLanguageSpecif
134: 000046ac 8 FUNC GLOBAL DEFAULT 7 _Unwind_GetDataRelBase
135: 000046b4 8 FUNC GLOBAL DEFAULT 7 _Unwind_GetTextRelBase
主要是unwind库和软浮点库的实现。除此之外,还有几个符号比较有意思,这是全局变量符号:
25: 00006028 4 OBJECT GLOBAL DEFAULT 15 eglSwapBuffers_addr
26: 00006024 4 OBJECT GLOBAL DEFAULT 15 frames
27: 00006010 8 OBJECT GLOBAL DEFAULT 15 current_timer
28: 00006018 8 OBJECT GLOBAL DEFAULT 15 timer
29: 00006020 4 OBJECT GLOBAL DEFAULT 15 fps
如果对绘图和刷屏及so注入原理比较了解的话,这里可能已经可以猜出来它干了什么,不过暂且先放一放。
从上一节的ptrace分析可以知道,fps meter这个apk运行后,将lib0.so注入到surfaceflinger中后,会运行lib0.so的load方法,那么我们就接着分析这个注入的so库都做了些什么。
用IDA pro看一下load函数的反汇编:
这个函数很长,上图只截了开头一部分。此函数的一大半工作都在往栈上压数据。一开始压GOT表的地址,接下来压的都是ASCII码,只要细心一点,就能推出栈中压入的数据。这里理了一下,栈上压的字符串是:
1.eglSwapBuffers
2./system/lib/hw
3./system/vendor/lib/hw
4.hwcomposer
5./system/lib/libsurfaceflinger.so
6./data/data/com.aatt.fpsm/pipe
这些实际上就是常量字符串,不知为何要代码一个字符一个字符往栈里压,如果是为阻止别人偷窥代码行为,至少也要稍微加扰绕一绕,这也太简单了,根本无法保护。
不过,OK,整理出这些字符串,也不想费劲的抠汇编了,这个函数接下来的代码不用分析也能猜出来了:
- 创建/data/data/com.aatt.fpsm/pipe ,surfaceFlinger向这个pipe中写入帧率,fps meter读出数据并显示在屏幕上。
- 搜索hwcomposer HAL的实现代码,这个HAL通常位于/system/lib/hw或/system/vendor/lib/hw下
- 搜索eglSwapBuffers在GOT表中的地址,将其地址修改掉,换成自己实现的代码,做一番处理后,再调用真正的eglSwapBuffers。
我们可以在egl.cpp的eglSwapBuffers的实现中打印出CallStack验证一下,可以按照如下方式修改代码,打印出每次对eglSwapBuffers的调用堆栈情况:
~/android/frameworks/native/opengl/libs$ git diff
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 23e89da..e31f6f2 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -38,6 +38,7 @@
#include <utils/SortedVector.h>
#include <utils/String8.h>
#include <utils/Trace.h>
+#include <utils/CallStack.h> #include "egl_impl.h"
#include "egl_tls.h"
@@ -850,6 +851,10 @@ EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
ATRACE_CALL();
clearError(); + CallStack stk;
+ stk.update();
+ stk.dump();
+
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
mm后将重新生成的几个so用adb push到机器中,重启,再次运行fps meter,查看打印,见到如下:
D/CallStack( 2938): (null)#00 pc 0000e63c /system/lib/libEGL.so (eglSwapBuffers+99)
D/CallStack( 2938): (null)#01 pc 0000195c /data/data/com.aatt.fpsm/files/0.so
D/CallStack( 2938): (null)#02 pc 0001d72a /system/lib/libsurfaceflinger.so (android::DisplayDevice::swapBuffers(android::HWComposer&) const+41)
D/CallStack( 2938): (null)#03 pc 00025ae0 /system/lib/libsurfaceflinger.so (android::SurfaceFlinger::doDisplayComposition(android::sp<android::DisplayDevice const> const&, android::Region const&)+143)
D/CallStack( 2938): (null)#04 pc 00028b8c /system/lib/libsurfaceflinger.so (android::SurfaceFlinger::doComposition()+95)
D/CallStack( 2938): (null)#05 pc 00028df8 /system/lib/libsurfaceflinger.so (android::SurfaceFlinger::handleMessageRefresh()+51)
D/CallStack( 2938): (null)#06 pc 00029992 /system/lib/libsurfaceflinger.so (android::SurfaceFlinger::onMessageReceived(int)+57)
D/CallStack( 2938): (null)#07 pc 00014c50 /system/lib/libutils.so (android::Looper::pollInner(int)+423)
D/CallStack( 2938): (null)#08 pc 00014d70 /system/lib/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+103)
D/CallStack( 2938): (null)#09 pc 000243b4 /system/lib/libsurfaceflinger.so (android::MessageQueue::waitMessage()+39)
D/CallStack( 2938): (null)#10 pc 000249a0 /system/lib/libsurfaceflinger.so (android::SurfaceFlinger::threadLoop()+5)
D/CallStack( 2938): (null)#11 pc 00011264 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+111)
D/CallStack( 2938): (null)#12 pc 00010dca /system/lib/libutils.so
D/CallStack( 2938): (null)#13 pc 0000e3d8 /system/lib/libc.so (__thread_entry+72)
D/CallStack( 2938): (null)#14 pc 0000dac4 /system/lib/libc.so (pthread_create+160)
看到调用堆栈中有 D/CallStack( 2938): (null)#01 pc 0000195c /data/data/com.aatt.fpsm/files/0.so ,其调用真正的eglSwapBuffers,而它又是被DisplayDevice::swapBuffers调用,果然劫持替换了原生代码中的eglSwapBuffers!!
我们再看下劫持函数做了些什么事情, 通过pc 0000195c 我们找到相关的函数,函数的汇编如下:
.text:00001948 ; =============== S U B R O U T I N E ================================
.text:00001948
.text:00001948
.text:00001948 sub_1948 ; DATA XREF: .text:00001E26o
.text:00001948 ; .text:off_1E80o ...
.text:00001948
.text:00001948 var_38 = -0x38
.text:00001948 var_34 = -0x34
.text:00001948 tp = -0x28
.text:00001948
.text:00001948 PUSH {R4-R7,LR}
.text:0000194A MOV R7, R10
.text:0000194C MOV R6, R9
.text:0000194E MOV R5, R8
.text:00001950 PUSH {R5-R7}
.text:00001952 LDR R4, =(_GLOBAL_OFFSET_TABLE_ - 0x195C)
.text:00001954 LDR R3, =(eglSwapBuffers_addr_ptr - 0x5F94)
.text:00001956 SUB SP, SP, #0x18
.text:00001958 ADD R4, PC
.text:0000195A LDR R3, [R4,R3]
.text:0000195C LDR R3, [R3]
.text:0000195E BLX R3
.text:00001960 LDR R3, =(frames_ptr - 0x5F94)
.text:00001962 ADD R1, SP, #0x38+tp ; tp
.text:00001964 MOVS R0, #0 ; clock_id
.text:00001966 LDR R5, [R4,R3]
.text:00001968 LDR R3, [R5]
.text:0000196A ADDS R3, #1
.text:0000196C STR R3, [R5]
.text:0000196E BLX clock_gettime
.text:00001972 LDR R0, [SP,#0x38+tp]
.text:00001974 BLX __floatsidf
.text:00001978 LDR R3, =0x408F4000
.text:0000197A LDR R2, =0
.text:0000197C BLX __muldf3
.text:00001980 MOVS R6, R0
.text:00001982 LDR R0, [SP,#0x38+tp.tv_nsec]
.text:00001984 MOVS R7, R1
.text:00001986 BLX __floatsidf
.text:0000198A LDR R2, =0
.text:0000198C LDR R3, =0x412E8480
.text:0000198E BLX __divdf3
.text:00001992 MOVS R2, R0
.text:00001994 MOVS R3, R1
.text:00001996 MOVS R0, R6
.text:00001998 MOVS R1, R7
.text:0000199A BLX __aeabi_dadd
.text:0000199E LDR R3, =(current_timer_ptr - 0x5F94)
.text:000019A0 STR R0, [SP,#0x38+var_38]
.text:000019A2 STR R1, [SP,#0x38+var_34]
.text:000019A4 LDR R3, [R4,R3]
.text:000019A6 STR R0, [R3]
.text:000019A8 STR R1, [R3,#4]
.text:000019AA LDR R3, =(timer_ptr - 0x5F94)
.text:000019AC LDR R1, [R4,R3]
.text:000019AE MOV R8, R1
.text:000019B0 MOV R6, R8
.text:000019B2 LDR R2, [R6]
.text:000019B4 LDR R3, [R6,#4]
.text:000019B6 LDR R0, [SP,#0x38+var_38]
.text:000019B8 LDR R1, [SP,#0x38+var_34]
.text:000019BA BLX __subdf3
.text:000019BE LDR R2, =0
.text:000019C0 LDR R3, =0x406F4000
.text:000019C2 MOVS R6, R0
.text:000019C4 MOVS R7, R1
.text:000019C6 BLX __aeabi_dcmpge
.text:000019CA CMP R0, #0
.text:000019CC BEQ loc_1A36
.text:000019CE LDR R1, [R5]
.text:000019D0 MOV R10, R1
.text:000019D2 CMP R1, #3
.text:000019D4 BGT loc_19E6
.text:000019D6 MOVS R0, R6
.text:000019D8 MOVS R1, R7
.text:000019DA LDR R3, =0x408F4000
.text:000019DC LDR R2, =0
.text:000019DE BLX __aeabi_dcmpge
.text:000019E2 CMP R0, #0
.text:000019E4 BEQ loc_1A36
.text:000019E6
.text:000019E6 loc_19E6 ; CODE XREF: sub_1948+8Cj
.text:000019E6 LDR R3, =(fps_ptr - 0x5F94)
.text:000019E8 MOV R0, R10
.text:000019EA LDR R1, [R4,R3]
.text:000019EC MOV R9, R1
.text:000019EE BLX __floatsisf
.text:000019F2 LDR R1, =0x447A0000
.text:000019F4 BLX __mulsf3
.text:000019F8 MOVS R1, R7
.text:000019FA MOV R10, R0
.text:000019FC MOVS R0, R6
.text:000019FE BLX __truncdfsf2
.text:00001A02 MOVS R1, R0
.text:00001A04 MOV R0, R10
.text:00001A06 BLX __divsf3
.text:00001A0A MOVS R1, 0x3F000000
.text:00001A0E BLX __aeabi_fadd
.text:00001A12 BLX __fixsfsi
.text:00001A16 MOV R2, R9
.text:00001A18 MOV R3, R8
.text:00001A1A STR R0, [R2]
.text:00001A1C LDR R1, [SP,#0x38+var_38]
.text:00001A1E LDR R2, [SP,#0x38+var_34]
.text:00001A20 STR R1, [R3]
.text:00001A22 STR R2, [R3,#4]
.text:00001A24 MOVS R3, #0
.text:00001A26 STR R3, [R5]
.text:00001A28 LDR R3, =(fd_ptr - 0x5F94)
.text:00001A2A MOV R1, R9 ; buf
.text:00001A2C MOVS R2, #4 ; n
.text:00001A2E LDR R3, [R4,R3]
.text:00001A30 LDR R0, [R3] ; fd
.text:00001A32 BLX write
.text:00001A36
.text:00001A36 loc_1A36 ; CODE XREF: sub_1948+84j
.text:00001A36 ; sub_1948+9Cj
.text:00001A36 ADD SP, SP, #0x18
.text:00001A38 MOVS R0, #1
.text:00001A3A POP {R2-R4}
.text:00001A3C MOV R8, R2
.text:00001A3E MOV R9, R3
.text:00001A40 MOV R10, R4
.text:00001A42 POP {R4-R7,PC}
.text:00001A42 ; End of function sub_1948
此汇编函数不算复杂,从汇编代码我们大体能看出此函数的工作路径:
1. 调用真正的eglswapBuffers
2. 记录当前时间信息
3. 统计帧率,汇报给fps meter应用程序
翻译成C++代码,大约如下:
void *eglSwapBuffers_addr_ptr;
unsigned long frames;
unsigned long long current_timer;
unsigned long long timer; EGLBoolean myEglSwapBuffers(EGLDisplay dpy, EGLSurface draw){
struct timespect tp; // eglSwapBuffers_addr 就是前面的load函数,从GOT表中拿到的真正的eglSwapBuffers的地址
// 而原GOT表中的地址,已经被改为本函数的地址啦!
EGLBoolean result = eglSwapBuffers_addr(dpy, draw); // clock id is 0
clock_gettime(CLOCK_REALTIME, &tp); frames++; current_timer = tp.tv_sec*1000000 + tp.tv_nsec/1000; //计算timer的值
... //计算fps的值
... // 这里的fd是打开的/com.aatt.fpsm/pipe的文件句柄
write(fd, &fps, 4);
return result;
}
timer和fps的计算没大看明白具体计算方法,头疼,也就不抠了。最后,surfaceflinger进程通过写pipe,向fps meter进程上报了帧率数据,整个工作机制分析完成。
总结
一旦系统被root后,普通的应用程序几乎可以做它想做的任何事情,如果能再允许remount系统的只读分区,那可能会有灾难性的危险。试想你的手机中存在这些类似fps meter这样的apk,你还能放心吗?不过问题也没那么可怕,若从正规市场如google play中下载的apk,一般问题不大,但如果从未知来源或山寨APP市场中安装的apk,同时你又root了系统,就要当心点了。
android应用程序fps meter[帧数显示]的分析 —— 浅谈root的风险 (3)的更多相关文章
- android应用程序fps meter[帧数显示]的分析 —— 浅谈root的风险 (1)
fps meter是常用的检测帧率的软件,该软件需要root权限才能工作,一直比较好奇它一个apk是如何知道系统当前的帧率情况的,就针对此apk分析了一下其工作原理. Apk组成 首先看一下apk的组 ...
- Android应用程序键盘(Keyboard)消息处理机制分析
在Android系统中,键盘按键事件是由WindowManagerService服务来管理的,然后再以消息的形 式来分发给应用程序处理,不过和普通消息不一样,它是由硬件中断触发的:在上一篇文章< ...
- android studio 程序真机执行中文显示乱码
代码里中文显示正常,真机执行后中文显示乱码,解决的方法: build.gradle中加入一句 android { compileOptions.encoding = "GBK" }
- 【Android测试】【第三节】ADB——源码浅谈
◆版权声明:本文出自carter_dream的博客,转载必须注明出处. 转载请注明出处:http://www.cnblogs.com/by-dream/p/4651724.html 前言 由于本人精力 ...
- app流畅度测试--使用FPS Meter
1.FFPS Meter是一款非常实用的小软件,能够用数字实时显示安卓界面的每秒帧数,非常直观.此外,FPS Meter还可以显示最大帧数.最小帧数以及平均帧数,用来评价安卓流畅度极具价值.由于涉及到 ...
- Android应用程序窗口(Activity)与WindowManagerService服务的连接过程分析
在前两文中,我们分析了Activity组件的窗口对象和视图对象的创建过程.Activity组件在其窗口对象和视图对象创建完成之后,就会请求与WindowManagerService建立一个连接,即请求 ...
- Android应用程序窗口(Activity)的窗口对象(Window)的创建过程分析(转)
在前文中,我们分析了Android应用程序窗口的运行上下文环境的创建过程.由此可知,每一个Activity组件都有一个关联的ContextImpl对象,同时,它还关联有一个Window对象,用来描述一 ...
- Android应用程序窗口(Activity)实现框架简要介绍和学习计划
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8170307 前面我们学习了SurfaceFli ...
- 【转】Android应用程序窗口(Activity)窗口对象(Window)创建指南
在前文中,我们分析了Android应用程序窗口的运行上下文环境的创建过程.由此可知,每一个Activity组件都有一个关联的ContextImpl对象,同时,它还关联有一个Window对象,用来描述一 ...
随机推荐
- 【剑指offer】找出数组中出现一次的两个数
2013-09-08 10:50:46 一个整型数组中,除了两个数字之外,其他数字都出现了2次,找出这两个只出现一次的数字,要求时间复杂度是O(N),空间复杂度是O(1). 小结: 任何数与0异或,结 ...
- Javascript String类的属性及方法
String 类 Attribute and method anchor() 创建一个<a>标签的实例,将其name属性设置为被传递给此方法的字符串 big() ...
- WPF中映射clr namspace
1. xaml中直接映射为prefix xmlns:prefix="clr-namespace:MyApplication.Modules.Entity;assembly=MyAssembl ...
- poj1026Cipher(置换群)
链接 找循环节 然后所有子循环节的最小公倍数就是总的循环节 找结果的时候也按一个个置换来进行转换 不然也TLE #include <iostream> #include<cstdio ...
- Android 之 内存管理-查看内存泄露(三)
概述 在android的开发中,要时刻主要内存的分配和垃圾回收,因为系统为每一个dalvik虚拟机分配的内存是有限的,在google的G1中,分配的最大堆大小只有16M,后来的机器一般都为24M,实在 ...
- Java5 并发学习
在Java5之后,并发线程这块发生了根本的变化,最重要的莫过于新的启动.调度.管理线程的一大堆API了.在Java5以后,通过 Executor来启动线程比用Thread的start()更好.在新特征 ...
- bzoj3205
和bzoj2595类似,也是斯坦纳树 设f[l,r,]表示在点i机器人组合成了l-r最少推的次数,然后可得 f[l,r,i]=min(f[l,m,i]+f[m+1,r,i]) f[l,r,i]=min ...
- uva753 A Plug for UNIX
最大流. 流可以对应一种分配方式. 显然最大流就可以表示最多匹配数 #include<cstdio> #include<algorithm> #include<cstri ...
- poj 2185 (KMP)
完全不会啊…… 附一份题解:http://blog.sina.com.cn/s/blog_69c3f0410100tyjl.html var i,j,k,r,c,x:longint; ch:..,.. ...
- NOI2002 荒岛野人
这题其实黑书上有,只是我脑残的没想起来…… 其实就是拓展欧几里得算法 我参看的题解:http://www.cnblogs.com/Rinyo/archive/2012/11/25/2788373.ht ...