汇编入门

时间:2024-03-01 10:04:10

汇编指令入门

字符串处理指令

(1) lodsb、lodsw:把DS:SI指向的存储单元中的数据装入AL或AX,然后根据DF标志增减SI

(2) stosb、stosw:把AL或AX中的数据装入ES:DI指向的存储单元,然后根据DF标志增减DI

(3) movsb、movsw:把DS:SI指向的存储单元中的数据装入ES:DI指向的存储单元中,然后根据DF标志分别增减SI和DI

(4) scasb、scasw:把AL或AX中的数据与ES:DI指向的存储单元中的数据相减,影响标志位,然后根据DF标志分别增减SI和DI

(5) cmpsb、cmpsw:把DS:SI指向的存储单元中的数据与ES:DI指向的存储单元中的数据相减,影响标志位,然后根据DF标志分别增减SI和DI

(6) rep:重复其后的串操作指令。重复前先判断CX是否为0,为0就结束重复,否则CX减1,重复其后的串操作指令。主要用在MOVS和STOS前。一般不用在LODS前。

上述指令涉及的寄存器:段寄存器DS和ES、变址寄存器SI和DI、累加器AX、计数器CX
           涉及的标志位:DF、AF、CF、OF、PF、SF、ZF

转自:https://www.cnblogs.com/JCSU/articles/2137802.html

跳转指令

直接标志转移
指令格式               机器码                    测试条件                       如...则转移  
JC                       72                         C=1                            有进位
JNC                      73                         C=0                            无进位
JZ/JE                    74                         Z=1                            零/  
JNZ/JNE                  75                         Z=0                            不为零/  
JS                       78                         S=1                            负号
JNS                      79                         S=0                            正号
JO                       70                         O=1                            有溢出
JNO                      71                         O=0                            无溢出
JP/JPE                   7A                         P=1                            奇偶位为偶
JNP/IPO                  7B                         P=0                            奇偶位为奇

间接标志转移
先用cmp指令比较再用下面的判断(少了一个 JE 为等于):
指令格式       机器码           测试格式             如...则转移 
JA/JNBE()        77               CZ=0                   >/  
JAE/JNB()        73               C=0                    >=/  
JB/JNAE()        72               C=1                    </  
JBE/JNA()        76               CZ=1                   <=/  
JG/JNLE()        7F               (SO)Z=0                >/  
JGE/JNL()        7D               SO=0                   >=/  
JL/JNGE()        7C               SO=1                   </  
JLE/JNG()        7E               (SO)Z=1                <=/

作者:xingpacer 来源:CSDN 原文:https://blog.csdn.net/chenlycly/article/details/52235168 

jmpi是段间跳转指令,用于x86实模式下

      如:BOOTSEG = 0x0c70

            jmpi    4, #BOOTSEG

      假如当前段CS==00h,那么执行此指令后将跳转到段CS==0x0c70,当然段cs的值也变为0x0c70,接下来将执行指令0x0c70:0004处的指令。

test指令

test属于逻辑运算指令

功能:执行BIT与BIT之间的逻辑运算

#Test用来测试一个位,例如寄存器:
test eax, 100b;          b后缀意为二进制
jnz  ******;             如果eax右数第三个位为1,jnz将会跳转
jnz跳转的条件非0,即ZF=0,ZF=0意味着零标志没被置位,即逻辑与结果为1。

 

REP/REPE/REPZ/REPNE/REPNZ - 重复字符串操作前缀,转自:https://blog.csdn.net/qq_22642239/article/details/52161000

操作码

指令

说明

F3 6C

REP INS r/m8, DX

将 (E)CX 个字节从端口 DX 输入到 ES:[(E)DI]

F3 6D

REP INS r/m16,DX

将 (E)CX 个字从端口 DX 输入到 ES:[(E)DI]

F3 6D

REP INS r/m32,DX

将 (E)CX 个双字从端口 DX 输入到 ES:[(E)DI]

F3 A4

REP MOVS m8,m8

将 (E)CX 个字节从 DS:[(E)SI] 移到 ES:[(E)DI]

F3 A5

