x86 汇编语言核心知识整理

【什么是汇编】:汇编就是寄存器跟寄存器,寄存器跟内存,内存跟寄存器之间来回移动数据。没有内存跟内存 如果要操作有特殊的指令操作。(所以指令都是操作内存跟寄存器)

寄存器详解

通用寄存器

x86架构提供了8个32位通用寄存器,每个寄存器都有特定的用途:

编号32位16位8位用途
0EAXAXAL累加
1ECXCXCL计数
2EDXDXDL数据
3EBXBXBL基址
4ESPSPAH堆栈(栈顶)
5EBPBPCH堆栈(栈底)
6ESISIDH字符串
7EDIDIBH字符串

ESP和EBP用于管理函数调用堆栈,不可随意修改,否则会导致堆栈失衡,引发错误。

寄存器之间关系图

图片[1]-x86 汇编语言核心知识整理-萝莉猫博客

特殊寄存器

EIP:指令指针寄存器,存储下一条要执行的指令地址
EFLAGS:标志寄存器,存储CPU运行状态标志

段寄存器

段寄存器是96位的,包含选择子、属性、基址和界限:

struct	Sengment//96
{
	WORD Selector//选择子
	WORD Attributes//属性
	DWORD Base//基址
	DWORD Limit//界限
}
编号段寄存器扩展用途
0ESESI、EDI 字符串操作
1CSEIP 指令指针
2SSESP、EBP 堆栈操作
3DS通用数据段
4FS特殊用语
5GS特殊用语
6LDTR
7TR

标志寄存器

1514131211109876543210
OFDFIFTFSFZFAFPFCF

标志寄存器共两组标志位:运算结果标志、状态控制标志。

运算结果标志

CF进位标志:运算结果最高位产生进位或借位,CF=1 否则 CF=0

CF进位标志 例子

0010 0000 001 0<-CF

mov al,0xff
add al,0x1

PF奇偶标志:运算结果中1的个数,如果1的个数为偶数(二进制位限制八位) PF=1 否则 PF=0

PF奇偶标志 例子

0010 0000 0 0<PF 1 0

mov al,0x2
add al,0x8

AF辅助进位标志:低半字节向高半字节产生借位或进位,AF=1 否则 AF=0

AF辅助进位标志 例子

0010 000 0<–AF 0 0 1 0

mov al,0x8
add al,0x8

ZF零标志:反映运算结果是否为零,如果运算结果为零,ZF=1 否则 ZF=0

ZF零标志 例子

0010 0 0<–ZF 0 0 0 0 1 0

mov eax,0x8
sub eax,0x8

SF符号标志:运算结果最高位为1,SF=1 否则 SF=0

SF符号标志 例子

0010 0<–SF 0 0 0 0 0 1 0

mov al,0xff
sub al,0x0

OF溢出标志:用于有符号加减运算中,如果运算结果字节(大于0x7f-小于0x80)、字(大于0x7fff-小于0x8000)、双字(大于0x7fffffff-小于0x8000000)大于或者小于,OF=1 否则 OF=0

OF溢出标志 例子

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

状态控制标志

TF追踪标志:控制单步执行

IF中断允许标志:控制中断响应

DF方向标志:控制字符串操作方向,0为递增,1为递减

数据类型

无符号类型

类型大小说明
QWORD8字节四字
FWORD6字节六个字节
DWORD4字节双字、32位
WORD2字节字、16位
BYTE1字节字节、8位

有符号类型(C语言)

  • int:4字节
  • long:4字节
  • short:2字节
  • char:1字节

浮点类型(C语言)

  • float:4字节
  • double:8字节

内存操作

内存格式与书写方式

[ ] 内存是由两个框号代表的 可以是寄存器,立即数。

                                       dis32
mov eax,dword ptr ds:[ ebx+ecx * 1 + 0x12345678]      
							  2
							  4
							  8
							     
//ebx-->基址   ecx-->INDEX s索引  0x12345678-->偏移 
//内存里面寄存器都是32位因为内存数据都是4个字节 4个字节对齐

