maximilianfeldthusen/x86BackToC
GitHub: maximilianfeldthusen/x86BackToC
将x86二进制可执行文件反编译还原为C源代码的逆向工程教学与研究工具
Stars: 0 | Forks: 0
## x86BackToC
### 将 x86 二进制文件还原为 C 源代码


title: "将 x86 二进制文件还原为 C 代码"
layout: post
date: 2025-05-25 22:44
headerImage: false
tag:
- assembly
- c
- reverse engineering
star: true
category: blog
author: maximilian feldthusen
description: Reverse Engineering
* 目标:将 x86 二进制可执行文件还原为 C 源代码。
* 理解编译器如何将 C 语言转换为汇编代码。
* 底层 OS 结构和可执行文件格式。
算术指令
```
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
```
函数调用
首先调用一个函数:
call 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;
}
```
变为
```
a[0]=0;
a[1]=0;
```
循环不变量外提
```
The loop:
for (i = 0; i < 2; i++) {
a[i] = p + q;
}
```
变为:
```
temp = p + q;
for (i = 0; i < 2; i++) {
a[i] = temp;
}
```
公共子表达式消除
变量赋值:
* 目标:将 x86 二进制可执行文件还原为 C 源代码。
* 理解编译器如何将 C 语言转换为汇编代码。
* 底层 OS 结构和可执行文件格式。
算术指令
```
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
```
函数调用
首先调用一个函数:
call 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;
}
```
变为
```
a[0]=0;
a[1]=0;
```
循环不变量外提
```
The loop:
for (i = 0; i < 2; i++) {
a[i] = p + q;
}
```
变为:
```
temp = p + q;
for (i = 0; i < 2; i++) {
a[i] = temp;
}
```
公共子表达式消除
变量赋值:
```
a = b + (z + 1)
p = q + (z + 1)
```
变为
```
temp = z + 1
a = b + z
p = q + z
```
常量折叠与传播
赋值:
```
a = 3 + 5
b = a + 1
func(b)
```
变为:
```
func(9)
```
死代码消除
删除不必要的代码:
```
a = 1
if (a < 0) {
printf(“ERROR!”)
}
```
为
```
a = 1
```
低级优化
强度削弱
代码如:
```
y = x * 2
y = x * 15
```
变为:
```
y = x + x
y = (x << 4) - x
```
代码块重排
代码如 :
```
if (a < 10) goto l1
printf(“ERROR”)
goto label2
l1:
printf(“OK”)
l2:
return;
```
变为:
```
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
```
变为:
```
mov eax, [esi]
mov ebx, [edi]
add eax, 1
add ebx, 1
a = b + (z + 1)
p = q + (z + 1)
```
变为
```
temp = z + 1
a = b + z
p = q + z
```
常量折叠与传播
赋值:
```
a = 3 + 5
b = a + 1
func(b)
```
变为:
```
func(9)
```
死代码消除
删除不必要的代码:
```
a = 1
if (a < 0) {
printf(“ERROR!”)
}
```
为
```
a = 1
```
低级优化
强度削弱
代码如:
```
y = x * 2
y = x * 15
```
变为:
```
y = x + x
y = (x << 4) - x
```
代码块重排
代码如 :
```
if (a < 10) goto l1
printf(“ERROR”)
goto label2
l1:
printf(“OK”)
l2:
return;
```
变为:
```
if (a > 10) goto l1
printf(“OK”)
l2:
return
l1:
printf(“ERROR”)
goto l2
```
寄存器分配
* 内存访问比寄存器慢。
* 尝试将尽可能多的局部变量放入寄存器中。
* 局部变量到堆栈位置和寄存器的映射不是恒定的。
* 目标:将 x86 二进制可执行文件还原为 C 源代码。
* 理解编译器如何将 C 语言转换为汇编代码。
* 底层 OS 结构和可执行文件格式。
算术指令
```
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
```
函数调用
首先调用一个函数:
call 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;
```
循环不变量外提
循环:
```
for (i = 0; i < 2; i++) {
a[i] = p + q;
}
```
变为:
```
temp = p + q;
for (i = 0; i < 2; i++) {
a[i] = temp;
}
```
公共子表达式消除
变量赋值:
* 目标:将 x86 二进制可执行文件还原为 C 源代码。
* 理解编译器如何将 C 语言转换为汇编代码。
* 底层 OS 结构和可执行文件格式。
算术指令
```
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
```
函数调用
首先调用一个函数:
call 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;
}
```
变为
```
a[0]=0;
a[1]=0;
```
循环不变量外提
```
The loop:
for (i = 0; i < 2; i++) {
a[i] = p + q;
}
```
变为:
```
temp = p + q;
for (i = 0; i < 2; i++) {
a[i] = temp;
}
```
公共子表达式消除
变量赋值:
```
a = b + (z + 1)
p = q + (z + 1)
```
变为
```
temp = z + 1
a = b + z
p = q + z
```
常量折叠与传播
赋值:
```
a = 3 + 5
b = a + 1
func(b)
```
变为:
```
func(9)
```
死代码消除
删除不必要的代码:
```
a = 1
if (a < 0) {
printf(“ERROR!”)
}
```
为
```
a = 1
```
低级优化
强度削弱
代码如:
```
y = x * 2
y = x * 15
```
变为:
```
y = x + x
y = (x << 4) - x
```
代码块重排
代码如 :
```
if (a < 10) goto l1
printf(“ERROR”)
goto label2
l1:
printf(“OK”)
l2:
return;
```
变为:
```
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
```
变为:
```
mov eax, [esi]
mov ebx, [edi]
add eax, 1
add ebx, 1
a = b + (z + 1)
p = q + (z + 1)
```
变为
```
temp = z + 1
a = b + z
p = q + z
```
常量折叠与传播
赋值:
```
a = 3 + 5
b = a + 1
func(b)
```
变为:
```
func(9)
```
死代码消除
删除不必要的代码:
```
a = 1
if (a < 0) {
printf(“ERROR!”)
}
```
为
```
a = 1
```
低级优化
强度削弱
代码如:
```
y = x * 2
y = x * 15
```
变为:
```
y = x + x
y = (x << 4) - x
```
代码块重排
代码如 :
```
if (a < 10) goto l1
printf(“ERROR”)
goto label2
l1:
printf(“OK”)
l2:
return;
```
变为:
```
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
```
变为:
```
mov eax, [esi]
mov ebx, [edi]
add eax, 1
add ebx, 1
```
指令调度
汇编代码如:
```
mov eax, [esi]
add eax, 1
mov ebx, [edi]
add ebx, 1
```
变为:
```
mov eax, [esi]
mov ebx, [edi]
add eax, 1
add ebx, 1
```
标签:AST抽象语法树, TLS抓取, x86架构, 二进制分析, 云安全监控, 云安全运维, 云资产清单, 代码重构, 反编译器, 可执行文件格式, 可配置连接, 安全报告生成, 寄存器分配, 快速连接, 恶意代码分析, 指令集, 控制流恢复, 机器码转C, 汇编语言, 程序分析, 编译原理, 软件安全, 逆向工程, 配置文件, 静态分析