如何将x86二进制可执行文件转回C源代码
#c #reverse #engineering #executable
  • 目标:将X86二进制可执行文件转回C源代码。
  • 了解编译器如何将C变成装配代码。
  • 低级操作系统结构和可执行文件格式。

算术指令

mov eax,2 ; eax = 2 
mov ebx,3 ; ebx = 3
add eax,ebx ; eax = eax + ebx 
sub ebx, 2 ; ebx = ebx - 2

访问内存

mox eax, [1234] ; eax = *(int*)1234 
mov ebx, 1234 ; ebx = 1234 
mov eax, [ebx] ; eax = *ebx 
mov [ebx], eax ; *ebx = eax 

有条件分支

cmp eax, 2 ; compare eax with 2 
je label1 ; if(eax==2) goto label1
 ja label2 ; if(eax>2) goto label2
jb label3 ; if(eax<2) goto label3 
jbe label4 ; if(eax<=2) goto label4
 jne label5 ; if(eax!=2) goto label5
 jmp label6 ; unconditional goto label6

功能调用

首先调用函数:
致电Func;将返回地址存储在堆栈上并跳到Func
第一个操作是保存返回指针:

pop esi ; save esi 
Right before leaving the function:
pop esi ; restore esi
ret ; read return address from the stack and jump to it 

现代编译器架构

c代码 - >解析 - >中间表示 - >优化 - >
低级中间表示 - >注册分配 - > x86汇编

高级优化

内线

例如,功能C:

int foo(int a, int b){
     return a+b }
 c = foo(a, b+1) 

转化为

c = a+b+1

循环展开

循环:

for(i=0; i<2; i++){
      a[i]=0;
 } 
becomes
   a[0]=0; 
   a[1]=0; 

循环不变的代码运动

The loop:
for (i = 0; i < 2; i++) {
 a[i] = p + q; 
} 

becomes:

temp = p + q;
for (i = 0; i < 2; i++) {
    a[i] = temp;
}

常见的亚基消除

变量属性:

  • 目标:将X86二进制可执行文件转回C源代码。
  • 了解编译器如何将C变成装配代码。
  • 低级操作系统结构和可执行文件格式。

算术指令

mov eax,2 ; eax = 2 
mov ebx,3 ; ebx = 3
add eax,ebx ; eax = eax + ebx 
sub ebx, 2 ; ebx = ebx - 2

访问内存

mox eax, [1234] ; eax = *(int*)1234 
mov ebx, 1234 ; ebx = 1234 
mov eax, [ebx] ; eax = *ebx 
mov [ebx], eax ; *ebx = eax 

有条件分支

cmp eax, 2 ; compare eax with 2 
je label1 ; if(eax==2) goto label1
 ja label2 ; if(eax>2) goto label2
jb label3 ; if(eax<2) goto label3 
jbe label4 ; if(eax<=2) goto label4
 jne label5 ; if(eax!=2) goto label5
 jmp label6 ; unconditional goto label6

功能调用

首先调用函数:
致电Func;将返回地址存储在堆栈上并跳到Func
第一个操作是保存返回指针:

pop esi ; save esi 
Right before leaving the function:
pop esi ; restore esi
ret ; read return address from the stack and jump to it 

现代编译器架构

c代码 - >解析 - >中间表示 - >优化 - >
低级中间表示 - >注册分配 - > x86汇编

高级优化

内线

例如,功能C:

int foo(int a, int b){
     return a+b }
 c = foo(a, b+1) 

转化为

c = a+b+1

循环展开

循环:

for(i=0; i<2; i++){
      a[i]=0;
 } 
becomes
   a[0]=0; 
   a[1]=0; 

循环不变的代码运动

The loop:
for (i = 0; i < 2; i++) {
 a[i] = p + q; 
} 

becomes:

temp = p + q;
for (i = 0; i < 2; i++) {
    a[i] = temp;
}

常见的亚基消除

变量属性:

a = b + (z + 1)
p = q + (z + 1)

becomes

temp = z + 1
a = b + z
p = q + z

常数折叠和传播

作业:

a = 3 + 5
b = a + 1
func(b)

Becomes:

func(9)

消除代码

