ASM32 9-10 反汇编代码和函数
反汇编代码
根据CPU指令表找到对应的汇编代码
32位反汇编的默认操作数大小为32,若前面加了66前缀可以减小为16,即把eax改为ax;而如果加67可以前缀可以增大大小,但若本来就为eax则没有作用,反而可能使编译出错
示例
1 | 6A 00 push 0 |
6A 00 —
push 0
6A
是push
指令的操作码,用于将一个字节大小的立即数压入堆栈。00
是立即数,表示将0
压入堆栈。
E8 7C 00 00 00 —
call 81
E8
是call
指令的操作码,用于调用一个相对的函数地址,地址是相对当前指令指针(EIP)的偏移。7C 00 00 00
表示调用的偏移量是0x7C
,即跳转到当前指令后的0x7C
字节处。
A3 00 30 40 00 —
mov dword ptr [00403000], eax
A3
是mov
指令的操作码,用于将eax
寄存器中的值移动到内存中。00 30 40 00
是目标内存地址,表示将eax
的值存储到0x00403000
处。
E8 B4 00 00 00 —
call b9
E8
是call
指令的操作码,用于调用相对偏移的函数。B4 00 00 00
表示调用的偏移量是0xB4
,即跳转到当前指令后的0xB4
字节处。
6A 00 —
push 0
- 同第1行,
6A 00
再次将0
压入堆栈。
- 同第1行,
68 EF 11 40 00 —
push 0x004011ef
68
是push
指令的操作码,用于将一个 4 字节的立即数压入堆栈。EF 11 40 00
是立即数,表示将0x004011EF
压入堆栈。
6A 00 —
push 0
- 再次将
0
压入堆栈(与前面的push 0
相同)。
- 再次将
6A 65 —
push 65
6A
是push
指令,用于将一个字节大小的立即数压入堆栈。65
是立即数,表示将0x65
(十进制的 101)压入堆栈。
FF 35 00 30 40 00 —
push dword ptr [00403000]
FF 35
是push
指令的操作码,用于将存储在内存地址中的 4 字节的值压入堆栈。00 30 40 00
是内存地址,表示将0x00403000
地址中的值压入堆栈。
函数
新建空白工程
函数实例
1 | .386 |
文件头部和常量定义
1 | .386 |
- **
.386
**:指示编译器生成适用于 80386 或更高版本 CPU 的代码。 - **
.model flat,stdcall
**:定义了内存模型为平坦模式(flat
),使用stdcall
调用约定(用于 Windows API 调用)。 - **
option casemap:none
**:禁用大小写自动转换,汇编器将区分大小写。
包含 Windows 相关库
1 | include windows.inc |
- **
include
**:引入 Windows API 所需的头文件和声明。 - **
includelib
**:指定链接的库文件,user32.lib
和kernel32.lib
分别包含常用的 Windows API 函数。
MyAdd
函数
1 | MyAdd: |
- **
push ebp
**:将当前的基指针 (ebp
) 压入栈中,保存上一次的栈帧。 - **
mov ebp,esp
**:将当前栈指针 (esp
) 赋值给基指针 (ebp
),建立新的栈帧。 - **
sub esp,16
**:在栈上为局部变量分配 16 字节空间。 - **
push ebx
**:将ebx
寄存器的值压入栈,保护其值不被修改。
1 | mov eax,dword ptr [ebp+8] |
- **
mov eax,dword ptr [ebp+8]
**:从栈中获取第一个函数参数并存入eax
寄存器。 - **
mov [ebp-4],eax
**:将第一个参数存储到栈中的局部变量位置。 - **
mov eax,dword ptr [ebp+12]
**:从栈中获取第二个函数参数并存入eax
。 - **
mov [ebp-8],eax
**:将第二个参数存储到栈中的局部变量位置。
1 | pop ebx |
- **
pop ebx
**:恢复之前保存的ebx
寄存器值。 - **
leave
**:相当于mov esp,ebp
和pop ebp
,恢复栈指针和基指针。 - **
retn 8
**:从函数返回,并在返回时清理 8 字节的栈参数(即两个DWORD
参数)。
程序入口 START
1 | START: |
- **
push eax
**:将eax
压入栈,保存其值。 - **
mov ebp,esp
**:将当前栈指针复制到基指针,建立栈帧。
1 | push 2 |
- **
push 2
**:将值2
压入栈作为第二个参数。 - **
push 1
**:将值1
压入栈作为第一个参数。 - **
call MyAdd
**:调用MyAdd
函数。
1 | pop eax |
- **
pop eax
**:将栈顶值弹出到eax
寄存器中。 - **
invoke ExitProcess,0
**:调用 Windows API 函数ExitProcess
结束程序,参数为0
表示正常退出。 - **
ret
**:返回到调用程序(程序结束)。
调试结果
观察堆栈可看到刚开始被压入栈的两个参数1和2在函数调用的过程中被取出作为函数的局部变量
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Hexo!