ds-->段寄存器	ptr-->指针	dword-->4个字节

为什么是1 2 4 8 因为2的二次方 

//读内存
mov eax,0x0012ff34
mov ecx,dword ptr ds:[eax]  

// 写内存
mov eax,0x0012ff34
mov dword ptr ds:[eax],ecx 

内存是4个字节4个字节对齐、4G空间 2的32次方刚好4G

汇编书写格式(C/C++语言)

_asm//汇编格式
{
  //这里只能写汇编指令
}

汇编指令集

如何分辨参数

看到MOV r/m8,r8 r代表register m代表memory r8代表8位寄存器

imm代表立即数 r代表寄存器 m代表内存

ib—byte imm(imm8)

iw—word imm(imm16)

id—dword imm(imm32)

0xC0000005 内存访问错误

数据只有反复利用才会产生意义,只要执行指令EIP都会发生变化因为EIP就是指令指针

MOV 移动指令

mov 目标操作数,源操作数—>源操作数移动到目标操作数

目标操作数:r、m

源操作数:r、m、imm

mov ecx,0x11111111
mov eax,0x22222222
mov eax,ecx

ADD 加法指令

add 目标操作数,源操作数—>目标操作数 + 源操作数 把结果放到目标操作数

目标操作数:r、m

源操作数:r、m、imm

mov eax,0x12345678
mov ecx,0x11111111
add eax,ecx

SUB 减法指令

sub 目标操作数,源操作数—>目标操作数 – 源操作数 把结果放到目标操作数

目标操作数:r、m

源操作数:r、m、imm

mov eax,0x12345678
mov ecx,0x11111111
sub  eax,ecx

INC 自加一指令

inc 目标操作数—>目标操作数加一

目标操作数:r、m

mov al,0x1
inc  al

DEC 自减一指令

dec 目标操作数—>目标操作数减一

mov al,0x1
dec  al

LEA 获取内存地址

lea 目标操作数,源操作数—>获取内存地址

目标操作数:必须R16、R32寄存器

源操作数:必须m内存

mov ecx,dword ptr ds:[eax] 
lea edx, dword ptr ds:[eax]--->mov edx,eax 值是一样的

MOV 和 LEA指令的区别

  • mov 是获取内存地址里面的内容
  • lea 是获取内存地址

PUSH 把值压入堆栈

push 目标操作数—>功能:压栈 。分解成两条指令,即使同时改变寄存器也改变内存

目标操作数:r、m、imm、Seg

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 目标操作数—>功能:将值弹出堆栈

目标操作数:r、m、Seg

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

mov eax,0x11111111
xchg eax,dword ptr ds:[esp]

NOP 无操作

MUL 无符号乘法

mul 源操作数—>目标操作数 × 源操作数 执行无符号乘法。结果存储到 AX、DX:AX 或 EDX:EAX 寄存器。(取决于操作数的大小)

目标操作数:AL、AX、EAX(取决于操作数的大小)

源操作数:r、m

操作数大小目标操作数源操作数目标操作数结果
字节ALr/m8AX
AXr/m16DX:AX
双字EAXr/m32EDX:EAX
mov al,0x8
mov cl,0x2
mul cl 

IMUL 有符号乘法

  • 单操作数形式

imul 源操作数—>目标操作数 × 源操作数 执行有符号乘法。结果存储到 AX、DX:AX 或 EDX:EAX 寄存器。(取决于操作数的大小)

目标操作数:AL、AX、EAX(取决于操作数的大小)

源操作数:r、m

mov al,0x8
mov cl,0x2
imul cl 
  • 双操作数形式

imul 目标操作数,源操作数—>目标操作数 × 源操作数 结果存储到目标操作数

目标操作数:r、m

源操作数:r、m、imm

mov cx,0xf
mov dx,0x2
imul cx,dx
  • 三操作数形式

