逆向入门(5)汇编学习————80X86指令系统

本文详细介绍了x86指令系统的基本概念,包括指令、指令格式和操作数。重点讲解了数据指令,如mov、movzx/movsx、xchg、xlat、push/pop等,阐述了它们的功能和使用场景。此外,还涵盖了算术运算指令,如add、sub、inc、dec、imul、div/idiv,以及控制转移指令,如 jmp、jxx、loop 等,详述了这些指令在程序流程控制中的作用。
摘要由CSDN通过智能技术生成

一.基本概念

1.指令:或称为语句,规定计算机执行某种操作的代码;汇编程序中最小的代码单元。
2.指令系统:cpu能够识别的所有指令集合;
3.操作数的不同(位数/浮点数),工作模式的不同(实模式/保护模式),向下兼容;
4.指令格式:源程序中指令格式/符号指令:
[name:] operation operand [; comment]
[标号:] 助记符 操作数1,操作数2,……;注释
标号:表示一个地址,本条指令的保存位置,可以作为跳转指令的操作数。可选
助记符(operation):表示指令功能,也称为操作码,一般用表明指令功能的英语单词或其缩写表示。
5.操作数:表示指令操作数,操作数可以是0个(默认指定操作数) /1个/2个/……
两个操作数,左边→目的操作数 右边→源操作数
注释:分号开头,指令的说明。
分隔符:各个部分之间使用空格分隔。
续行符: “\”,在多行写1条指令。
注意:指令中不能使用任意中文符号。不区分大小写。
令格式:指令编码格式:操作码 + 操作数/地址码
操作码:指令实现的功能
操作数/地址码:指令的数据
mov ax,1234h → B83412
mov ax,[1234h] → A13412
in al,10h → E410

二.数据指令传送

1.概念

数据搬运工,实现数据在各个设备、保存位置之间传递。一次传送,数据大小可以是8/16/32位。
指令对标志位的影响:除SAHF和POPF/POPFD指令外,执行其他指令对标志位没有影响。
在这里插入图片描述

2.mov-通用数据传送指令

指令格式: mov dest, src
指令功能:复制源操作数传送给目的操作数
mov reg, reg ;寄存器→寄存器
mov mem, reg ;寄存器→内存单元
mov reg, mem ;内存单元→寄存器
mov mem, imm ;立即数→内存单元
mov reg, imm ;立即数→寄存器
注意问题:
dest不能够是CS、EIP和IP
两个操作数不能同为内存操作数(mem),不能同为段寄存器(seg)
立即数不能直接送段寄存器(seg)
dest和src操作数位数必须相同,如果无法确定传送数据位数,要使用ptr进行说明
小尺寸操作数复制到大尺寸操作数中的问题:前补0。

3.movzx/movsx-数据扩展传送指令

指令格式: movzx/movsx dest, src
指令功能:src做Z/S扩展,复制扩展后的src给目的操作数; IA-32的cpu使用。
Z扩展:在操作数的高位补0,zero扩展,无符号操作数扩展
1a2bh→00001a2bh ;操作数16位扩展为32位
S扩展:在操作数的高位补符号位取值,signal扩展,带符号操作数扩展
1a2bh→00001a2bh ;操作数16位扩展为32位
0a1b2h→0ffffa1b2h ;操作数16位扩展为32位
src可以是8/16位的寄存器或内存操作数,而dest必须是16/32位的寄存器操作数
movsx eax,cl
movzx dx,al
movsx edx,[edi]

4.xchg-交换指令

指令格式: xchg dest, src
指令功能:src与dest互换,互换只能在在寄存器操作数之间或寄存器与内存操作数之间进行;
xchg reg, reg ;寄存器 与 寄存器
xchg mem, reg ;内存 与 寄存器
xchg reg, mem ;寄存器 与 内存
注意问题:
段寄存器不能作为操作数
不能直接交换两个内存操作数
AX=2000H,DS=3000H,BX=1800, (31A00H)=1995H
实模式下执行指令XCHG AX,[BX+200H]后,
AX=1995H, (31A00H)=2000H

5.xlat-查表指令

