1. 程式人生 > >android應用程式fps meter[幀數顯示]的分析 —— SurfaceFlinger被注入統計程式碼 (1)

android應用程式fps meter[幀數顯示]的分析 —— SurfaceFlinger被注入統計程式碼 (1)

fps meter是常用的檢測幀率的軟體,該軟體需要root許可權才能工作,一直比較好奇它一個apk是如何知道系統當前的幀率情況的,就針對此apk分析了一下其工作原理。

Apk組成

首先看一下apk的組成,apk檔案就是一個壓縮包,可以解壓縮軟體如winrar解壓檢視,也可以用[apktools]反編譯apk,以供進一步分析。

 

從執行結果和程式碼組織上的推測

  • java程式碼主要負責上層控制和顯示。
  • bin0和lib0.so是一個真正獲取fps的binary工作程序的程式碼
  • jni層的libnp_read.so,負責和工作程序橋接,通過pipe與工作程序通訊,上報分析的資料給java層顯示。

Apk的靜態分析

Apk的包組成結構如上圖。常規的dex/res/lib目錄下的內容外,還要看一下res/raw和assets目錄下是否有東西,這裡通常是藏汙納垢的場所。fps meter這個apk中,在res/raw/下有bin0和lib0.so 兩個檔案。

使用[dex2jar]反編譯java程式碼,檢視其中的資訊。對於這個apk,可以看到它使用了[RootTools]的jar庫,來實現通過su過的shell執行一些命令或binary程式。從dex檔案的常量字元中可以看到,這個apk中使用的庫是v2.2版本,該版本的原始碼可以在[https://code.google.com/p/roottools/source/checkout

]下載到到,svn版本號是208。

Java程式碼:

接下來我們可以分析java程式碼。java程式碼都已經被加擾過了,不過如果你有足夠的耐心並足夠仔細,還是能從中讀出很多內容。對java程式碼的分析,一般都是從activity/Application或service的onCreate方法入手(對外的介面不可能加擾,這些方法還是存在的),可以對照AndroidManifest.xml找到入口的Activity及Service,再檢視相關資訊

在FPSMActivity的onCreate中,如下兩句:

t.a(this, 2131034112, "0", "744");
t.a(this, 2131034113, "0.so", "744");

這是混淆過的程式碼,不過從引數來分析,這是呼叫RootTools的installBinary()方法,可以直接對照RootTools的原始碼來看。這個方法的作用是將apk的res/raw下的bin0和lib0.so分別安裝到/data/data/com.aatt.fpsm/files/下,分別命名為0和0.so。

FPSMService的onStartCommand方法中,可以看到這個機制就是建立一個pipe:/data/data/com.aatt.fpsm/pipe,不停的從這個pipe中讀取資料,顯示在前端建立的的浮動window中。可以在adb shell中,

busybox dumphex /data/data/com.aatt.fpsm/pipe

驗證幀率的值,剛好是從這個pipe中讀入的。

其他位置未看到特別有用的資訊。

JNI程式碼:

Jni庫libnp_reader的分析,主要是一些Java的native方法的實現,並沒有看到特別異常的現象。

$ arm-linux-androideabi-readelf -s libnp_read.so  
  
