IDA調試android so的.init_array數組




參考: http://www.itdadao.com/articles/c15a190757p0.html


一. 為什么要調試init_array

init_array的用途

1. 一些全局變量的初始化 (我這里試過, 一些全局變量的初始化,會統一用一個init_array表項來完成初始化)

2. 通過__attribute__ ((constructor)) 聲明的函數 (可以定義n個)

通過so加載流程來看,init_array是我們程序代碼可以控制的最早的時機了, 其次才加載Jni_onload

所以有些樣本會在init_array做一些反調試和相關環境檢測的活, 所以我們需要在init_array中和對方兵戎相見


當然網上已有很多教我們如何在init_array下斷的函數, 但是卻都只教了方法, 沒有細說原理, 最后我們可能只學會了幾個快捷鍵, 空有招式卻無內功, 知其然卻不知其所以然, 下面我們就姿勢和知識這2方面來進行討論


二. 斷init_array的姿勢

1. 定位調試進程中linker的dlopen函數地址

把調試機器中的linker拷貝出來, 路徑為/system/bin/linker, 然后開一個IDA分析

在Shift+F12在字符串窗口中查找"dlopen", 跟蹤引用到一個函數, 如下圖

 得到其文件偏移為0xF30


附加上調試器后, 我們得到linker加載到內存的起始地址為400BD000 

 所以我們在代碼窗口Go過去看看400BD000 + F30 = 400BDF30


發現全部是DCB形式的代碼(代碼沒有解析出來), 這個時候我們需要對linker進行分析, 操作如下: 右鍵->Analyze Module


go過去我們發現和靜態分析中的一樣,  在函數頭部下一個斷點

  


2. 定位到calling相關代碼

同樣在拷貝出來的ida搜索字符串calling


同樣定位到代碼,得到文件偏移 2720


那么我們內存中的地址就是 400BD000 + 2720 = 400BF720

同樣在調試的ida中下好斷點, 第2個斷點就是調用.init_array數組的代碼

  


然后按F9,注意觀察寄存器窗口, 當有顯示調試的是你想要斷的so的時候開始注意

當斷點斷在BLX R4的時候,下一步就是調用init_array數組了, 所以F7跟進去

 


在直接把我們想要分析的so拖到ida分析進行驗證, 代碼一樣, 說明我們成功的斷點在了init_array數組

 


二. 斷init_array的知識

通過上面的操作我們學會了招式, 內功心法卻不見修習, 下面我們通過Android的系統源碼來一探究竟


環境介紹

源碼環境: Android 6.0.1

沒有下載源碼的同學可以去androidxref在線看源碼也很方面

http://androidxref.com/


1. 回到源頭看問題

我們都知道我們要在apk中要加載一個so我們可以通過

System.loadLibrary("libname");  

System.load("lib_path");                  

這2者區別如下:

(1). System.load參數必須為庫文件的絕對路徑,可以是任意路徑;

(2). System.loadLibrary參數為庫文件名,不包含庫文件的擴展名,必須是在JVM屬性Java.library.path所指向的路徑中,路徑可以通過System.getProperty('java.library.path')


2. java層到native層的過程

我們把android_source\libcore\luni部分的源碼作為單獨的部分丟進Source Insight進行分析

定位到android_source\libcore\luni\src\main\java\java\lang\System.java, 搜索loadLibrary, 就可以開始分析了


java層代碼主要是一些路徑, 和標記值的初始化

最后比較關鍵的函數是JavaVMExt.LoadNativeLibrary, 該函數主要完成如下事情

1. 調用linker的dlopen完成加載

2. 調用dlsym獲取目標so的JniOnload地址並調用

3. 初始化SharedLibrary對象並添加到表中, 下次加載相同的so則不在重復加載


linker之前的函數調用流程圖如下:


3. linker的dlopen簡易分析

android系統通過調用linker的dlopen來完成so的轉載


把aosp\bionic目錄添加到source insight中進行分析

配合AndroidXref站點我們找到, dlopen定義在dlfcn.cpp中


dlopen函數定義如下, 只是簡單的調用了dlopen_ext

 
跟進 dlopen_ext 函數, 該函數返回一個soinfo的結構體指針
而且這個指針最后作為函數返回值返回了


do_dlopen簡單的判斷了一下參數, 然后調用find_library進行轉載鏈接so文件

加載成功后,返回soinfo對象指針,同時調用soinfo的成員函數call_constructors來調用so中的init_array


call_constructors先完成其他模塊的加載,然后調用call_array()來調用init_array數組的調用

 
call_array循環調用call_funtion來進行加載

最后call_function只是簡單的調用傳進來的函數指針, 可以看到我們上面的下斷點的字符串就來自於下面 
 

由於篇幅問題,大致介紹下linker的調用流程, 函數調用流程如下:

1. 在do_dlopen中通過find_library進行加載so

    在加載完so后通過call_constructors完成init_array的加載

2. find_library最后調用load_libray完成so的轉載

3. 最后通過load_library的elf_reader.load完成so的裝載


四.總結

由於android是開源的操作系統, android中的很多問題我們都可以通過分析源碼來了解細節, 解決問題, 並知其所以然

同時我們還可以通過編譯源碼來定制我們想要的功能, 達到我們想要的目的













免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM