淺談被加殼ELF的除錯

wyzsk發表於2020-08-19
作者: 騰訊電腦管家 · 2015/05/20 16:33

0x00 ELF格式簡介:


注:本文只討論如何除錯被加殼的ELF檔案,包括除錯中的技巧運用及除錯過程中可能遇到的問題的解決方法,不包含如何還原加固的DEX

本文將以某加殼程式和某加固為目標

ELF全稱:Executable and Linkable Format,是Linux下的一種可執行檔案格式。 此種檔案格式和WINDOWS一樣,常見分為兩種型別:

  1. 可執行檔案(Executable File),對應PE子型別:EXE

  2. 共享目標檔案(Shared Object File),字尾名:.so,對應PE子型別:DLL

0x01 ELF檔案載入大概流程:


  1. 透過Section Header或者Program Header載入需要的映象資料 和WINDOWS PE載入機制不同,ELF有些檔案資料是不會載入到記憶體映象中
  2. 載入SO NEED LIB和SYM 類似PE的Import_table
  3. 執行重定位(如果有) 類似PE的Reloc_table
  4. 執行INIT_ARRAY段或者INIT段(如果有,陣列中的地址不等於0xffffffff,0表示結束)

    類似PE的TLS,已知的被加殼的ELF,殼程式碼都出現在這兩個段裡 PE中的TLS也常常出現在殼中,例如Vmprotect, Execryptor等

  5. 執行入口點程式碼(如果有)

所有的上述載入流程程式碼全部包含在linker.so裡,可參看安卓原始碼或逆向linker.so

0x03 ARM CPU簡介:
1.指令集簡介:


ARMCPU採用RISC(精簡指令集)架構(X86是CISC,複雜指令集),指令等長,相對CISC架構更加省電,執行效率更高

2. ARM指令集三種型別:

ARM(4位元組等長),THUMB(2位元組等長),THUMB2(4位元組等長)。這三種指令集可以在同一執行程式中切換,切換原則為:

ARM <-->THUMB,THUMB<-->ARM(PC的最高位確定指令集型別:1為THUMB;0為ARM)

THUMB<-->THUMB2(由27-31位決定)

thumb2其實就是thumb的擴充套件,其目的是為了一條4位元組指令完成多條2位元組指令

*|3.暫存器: *|

通用暫存器:r0-r15

特殊暫存器:r13 = SP(棧地址), r14 = LR(函式返回地址), r15 = PC(當前指令流地址)

還包括CPSR,APSR,浮點等暫存器,具體可參照ARM指令集手冊

0x04 加殼SO的除錯


1.ELF程式碼執行順序

上面介紹了,加殼的SO的殼程式碼都在INIT_ARRAY段和INIT段

那我們先看下一個被加殼以後的SO,在linux下面用readelf -a命令檢視ELF資訊

enter image description here

enter image description here

在ELF-HEADER裡我們看到有Entry,地址為0x22a8

在動態段裡看到了INIT_ARRAY陣列,陣列地址為0x21000,大小是12 BYTES

用IDA看看陣列的內容

enter image description here

上面說了,-1為無效,0代表結束,那INIT有效地址僅是0x2418這個地址

也就是說,這個SO載入起來以後,會先從0x2418這個地址開始執行,執行完成後再去執行Entry

我們再來看下某加固的ELF資訊

enter image description here

enter image description here

在ELF-HEADER裡我們看到有Entry,地址為0x3860

enter image description here

DA開啟某加固的檔案時,會提示錯誤,不能開啟,後面在Anti Anti Debugger中會講到為什麼

在動態段裡看到了INIT_ARRAY陣列,陣列地址為0x28CA4,大小是8 BYTES

我們還看到了INIT段,地址是0x11401

我們在這裡,總結下執行的順序:

根據linker的程式碼,當INIT段和INIT_ARRAY段都存在的情況下,先執行INIT段,再執行INIT_ARRAY段,否則單獨執行對應指向的函式,最後執行ENTRY

enter image description here

2. 自己準備SO_LOADER

除錯SO和PE_DLL其實道理是一樣的,都需要一個宿主程式,這裡要寫一個SO_LOADER,參看程式碼如下,可透過NDK編譯。(程式碼是王晨同學早期提供的)

enter image description here

3.環境準備:

我這裡選用IDA6.6做為偵錯程式。

第一步:複製偵錯程式到安卓手機上

enter image description here

命令:adb push android_server /data/local/tmp/and

這裡為什麼把android_server 改名成and呢~~~,其實就是為了避免被檢測出偵錯程式,後面我在Anti Anti Debugger中會詳細說一下關於這部分的內容

第二步:啟動偵錯程式

adb shell回車,進入/data/local/tmp/目錄,啟動偵錯程式,啟動後畫面

enter image description here

第三步:重定向除錯埠

adb forward tcp:23946 tcp:23946

至此手機端設定完畢,下面來看看IDA裡如何設定

IDA載入我們自己寫的so_loader,在854C處,按F2下斷點