Symbol table '.dynsym' contains 69 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: 00000ed5    32 FUNC    GLOBAL DEFAULT    7 Java_com_aatt_fpsm_FPSMSe  
      4: 00000000     0 FUNC    GLOBAL DEFAULT  UND umask  
      5: 00000000     0 FUNC    GLOBAL DEFAULT  UND mknod  
      6: 000017c4     8 FUNC    WEAK   DEFAULT    7 __aeabi_unwind_cpp_pr1  
      7: 00000ef5    16 FUNC    GLOBAL DEFAULT    7 Java_com_aatt_fpsm_FPSMSe  
      8: 00000000     0 FUNC    GLOBAL DEFAULT  UND remove  
      9: 00000f05    40 FUNC    GLOBAL DEFAULT    7 Java_com_aatt_fpsm_FPSMSe  
     10: 00000000     0 FUNC    GLOBAL DEFAULT  UND read  
     11: 00004004     4 OBJECT  GLOBAL DEFAULT   16 fd  
     12: 00004008     4 OBJECT  GLOBAL DEFAULT   16 trash  
     13: 000017cc     8 FUNC    GLOBAL DEFAULT    7 __aeabi_unwind_cpp_pr0  
     14: 00000f2d    36 FUNC    GLOBAL DEFAULT    7 Java_com_aatt_fpsm_FPSMSe  
     15: 00000000     0 FUNC    GLOBAL DEFAULT  UND open  
     16: 00000f51    20 FUNC    GLOBAL DEFAULT    7 Java_com_aatt_fpsm_FPSMSe  
     17: 00000000     0 FUNC    GLOBAL DEFAULT  UND close  
     18: 00000f65    36 FUNC    GLOBAL DEFAULT    7 Java_com_aatt_fpsm_FPSMSe  
     19: 0000400c     4 OBJECT  GLOBAL DEFAULT   16 value  
     20: 00004004     0 NOTYPE  GLOBAL DEFAULT  ABS _edata  
     21: 00004004     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start  
     22: 00004010     0 NOTYPE  GLOBAL DEFAULT  ABS _end  
     23: 00000000     0 FUNC    WEAK   DEFAULT  UND __gnu_Unwind_Find_exidx  
     24: 00000000     0 FUNC    GLOBAL DEFAULT  UND abort  
     25: 00000000     0 FUNC    GLOBAL DEFAULT  UND memcpy  
     26: 000017bc     8 FUNC    WEAK   DEFAULT    7 __aeabi_unwind_cpp_pr2  
     27: 00001d88     0 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_Restore_VFP_  
     28: 00001d78     0 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_Restore_VFP  
     29: 00001d98     0 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_Restore_VFP_  
     30: 00001da8     0 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_Restore_WMMX  
     31: 00001e30     0 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_Restore_WMMX  
     32: 00001d64    20 FUNC    GLOBAL DEFAULT    7 restore_core_regs  
     33: 0000134c    68 FUNC    GLOBAL DEFAULT    7 _Unwind_VRS_Get  
     34: 000013b8    68 FUNC    GLOBAL DEFAULT    7 _Unwind_VRS_Set  
     35: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __cxa_begin_cleanup  
     36: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __cxa_type_match  
     37: 00001f64   916 FUNC    GLOBAL DEFAULT    7 __gnu_unwind_execute  
     38: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __cxa_call_unexpected  
     39: 000017d4   856 FUNC    GLOBAL DEFAULT    7 _Unwind_VRS_Pop  
     40: 00001d90     0 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_Save_VFP_D  
     41: 00001d80     0 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_Save_VFP  
     42: 00001da0     0 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_Save_VFP_D_1  
     43: 00001dec     0 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_Save_WMMXD  
     44: 00001e44     0 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_Save_WMMXC  
     45: 00001b2c     8 FUNC    GLOBAL DEFAULT    7 _Unwind_GetCFA  
     46: 00001b34   164 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_RaiseExcepti  
     47: 00001bd8    28 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_ForcedUnwind  
     48: 00001bf4   108 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_Resume  
     49: 00001c60    32 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_Resume_or_Re  
     50: 00001c80     4 FUNC    GLOBAL DEFAULT    7 _Unwind_Complete  
     51: 00001c84    32 FUNC    GLOBAL DEFAULT    7 _Unwind_DeleteException  
     52: 00001ca4   192 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_Backtrace  
     53: 00001d64    20 FUNC    GLOBAL DEFAULT    7 __restore_core_regs  
     54: 00001e58    36 FUNC    GLOBAL DEFAULT    7 ___Unwind_RaiseException  
     55: 00001e58    36 FUNC    GLOBAL DEFAULT    7 _Unwind_RaiseException  
     56: 00001e7c    36 FUNC    GLOBAL DEFAULT    7 ___Unwind_Resume  
     57: 00001e7c    36 FUNC    GLOBAL DEFAULT    7 _Unwind_Resume  
     58: 00001ea0    36 FUNC    GLOBAL DEFAULT    7 ___Unwind_Resume_or_Rethr  
     59: 00001ea0    36 FUNC    GLOBAL DEFAULT    7 _Unwind_Resume_or_Rethrow  
     60: 00001ec4    36 FUNC    GLOBAL DEFAULT    7 ___Unwind_ForcedUnwind  
     61: 00001ec4    36 FUNC    GLOBAL DEFAULT    7 _Unwind_ForcedUnwind  
     62: 00001ee8    36 FUNC    GLOBAL DEFAULT    7 ___Unwind_Backtrace  
     63: 00001ee8    36 FUNC    GLOBAL DEFAULT    7 _Unwind_Backtrace  
     64: 000022f8    64 FUNC    GLOBAL DEFAULT    7 __gnu_unwind_frame  
     65: 00002338    44 FUNC    GLOBAL DEFAULT    7 _Unwind_GetRegionStart  
     66: 00002364    56 FUNC    GLOBAL DEFAULT    7 _Unwind_GetLanguageSpecif  
     67: 0000239c     8 FUNC    GLOBAL DEFAULT    7 _Unwind_GetDataRelBase  
     68: 000023a4     8 FUNC    GLOBAL DEFAULT    7 _Unwind_GetTextRelBase 