REP MOVS m16,m16

将 (E)CX 个字从 DS:[(E)SI] 移到 ES:[(E)DI]

F3 A5

REP MOVS m32,m32

将 (E)CX 个双字从 DS:[(E)SI] 移到 ES:[(E)DI]

F3 6E

REP OUTS DX,r/m8

将 (E)CX 个字节从 DS:[(E)SI] 输出到端口 DX

F3 6F

REP OUTS DX,r/m16

将 (E)CX 个字从 DS:[(E)SI] 输出到端口 DX

F3 6F

REP OUTS DX,r/m32

将 (E)CX 个双字从 DS:[(E)SI] 输出到端口 DX

F3 AC

REP LODS AL

将 (E)CX 个字节从 DS:[(E)SI] 加载到 AL

F3 AD

REP LODS AX

将 (E)CX 个字从 DS:[(E)SI] 加载到 AX

F3 AD

REP LODS EAX

将 (E)CX 个双字从 DS:[(E)SI] 加载到 EAX

F3 AA

REP STOS m8

使用 AL 填写位于 ES:[(E)DI] 的 (E)CX 个字节

F3 AB

REP STOS m16

使用 AX 填写位于 ES:[(E)DI] 的 (E)CX 个字

F3 AB

REP STOS m32

使用 EAX 填写位于 ES:[(E)DI] 的 (E)CX 个双字

F3 A6

REPE CMPS m8,m8

在 ES:[(E)DI] 与 DS:[(E)SI] 中查找不匹配的字节

F3 A7

REPE CMPS m16,m16

在 ES:[(E)DI] 与 DS:[(E)SI] 中查找不匹配的字

F3 A7

REPE CMPS m32,m32

在 ES:[(E)DI] 与 DS:[(E)SI] 中查找不匹配的双字

F3 AE

REPE SCAS m8

从 ES:[(E)DI] 开始查找非 AL 字节

F3 AF

REPE SCAS m16

从 ES:[(E)DI] 开始查找非 AX 字

F3 AF

REPE SCAS m32

从 ES:[(E)DI] 开始查找非 EAX 双字

F2 A6

REPNE CMPS m8,m8

在 ES:[(E)DI] 与 DS:[(E)SI] 中查找匹配字节

F2 A7

REPNE CMPS m16,m16

在 ES:[(E)DI] 与 DS:[(E)SI] 中查找匹配字

F2 A7

REPNE CMPS m32,m32

在 ES:[(E)DI] 与 DS:[(E)SI] 中查找匹配双字

F2 AE

REPNE SCAS m8

从 ES:[(E)DI] 开始查找 AL

F2 AF

REPNE SCAS m16

从 ES:[(E)DI] 开始查找 AX

F2 AF

REPNE SCAS m32

从 ES:[(E)DI] 开始查找 EAX

 

 

汇编基础教程


16位和32位的80x86汇编语言的区别

需要注意的是汇编不是一种语言,不同平台有不同的汇编语言对应,因为汇编和操作系统平台相关,所以汇编语言没有移植性。对于IA-32架构平台而言,选用的是32位80386汇编语言,也就是说本教程讨论的操作系统平台是32位的,可执行文件的格式也是32位而不是64位或16位的。
实际分析中读者要知道研究的程序是运行在什么平台上,以选择相应的汇编语言,对应IA-32架构而言,IA-16架构的汇编语言原理其实和IA-32的汇编语言一样,学习过16位的80x386汇编语言的读者只需花一点时间就可以转到32位80386汇编语言上。

什么是IA-32?
IA-32(Intel Architecture),英特尔体系架构,英特尔从486开始采用,也就叫X86-32架构,

16位操作系统与32位操作系统的80x86汇编语言主要区别如下:

  1. 16位操作系统中的中断调用相当于32位操作系统中的API调用。16位操作系统中的段地址和偏移地址在32位中消失了,在32位操作系统中统一采用平坦的内存地址模式寻址

  2. 16位操作系统中的程序运行在RING0级,也就是说普通程序和操作系统程序运行在同一个级别并且拥有最高权限,而32位操作系统中的程序一般只拥有RING3级运行权限,程序的所有操作都受到操作系统控制,若程序要获得RING0操作特权只能通过驱动程序实现

  3. 16位操作系统的可执行文件格式和32位操作系统的可执行文件格式不同,在32位的Windows操作系统中,可执行文件的格式叫PE格式,32位的Windows操作系统运行在CPU的保护模式之上,而16位的系统则运行在CPU的实模式上。


