上节已经详细说了下注入过程,最后寄生进程在宿主进程中下了个蛋,这下完的蛋有什么作用呢?接下来再具体分析一下。

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,整理出这些字符串,也不想费劲的抠汇编了,这个函数接下来的代码不用分析也能猜出来了:

  1. 创建/data/data/com.aatt.fpsm/pipe ,surfaceFlinger向这个pipe中写入帧率,fps meter读出数据并显示在屏幕上。
  2. 搜索hwcomposer HAL的实现代码,这个HAL通常位于/system/lib/hw或/system/vendor/lib/hw下
  3. 搜索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了系统,就要当心点了。

最新文章

  1. JAVA 设计模式 代理模式
  2. POJ 3714 Raid
  3. CLion注册码算法逆向分析实录
  4. git的使用(3) 多分支情况下的pull
  5. javaSE第十六天
  6. FMS (端口问题)如何穿透防火墙
  7. Codevs 1690 开关灯 USACO
  8. android开发工具类总结(一)
  9. Unity该插件NGUI学习(1)—— 环境结构
  10. uva10718 - Bit Mask(贪心)
  11. sequence diagram
  12. Android Fragment 真正的完全解析(下)---转
  13. 去除 MyEclipse updating index
  14. shiro笔记-AuthenticatingRealm和AuthorizingRealm关系
  15. python zlib ,zlib 压缩流
  16. 【原创】jssh linux scp ssh 免密登录开源工具
  17. esp8266尝鲜
  18. 07_组件三大属性(1)_state
  19. OD之破解密钥文件授权(三)
  20. maven配置文件中modules的作用

热门文章

  1. Creating a web server in pure C(c/c++ 写web server)
  2. 敏捷开发系列之旅 第二站(走近XP极限编程)
  3. Dreamweaver CS6破解教程[序列号+破解补丁]
  4. 关于rewriteRule的一个小问题
  5. linux bash脚本把A和B文件中有相同ID的B文件的内容输出到文件C
  6. centos 如何用 rsyslog 搭建本地日志服务
  7. UVa 11572 (滑动窗口) Unique Snowflakes
  8. ORACLE参数文件
  9. Mysql主从复制的实现
  10. 使用 document.onreadystatechange()来判断页面加载完