從elf資訊可以見到,這個庫主要是JNI的實現及將unwind實現包含在庫中,unwind庫一般是用作異常處理的,用它可以獲取函式的呼叫棧資訊。

這裡由於使用pipe,則懷疑這裡需要跨程序通訊;而此pipe的通訊使用是apk私有的pipe,則推論此apk通過rootTool中提供的Shell類來執行su後的shell,su的作用是通過linux開的後門,允許使用者程式通過setuid系統呼叫,更改使用者id,達到root效果。su root後,執行一個native程式,native程式應該就是res/raw/下的bin0。初步懷疑pipe的寫端是這個bin0,bin0的symbol資訊:
 

$ readelf.exe -s bin0

Symbol table '.dynsym' contains 32 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00000000     0 FUNC    GLOBAL DEFAULT  UND __libc_init
     2: 00000000     0 FUNC    GLOBAL DEFAULT  UND __cxa_atexit
     3: 00000000     0 FUNC    GLOBAL DEFAULT  UND snprintf
     4: 00000000     0 FUNC    GLOBAL DEFAULT  UND fopen
     5: 00000000     0 FUNC    GLOBAL DEFAULT  UND fgets
     6: 00000000     0 FUNC    GLOBAL DEFAULT  UND strstr
     7: 00000000     0 FUNC    GLOBAL DEFAULT  UND strtok
     8: 00000000     0 FUNC    GLOBAL DEFAULT  UND strtoul
     9: 00000000     0 FUNC    GLOBAL DEFAULT  UND fclose
    10: 00000000     0 FUNC    GLOBAL DEFAULT  UND __stack_chk_fail
    11: 00000000     0 OBJECT  GLOBAL DEFAULT  UND __stack_chk_guard
    12: 00000000     0 FUNC    GLOBAL DEFAULT  UND memcpy
    13: 00000000     0 FUNC    GLOBAL DEFAULT  UND ptrace
    14: 00000000     0 FUNC    GLOBAL DEFAULT  UND waitpid
    15: 00000000     0 FUNC    GLOBAL DEFAULT  UND opendir
    16: 00000000     0 FUNC    GLOBAL DEFAULT  UND readdir
    17: 00000000     0 FUNC    GLOBAL DEFAULT  UND atoi
    18: 00000000     0 FUNC    GLOBAL DEFAULT  UND sprintf
    19: 00000000     0 FUNC    GLOBAL DEFAULT  UND strcmp
    20: 00000000     0 FUNC    GLOBAL DEFAULT  UND closedir
    21: 00000000     0 FUNC    GLOBAL DEFAULT  UND dlsym
    22: 00000000     0 FUNC    GLOBAL DEFAULT  UND strlen
    23: 0000c000     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
    24: 0000c000     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
    25: 0000c004     0 NOTYPE  GLOBAL DEFAULT  ABS _end
    26: 00000000     0 FUNC    WEAK   DEFAULT  UND __gnu_Unwind_Find_exidx
    27: 00000000     0 FUNC    GLOBAL DEFAULT  UND abort
    28: 00000000     0 FUNC    GLOBAL DEFAULT  UND raise
    29: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __cxa_begin_cleanup
    30: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __cxa_type_match
    31: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __cxa_call_unexpected