寄存器

通用寄存器EAX、EBX、ECX和EDX

IA-32架构中一共有4个32位寄存器,用于保存临时数据,它们分别是EAX、EBX、ECX和EDX。

这4个32位寄存器的通用寄存器名字前面都有一个“E”字母,含义是“Expand”扩展,这是由于在16位的时代,这4个通用寄存器的名字是AX、BX、CX和DX,到了32位后就在它们的名字前面加个“E”来区别是32位还是16位。
这4个32位的通用寄存器可以当作16位使用,也可以当作8位使用。当作8位使用时,就将AX折开为AH和AL,AH中的“H”代表“high”,意思是高位的意思,AL中的“L”代表“low”,意思是地位的意思。同理,BX、CX和DX可折开为BH、BL、CH、CL、DH、DL来使用。

一些寄存器是别的寄存器的一部分:例如,如果EAX保存了值12782345,这里是其他寄存器的值。

|:--- |:------:|:------:|:------:|:------:|
| EAX | 12 | 78 | 23 | 45 |
| AX | 12 | 78 | 23 | 45 |
| AH | 12 | 78 | 23 | 45 |

学习EAX、EBX、ECX和EDX寄存器的用途

  1. EAX寄存器:EAX称为累加器,常用于算数运算、布尔操作、逻辑操作、返回函数结果等。
  2. EBX寄存器:EBX称为基址寄存器,常用于存档内存地址。
  3. ECX寄存器:ECX称为计数寄存器,常用于存放循环语句的循环次数,字符串操作中也常用。
  4. EDX寄存器:称为数据寄存器,常常和EAX一起使用。

注意:上面所述的4个通用寄存器的专门用途不是一成不变的,编译器在编译程序的时候会根据很多因素,例如编译器、编译条件、操作系统等做出相应的改变,读者要知道着手研究的程序是用什么编译器编译,然后针对具体的编译器参考该编译器的说明。

segment register

DS is called data segment register. It points to the segment of the data used by the running program. You can point this to anywhere you want as long as it contains the desired data.

ES is called extra segment register. It is usually used with DI and doing pointers things. The couple DS:SI and ES:DI are commonly used to do string operations.

SS is called stack segment register. It points to stack segment. 

变址寄存器index registers

The register SI and DI are called index registers. These registers are usually used to process arrays or strings. As the name follows, SI is always pointed to the source array and DI is always pointed to the destination. This is usually used to move a block of data, such as records (or structures) and arrays. These register is commonly coupled with DS and ES. 

顾名思义,变址的含义是内存地址会变动的,也就是说变址寄存器中存放在变动的内存地址。80386架构中有两个变址寄存器,分别是ESI和EDI。

ESI:(SI is source index)ESI称为源变址寄存器,通常存放要处理的数据的内存地址。

EDI:(DI is destination index.)EDI称为目的变址寄存器,通常存放处理后的数据的内存地址。

ESI和EDI常用来配合使用完成数据的赋值操作,下面是一个ESI和EDI配合使用的例子。

Rep movs dword ptr [edi],dword ptr [esi]

上面的指令把ESI所指向的内存地址中的内容复制到EDI所指向的内存中,数据的长度在ECX寄存器中指定。

指针寄存器pointer registers

The register BP, SP, and IP are called pointer registers.Usually BP is used for preserving space to use local variables. SP is used to point the current stack. Although SP can be modified easily, you must be cautious. It\'s because doing the wrong thing with this register could cause your program in ruin. IP denotes the current pointer of the running program. It is always coupled with CS and it is NOT modifiable. So, the couple of CS:IP is a pointer pointing to the current instruction of running program. You can NOT access CS nor IP directly.