指令格式: xlat
指令功能:将ds:[bx+al]指定位置的内存单元中数据传送到al寄存器。
xlat指令常用于获取表结构(数组)中的一个数据,使用方法:
在内存段中建立一个ASCII码表;
将表首逻辑地址传送给DS:BX/EBX;
将要获取的表结构中的数据相当于表首的偏移量传送给AL;
执行xlat指令,获取表中选的的数据;

6.PUSH/POP-进栈/出栈指令

指令格式: push/pop src/dest
指令功能:
push指令将16/32位数据src压入栈顶位置。
pop指令将16/32位栈顶位置数据弹出到dest。
push指令的执行过程:
修改堆栈栈顶指针:src是16位操作数,sp=sp-2; src是32位操作数,sp=sp-4;
src→ss:sp ;16/32位操作数压入ss:sp指定的栈顶位置;
pop指令的执行过程:
ss:sp→dest; ss:sp指定的栈顶位置16/32位操作数弹出到dest;
修改堆栈栈顶指针: dest是16位操作数,sp=sp+2;dest是32位操作数,sp=sp+4;

7.PUSHA/PUASHAD-通用寄存器进栈指令

指令格式: pusha/pushad
指令功能: IA-32的cpu使用
pusha:将8个16位通用寄存器中数据送到堆栈的栈顶位置。
pushad:将8个32位通用寄存器中数据送到堆栈的栈顶位置。
pusha指令的执行过程:
修改堆栈栈顶指针:sp=sp-16;
在16个当前堆栈栈顶位置依次压入 AX,CX,DX,BX,指令执行前的SP,BP,SI,DI
pushad指令的执行过程:
修改堆栈栈顶指针:sp=sp-32;
在32各当前堆栈栈顶位置一次压入 EAX,ECX,EDX,EBX,指令执行前的ESP,EBP,ESI和EDI

8.POPA/POPAD-通用寄存器出栈指令

指令格式: popa/popad
指令功能: IA-32的cpu使用
popa:将堆栈的栈顶指针ss:sp指定的16个内存单元中的数据送到8个16位通用寄存器。
popad:将堆栈的栈顶指针ss:sp指定的32个内存单元中的数据送到8个32位通用寄存器。
popa指令的执行过程:
将ss:sp指定的16个内存单元中的数据依次送入8个16位通用寄存器DI,SI,BP,SP,BX,DX,CX,AX
修改堆栈栈顶指针:sp=sp+16;
popad指令的执行过程:
将ss:sp指定的32个内存单元中的数据依次送入8个32位通用寄存器EDI,ESI,EBP,ESP,EBX,EDX,ECX,EAX
修改堆栈栈顶指针:sp=sp+32;

9.LAHF/SAHF-标志位数据(低8位)传送指令

指令格式: lahf/sahf
指令功能:
lahf:将标志寄存器中最低8位数据传送到AH寄存器。
sahf:将AH寄存器中数据传送到标志寄存器最低8位。
在这里插入图片描述

10.PUSHF/PUSHFD-标志位数据进栈指令

指令格式: pushf/pushfd
指令功能: IA-32的cpu使用
pushf:将16位标志寄存器中数据送到堆栈的栈顶位置。
pushfd:将32位标志寄存器中数据送到堆栈的栈顶位置。
pushf指令的执行过程:
修改堆栈栈顶指针:sp=sp-2;
16位标志寄存器数据压入当前堆栈栈顶位置
pushfd指令的执行过程:
修改堆栈栈顶指针:sp=sp-4;
32位标志寄存器数据压入当前堆栈栈顶位置

11.POPF/POPFD-标志位数据出栈指令

指令格式: popf/popfd
指令功能: IA-32的cpu使用
popf:将堆栈栈顶位置保存16位数据送入16位标志寄存器。
popfd:将堆栈栈顶位置保存32位数据送入32位标志寄存器。
popf指令的执行过程:
将ss:sp指定的2个内存单元中的数据送到16位标志寄存器
修改堆栈栈顶指针:sp=sp+2;
popfd指令的执行过程:
将ss:sp指定的4个内存单元中的数据送到32位标志寄存器
修改堆栈栈顶指针:sp=sp+4;

