2016-11-18 50 views
1

在(32位)ARM Linux內核中,如何區分嵌入代碼段的數據和指令?從ARM指令中區分數據

最好有一個輕量級的方法,比如位掩碼,它可以很容易地實現。將一個拆裝器嵌入到內核中並不明智。

回答

1

一般來說,你所要求的是不可能的。

考慮這個功能恰好使用的數據值過大,編碼爲直接:

@ void patch_nop(void *code_addr); 
patch_nop: 
    ldr r1, =0xe1a00000 
    str r1, [r0] 
    bx lr 

其中,由時間它已經通過彙編和背部,看起來像這樣:

$ arm-none-eabi-objdump -d a.out 

a.out:  file format elf32-littlearm 


Disassembly of section .text: 

    00000000 <patch_nop>: 
     0: e59f1004  ldr  r1, [pc, #4] ; c <patch_nop+0xc> 
     4: e5801000  str  r1, [r0] 
     8: e12fff1e  bx  lr 
     c: e1a00000  .word 0xe1a00000 

由於ELF數據,我們仍然可以確定函數結束位置和文字池開始的位置,但objdump正在挖掘這些部分並且符號很難「輕量化」,而且誰說你有這些?如果你有只是的代碼?

$ arm-none-eabi-objcopy -Obinary a.out bin 
$ arm-none-eabi-objdump -D -marm -bbinary bin 

bin:  file format binary 


Disassembly of section .data: 

00000000 <.data>: 
    0: e59f1004  ldr  r1, [pc, #4] ; 0xc 
    4: e5801000  str  r1, [r0] 
    8: e12fff1e  bx  lr 
    c: e1a00000  nop      ; (mov r0, r0) 

那裏。嵌入你的指令流中,你有數據,這是一條指令。甚至沒有數據偶然發生看起來像一條指令。從字面上看,沒有任何東西可以從這32位中單獨推斷出它們不會被執行(嗯,至少不是位置)。

有幾個啓發式這可能有助於使一個受過教育的猜測,尤其是如果任何額外的先驗知識,可以假定它縮小:

  • 可以被編碼爲即時任何事情都是差不多當然是一條指令,因爲編譯器/彙編程序首先不會將它作爲文字發送出去。但是,理想情況下,您至少要知道前面的代碼是ARM還是Thumb,以便知道相應的即時範圍是*

  • 任何未定義的指令通常都是數據,除非碰巧它是想要故意引發undef異常的代碼。而且你基本上必須擁有大部分的反彙編程序來檢查某些東西是否與任何已定義的編碼不匹配。在ARM/Thumb之上。

  • 緊隨無條件分支之後的任何東西都可能是文字數據,特別是如果您有符號並且可以告訴它非常接近以下函數的開頭,或者您對所查找的數據有一定的瞭解,它看起來像數據。後一點當然是相關的,如果你只是眼球反彙編 - 在實踐中,文字數據往往是地址的東西,通常脫穎而出像一個拇指拇指一旦你看整個代碼。

  • 檢查文字是否是文字的最可靠方法是查看前面的代碼(最多1025條指令),檢查以該地址爲目標的PC相對負載。你只需要檢查字面加載編碼(這是你的簡單掩碼操作),然後解碼相對偏移量,如果你找到一個。理想情況下,您想要解決ARM/Thumb的問題,以避免檢測不適當的編碼時出現誤報,並且在最絕對的病態情況下,您仍然可以運行前面的文字池中的某些數據,看起來像是文字加載定位你的地址;永不說永不。

當然,這仍然是假設編譯器/彙編程序自動發出的文字池;當涉及到完全手寫彙編代碼時,所有投注都關閉:

patch_nop2: 
    ldr r1, [pc, #-4] 
    mov r0, r0 
    str r1, [r0] 
    bx lr 

是代碼?是。它是數據嗎?是。 *順便說一句,ARM和Thumb代碼之間的區分歸結爲基本上與此相同的問題 - 「這個位模式是什麼意思?」 - 在沒有外部幫助的情況下也同樣不重要。

†沒有雙關語意

+0

和[這裏是一個更狡猾的一個(http://stackoverflow.com/q/38294896/3156750)。 – Notlikethat