imul 目标操作数,源操作数1,源操作数2—>源操作数1 × 源操作数2 结果存储到目标操作数

目标操作数:r

源操作数1:r、m

源操作数2:imm

mov ax,0x0000
mov cx,0x2222
imul ax,cx,0x2

DIV 无符号除法

div 源操作数—>目标操作数 ÷ 源操作数 结果存储到 AX (AH:AL)、DX:AX 或 EDX:EAX 寄存器。(取决于操作数大小)

目标操作数:AX、DX:EAX、EDX:EAX(取决于操作数大小)

源操作数:r、m

操作数大小被除数除数余数商的范围
字/字节AXr/m8ALAH-128 到 +127
双字/字DX:AXr/m16AXDX-32,768 到 +32,767
四字/双字EDX:EAXr/m32EAXEDX-231 到 232 – 1
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 源操作数—>目标操作数 ÷ 源操作数 结果存储到 AX (AH:AL)、DX:AX 或 EDX:EAX 寄存器。(取决于操作数大小)

目标操作数:AX、DX:EAX、EDX:EAX(取决于操作数大小)

源操作数:r、m

mov ax,0xff
mov cx,0x2
cwd
idiv cx

CDQ CWD CBW 符号扩展

按高位扩展最高位是为几那就扩展成几

CDQ: EAX—>EDX:EAX(4字节转化8字节)

CWD:AX—>DX:AX(2字节转化4字节)

CBW:AL—>AX(1字节转化2字节)

ADC 带进位加法

adc 目标操作数,源操作数—>目标操作数+源操作数,如果CF进位标志是1,加法结果递增1,然后存储到目标操作数

目标操作数:r、m

源操作数:r、m、imm

mov ax,0xffff
add ax,0x1
mov cx,0x1
adc cx,0x1

SBB 带借位整数减法

sbb 目标操作数,源操作数—>源操作数+CF进位标志-目标操作数,结果存储目标操作数

目标操作数:r、m

源操作数:r、m、imm

mov ax,0xffff
add ax,0x1
mov cl,0x8
mov al,0x3
SBB cl,al

DAA 加之后AL十进制调整

执行ADD后对AL进行十进制调整(0-F),用于在BCD(二进制编码的十进制)加法运算后,将AL寄存器中的结果调整为标准BCD格式。

调整规则(处理器内部自动判断)

  1. 如果AL的低4位 > 9 或 AF = 1,则AL = AL + 6,并置AF = 1
  2. 如果AL的高4位 > 9 或 CF = 1,则AL = AL + 60H,并置CF = 1
MOV AL, 0x35   ; AL = 35H(十进制35的BCD)
ADD AL, 0x47   ; AL = 7CH(35+47=7C,但7C不是有效BCD)
DAA            ; 调整后:AL = 82H(35+47=82,正确BCD),CF=0

DAS 减之后AL十进制调整

执行SUB后对AL进行十进制调整(0-F),用于在BCD(二进制编码的十进制)减法运算后,将AL寄存器中的结果调整为标准BCD格式。

调整规则(处理器内部自动判断)

  1. 如果 AL 的低4位 > 9 或 AF = 1,则 AL = AL – 6,并置 AF = 1
  2. 如果 AL 的高4位 > 9 或 CF = 1,则 AL = AL – 60H,并置 CF = 1
MOV AL, 0x85   ; AL = 85H(十进制85的BCD)
SUB AL, 0x47   ; AL = 3EH(85-47=3E,但3E不是有效BCD)
DAS            ; 调整后:AL = 38H(85-47=38,正确BCD),CF=0

AAA 加之后 ASCII 调整

AL​ 寄存器中的值(由加法指令如 ADDADC得到的结果)进行调整,使其成为正确的非压缩BCD(即高4位为0,低4位为十进制数字0–9)。

调整规则

1. 如果 AL 的低4位 > 9 或 AF = 1,则:

  • AL = AL + 6
  • AH = AH + 1
  • AF = 1
  • CF = 1

2. 否则 AF = 0,CF = 0。