我們通過ps來看一下執行時的程序情況,並沒有看到此bin0程序,看樣子不像是常駐記憶體的,那麼它太不可能是pipe的write端。

從elf的symbol來看,此bin檔案應該會使用dlsym和ptrace。使用ptrace的話,基本可以確定,這個bin檔案會通過PTRACE_ATTACH到別的程序中,然後修改別的程序資料或程式碼,以達到自己的目的。ptrace的執行過程應該就是分析的關鍵,接下來需要從ptrace入手。

小結

這個fps meter沒有按照android應用程式的開發規範,通過使用SDK和NDK開發java和jni程式碼實現,而是使用第三方庫,通過su獲取root許可權,執行自己的可執行binary程式,apk自己實現的庫或binary程式,以android資源的形式打包在apk中。這種執行方式,對使用者安全及系統穩定來說,是一個危險的動作。

本小結簡單瞭解了此apk的內容,下節將詳細介紹下apk資源包中bin檔案通過ptrace感染android系統程序的過程。

相關推薦

android應用程式fps meter[顯示]的分析 —— SurfaceFlinger注入統計程式碼 (1)

fps meter是常用的檢測幀率的軟體,該軟體需要root許可權才能工作,一直比較好奇它一個apk是如何知道系統當前的幀率情況的,就針對此apk分析了一下其工作原理。 Apk組成 首先看一下apk的組成,apk檔案就是一個壓縮包,可以解壓縮軟體如winrar解壓檢視,也可

android應用程式第一次啟動時顯示引導介面

市面上好多優秀的應用(舉例新浪微博、UC瀏覽器)都採用了歡迎頁面與使用嚮導的方式給使用者帶來了良好的使用者體驗。 一般來說使用者第一次安裝應用或者安裝了新版本後第一次進入應用都會顯示成 歡迎頁面-使用嚮導-主介面 的方式 使用者沒有安裝新版本或者不是第一次進入的時候都

瀏覽器判別下載安裝/開啟Android應用程式

摘要: 通過手機瀏覽器直接開啟Android應用程式。 如果本地已經安裝了指定Android應用,就直接開啟它; 如果沒有安裝,則直接下載該應用的安裝檔案(也可以跳轉到下載頁面)。 之前寫過一篇blog,介紹如何通過點選手機瀏覽器中的連結,直接開啟本地Android App。 實現方式

Android應用程式框架講解

在我們的android的程式中會有很多的檔案,那麼這些檔案到底是有什麼作用呢? 我們編譯android專案,可以使用eclipse和AS,首先介紹一下eclipse中的框架 1、src檔案:存放的是應用程式使用到的java檔案 2、gen檔案:系統自動生成的目錄。不需要程式設計師進行

android應用程式的介面程式設計

要點 android的介面與view元件 view元件和viewgroup元件 android控制程式的三種方式 通過繼承view開發自定義view android常見的佈局管理器 文字框元件:textview和edittext 按鈕元件:button 特殊按鈕元件:radiobut

Android應用程式進行系統簽名

有時寫一個程式需要呼叫系統的庫,如果許可權不夠,是用不了庫裡面一些方法的 。這時就需要將apk進行系統簽名。  簡單常用的方法:                 1,在apk的AndroidMani

Android應用程式簽名打包(AS)

使用Android studio對Android應用簽名步驟: 第一步: 第二步: 第三步: 第四步: 數字證書建立完成後,點選OK----->點選Next------>Finish。 注意:生成後的數字證書千萬不能丟失,還有密碼也不能忘記了

怎麼獲取Android應用程式的上下文

前面我做了一個類似於騰訊QQ一樣的聊天應用,在這個應用裡面,有很多activity,而這些activity之間經常要進行互相啟動、往復跳轉、還有就是通過Notification啟動。當activity多了之後,如果設定他的模式為單例模式,或者不設定模式。在反覆啟動後會出現數據不同步、fc等各種未知的

Android 應用程式崩潰日誌捕捉