删除不必要的代码:

a = 1
if (a < 0) {
printf(ERROR!)
}

to

a = 1

低级优化

强度降低

代码,例如:

y = x * 2
y = x * 15

Becomes:

y = x + x
y = (x << 4) - x

代码块重新排序

代码,例如:

if (a < 10) goto l1
printf(ERROR)
goto label2
l1:
    printf(OK)
l2:
    return;

Becomes:

if (a > 10) goto l1
printf(OK)
l2:
return
l1:
printf(ERROR)
goto l2

注册分配

  • 内存访问比寄存器慢。
  • 尝试在寄存器中尽可能多地适合本地变量。
  • 将本地变量映射到堆栈位置和寄存器不是恒定的。

指令计划

汇编代码如下:

mov eax, [esi]
add eax, 1
mov ebx, [edi]
add ebx, 1

Becomes:

mov eax, [esi]
mov ebx, [edi]
add eax, 1
add ebx, 1

a = b + (z + 1)
p = q + (z + 1)

becomes

temp = z + 1
a = b + z
p = q + z

常数折叠和传播

作业:

a = 3 + 5
b = a + 1
func(b)

Becomes:

func(9)

消除代码

删除不必要的代码:

a = 1
if (a < 0) {
printf(ERROR!)
}

to

a = 1

低级优化

强度降低

代码,例如:

y = x * 2
y = x * 15

Becomes:

y = x + x
y = (x << 4) - x

代码块重新排序

代码,例如:

if (a < 10) goto l1
printf(ERROR)
goto label2
l1:
    printf(OK)
l2:
    return;

Becomes:

if (a > 10) goto l1
printf(OK)
l2:
return
l1:
printf(ERROR)
goto l2

注册分配

  • 内存访问比寄存器慢。
  • 尝试在寄存器中尽可能多地适合本地变量。
  • 将局部变量映射到堆栈位置和寄存器不是恒定的。

  • 目的:将X86二进制可执行文件转回C源代码。

  • 了解编译器如何将C变成装配代码。

  • 低级操作系统结构和可执行文件格式。

算术指令

mov eax,2 ; eax = 2 
mov ebx,3 ; ebx = 3
add eax,ebx ; eax = eax + ebx 
sub ebx, 2 ; ebx = ebx - 2

访问内存

mox eax, [1234] ; eax = *(int*)1234 
mov ebx, 1234 ; ebx = 1234 
mov eax, [ebx] ; eax = *ebx 
mov [ebx], eax ; *ebx = eax 

有条件分支

cmp eax, 2 ; compare eax with 2 
je label1 ; if(eax==2) goto label1
 ja label2 ; if(eax>2) goto label2
jb label3 ; if(eax<2) goto label3 
jbe label4 ; if(eax<=2) goto label4
 jne label5 ; if(eax!=2) goto label5
 jmp label6 ; unconditional goto label6

功能调用

首先调用函数:
致电Func;将返回地址存储在堆栈上并跳到Func
第一个操作是保存返回指针:

pop esi ; save esi 
Right before leaving the function:
pop esi ; restore esi
ret ; read return address from the stack and jump to it 

现代编译器架构

c代码 - >解析 - >中间表示 - >优化 - >
低级中间表示 - >注册分配 - > x86汇编

高级优化

内线

例如,功能C:

int foo(int a, int b){
     return a+b }
 c = foo(a, b+1) 

转化为

c = a+b+1

循环展开

循环:

for(i=0; i<2; i++){
      a[i]=0;
 } 
becomes
   a[0]=0; 
   a[1]=0; 

循环不变的代码运动

The loop:
for (i = 0; i < 2; i++) {
 a[i] = p + q; 
} 

becomes:

temp = p + q;
for (i = 0; i < 2; i++) {
    a[i] = temp;
}

常见的亚基消除

变量属性:

  • 目标:将X86二进制可执行文件转回C源代码。
  • 了解编译器如何将C变成装配代码。
  • 低级操作系统结构和可执行文件格式。

算术指令

mov eax,2 ; eax = 2 
mov ebx,3 ; ebx = 3
add eax,ebx ; eax = eax + ebx 
sub ebx, 2 ; ebx = ebx - 2