3. 无论何种情况,AL 的高4位被清零(AL = AL & 0x0F)。

MOV AX, 0x0105  ; AH=01, AL=05(非压缩BCD数字5)
ADD AL, 0x39    ; AL = 05 + 39 = 3E(对应ASCII '9'的值为39H)
AAA             ; 调整后:AL = 04, AH = 02, CF=1, AF=1
                ; 结果表示十进制 5 + 9 = 14,调整后 AH=1(进位)变为2,AL=4

AAS 减之后 ASCII 调整

AL​ 寄存器中的值(由减法指令如 SUBSBB得到的结果)进行调整,使其成为正确的非压缩BCD(高4位为0,低4位为十进制数字0–9)。

调整规则

  1. 如果 AL 的低4位 > 9 或 AF = 1,则:
    • AL = AL – 6
    • AH = AH – 1
    • AF = 1
    • CF = 1
  2. 否则 AF = 0,CF = 0。
  3. 无论何种情况,AL 的高4位被清零(AL = AL & 0x0F)。
MOV AX, 0x0208  ; AH=02, AL=08(非压缩BCD数字8)
SUB AL, 0x35    ; AL = 08 - 35 = D3(借位发生)
AAS             ; 调整后:AL = 03, AH = 01, CF=1, AF=1
                ; 结果表示十进制 28 - 5 = 23,调整后 AH 从2借位变为1,AL=3

JMP 跳转指令

jmp 目标操作数—>改变EIP寄存器,相当mov eipeip 不能随意修改,除法英特尔提供特殊指令)

目标操作数:r、m、imm

	lea ecx,lab
	jmp ecx
lab:
	mov  eax,0x12345678

LAB 标签

	lea ecx,lab
	jmp ecx
lab:
	mov  eax,0x12345678

CALL 调用过程

call 目标操作数—>调用过程 先push 后jmp

call edx
push IL	//esp+len(il)下一条指令的地址-->当前EIP+本条指令的长度
jmp edx

call edx

lea eax,leb
push eax
jmp edx

leb:
mov eax,0x0

RET 从过程返回

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的下一条指令

JCC 条件跳转指令

jcc 目标操作数—>立即数(地址)

根据标志位状态决定是否跳转:

指令条件说明
JZ、JEZF=1等于零/相等跳转
JNZ、JNEZF=0不等于零/不相等跳转
JSSF=1符号为负跳转
JNSSF=0符号为正跳转
JOOF=1溢出跳转
JNOOF=0无溢出跳转
JP、JPEPF=11的数为偶数跳转
JNP、JPOPF=01的个数不为偶尔跳转
JCCF=1有进位跳转
JNCCF=0无进位跳转

根据比较决定跳转:

指令说明
JG、JNLE>(有符号)
JL、JNGE<(有符号)
JGE、JNL>=(有符号)
JLE、JNG<=(有符号)
JE=(有符号、无符号)
JA、JNBE>(无符号)
JB、JABE<(无符号)
JAE、JNB>=(无符号)
JBE、JNA<=(无符号)

CMP 比较两个操作数

cmp 目标操作数,源操作数—>功能:比较两个操作数,相当于SUB指令,结果丢弃,设置标志位

目标操作数:r、m

源操作数:r、m、imm

leb:
mov eax,0x5
mov edx,0x4
cmp eax,edx
jae leb

TEST 逻辑比较指令

test 目标操作数,源操作数—>功能:相当于AND指令(OF CF标志清零),根据结果设置PF ZF SF

目标操作数:r、m

源操作数:r、m、imm

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、m8

mov al,0xff
add al,0x2
setc cl

MOVS系列 数据从字符串移到字符串

movs 目标操作数,源操作数—>将 [源操作数] 移动到 [目标操作数] (ESI和EDI 地址不能相同)

目标操作数:[EDI]

源操作数:[ESI]

movsb m8,m8—>MOVSB 字节移动(ESI和EDI同时加4还是减4(看DF位)再把dword ptr ds:[ESI]—>dword ptr ds:[EDI])

