天天看點

android逆向筆記,Android逆向分析筆記(1)

android逆向筆記,Android逆向分析筆記(1)

8種機械鍵盤軸體對比

本人程式員,要買一個寫代碼的鍵盤,請問紅軸和茶軸怎麼選?

最近在讀《Android軟體安全與逆向分析》,雖然不從事逆向研究的工作,但作為一名Android開發者,覺得了解一下相關知識還是有必要的。是以,這裡記錄下該書所闡述的主要知識點,友善記憶和了解。

Dalvik虛拟機與Java虛拟機

差別:Java: 代碼-編譯-java位元組碼-class檔案,虛拟機解碼class檔案

Dalvik:java位元組碼-Dalvik位元組碼-Dex,虛拟機解釋Dex檔案

Dalvik檔案體積更小dx工具将java位元組碼-Dalvik位元組碼

dx工具對java檔案重新排序,消除類檔案中的備援資訊

例如:多個類檔案互相引用,被引用的類檔案中的方法簽名會複制到引用類檔案中;

常量字元串在多個類中也會被重複引用

dx工具分解常量池,所有檔案共享一個常量池

class檔案結構:

android逆向筆記,Android逆向分析筆記(1)
android逆向筆記,Android逆向分析筆記(1)

Java: 基于棧架構,需要頻繁讀寫資料

Dalvik:寄存器架構,資料通路通過寄存器直接傳遞(lua的VM也是寄存器實作)無論是棧虛拟機,還是寄存器虛拟機,都要:将源碼編譯為VM指定的位元組碼

包含操作數,指令(處理操作數運算),操作數資料結構

一個為所有函數操作的調用棧

指向下一條将要執行的指令位置的指令指針(PC計數器)——類似ARM架構cpu的PC寄存器與x86架構cpu的IP寄存器

操控指令的虛拟CPU根據PC計數器擷取下一條指令

解析指令的具體含義(+/-

public int getMemoryClass() {

return staticGetMemoryClass();

}

static public int staticGetMemoryClass() {

// Really brain dead right now -- just take this from the configured

// vm heap size, and assume it is in megabytes and thus ends with "m".

String vmHeapSize = SystemProperties.get("dalvik.vm.heapsize", "16m");

return Integer.parseInt(vmHeapSize.substring(0, vmHeapSize.length()-1));

}Bitmap Memory:3.1之前,在Native Heap配置設定,但是同樣算入Java Object Heap中,是以Bitmap+Java Object<=Xmx

3.1之後,直接放入Java Object Heap,接受Gc管理

Native Heap:malloc()配置設定。不收Gc限制。

Android内部代碼使用了大量智能指針避免記憶體洩漏

GC2.3之前:Stop-the-world,垃圾收集線程在執行時,其它線程都停止

Full heap collection,一次收集完全部的垃圾

程式中止通常大于100ms

2.3之後:Cocurrent,垃圾收集線程與其它線程是并發執行的

Partial collection,一次可能隻收集一部分垃圾

程式中止通常都小于5ms

Gc日志:D/dalvikvm(9050): GC_CONCURRENT freed 2049K, 65% free 3571K/9991K, external 4703K/5261K, paused 2ms+2msGC_CONCURRENT:GC原因

2049K:總共回收的記憶體

3571K/9991K:在9991K的Java Object Heap中,3571K正在使用的

4703K/5261K:在5261K的External Memory中,4703K正在使用的

2ms+2ms:垃圾收集造成的程式中止時間

JIT運作時編譯,可以有效優化代碼,但是占用運作時。

2-8原則:80%時間重複運作20%代碼,是以隻JIT這20%代碼

假設某種情況,并作出代碼優化–這種假設成立,保持現狀–假設不成立,調整政策–隻要假設不成立的情況很少發生或不發生,就會獲得巨大收益–Gambing

例子:Java的同步,Lock和Unlock操作是非常耗時的,多線程環境下需要這種操作

但有些程式(同步塊、同步函數),很可能始終保持着單線程執行狀态

JIT采取一種Lazy Unlocking機制:線程T1執行同步代碼塊C,先按照正常流程擷取輕量級鎖L1,線程T1的ID會記錄在L1上

當T1離開C時,并不釋放L1

當T1再次進入C,發現L1所有者就是自己,直接執行C

此時另一個線程T2需要執行C,發現L1已經被T1占有

JIT檢查T1調用堆棧,檢視T1是否還在執行C

是,将輕量級鎖L1轉換為重量級鎖L2,将L2狀态設定為鎖定,再讓T2在L2上睡眠

T1執行完C後,按正常流程釋放L2,進而喚醒T2,執行C

否,直接将L1所有者标記為T2,T2執行C

靜态語言無法這麼做。”從這個角度來看,我們就可以說,靜态編譯語言(如C++)并不一定比在虛拟機上執行的語言(如Java)快,這是因為後者可以有一種強大的武器叫做JIT”——羅升陽

NDK

程序和線程管理

Android程式的安裝流程系統程式:開機時安裝,沒有安裝界面。開機時啟動PackageManagerService服務,掃描/system/app重新安裝所有程式Zygote程序–SystemServer元件–PackageManagerService:

android逆向筆記,Android逆向分析筆記(1)

圖檔來源:Android應用程式安裝過程源代碼分析

Android市場安裝:網絡安裝,沒有安裝界面。

Adb:沒有安裝界面

SD卡:apk檔案安裝,有安裝界面。調用Android系統軟體包packageinstall.apk安裝。當點選apk,進入安裝頁面時,實際上就是啟動了packageinstall.apk的PackageInstallerActivity,通過初始化PagcageManager和PackageParser.Packager對象,通過PackageUtil.getPackageInfo()解析程式包資訊,主要解析Menifest.xml中的标簽資訊。失敗,傳回;成功,setContentView顯示安裝界面。

點選安裝按鈕–startActivity–InstallAppProgress.class–PackageManager.installPackage()。這個方法最終通過PackageManagerService.java實作。總之,通過installPackage(),進行了程式安裝權限驗證,随後進行安裝或替換。

安裝過程中會通過scanPackageLI()完成apk依賴庫檢測、簽名驗證、sharedUser的簽名檢查、更新Native庫目錄檔案、元件名稱檢查等,這些都完成後,通過mInstaller.install()安裝程式

install()構造字元串“install name uid gid”–transaction()–通過socket發送install指令–/system/bin/installd(常駐記憶體)–install指令函數installd.c do_install() install()–建立包路徑/建立庫路徑/建立包目錄/設定包目錄權限/建立庫目錄/設定庫目錄權限/設定庫目錄所有者/設定包目錄所有者–socket回傳結果–成功/失敗