EBP:(BP is base pointer)EBP称为基址寄存器,可作为通用寄存器用于存放操作数,常用来代替堆栈指针访问堆栈中的数据。

ESP:(SP is stack pointer)ESP称为堆栈指针寄存器,不可作为通用寄存器使用,ESP存放当前堆栈栈顶的地址,一般情况下,ESP和EBP联合使用来访问函数中的参数和局部变量。

EIP:(IP is instruction pointer)指令指针寄存器,指令指针寄存器EIP总是指向下一条要执行的指令的地址,一般情况下无需修改EIP。

EBP和ESP寄存器的用途:

EBP和ESP常配合使用完成堆栈的访问,下面是一段常见的堆栈访问指令。

Push ebp
Mov ebp,esp
Sub esp,78
Push esi
Push edi
Cmp dword ptr [ebp+8],0

学习标志寄存器-EFLAGS寄存器与其用途

标志寄存器EFLAGS一共有32位,在这32位中大部分是保留和给编写操作系统的人用的,一般情况下只需知道32位的低16位中的8位即可.

下面的图列出了标志寄存器EFLAGS中需要了解的8个位的位置。

 
  • OF(Overflow Flag):溢出标志,溢出时为1,否则置0。
  • DF (Direction Flag):方向标志,在串处理指令中控制信息的方向。
  • IF (Interrupt Flag) :中断标志
  • AF (Auxiliary carry Flag) :辅助进位标志,有进位时置1,否则置0。
  • ZF (Zero Flag) :零标志,运算结构为0时ZF位位置1,否则置0。
  • SF (Sign Flag):符号标志,结果为负时置1,否则置0。
  • CF (Carry Flag): 进位标志,进位时置1,否则置0。
  • PF (Parity Flag): 奇偶标志。结果操作数中1的个数为偶数时置1,否则置0。

EFLAGS寄存器的用途

正如上面所说EFLAGS是实现条件判断和逻辑判断的一种机制,在汇编语言中一般不直接访问EFLAGS寄存器,而是通过指令的操作隐含访问EFLAGS寄存器,下面是一个利用EFLAGS寄存器的例子。

Cmp dword ptr [ebp+8],0    ;影响标志CFZFSFOFAFPF
Jz 00405898               ; 如果ZF等于1,则跳转到00405898

学习6种灵活的寻址方式与其作用

  • 立即寻址

示例:

Mov eax,56H

作用:通常用于赋值。

  • 直接寻址

示例:

Mov eax,[12558878H]

作用:通常用于处理变量。

  • 寄存器寻址

示例

Mov eax,[edi]

作用:地址在寄存器中。

  • 寄存器相对寻址

示例

Mov EAX,[EDI+32H]

作用:常用于访问数组和结构。

  • 基址加变址寻址

示例

Mov EAX,[EBP+ESI]

作用:常用于访问数组

  • 相对基址加变址寻址。

示例

MOV EAX,[EBX+EDI-10H]

作用:常用于访问结构。


高级语言中的数据结构和80386寻址方式的关系

一般高级语言中的数据结构和寻址方式有一定的关系,熟悉这些关系对逆向分析反汇编指令有很大的帮助。

表1-1所示为高级语言中的数据结构和80386寻址方式的关系。

数据结构和80386寻址方式的关系
数据结构和80386寻址方式的关系

全局类型

全部使用数据段,变量寻址使用直接的内存地址,数组寻址使用ESI(源变址寄存器)+内存地址。

局部类型

全部使用堆栈,变量寻址使用ESP(堆栈指针寄存器)+偏移,数组寻址使用ESP(堆栈指针寄存器)+ESI(源变址寄存器)+地址偏移

动态分配类型

全部使用数据段,变量寻址使用EBX(基址寄存器)或EAX(累加寄存器)+地址偏移,数组寻址使用EBX(基址寄存器)+ESI(源变址寄存器)+地址偏移

局部类型和动态分配类型都的数组寻址都是用了ESI(源变址寄存器)+地址偏移


学习80386指令-Intel格式和AT&T格式的指令格式

80386指令

