一、elfheader修復
dump出來的內存如下圖所示,elf header結構有缺失
下面是正常elf頭的對比圖
下面是010editor對正常elf header的解析
由上圖可知,dump出來的elf header除了e_phoff、e_phentsize、e_phum三個值,其它都爲0。
不過這裏缺失的,除了e_shoff, e_shnum, e_shtrndx三個是變量,其它都是固定值。而實際上e_shoff, e_shnum, e_shtrndx這三個值在dlopen時並沒有用到,全部填0,也可以正常使用。
那麼這裏elf header把固定值填上,e_shoff, e_shnum, e_shtrndx三個值留空,elf header就修復好了。
elf header修復完成後的dump就跟一個so經過dlopen後,dump出來的內存是一樣的了。但是這樣的dump是不能直接加載的,很多情況下用IDA分析也會缺失導入函數的解析。
二、so及其dump差異分析
爲了修復這個dump出來的so,我們寫一個so來做個測試。
將測試so加載後,dump出來進行加載前後的對比
後面一大塊數據不一樣。首先有個問題就是內存裏的對齊跟文件是有差異的。
看下elf Loadable Segment。
可以發現第二個Loadable Segment的p_offset和p_vadder是一樣的,相差了0x1000,dump出來的內存在這個位置會比file多0x1000
Dynamic Segment同樣存在這樣的差異。
三、so dump修復
由於dump的數據是跟內存加載後是一致的,把上面兩個Segment裏的p_offset都改成跟p_vaddr一樣的值。
完成這樣的修改後,IDA就可以正常解析導入函數了,因爲IDA對導入函數的解析依賴於Dynamic Segment裏的數據。
如果要能讓dump能正常被dlopen起來,還需要繼續對重定位數據進行修復。
下面是DynamicSegment裏rel對應的數據
可知rel對應的數據開始於0x6aa8,大小爲0xf30
0x6aa8指向的elf32_rel結構體數組
typedef structelf32_rel {
Elf32_Addr r_offset;
Elf32_Word r_info;
} Elf32_Rel;
r_offset指向的地址會被重定位
下圖是原始so的數據:
下圖是dump內經過重定位的數據:
可以發現dump裏的數據被加上了so的加載基址,修復的時候,減去基址就可以恢復原始數據
除了rel還有plt_rel需要修復,修復方法跟rel一樣
由於rel和plt_rel需要修復的數據量比較大,手動修復不太現實,需要編寫個工具來完成這樣的修復。可以把dlopen裏的源碼扣出來做一些修改完成這樣的操作。
下面是兩張IDA分析的截圖:
修復後的so,跟普通so已經沒什麼區別了,導入函數和字符串暴露無遺。居然沒有對字符串做加密,這樣給分析者帶來很大方便,對於加固核心so來說有點太依賴so加固了。
(創建了一個Android逆向分析羣,歡迎有興趣的同學加入,羣號碼:376745720)