访问内存

mox eax, [1234] ; eax = *(int*)1234 
mov ebx, 1234 ; ebx = 1234 
mov eax, [ebx] ; eax = *ebx 
mov [ebx], eax ; *ebx = eax 

有条件分支

cmp eax, 2 ; compare eax with 2 
je label1 ; if(eax==2) goto label1
 ja label2 ; if(eax>2) goto label2
jb label3 ; if(eax<2) goto label3 
jbe label4 ; if(eax<=2) goto label4
 jne label5 ; if(eax!=2) goto label5
 jmp label6 ; unconditional goto label6

功能调用

首先调用函数:
致电Func;将返回地址存储在堆栈上并跳到Func
第一个操作是保存返回指针:

pop esi ; save esi 
Right before leaving the function:
pop esi ; restore esi
ret ; read return address from the stack and jump to it 

现代编译器架构

c代码 - >解析 - >中间表示 - >优化 - >
低级中间表示 - >注册分配 - > x86汇编

高级优化

内线

例如,功能C:

int foo(int a, int b){
     return a+b }
 c = foo(a, b+1) 

转化为

c = a+b+1

循环展开

循环:

for(i=0; i<2; i++){
      a[i]=0;
 } 
becomes
   a[0]=0; 
   a[1]=0; 

循环不变的代码运动

The loop:
for (i = 0; i < 2; i++) {
 a[i] = p + q; 
} 

becomes:

temp = p + q;
for (i = 0; i < 2; i++) {
    a[i] = temp;
}

常见的亚表达消除

The variable attributions:

a = b + (z + 1)
p = q + (z + 1)

becomes

temp = z + 1
a = b + z
p = q + z

常数折叠和传播

作业:

a = 3 + 5
b = a + 1
func(b)

Becomes:

func(9)

消除代码

删除不必要的代码:

a = 1
if (a < 0) {
printf(ERROR!)
}

to

a = 1

低级优化

强度降低

代码,例如:

y = x * 2
y = x * 15

Becomes:

y = x + x
y = (x << 4) - x

代码块重新排序

代码,例如:

if (a < 10) goto l1
printf(ERROR)
goto label2
l1:
    printf(OK)
l2:
    return;

Becomes:

if (a > 10) goto l1
printf(OK)
l2:
return
l1:
printf(ERROR)
goto l2

注册分配

  • 内存访问比寄存器慢。
  • 尝试在寄存器中尽可能多地适合本地变量。
  • 将本地变量映射到堆栈位置和寄存器不是恒定的。

指令计划

汇编代码如下:

mov eax, [esi]
add eax, 1
mov ebx, [edi]
add ebx, 1

Becomes:

mov eax, [esi]
mov ebx, [edi]
add eax, 1
add ebx, 1

a = b + (z + 1)
p = q + (z + 1)

becomes

temp = z + 1
a = b + z
p = q + z

常数折叠和传播

作业:

a = 3 + 5
b = a + 1
func(b)

Becomes:

func(9)

消除代码

删除不必要的代码:

a = 1
if (a < 0) {
printf(ERROR!)
}

to

a = 1

低级优化

强度降低

代码,例如:

y = x * 2
y = x * 15

Becomes:

y = x + x
y = (x << 4) - x

代码块重新排序

代码,例如:

if (a < 10) goto l1
printf(ERROR)
goto label2
l1:
    printf(OK)
l2:
    return;

Becomes:

if (a > 10) goto l1
printf(OK)
l2:
return
l1:
printf(ERROR)
goto l2

注册分配

  • 内存访问比寄存器慢。
  • 尝试在寄存器中尽可能多地适合本地变量。
  • 将本地变量映射到堆栈位置和寄存器不是恒定的。

指令计划

汇编代码如下:

mov eax, [esi]
add eax, 1
mov ebx, [edi]
add ebx, 1

Becomes:

mov eax, [esi]
mov ebx, [edi]
add eax, 1
add ebx, 1

指令计划

汇编代码如下:

mov eax, [esi]
add eax, 1
mov ebx, [edi]
add ebx, 1

Becomes:

mov eax, [esi]
mov ebx, [edi]
add eax, 1
add ebx, 1