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语言。

  

  

版权声明:本文版权归作者所有,遵循 CC 4.0 BY-SA 许可协议, 转载请注明原文链接
https://www.cnblogs.com/iszhang/p/15615344.html