12.LEA-取内存操作数保存位置EA地址指令

指令格式: lea r16/r32,mem
指令功能:获取内存操作数mem保存位置的EA地址,传递到r16/r32中。
R16/R32:通用寄存器。 mem:内存操作数。
注意:lea与mov指令的区别。
lea指令传递保存内存操作数位置的EA地址;
mov指令传递内存操作数本身;
SI=1000H,DS=5000H,(51000H)=1234H
LEA BX,[SI] ;执行完该指令后,BX=l000H
MOV BX,[SI] ;执行完该指令后,BX=1234H
下面指令功能等价
LEA BX,TABLE ;用户定义table符号地址
MOV BX,OFFSET TABLE

13.LDS/LES/LSS/LFS/LGS-传送逻辑地址指令

指令格式: lds/les/lss/lfs/lgs r16/r32,mem
指令功能:内存操作数mem是一个逻辑地址类型数据(段地址:偏移地址),将偏移地址传递到r16/r32中,段地址传递到ds/es/ss/fs/gs中。
R16/R32:通用寄存器。mem:内存操作数,一个32位/48位逻辑地址。
注意:lss/lfs/lgs只用于IA-32的cpu。
1:DS=0100H, BX=0020H, (01020H)=0300H, (01022H)=0500H。
执行指令LES DI,[BX] 后,DI=0300H,ES=0500H
2:DS=1200H,(12450H)=0F346H,(12452H)=0A90H。
执行指令LDS SI,DS:[450H] 后,SI=0F346H,DS=0A90H

14.IN/OUT-传送IO数据指令

指令格式:in al/ax,imm8/dx ;输入
指令功能:将端口imm8/dx中一个8/16位数据传送到al/ax中。
指令格式:out imm8/dx,al/ax ;输出
指令功能:将al/ax中一个8/16位数据传送到端口imm8/dx中。
imm8/dx:8位立即数表示端口号(直接端口寻址)或dx中16位数据表示端口号(间接端口寻址) 。
16位:一个端口保存一个8位数据,16位数据保存在连续两个端口中。高端口编号高字节数据。
IN AL,0F1H ;端口0F1H中8位数据传送到AL中
OUT DX,AX ;AX中16位数据传送到DX指定的连续两个端口中

三.算术运算指令

1.概念

机器指令的操作数都是0,1表示的,程序员编写程序使用运算数据:
无符号二进制整数
带符号二进制整数(补码)
无符号压缩十进制整数(8421/5421/2421)
无符号非压缩十进制整数(8421/5421/2421)
计算机执行程序使用运算数据:
add(加)/sub(减):无符号二进制整数
乘/除:区分运算数据为无符号/带符号(补码)二进制整数
则对于计算机给出的add/sub指令的运算结果,程序员理解可能是错误的运算结果。
将add/sub的运算数据理解为无符号二进制整数,将运算后cf标志位取值作为运算结果最高位的取值,结果正确。
将add/sub的运算数据理解为带符号二进制整数,则运算后of标志位=0,结果正确; of标志位=1,结果不正确;

2.ADD/ADC-加法运算指令

指令格式:add/adc dest , src
指令功能:dest→被加数,src→加数
add:dest=dest+src ;半加运算
adc:dest=dest+src+cf当前 ;全加运算
注意:
src/dest操作数不能同时为内存操作数;
dest操作数不能是立即数;
指令执行要影响标志位:CF、OF、PF、SF、ZF和AF。
MOV AL, 5EH MOV BL, 3CH ADD AL, BL

         	 0101  1110               	5EH    =    94
         +  0011  1100     即: +	3CH    =    60
         	 1001  1010              	9AH    =  154
		ZF=0,AF=1,CF=0,SF=1,PF=1,OF=1。

3.XADD-相加并交换指令

指令格式:xadd dest,src
指令功能:486以上cpu使用
dest→被加数,src→加数
1:dest 与 src ;交换
2:dest=dest+src ;半加运算
注意:
源/目的操作数不能同时为内存操作数,目的操作数不能是立即数;
指令执行要影响标志位:CF、OF、PF、SF、ZF和AF。

