一. 反編譯一種可能的實現方式
我們的目的是將多種平臺的彙編如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語言。