观察一下Intel 的80x86 CPU文档手册会发现,Intel的80x86 CPU支持几百条指令,如此多的指令莫说深入研究,连入门恐怕也非易事。

幸运的是,在这几百条的指令中,常用的也不过几十条而已,Intel 的80x86 CPU之所以支持几百条指令,原因在于Intel 的80x86 CPU为了保持向下兼容的问题,所以从过去到现在的所有指令都包含在CPU里面,例如有8086/8088、80186、80286和80386等。

Intel格式和AT&T格式(&在英语里读and)

编写IA-32架构的汇编语言常见有两种格式,一种是Intel格式,另一种是AT&T格式。

  • Intel 格式的指令格式。

指令名称 目标操作数DST,源操作数SRC
示例代码:
Mov eax,[edx] //将内存地址为EDX的数据放入EAX寄存器
Xchg eax,edi //交换EAX和EDI寄存器的值
Add eax,ebx // 将EAX和EBX相加,结构放回EAX中
Shl eax,4 //将EAX逻辑左移4位。

  • AT&T格式的指令格式。

指令名称 源操作数SRC,目标操作数DST

示例代码:

Mov (%EDX),%EAX    //将内存地址为EDX的数据放入EAX寄存器
XCHG %EDI,%EAX    //交换EAX和EDI寄存器的值
ADD %EBX,%EAX    //将EAX和EBX相加,结构放回EAX中
SHL $4,%EAX        //将EAX逻辑左移4位。

本教程中讲解的汇编语言统一采用Intel 格式的汇编格式。


学习数据传送指令MOV、XCHG

80386的数据传送指令是为了实现CPU和内存、输入/输出端口之间的数据传送。

  • MOV:称为数值传送指令,格式是“MOV DST,SRC”。
  • MOV指令将源操作数SRC传送到目的操作数DST中,
  • 传送的数据格式可以是8字节、16字节和32字节。

示例代码:

MOV EAX,56  //将56H立即数传送到EAX寄存器
MOV ESI,DWROD PTR [EAX*2+1] //将内存地址为EAX*2+1处的4字节数据传送到ESI寄存器。
MOV AH,BYTE PTR [ESI*2+EAX]  //将内存地址为ESI*2+EAX处的8位数据传送到AH寄存器。
MOV DWORD PTR [ESP+36],EBX  //将EBX寄存器的值以4字节传送到堆栈地址为ESP+36所指向的地方。
  • XCHG:称为交换指令,XCHG实现寄存器间和内存间的数据交换。

格式是“XCHG DST,SRC”。XCHG指令交换SRC和DST之间的数据,
交换的数据可以是8字节、16字节和32字节,其中SRC和DST必须格式相同。

示例代码:

XCHG EAX,EDX   //将EDX寄存器的值和EAX寄存器的值交换
XCHG [ESP-55],EDI //将EDI寄存器的值和堆栈地址为[esp-55]处的值交换。
XCHG BH,BL      //将BL寄存器和BH寄存器的值交换。

学习数据传送指令PUSH、POP

PUSH和POP:称为压入堆栈指令和弹出堆栈指令,格式是“PUSH SRC(源操作数)”和“POP DST(目的操作数)”。

PUSH指令和POP指令是匹配出现的,上面的代码有多少个PUSH下面的代码就有多少个POP,否则堆栈就会不平衡。

PUSH指令将源操作数SRC压入堆栈,同时ESP-4,而POP恰恰相反,POP指令从堆栈的顶部弹出4字节的数值然后放入DST。在32位的Windows操作系统上,PUSH和POP指令的操作是以4字节为单位的

PUSH和POP指令常用于向函数传递参数。

示例代码:

PUSH EAX //将EAX寄存器的值以4字节压入堆栈,同时ESP-4
PUSH DWORD PTR [12FF8589] //将内存地址为12FF8589所指向的值以4字节压入堆栈,同时ESP-4

POP DWORD PTR [12FF8589] //将堆栈顶部的4字节弹出到内存地址为12FF8589所指地方,同时ESP+4
POP EAX  //将堆栈顶部的4字节弹出到EAX寄存器,同时ESP+4