4.SUB/SBB-减法运算指令指令格式:sub/sbb dest , src

指令功能:dest→被减数,src→减数
sub:dest=dest-src ;半减运算
sbb: dest=dest-src-cf当前 ;全减运算
注意:
源/目的操作数不能同时为内存操作数,目的操作数不能是立即数;
指令执行要影响标志位:CF、OF、PF、SF、ZF和AF。

5.INC/DEC-自加/自减1指令

指令格式:inc/dec dest
指令功能:dest→目的操作数
inc:dest=dest+1/dest++ ;自加1
dec:dest=dest-1/dest-- ;自减1
NEG-求相反数指令
指令格式:neg dest
指令功能:dest→0-dest ;求相反数
注意:
dest为内存操作数,请使用ptr说明是几位操作数(byte/word/dword);
INC WORD PTR[BX]
指令执行要影响标志位:OF、PF、SF、ZF和AF。 不影响CF
inc/dec一般用于循环程序中修改循环次数。
neg指令的dest理解为补码表示的带符号操作数。

6.CMP-比较指令

指令格式:xadd dest,src
指令格式:cmp dest,src
指令功能:比较dest与src的大小,比较后二者取值不改变。
1:做减法,求差(不保存):dest-src
2:设置标志位:=根据差,设置条件标志位
3:在后面的程序中,可以使用设置的条件标志位判断(dest,src)两个数据的大小相等关系:
如果zf=1,dest=src;
如果of=0&&sf=0,dest≥src;
如果of=0&&sf=1,dest<src;

7.CMPXCHG-比较并交换指令

指令格式:cmpxchg dest,src
指令功能:486的cpu使用
1:比较:累加器AC(AL/AX/EAX寄存器)与dest比较
2:AC=dest: ZF←1,(dest) ← (src)
3:AC≠dest: ZF←0,(AC) ← (dest)
注意:
dest可以是寄存器或内存操作数,src只能是寄存器操作数。
分析指令:CMPXCHG CX , DX
1:如果指令执行前:(AX)=2300H,(CX)=2300H,(DX)=2400H
则指令执行后:(AX)= (CX),(CX)=2400H,ZF=1
2:如指令执行前:(AX)=2500H,(CX)=2300H,(DX)=2400H
则指令执行后:(CX)≠(AX),(AX)=2300H,ZF=0

8.CMPXCHG8B-比较并交换8字节指令

指令格式:cmpxchg8b dest
指令功能:486的cpu使用
1:比较:64位隐含操作数(edx,eax)与dest比较
2: (edx,eax) =dest: ZF←1, (dest) ← (edx,eax)
3: (edx,eax) ≠ dest: ZF←0, (edx,eax) ← (dest)
注意:
dest是64位的内存操作数。

9.imul-带符号多操作数乘法指令

指令格式: imul reg,src
指令格式: imul reg,src,imm
指令功能:
1:双操作数:被乘数:reg / 乘数:src

  1. 16位乘法:reg16=reg16×src;
  2. 32位乘法:reg32=reg32×src;
    2:三操作数:被乘数:src / 乘数:imm
  3. 16位乘法:reg16=src×imm;
  4. 32位乘法:reg32=src×imm;
    说明:
    16位乘法的乘积在16位范围之内,或32位乘法的乘积在32位范围之内时,OF=CF=0,否则OF=CF=1,乘积溢出。

10.div / idiv -无符号/带符号除法指令

指令格式:div / idiv src
指令功能:
1:被除数:累加器AC(AX/DX,AX/EAX寄存器)
除数: src
要求:被除数位数必须是除数位数的1倍。
2:AC=AC÷src,,根据除数src位数的不同,商和余数规定如表:
div无符号除法,idiv带符号除法。
在这里插入图片描述
注意:
src可以是寄存器、存储单元,但不能是立即数;
除法运算的商为整数商,位数与除数位数相同。余数位数与除数相同,带符号除法,余数与被除数同号。
为了满足运算结果的规定,被除数位数必须是除数位数的1倍,同时被除数高一半小于除数。
如果不满足上面的要求使用除法运算指令,执行时将产生divide overflow的错误。

