iOS安全攻防(十九)重組mach-o格式實現簡單反ida
之前3篇大致講了下mach-o的相關知識,這篇主要講解如何通過對mach-o檔案簡單的更改達到反ida靜態分析的目的,此篇目的是拋磚引玉,掌握mach-o格式可以按自己的思路去更改,做到防反彙編器。
mach-o檔案格式的節:
1.struct section { /* for 32-bit architectures */
2. char sectname[16]; /* name of this section */
3. char segname[16]; /* segment this section goes in */
4. uint32_t addr;
5. uint32_t size; /* size in bytes of this section */
6. uint32_t offset; /* file offset of this section */
7. uint32_t align; /* section alignment (power of 2) */
8. uint32_t reloff; /* file offset of relocation entries */
9. uint32_t nreloc;
10. uint32_t flags; /* flags (section type and attributes)*/
11. uint32_t reserved1; /* reserved (for offset or index) */
12. uint32_t reserved2; /* reserved (for count or sizeof) */
13.};
節屬性的主要作用是告訴載入器,本節要載入到記憶體的虛擬地址(addr),大小(size),及節在檔案實體地址的偏移(offset)。
實際上mach-o檔案格式詳細的指導了載入器如何載入檔案到記憶體,但是ios並沒有完全按照格式來載入,對可執行檔案合法性的驗證只是做到了segment一層,對於節section一層並沒有驗證,載入器只是簡單的將段地址線性的對映到記憶體,粒度很大,沒有細化到節,所以節屬性在載入的時候沒有用。
但是ida是完全依靠mach格式來分析檔案,如此,bug就出現了。(實際上在win下,od也有類似的bug),那麼下面手動做2個實驗,達到ida不能載入,ios卻能正常執行的效果。
實驗1:更改節的實體地址偏移。
1,首先將檔案拖到ida,我們看到TEXT段下面的2個節。
“__text"與"__stub_helper"
HEADER:0000408C DCB "__text",0,0,0,0,0,0,0,0,0,0; sectname
HEADER:0000408C DCB "__TEXT",0,0,0,0,0,0,0,0,0,0; segname
HEADER:0000408C DCD 0xAD00 ; addr
HEADER:0000408C DCD 0xD6938 ; size
HEADER:0000408C DCD 0x6D00 ; offset
HEADER:0000408C DCD 3 ; align
HEADER:0000408C DCD 0 ; reloff
HEADER:0000408C DCD 0 ; nreloc
HEADER:0000408C DCD 0x80000400 ; flags
HEADER:0000408C DCD 0 ; reserved1
HEADER:0000408C DCD 0 ; reserved2
HEADER:000040D0 DCB "__stub_helper",0,0,0; sectname
HEADER:000040D0 DCB "__TEXT",0,0,0,0,0,0,0,0,0,0; segname
HEADER:000040D0 DCD 0xE1638 ; addr
HEADER:000040D0 DCD 0xE88 ; size
HEADER:000040D0 DCD 0xDD638 ; offset
HEADER:000040D0 DCD 2 ; align
HEADER:000040D0 DCD 0 ; reloff
HEADER:000040D0 DCD 0 ; nreloc
HEADER:000040D0 DCD 0x80000400 ; flags
HEADER:000040D0 DCD 0 ; reserved1
HEADER:000040D0 DCD 0 ; reserved2
“__text”節的的記憶體載入地址為 0xad00,檔案偏移為0x6d00
"__stub_helper"節的的記憶體載入地址為 0xE1638,檔案偏移為0xDD638
2,我們將“__text”的的檔案偏移更改為"__stub_helper"的檔案偏移,修改後保持檔案,繼續拖到ida下分析,如下圖:
HEADER:0000408C DCB "__text",0,0,0,0,0,0,0,0,0,0; sectname
HEADER:0000408C DCB "__TEXT",0,0,0,0,0,0,0,0,0,0; segname
HEADER:0000408C DCD 0xAD00 ; addr
HEADER:0000408C DCD 0xD6938 ; size
HEADER:0000408C DCD 0xDD638 ; offset
HEADER:0000408C DCD 3 ; align
HEADER:0000408C DCD 0 ; reloff
HEADER:0000408C DCD 0 ; nreloc
HEADER:0000408C DCD 0x80000400 ; flags
HEADER:0000408C DCD 0 ; reserved1
HEADER:0000408C DCD 0 ; reserved2
HEADER:000040D0 DCB "__stub_helper",0,0,0; sectname
HEADER:000040D0 DCB "__TEXT",0,0,0,0,0,0,0,0,0,0; segname
HEADER:000040D0 DCD 0xE1638 ; addr
HEADER:000040D0 DCD 0xE88 ; size
HEADER:000040D0 DCD 0xDD638 ; offset
HEADER:000040D0 DCD 2 ; align
HEADER:000040D0 DCD 0 ; reloff
HEADER:000040D0 DCD 0 ; nreloc
HEADER:000040D0 DCD 0x80000400 ; flags
HEADER:000040D0 DCD 0 ; reserved1
HEADER:000040D0 DCD 0 ; reserved2
兩個節的物理偏移都為0xDD638。
雙擊“__text”節,進入程式碼的。
可以看到左下角,實體地址為0xdd638,實際上這是錯誤的,實體地址應該為0x6D00。我們可以得出結論,ida直接使用了節的實體地址,偷懶了,實際上應該使用段地址來計算。
實驗2:給節的物理偏移更改為一個遠超檔案大小的數。
HEADER:0000408C ; Sections
HEADER:0000408C DCB "__text",0,0,0,0,0,0,0,0,0,0; sectname
HEADER:0000408C DCB "__TEXT",0,0,0,0,0,0,0,0,0,0; segname
HEADER:0000408C DCD 0xAD00 ; addr
HEADER:0000408C DCD 0xD6938 ; size
HEADER:0000408C DCD 0xFFFFFFFF ; offset
HEADER:0000408C DCD 3 ; align
HEADER:0000408C DCD 0 ; reloff
HEADER:0000408C DCD 0 ; nreloc
HEADER:0000408C DCD 0x80000400 ; flags
HEADER:0000408C DCD 0 ; reserved1
HEADER:0000408C DCD 0 ; reserved2
更改後儲存檔案,拖到ida,如圖:
點選後,還是可以分析的,但是點選"__text"進入程式碼段,對比原來得資料(上面有圖)你可以發現程式碼明顯不對,實體地址也變成了未知:
經測試,程式可以正常執行。
我們再將其改為一個比較大的正數,0x01000000,結果ida不能開啟。
以上修改經測試程式可以正常執行。實際上節的屬性都可以改,比如addr,混淆的效果比offset要好的多。將text部分節的資料填充隨機資料,ida直接卡死。