- 浏览: 935814 次
文章分类
最新评论
-
sunnyhappylg:
网上怎么复制了 这个页面内容这么多 没介绍怎么解决啊
服务器系统及软件常见漏洞 -
数据工厂:
我用JS实现的糗事百科的爬虫源码如下,运行步骤请参考我的git ...
[Python]网络爬虫(八):糗事百科的网络爬虫(v0.2)源码及解析 -
yzg0885:
解决了,谢谢你
Could not create the view: An unexpected exception was thrown. 电脑突然断电,myeclipse非正常关闭,出现错误 -
jjlin00:
楼主好,我今年报考南大软院,能分享计算机综合的资料吗,真心谢谢 ...
2013南京大学软件学院考研有感 -
govy.b:
楼主的资料能分享吗?QQ:282577229
2013南京大学软件学院考研有感
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了系统,就要当心点了。
相关推荐
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线程阻塞都将导致应用运行...
工具会显示当前应用的帧率变化,以及其它性能数据。 5. **分析结果**:测试完成后,你可以查看详细报告,包括平均帧率、帧率波动、硬件资源利用率等,这些信息对于优化游戏性能非常有价值。 6. **共享与导出**:...
- 开启定时器,定时调用捕获帧的函数,并更新帧数显示。 - 实现捕获帧的回调函数,计算并更新帧数。 - 记得在适当的时候释放资源,关闭捕获设备。 7. **注意事项**: - 确保正确处理VFW错误,例如设备未连接或...
标题提到的"在屏幕上显示 FPS,CPU 使用率,更好的监控应用性能",这是一个旨在提升用户体验和系统监控能力的工具或技术。这种技术通常用于实时监测应用运行时的系统资源消耗情况,帮助开发者定位性能瓶颈,以实现更...
8. **帧数显示**:显示每秒帧率(FPS)是衡量游戏或应用程序性能的重要指标。这个例子中,开发者添加了帧数显示功能,用户可以看到程序运行时的实时性能表现。 9. **3D漫游**:允许用户在3D环境中自由移动和旋转...
在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...