三.控制转移指令

1.概念

控制转移指令:修改程序的顺序执行流程。
程序中用于修改IP/EIP取值的指令,以实现程序的选择,循环,分支,函数调用等结构;
无条件转移指令:goto,必须转移;
条件转移指令:根据标志位取值,实现if(选择)结构;
循环控制指令:根据循环次数,实现for(循环)结构;
过程调用指令:实现过程/函数调用及返回;
中断调用指令:实现中断功能调用及返回;
转移类型:
段内转移: near转移,当前执行的指令与下一条要执行的指令在同一个代码段中,转移控制指令修改IP/EIP
段间转移:far转移,当前执行的指令与下一条要执行的指令不在同一个代码段中,转移控制指令修改CS:IP/EIP

2.JMP-无条件转移指令

指令格式:jmp address/标号
指令功能:
程序要执行的下一条指令(目标指令)保存位置=address/标号;无条件跳转到address/标号指定位置继续执行程序。
即:使用address/标号提到的取值去修改ip/eip,从而修改程序的执行流程。
转移类型:
near/近转移方式:address/标号=1个偏移地址
far/远转移方式: address/标号=1个逻辑地址
直接转移: address/标号 是 立即数操作数/寄存器操作数/符号表示的立即数;
间接转移: address/标号 是 内存操作数;
组合:段内直接/段内间接/段间直接/段间间接;

3.JXX-条件转移指令-直接标志转移指令

指令格式:jxx address/标号
指令功能:测试条件xx
如果条件xx成立,转移,目标指令保存位置=address/标号;
如果条件xx不成立,不转移,顺序执行程序;
xx是某个标志位当前取值:CF/ZF/SF/OF/PF;
jc/jnc:测试cf标志位的取值是否为1/0;
jz(je)/jnz(jne):测试zf标志位的取值是否为1/0;
js/jns:测试sf标志位的取值是否为1/0;
jo/jno:测试of标志位的取值是否为1/0;
jp/jnp:测试pf标志位的取值是否为1/0;
注意:
jxx测试1个标志位的取值→直接标志转移;如果转移需要测试多个标志位的取值→间接标志转移;
所有条件转移指令为短转移指令(short transfer),目标指令保存位置与当前指令保存位置距离-128~+127;

4.LOOP/LOOPE/LOOPNE-循环控制指令

指令格式:LOOP/LOOPE/LOOPNE address/标号
指令功能: LOOP/LOOPE/LOOPNE一般是循环结构中的最后一条指令,实现程序的循环执行; address/标号是循环的入口。
如果循环条件成立,转移到循环入口,继续执行循环程序;
如果循环条件不成立,不转移,顺序执行循环后面的指令。
循环条件:CX/ECX & ZF 标志位当前取值
CX/ECX:保存循环次数,每循环1次, CX/ECX自减1;如果CX/ECX =0,退出循环。
ZF:提供一种提前退出循环的条件(break功能),如果循环需要的ZF标志位取值不满足,则break,不管CX/ECX等于多少。

LOOP循环控制指令:CX/ECX

  1. CX/ECX自减1;
  2. 判断CX/ECX是否为0;
    如果CX/ECX ≠0,转移到 address/标号 继续循环;
    如果CX/ECX =0,不转移,退出循环;
    LOOPE循环控制指令:CX/ECX & ZF
  3. CX/ECX自减1;
  4. 判断CX/ECX是否为0 ?同时判断ZF是否为1?
    如果CX/ECX ≠0 且 ZF =1,转移到 address/标号 继续循环;
    如果CX/ECX =0 或 ZF =0,不转移,退出循环;
    LOOPNE循环控制指令:CX/ECX & ZF
  5. CX/ECX自减1;
  6. 判断CX/ECX是否为0?同时判断ZF是否为0?
    如果CX/ECX ≠0 且 ZF =0,转移到 address/标号 继续循环;
    如果CX/ECX =0 或 ZF =1,不转移,退出循环;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值