x86彙編反編譯到c語言之——(1)表達式求值及賦值語句-編程思維

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

  我們的目的是将多種平台的彙編如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語言。