x86彙編反編譯到c語言之——(1)表示式求值及賦值語句

Just_4_fun發表於2021-11-28

一. 反編譯一種可能的實現方式

  我們的目的是將多種平臺的彙編如x86,ARM,6502反編譯為c語言,所以實現時先將多種彙編轉化為

特定虛擬機器組合語言,然後只需要將虛擬機器組合語言反編譯為c語言。其中多種平臺組合語言到虛擬機器組合語言

也計劃由程式通過學習自動完成。

 

二. 測試的C語句及編譯後的x86彙編程式碼

int a;

int main(void) {
    a = 2+3*4;
    return 0;
}
 1 lea     rax, a
 2 push    rax
 3 mov     rax, 4
 4 push    rax
 5 mov     rax, 3
 6 pop     rdi
 7 imul    eax, edi
 8 push    rax
 9 mov     rax, 2
10 pop     rdi
11 add     eax, edi
12 pop     rdi
13 mov     [rdi], eax

 

三. x86彙編到虛擬機器彙編

  我們的目標是將上面的彙編反編譯為c語言,在這個過程中先將彙編轉化為虛擬機器組合語言。

  這個演算法只關注記憶體操作,因為c語言沒有暫存器和棧的概念。

  演算法的執行如下,首先彙編的最後一句是記憶體操作,具體是寫記憶體,演算法會首先確定寫的記憶體的具體地址,

通過觀察這個地址在rdi暫存器中,修改rdi的為上一條語句"pop rdi",所以會查詢哪句將地址壓棧,具體會查詢到

是第二行"push rax",然後追尋rax的值,追尋到為第一句"lea rax, a",至此具體記憶體地址確定了。

  下面演算法開始追尋eax的值,追尋到第11句"add eax, edi",這句可以理解為eax=eax+edi,所以下面的工作

確定eax和edi的值,同時生成add虛擬機器彙編語句。

  eax的值在第9句"mov rax, 2"確定,此時確定了add虛擬機器彙編語句的第一個運算元。edi的值在第10句

"pop rdi",所以查詢哪句壓棧了,找到第8句"push rax",所以查詢誰修改了rax的值,查詢到第7句

"imul eax, edi",這句可以理解為eax=eax*edi,所以下面追尋eax和edi的值,此時生成mul虛擬機器彙編語句,

同時確定了add虛擬機器彙編語句的第二個運算元。

  eax在第5句"mov rax, 3"確定,此時確定mul虛擬機器彙編語句的第一個運算元,edi由第6句"pop rdi"確定,

所以查詢誰壓棧了,查詢到第4句"push rax",所以查詢rax的值,結果為第3句"mov rax, 4",所以edi值確定為4,

此時確定mul虛擬機器彙編語句的第二個運算元。

  最後生成將值寫入記憶體的虛擬機器彙編語句。

 

四. 虛擬機器彙編到c語言

  1. 虛擬機器組合語言

  設計的虛擬機器是基於棧的,所以上面生成的語句code段部分可能如下。

   |OP_CONSTANT|

   |0|

   |OP_CONSTANT|

   |1|

   |OP_CONSTANT|

   |2|

   |OP_MUL|

   |OP_ADD|

   |OP_SET_GLOBAL|

   |3|

  常量段為

   |2|

   |3|

   |4|

   |a|

  上面的語句執行過程為,OP_CONSTANT會從常量段中取出對應下標的數字壓入棧中,

OP_CONSTANT 0將2壓入棧中,OP_CONSTANT 1將3壓入棧中,OP_CONSTANT 2將4壓入棧中,

OP_MUL將棧中最頂層的2個數彈出並計算他們的乘積,將結果壓回棧中,這樣棧中就是2和12,

OP_ADD將棧中最頂層的2個數彈出並計算他們的和,將結果壓回棧中,這樣棧中就是14。最後將棧頂的

14寫回到變數a中。

  

  2. 反編譯為c語言

  遇到OP_MUL,分析最近的兩個壓棧操作,這裡是兩個OP_CONSTANT,於是生成語句3*4,遇到指令

OP_ADD,分析最近的兩個壓棧操作,這裡是OP_MUL和OP_CONSTANT,於是生成語句2+3*4。最後

OP_SET_GLOBAL尋找最近操作棧頂的操作,發現是OP_ADD,於是生成語句a = 2+3*4,至此x86組合語言被

反編譯為c語言。

  

  

相關文章