程式崩潰是應用迭代中不可避免的問題,即使有著5年或者10年經驗的程式猿也無法完全保證自己的程式碼沒有任何的bug導致崩潰,現在有一些第三方平臺可以幫助我們蒐集應用程式的崩潰,比如友盟,詳情如下圖 雖然能夠看到崩潰的日誌以及機型等,但還是不是很方便,如果需要精確定位的話需要使用者提供崩潰的時間點、機型

轉老羅 Android應用程式資源的查詢過程分析

原文地址  http://blog.csdn.net/luoshengyang/article/details/8806798   轉載請說明     我們知道,在Android系統中,每一個應用程式一般都會配置很多資源,用來適配不同密

轉自老羅 Android應用程式資源的編譯和打包過程分析

原文地址   http://blog.csdn.net/luoshengyang/article/details/8744683 轉載自老羅,轉載請說明   我們知道,在一個APK檔案中,除了有程式碼檔案之外,還有很多資原始檔。這些資原始檔是通過An

轉自 老羅 Android應用程式資源管理器(Asset Manager)的建立過程分析

原文地址在 http://blog.csdn.net/luoshengyang/article/details/8791064 原創老羅,轉載請說明     在前面一篇文章中,我們分析了Android應用程式資源的編譯和打包過程,最終得到的應用程式資源就與

模組化惡意Android應用程式偽裝成語音工具,通過調查收集PII資料

“這些惡意應用程式和惡意軟體的觀察變體自10月份開始逐一部署,其演變包括規避技術及其感染行為分為幾個階段,”趨勢科技在他們的分析中表示。 在嘗試通過虛假調查收集使用者的個人身份資訊(PII)並提供禮品卡作為獎勵以填寫它們時,已經觀察到被稱為AndroidOS_FraudBot.OPS的惡意軟體。此外,惡意應

ubuntu中ffmpeg修改視訊FPS

1. 降低FPS,增加視訊時長 說對於輸入檔案是40幀的媒體,我們可以通過 ffmpeg -r 80 -i input output ffmpeg -r 20-i input output 使其輸出檔案的時長分別為原來的一半和兩倍,即播放速度為原來的兩倍和一半。

android應用程式的混淆打包(轉)

target=android-8 proguard.config=proguard.cfg Eclipse會通過此配置在工程目錄生成proguard.cfg檔案  2 . 生成keystore (如已有可直接利用) 按照下面的命令列 在D:\Program 

android應用程式安裝後點擊開啟帶來的問題

前幾天專案組反饋回來一個這樣的情況就是我在安裝應用之後點選了開啟 然後按home鍵 這個時候應用程式進入後臺 我點選手機桌面的時候圖片啟動應用程式 程式重新再次啟動 而不是後臺的程式返回到前臺;  /

Android應用程式啟動詳解(二)從原始碼瞭解App的啟動過程

本文承接《Android應用程式啟動詳解(一)》繼續來學習應用程式的啟動的那些事。上文提到startActivity()方法啟動一個app後經過一翻過程就到了app的入口方法ActivityThread.main()。其實我們在之前的文章中《Android的訊息機制(二)之L

Android 應用程式開發環境搭建說明

之前開發一直用的Eclipse,今年接了個Android 車載POS機專案,系統使android 7.1 的,然後準備更新sdk發現已經停止更新了,儘管之前SDK的更新也很辛苦,國內google被牆了,只能利用國內的某些映象網站實現Android SDK線上更新。然後查閱論壇,才發現我已經落伍了,

(轉載)Android應用程式簽名系統的簽名(SignApk.jar)

1. 在安卓工具箱中,下載SignApk.jar。 2. 拿到終端上系統的簽名(由定製系統的廠商提供): 3. 在應用程式的專案中配置: androidManifest.xml中新增android:sharedUserId="android.uid.system"

Android應用程式內部啟動Activity過程 startActivity 的原始碼分析

                        上文介紹了Android應用程式的啟動過程,即應用程式預設Activity的啟動過程,一般來說,這種預設Activity是在新的程序和任務中啟動的;本文將繼續分析在應用程式內部啟動非預設Activity的過程的原始碼,這種非預設Activity一般是在原來的程序