什么是汇编
汇编就是寄存器跟寄存器,寄存器跟内存,内存跟寄存器之间来回移动数据,没有内存跟内存 如果要操作有特殊的指令操作。(所有指令都是操作内存跟寄存器)
寄存器
编号 | 32位 | 16位 | 8位 | 寄存器 |
0 | EAX | AX | AL | 累加/通用 |
1 | ECX | CX | CL | 计数/通用 |
2 | EDX | DX | DL | 数据/通用 |
3 | EBX | BX | BL | 基址 |
4 | ESP | SP | AH | 堆栈(栈顶) |
5 | EBP | BP | CH | 堆栈(栈底) |
6 | ESI | SI | DH | 字符串 |
7 | EDI | DI | BH | 字符串 |
EIP | IP | 指令指针 | ||
EFLAGS | FLAGS | 标志 |
寄存器之间关系
VC6快捷键
- F7 编译
- F9 断点调试
- F5 断到断点处
- F10 步过
- F11 步入
- Shift+F5 退出调试
- Alt+8 反汇编
- F12 转到定义处
汇编书写格式
_asm//汇编格式
{
//这里只能写汇编指令
}
如何分辨参数
看到MOV r/m8,r8 r代表register m代表memory r8代表寄存器
imm代表立即数 r代表寄存器 m代表内存
ib—>byte imm(imm8)
iw—>word imm(imm16)
id—->dword imm(imm32)
0xC0000005
内存访问错误
数据只有反复利用才会产生意义
只要执行指令EIP都会发生变化因为EIP就是指令指针
双斜杠代表注释 斜杠+星范围之间全部注释
汇编 读写内存
内存格式与书写方式
[ ] 内存是由两个括号代表的 可以是寄存器,立即数。
dis32
mov eax,dword ptr ds:[ ebx+ecx * 1 + 0x12345678 ]
2
4
8
//ebx--->基址 ecx--->INDEX s索引 0x12345678--->偏移
//内存里面寄存器都是32位因为内存数据都是4个字节4个字节对齐
ds--->段寄存器 prt--->指针 dword--->4个字节
为什么是1 2 4 8 因为2的二次方
//读内存
mov eax,0x0012ff34
mov ecx,dword ptr ds:[eax]
//写内存
mov eax,0x0012ff34
mov ecx,0x12345678
mov dword ptr ds:[eax],ecx
内存是4个字节4个字节对齐 4G空间 2的32次方刚好是4G
内存注意事项
0012FF34 A6 F5 AF 0F 3F 9B ---》0x9b3f0fafa6
观察内存首先前面是内存地址,后面是内存里面的内容,内存的数据是反着存储。右高左低
esp
ebp
不能随意修改 因为函数放到堆栈里面的,esp ebp
是对堆栈操作的,如果改变了堆栈失去平衡,就会出现错误
段寄存器(96位)
编号 | 96位 | 扩展 |
0 | es | esi edi |
1 | cs | eip |
2 | ss | esp ebp |
3 | ds | 通用 |
4 | fs | |
5 | gs | |
↑ //普通段 | ↑ //普通段 | ↑ //普通段 |
↓ //系统段 | ↓ //系统段 | ↓ //系统段 |
6 | ldtr | |
7 | tr |
段寄存器结构体
struct Sengment//96
{
WORD Selector//选择子
WORD Attributes//属性
DWORD Base//基址
DWORD Limit//界限
}
无符号类型
QWORD
—> 8个字节FWORD
—> 6个字节DWORD
—> 4个字节 //32位WORD
—> 2个字节 //16位BYTE
—> 1个字节 //8位
有符号类型(C语言)
int
—> 4个字节long
—> 4个字节short
—> 2个字节char
—> 1个字节
浮点类型(C语言)
float
—> 4个字节double
—> 8字节
汇编指令
MOV 移动指令
mov 目标操作数,源操作数—>源操作数移动到目标操作数
目标操作数—> r/m
源操作数—> imm/r/m
源操作数和目标操作数不能同时为内存 (根据编译器而定)
mov ecx,0x11111111
mov eax,0x22222222
mov eax,ecx
ADD 加法指令
add 目标操作数,源操作数—>目标操作数+源操作数 把结果放到目标操作数
目标操作数—> r/m
源操作数—> imm/r/m
mov eax,0x12345678
mov ecx,0x11111111
add eax,ecx
SUB 减法指令
sub 目标操作数,源操作数—>目标操作数-源操作数 把结果放到目标操作数
目标操作数—>r/m
源操作数—> imm/r/m
mov eax,0x12345678
mov ecx,0x11111111
sub eax,ecx
INC 自加一指令
inc 目标操作数—>目标操作数加一
目标操作数—> r/m
mov al,0x12
inc al
DEC 自减一指令
dec 目标操作数—>目标操作数减一
目标操作数—> r/m
mov cl,0xff
dec cl
逻辑指令 位与位之间的运算
- 位与位之间没有任何联系
- 不进位,取最大值
OR 或运算
or 目标操作数,源操作数—>结果存储目标操作数。算加法两个操作数有一个1就为1,否则为0。C语言符号( | )
目标操作数—> r/m
源操作数—>imm/r/m
mov al,0x8
mov cl,0x9
or al,cl
目标操作数 1000
源操作数 1001
运算结果 1001
AND 与运算
and 目标操作数,源操作数—>结果存储目标操作数。算乘法两个操作数对应的位为1才为1,否则为0。C语言符号( & )
目标操作数—> r/m
源操作数—> imm/r/m
mov al,0x5
mov cl,0x6
and al,cl
目标操作数: 0101
源操作数: 0110
运算结果: 0100
XOR 异或
xor 目标操作数,源操作数—>结果存储目标操作数。两个操作数相同为0,不同为1。C语言符号( ^ )
目标操作数—> r/m
源操作数—> imm/r/m
mov al,0x8
mov cl,0x9
xor al,cl
目标操作数:1000
源操作数: 1001
运算结果: 0001
NOT 取反
not 目标操作数—>结果存储目标操作数,操作数对应的位是0就为1,是1就为0。(快捷方式用F去减注意宽度) C语言符号( ~/! )
目标操作数—> r/m
mov cl,0x9 -->根据位宽用比如CL 用FF去减
not cl
直接用F去减
0x5739752bac482432
0xa8c68ad453b7dbcd
SAR 右移
sar 目标操作数,源操作数—>对目标操作数除以2的幂(源操作数)结果存储目标操作数
目标操作数—> r/m
源操作数—>寄存器cl,imm8立即数
mov al,0x8
mov cl,0x2
sar al,cl
SHL 左移
shl 目标操作数,源操作数—>对目标操作数乘以2的幂(源操作数)结果存储目标操作数
目标操作数—> r/m
源操作数—> 寄存器cl,imm8立即数
mov al,0x4
shl al,0x1
LEA 获取内存地址
lea 目标操作数,源操作数—>功能:获取内存地址
目标操作数—>必须是 r16/r32 寄存器Register
源操作数—>必须是内存 [ ]
mov ecx,dword ptr ds:[eax]
lea edx, dword ptr ds:[eax]---> mov edx,eax 值是一样的
MOV 和 LEA指令的区别
- MOV 获取内存地址里面的内容
- LEA 获取内存地址
PUSH 把值压入堆栈
push 目标操作数—>功能:压栈
目标操作数—> imm/r/m/reg
分解成两条指令,即使同时改变寄存器也改变内存
push eax //先减4在给值
lea esp,dword ptr ds:[esp-0x4]
mov dword ptr ds:[esp],eax
push esp //通用方法 反
mov dword ptr ds:[esp-0x4],esp
lea esp,dword ptr ds:[esp-0x4]
POP 将值弹出堆栈
pop 目标操作数—>功能:将值弹出堆栈
目标操作数—> r16/r32/m/reg
pop ecx //先弹赋值在加4
mov ecx,dword ptr ds:[esp]
lea esp,dword ptr ds:[esp+0x4]
pop esp //通用方法 先加4在弹值
lea esp,dword ptr ds:[esp+0x4]
mov esp,dword ptr ds:[esp-0x4]
XCHG 交换
xchg 目标操作数,源操作数—>功能:目标操作数和源操作数的值交换内容
目标操作数—> r/m
源操作数—> r/m
xchg eax,eax // 自己跟自己交换没有意义,所以演变成一个新的指令 NOP
mov eax,0x11111111
xchg eax,dword ptr ds:[esp]
NOP 无操作
nop —>不执行操作
MUL 无符号乘法
操作数大小 | 源操作数 1 | 源操作数 2 | 目标操作数 |
字节 | AL | r/m8 | AX |
字 | AX | r/m16 | DX:AX |
双字 | EAX | r/m32 | EDX:EAX |
mul 源操作数—>目标操作数 × 源操作数 执行无符号乘法,结果存储到目标操作数。默认 AL、AX 或 EAX 寄存器的值(取决于操作数的大小),结果存储到 AX、DX:AX 或 EDX:EAX 寄存器。(取决于操作数的大小)
源操作数—> r/m
mov al,0x8
mov cl,0x2
mul cl
IMUL 有符号乘法
单操作数形式 —> 单操作数形式 只有一个操作数跟无符号乘法(mul)一样, 默认 AL、AX 或 EAX 寄存器。结果存储到 AX、DX:AX 或 EDX:EAX 寄存器。(取决于操作数的大小)
mov al,0x8
mov cl,0x2
imul cl
双操作数形式 —>目标操作数乘以源操作数,目标操作数是通用寄存器,源操作数可以是立即数、通用寄存器或内存,结果放到目标操作数。(如果没有用到EAX ,溢出的位放到EFLAGS里去)
mov cx,0xf
mov dx,0x2
imul cx,dx
三操作数形式 —>(指定目标操作数)两个源操作数相乘,结果放到目标操作数(通用寄存器),源操作数1(可以是通用寄存器或内存),源操作数2(立即数)。
mov ax,0x0000
mov cx,0x2222
imul ax,cx,0x2
DIV 无符号除法
操作数大小 | 被除数 | 除数 | 商 | 余数 | 商的范围 |
字/字节 | AX | r/m8 | AL | AH | -128 到 +127 |
双字/字 | DX:AX | r/m16 | AX | DX | -32,768 到 +32,767 |
四字/双字 | EDX:EAX | r/m32 | EAX | EDX | -231 到 232 – 1 |
div 将 AL、AX 或 EAX 寄存器中的值除以(无符号)源操作数,结果存储到 AX、DX:AX 或 EDX:EAX 寄存器。
源操作数—> r/m
mov al,0x10
mov cl,0x2
cbw
div cl
mov ax,0x7000
mov cx,0x4
cwd
div cx
mov eax,0x40000000
mov ecx,0x20
cdq
div ecx
IDIV 有符号除法
idiv 将 AL、AX 或 EAX 寄存器中的值除以(有符号)源操作数,结果存储到 AX、DX:AX 或 EDX:EAX 寄存器。
源操作数—> r/m
mov ax,0xff
mov cx,0x2
cwd
idiv cx
扩展CBW CWD CDQ
按高位扩展最高位是为几那就扩展成几
CBW—> 1个字节转换2个字节 AX←AL
CWD—> 2个字节转换4个字节 DX:AX←AX
CDQ—> 4个字节转8个字节 EDX:EAX ← EAX
ABC 带进位加法
abc 目标操作数,源操作数—>功能:指令将两个操作数相加,如果 CF 标志是 0 ,则将结果存储到目标操作数。如果 CF 标志是 1,加法的结果递增 1,然后存储到目标操作数。
目标操作数—> imm/r/m
源操作数—> r/m
mov ax,0xffff
add ax,0x1
mov cx,0x1
adc cx,0x1
SBB 带借位整数减法
sbb 目标操作数,源操作数—>源操作数+CF进位标志-目标操作数 结果存储目标操作数 不区分有符号或无符号操作数
目标操作数—> imm/r/m
源操作数—> r/m
mov ax,0xffff
add ax,0x1
mov cl,0x8
mov al,0x3
SBB cl,al
DAA 加之后AL十进制调整
执行add加法后对al进行十进制调整(0-F)
如果AL的低4位大于9或AF=1,则AL的内容加06H,并将AF置1;
如果AL的高4位大于9或CF=1,则AL的内容加60H,且将CF置1。
mov al,0x9
add al,0x1
daa
DAS 减之后 AL 十进制调整
执行sub减法后对al进行十进制调整(0-F)
如果AL低四位>9或AF=1 ,则AL的值减06h,并置AF=1
如果AL高四位>9或CF=1 ,则AL的值减60h ,且置CF=1
mov al,0x10
sub al,0x1
das
AAA 加之后 ASCII 调整
aaa 执行add后对al进行ASCII调整
mov al,0x5
add al,0x5
aaa
AAS 减之后 ASCII 调整
AAA 执行sub后对al进行ASCII调整
mov al,0x5
sub al,0x1
aas
JMP 跳转
jmp 目标操作数—>改变EIP寄存器,想当于mov eip(eip不能随意修改,除非英特尔提供特殊指令)
目标操作数—> imm/r/m
mov eax,0x0012ff34
jmp eax
LAB 标签
lea ecx,lab
jmp ecx
xor eax,eax
lab:
mov eax,0x12345678
CALL 调用过程
call 目标操作数—>调用过程 先push后jmp
目标操作数—> imm/r/m
call edx
push IL //esp+len(il)下一条指令的地址-->当前EIP+本条指令的长度
jmp edx
call edx
lea eax,leb
push eax
jmp edx
leb:
mov eax,0x0
RET 从CALL返回
ret 无或iw—>从过程返回
ret
lea esp,dword ptr ds:[esp+0x4]
jmp dword ptr ds:[esp-0x4]---》返回 CALL的下一条指令
ret iw
lea esp,dword ptr ds:[esp+0x4+iw]
jmp dword ptr ds:[esp-0x4-iw]---》返回 CALL的下一条指令
注意:CALL指令跟RET是配套使用的
JCC 条件转移指令
jcc 目标操作数—>立即数(地址)
指令 | 条件 |
jc | cf=1 |
jnc | cf=0 |
jp | pf=1 |
jpe | pf=1 |
jnp | pf=0 |
jpo | pf=0 |
jz | zf=1 |
je | zf=1 |
jnz | zf=0 |
jne | zf=0 |
js | sf=1 |
jns | sf=0 |
jo | of=1 |
jno | of=0 |
指令 | 条件 |
jg | > |
jl | < |
je | = |
jge | >= |
jle | <= |
jng | <= |
jnl | >= |
jnle | > |
jnge | < |
指令 | 条件 |
ja | > |
jb | < |
je | = |
jae | >= |
jbe | <= |
jna | <= |
jnb | >= |
jnae | < |
jnbe | > |
CMP 比较两个操作数
cmp 目标操作数,源操作数—>功能:比较两个操作数,相当于SUB指令结果丢弃,影响标志位
目标操作数—> r/m
源操作数—> imm/r/m
leb:
mov eax,0x5
mov edx,0x4
cmp eax,edx
jae leb
TEST 逻辑比较
test 目标操作数,源操作数—>功能:相当于AND指令(CF OF标志清零),根据结果设置PF SF ZF
目标操作数—> r/m
源操作数—> imm/r/m
leb:
//案例1
mov eax,0x1
mov ecx,0x1
test eax,ecx
//案例2
mov eax,0x800000000
xor eax,0x4
jnc leb
CMOVCC 条件移动 类似JCC指令系列
cmovcc 目标操作数,源操作数—>条件移动
目标操作数—> r
源操作数—> r/m
mov ax,0xffff
mov cx,0x2222
cmovg ax,cx
SETCC 按条件设置字节 类似JCC指令系列
setcc 目标操作数—>功能:标志位满足条件,将目标操作数设置为 0 或 1。
目标操作数—> r/m
mov al,0xff
add al,0x2
setc cl
MOVS系列 数据从字符串移到字符串
movs 目标操作数(m8/m16/m32),源操作数(m8/m16/m32) (ESI和EDI地址不能相同)
目标操作数—> [ EDI ]
源操作数—>[ ESI ]
movsd—>ESI和EDI同时加4(看DF位)在把dword ptr ds:[ESI]—->dword ptr ds:[EDI]
movsw—>ESI和EDI同时加4(看DF位)在把word ptr ds:[ESI]—->word ptr ds:[EDI]
movsb—>ESI和EDI同时加4(看DF位)在把byte ptr ds:[ESI]—->byte ptr ds:[EDI]
如果 DF 标志为 0,则 (E)SI 与 (E)DI 寄存器递增)
如果 DF 标志为 1,则 (E)SI 与 (E)DI 寄存器递减)
mov esi,0x0012FD84
mov edi,0x0012FDB8
mov dword ptr ds:[esi],0x12345678
mov dword ptr ds:[edi],0x11111111
movsd
movs dword ptr ds:[edi],dowrd ptr ds:[esi] //MOVSD分解
add esi,0x4
add edi,0x4
CLD 清除方向标志
cld—>功能:DF 标志 清除为0
mov esi,0x0012FD84
mov edi,0x0012FDB8
mov dword ptr ds:[esi],0x12345678
mov dword ptr ds:[edi],0x11111111
cld
movsd
STD 设置方向标志
std—>功能:DF 标志设置为 1
mov esi,0x0012FD84
mov edi,0x0012FDB8
mov dword ptr ds:[esi],0x12345678
mov dword ptr ds:[edi],0x11111111
std
movsd
STOS系列 存储字符串
stosd stosw stosb 目标操作数(源操作数默认操作 EAX AX AL)
目标操作数—>[ EDI ]
stosb—>al—>byte ptr ds:[EDI] (看DF位)EDI+1或EDI-1
stosw—>al—>word ptr ds:[EDI] (看DF位)EDI+2或EDI-2
stosd—>al—>dword ptr ds:[EDI] (看DF位)EDI+4或EDI-4
如果 DF 标志为 0,则 (E)SI 与 (E)DI 寄存器递增)
如果 DF 标志为 1,则 (E)SI 与 (E)DI 寄存器递减)
mov eax,0x12345678
mov edi,0x0012FF34
stosd
mov dword ptr ds:[edi],eax //stosd 分解
add edi,0x4
REP 重复指令 注意(MOVS和STOS以上指令配套使用)
rep —> 功能:重复操作,看ECX值。 依赖ECX ECX=0 结束
重复前缀 | 终止条件 1 | 终止条件 2 |
REP | ECX=0 | 无 |
REPE/REPZ | ECX=0 | ZF=0 |
REPNE/REPNZ | ECX=0 | ZF=1 |
//rep stosd 案例
mov edi,0x0012FE70
mov eax,0x11111111
mov ecx,0x10
rep stosd
//rep movsd 案例
mov esi,0x0012FE30
mov edi,0x0012FE34
mov dword ptr ds:[esi],0x11111111
mov dword ptr ds:[edi],0x22222222
mov ecx,0x10
rep movsd
标志寄存器
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
OF | DF | IF | TF | SF | ZF | AF | PF | CF |
- 第1组6个标志位 CF PF AF ZF SF OF 称为运算结果标志,主要受加减运算和逻辑运算结果的影响。
- 第2组3个标志位 TF IF DF 称为状态控制标志。
- 空是保留的。
CF进位标志:主要用于反映运算是否产生进位或借位。如果运算结果的最高位,产生进位或借位,CF = 1 否则 CF = 0。
0010 0000 001 0<---CF
mov al,0xff
add al,0x1
PF 奇偶标志:运算结果中 1 的个数,如果 1 的个数为偶数(二进制位限制8位) PF = 1 否则 PF = 0。
0010 0000 0 0<--PF 1 0
mov al,0x2
add al,0x8
AF辅助进位标志:低半字节向高半字节产生进位或借位 AF = 1 否则 AF = 0。(注意)
0010 000 0<--AF 0 0 1 0
mov al,0x8
add al,0x8
ZF 零标志:反映运算结果是否为0,如果运算结果为0 ZF = 1 否则 ZF = 0。
0010 0 0<--ZF 0 0 0 0 1 0
mov eax,0x8
sub eax,0x8
SF 符号标志:运算结果最高位为1 SF = 1 否则 SF = 0。
0010 0<--SF 0 0 0 0 0 1 0
mov al,0xff
sub al,0x0
OF 溢出标志:用于有符号加减运算中,如果运算结果字节(大于0x7f-小于0x80)字(大于0x7fff-小于0x8000)双字(大于0x7fffffff-小于0x80000000)大于或者小于 OF=1 否则OF=0
处理器计算两种数据类型的结果。并分别设置OF 与 CF标志以表示有符号或无符号结果的进位。SF标志表示有符号结果的符号。
0<--OF 0 1 0 0 0 0 0 0 0 1 0
mov al,0x7f
add al,0x1
mov al,0x80
add al,0xff
DF 方向标志
IF 中断允许标志
TF 追踪标志
函数框架
函数构成
- 函数的类型—> 决定了返回值
- 函数的名字
- 函数的参数—>参数可以有很多个
- 函数的返回值
int main(int argc, char* argv[])
{
//;--->变量,语法,数据类型
int c;//类型 类型名字;反汇编:dword ptr ds:[ebp-0x4]
return 0;
}
//int-->代表函数的类型(函数返回类型) //main-->函数的名字 //()-->阔号代表参数 //return 0;--->代表返回值
//dword word byte int char short long void 空类型--->没有返回值
函数框架与堆栈图
0012FEE0 0x0012FF80 edi ---》恢复EDI
0012FEE4 0x7C939B3F esi ---》恢复ESI
0012FEE8 0x0012FEE8 ebx ---》恢复EBX
0012FEEC 0xCCCCCCCC ---》sub esp-0x40
0012FEF0 0xCCCCCCCC
0012FEF4 0xCCCCCCCC
0012FEF8 0xCCCCCCCC
0012FEFC 0xCCCCCCCC
0012FF00 0xCCCCCCCC
0012FF04 0xCCCCCCCC
0012FF08 0xCCCCCCCC
0012FF0C 0xCCCCCCCC
0012FF10 0xCCCCCCCC
0012FF14 0xCCCCCCCC
0012FF18 0xCCCCCCCC
0012FF1C 0xCCCCCCCC
0012FF20 0xCCCCCCCC
0012FF24 0xCCCCCCCC
0012FF28 0xCCCCCCCC
0012FF2C 0x0012FF80 ebp ---》恢复EBP
0012FF30 0x0040106D 下一条指令地址
0012FF34 esp
//函数头
00401020 push ebp --->保存EBP
00401021 mov ebp,esp --->保存ESP
00401023 sub esp,0x40
00401026 push ebx --->保存EBX
00401027 push esi --->保存ESI
00401028 push edi --->保存EDI
00401029 lea edi,dword ptr ds:[ebp-0x40]
0040102C mov ecx,0x10
00401031 mov eax,0xCCCCCCCC
00401036 rep stosd 以上三条指令都在为本条指令做准备
//函数尾
0040103A pop edi ---》恢复EDI
0040103B pop esi ---》恢复ESI
0040103C pop ebx ---》恢复EBX
0040103D mov esp,ebp ---》恢复ESP
0040103F pop ebp ---》恢复EBP
00401040 ret
保存顺序:ebp esp ebx esi edi
恢复顺序:edi esi ebx esp ebp
为什么减0x40?
sub esp,0x40
- 函数跟函数之间方便隔开
- 参数(因为他觉得16个参数够了)
- 因为是16进制每一项4个字节刚好是40
- 为什么赋值是CCCCCCCC 为了安全 防止出错 因为CCC是INT3 断点
怎么画堆栈图:谁改变ESP这段内存就把谁记录下来
只要调用函数都会产生 _chkesp()
检查堆栈平衡
只要是函数肯定用到call
指令
_declspec(naked)
裸汇编 自己生成函数头 函数尾
word特殊之处
因为word
比较特殊,因为内存是4个字节4个字节对齐,如果我用内存的话4个对齐,首先从2个字节扩展成4个字节,扩展完了还要进行对齐 所以说这样比较麻烦,编译器干脆把word
这种类型把他放到全局变量就是short
这种 2个字节的数据 放到全局变量里面 我直接从这个地址,我把全局变量的地址记录下来,然后从这个地址中去取(word
是放到堆里面,运行速度快)
参数存放位置
参数是从右往左push
最左边是第一个参数 最右边的最后一个
参数是放到[EBP+0x8]
位置 第1个参数放到[EBP+0x8]
第2个参数放到[EBP+0xC]
第3个参数放到[EBP+0x10]
依此类推
int fun(int a, int b, int c)
{
return 0;
}
fun(1,2,3);
//反汇编 fun(1,2,3);
00401068 6A 03 push 3
0040106A 6A 02 push 2
0040106C 6A 01 push 1
0040106E E8 9C FF FF FF call @ILT+10(fun) (0040100f)
00401073 83 C4 0C add esp,0Ch //外平栈
变量存放位置
放到EBP-0x4
这段内存里面第1个变量放到[EBP-0x4]
第2个变量放到[EBP-0x8]
第3个变量放到[EBP-0xC]
依此类推
返回值
函数返回值是放到EAX
这个寄存器里面的
逆向三要素
- 变量
- 返回值
- 参数
暂无评论内容