enter image description here

選擇選單欄裡面的Debuger-Select Debugger,選擇Remote Arm linux/Andoid debugger

enter image description here

點選OK,然後F9執行

enter image description here

在配置裡面,Hostname裡面填入127.0.0.1,點選OK

如果你的手機裡面沒有這個檔案,會提示你COPY,點選確定即可,如果有這個檔案,會出現下面的選擇,一般選擇USE FOUND就可以了,如果你要除錯的程式有修改,選擇COPY NEW覆蓋一個新的進去

enter image description here

然後一路OK,就出現除錯狀態了~~,當前PC就是剛才我們F2設定的斷點

enter image description here

4.如何斷住SO的INIT_ARRAY段和INIT段

上面說了,SO的載入在linker.so裡完成,我們要做的,就是把斷點設定在linker.so裡面

先找程式碼,IDA開啟linker.so,在string視窗裡找

call_constructors_recursive,雙擊並檢視引用

enter image description here

enter image description here

雙擊第二個引用處,然後往上找blx r3(init段的呼叫),b.w xxxxxxxx(init_array段的呼叫)

enter image description here

enter image description here

好了,現在我們找到了地址0x54d0, 0x3af0這兩個地方,回到剛才除錯的IDA裡面,

選擇選單欄debugger-Debugger windows-module list開啟程式模組列表

enter image description here

linker.so的base是40002000,分別對應的兩個地址就是

0x40002000+0x54d0 = 0x400074d0
0x40002000+0x3af0 = 0x40005af0

我們在IDA View-PC視窗GO 過去

enter image description here

在0x74d0處,按C鍵,變成程式碼.奇怪,為什麼沒有反應!!而且在最下面的output window有如下提示

enter image description here

這裡就是我說的很重要的問題了,上面我提到了,被除錯的程式可以在3種指令集之間切換,這時的IDA並不知道當前要變成程式碼的地址是ARM還是THUMB,這時我們需要對照靜態的來看,或者你對指令集絕對的熟悉,看到BYTE CODE就知道是哪種指令集

enter image description here

靜態中,顯然IDA給的是2位元組指令,那必然是THUMB,我們需要把當前地址改成THUMB

方法:按鍵盤的ALT+G,呼喚出視窗

enter image description here

T,DS不用管,我們只需要把VALUE改成1就是THUMB指令集了,變成1點選OK以後

在原來的地址上出現了CODE16,這時我們再去C一次

enter image description here

C完以後,就出現程式碼了!!!ARM和THUMB就是這麼切換的,切記,切記

enter image description here

再看另外一個地址,0x400a5af0,按照同樣的方法再來一次

enter image description here

問題又來了,奇怪了,為什麼下面不是指令?!這個是IDA的BUG,6.6版本對THUMB2指令在除錯狀態的解析就是有問題。。。。,不過沒關係,我們往下看

enter image description here

這段程式碼才是最重要的,執行每一個init_array中地址的函式,就在blx r2這句。 至此,如何斷住INIT段和INIT_ARRAY段,就講完了,剩下的大家就自己除錯吧

0x05 Anti Anti Debugger


1.Anti IDA

其實這種問題,是IDA解析ELF和linker解析ELF不一致造成的,IDA更加嚴格

用ida開啟某加固的so,提示

enter image description here

這個提示就是說,有個資料描述是無效的,我們來看看,是哪個。

SHT說的就是Section Table,來看看ELF頭部資料如下

enter image description here

shoff就是這個值,我們用16進位制編輯器過去看看

enter image description here

全是0,顯然這裡有問題,我們首先要把這個值清0,儲存檔案。

再次載入,還有問題,提示如下:

enter image description here

這次透過除錯IDA的ELF外掛,發現當PROGRAM HEADER中的物理偏移大於檔案大小時,就會出現該錯誤。

enter image description here

顯然,Program Header中的第一組資料,p_offset超過了檔案大小,根據ELF結構,定位到該資料偏移,改成0,IDA載入成功

2.Anti Debugger

透過除錯該加殼程式,總結他用到的方法:

方法1:檢測父程式的檔名

呼叫getppid,獲取父程式的id, open("/proc/ppid/cmdline")獲取父程式名稱,檢測常用偵錯程式的名字,這就是上面我COPY檔案時,為啥要把android_server變成隨意一個檔名的原因了

對策:修改getppid的返回值,隨便給一個可以用的就行了

其實還有其他方法可以獲取ppid,比如open("/proc/pid/status"),read這個handle的內容,在裡面尋找ppid也行

方法2:異常陷阱

和WINDOWS的方法類似,設定一個trap,檢測偵錯程式

對策:IDA預設所有的trap都交給偵錯程式處理,所以我們需要修改對應的設定。選單選擇debugger-debugger options,點選edit exceptions按鈕

enter image description here

在trap上,右鍵編輯改成如下即可

enter image description here

當然,檢測偵錯程式,還有很多方法,見招拆招就可以,這裡就不詳述了

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章