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函数的反汇编:

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

这个函数很长,上图只截了开头一部分。此函数的一大半工作都在往栈上压数据。一开始压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了系统,就要当心点了。