movsw m16,m16—>MOVSW 字移动(ESI和EDI同时加2还是减2(看DF位)再把word ptr ds:[ESI]—>word ptr ds:[EDI])

movsd m32,m32—>MOVSD 双字移动(ESI和EDI同时加1还是减1(看DF位)再把byte ptr ds:[ESI]—>byte ptr ds:[EDI])

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分解
//看DF是减还是加
add esi,0x4
add edi,0x4

CLD 清除方向标志

cld—>功能:DF标志清零

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系列 存储字符串

stos—>将AL、AX、EAX 移动到[EDI]内存里

目标操作数:[EDI]

stosb al—>byte ptr ds:[edi] (看DF位) EDI+1还是EDI-1

stosw ax—>word ptr ds:[edi](看DF位) EDI+2还是EDI-2

stosd eax—>dword ptr ds:[edi](看DF位) EDI+4还是EDI-4

mov eax,0x12345678
mov edi,0x0012FF34
stosd

mov dword ptr ds:[edi],eax	//stosd 分解
add edi,0x4

REP 重复指令

rep—>功能:重复操作,看ECX值。 依赖ECX ECX=0 结束

重复前缀终止条件 1终止条件 2
REPECX=0
REPE/REPZECX=0ZF=0
REPNE/REPNZECX=0ZF=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

逻辑指令

  1. 位与位之间没有任何联系
  2. 不进位,取最大值

OR 或运算

or 目标操作数,源操作数—>结果存储目标操作数 。算加法两个操作数对应的位有一个1就为1,否则为0。C语言符号(|)

目标操作数:r、m

源操作数:r、m、imm

mov al,0x8
mov cl,0x9
or al,cl

目标操作数	1000
源操作数	 1001
运算结果	 1001

AND 与运算

and 目标操作数,源操作数—>结果存储目标操作数。算乘法两个操作数对应的位为1 才为1,否则为0。C语言符号(&)

目标操作数:r、m

源操作数:r、m、imm

mov al,0x5
mov cl,0x6
and al,cl

目标操作数:0101
源操作数:  0110
运算结果:  0100

XOR 异或

xor 目标操作数,源操作数—>结果存储目标操作数,两个操作数对应的位相同为0,不同为1。C语言符号(^)

目标操作数:r、m

源操作数:r、m、imm

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 、SHR 右移指令

sar、shr 目标操作数,源操作数—》对目标操作数 ÷ 2的幂(源操作数) 结果存储目标操作数

目标操作数:r、m

源操作数:imm8、CL

mov al,0x8
mov cl,0x2
sar al,cl

SAL、SHL 左移指令

sal、shl 目标操作数,源操作数—》对目标操作数 × 2的幂(源操作数) 结果存储目标操作数

目标操作数:r、m

源操作数:imm8、CL

mov al,0x4
shl al,0x1

函数框架

函数构成

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 空类型--->没有返回值
  •  函数类型:决定返回值类型
  • 函数名字:标识符
  • 函数参数:可以有多个,从右往左push
  • 函数返回值:通过EAX寄存器返回

函数头(标准框架)

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

函数堆栈图:

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

为什么减0x40?sub esp,0x40

  1. 函数跟函数之间方便隔开
  2. 参数(因为他觉得16个参数够了)
  3. 因为是16进制每一项4个字节刚好是40
  4. 为什么赋值是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这个寄存器里面的

逆向三要素

  1. 参数
  2. 变量
  3. 返回值

VC6调试快捷键

快捷键功能
F7编译
F9设置/取消断点
F5运行到断点处
F10步过(Step Over)
F11步入(Step Into)
Shift+F5退出调试
Alt+8查看反汇编
F12转到定义处

双斜杠代表注释 斜杠+星范围之间全部注释

int main()
{
 int a;
 int b;

 //a = 1;

 /*b = a++;
 b++;
 */
 return 0;
}
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容