常见汇编指令整理

本文会整理在逆向中常见的指令汇总

目录

汇编符号

汇编指令的组成

mov

movzx 

lea

xchg

加法指令

减法指令

带进位加法

带进位减法

自增自减

乘法运算

除法运算

and

or

xor

not

shl

shr

逻辑指令

字符串操作

STOS

REP

movss指令

eax 与 [eax] 区别

test指令

 cmp指令

jle指令

jnz指令

cmovnz指令


汇编符号

在查询资料时,往往会遇见一些符号,需要对常见的符号先做一个了解

  • reg:通用寄存器    reg8 reg16 reg32
  • sreg:段寄存器
  • imm:立即数 数字 123456     imm8 imm16 imm32
  • mem:内存     mem8 mem16 mem32

汇编指令的组成

汇编指令是由 操作码和操作数 组成的

操作数的类型:

  • 立即数
  • 寄存器
  • 内存

mov

mov指令的作用就是将源操作数赋值给目的操作数。

mov 目的操作数,源操作数

注意事项

  1. 不能把一个大的值传给一个小的容器
  2. mov指令不允许这样操纵  mov mem,mem  传送数据少的化,可以借助寄存器中转
mov eax,ebx

常见汇编指令整理_第1张图片

movzx 

将源操作数(寄存器或内存位置)的内容复制到目标操作数(寄存器),并按照零扩展方式将值扩展到 16 或 32 位。转换后的值的大小取决于操作数大小属性。

mov eax,0xFFFF

低4为被FFFF覆盖,其它位置被0覆盖

lea

将源操作数的地址传送到目标操作数的寄存器中

lea eax,dword ptr ds:[0x00BCFB64]

常见汇编指令整理_第2张图片

dword ptr 表示偏移量为4个字节,表示以0x00BCFB64向下偏移4个字节

xchg

执行操作:将目标操作数与源操作数的内容进行交换

xchg dword ptr ds:[0x00BCFB64], eax

常见汇编指令整理_第3张图片

EAX寄存器的值和0x00BCFB64并偏移4个字节的值进行交换。

加法指令

add指令有两个操作数,add指令会把两个操作数相加,然后把结果存放在第一个操作数里面。操作数 的类型和mov指令一样

add eax,ecx

标志寄存器CF,x64dbg的解释

  • 有符号数计算,进位,借位进行设置
  • 无符号运算发生溢出

设置EAX为0xFF,令 al 加上 EAX.测试CF标志位变化

执行后,EAX被置为0

add eax,0x1

查看标志寄存器变化

常见汇编指令整理_第4张图片

  • ZF表示最近一次计算的结果为0,就设置为1
  • CF表示发生了进位借位,置为1
  • PF表示最近计算结果最低字节位,1的个数为偶数设置为1

减法指令

用第一个操作数减去第二个操作数,结果存放到第一个操作数里面

sub eax,ecx

带进位加法

带进位的加法,和add加法的区别在于会在原来的基础上,加上进位标志。格式和操作数跟add一样。

mov dl,0;
mov al,0xFF;
add al,1;
adc dl,0;

结果

dl=0+0=0+1(进位标志)
dl=00000001

带进位减法

在原来的减法基础上,再减去进位标志

mov edx,7;
mov eax,1;
sub eax,2;
sbb edx,0;

结果

edx=7;
eax=1;
eax=1-2=0xFFFFFFFF = -1
edx=7-0-1=6

自增自减

他们都只有一个操作数

inc eax
dec eax

乘法运算

无符号乘法

mov eax,0x12345;
mov ebx,0x10;
mul ebx;

乘法里面有两个东西,一个是乘数,一个是被乘数。 mul只有一个操作数,ebx是乘数,另外一个隐藏的操作数叫被乘数,这个操作数是隐藏的,也就是这 条指令执行的时候

mul ebx;=ebx=ebx*eax;

有符号乘法

mov eax.0x12345;
mov ebx,0x100000;
imul ebx,eax;

常见汇编指令整理_第5张图片

OF标志位发生了变化

常见汇编指令整理_第6张图片

此时注意OF位,会被置为1,这是因为计算结果 1234500000 ,已经超过了有符号位存储的范围了

补充:

imul ebx,eax,ecx;

第二个操作数和第三个操作数相乘,结果放到第一个操作数里面

除法运算

无符号 div 有符号 idiv

mov eax,5
mov ebx,3
div ebx

div指令的除法,商放在eax里,余数放在edx里。 有符号除法几乎与无符号除法几乎完全一样。

and

将操作数1与操作数2进行按位与运算,结果存储到操作数1中

and eax,1 如果eax=0xFFFF,则结果eax=0001

or

将操作数1与操作数2进行按位或运算,结果存储到操作数1中

or eax,1 如果eax=0xFFF0,则结果eax=0xFFF1

xor

将操作数1与操作数2进行按位异或运算,结果存储到操作数1中

xor eax,0x1F 如果eax=0xFFF0,则结果eax=0xFFEF

not

将目标操作数执行按位取反结果存储到目标操作数的位置

not eax; 如果eax=0xFF00,则结果eax=00FF

shl

左移,等于*2

shr

右移,等于/2

逻辑指令

逻辑运算都不会得到运算结果,仅仅设置标志寄存器中的相应标志位,通常都是配合跳转指令,实现汇 编程序中的选择或者循环结构

cmp用于比较两个数的大小;test指令最常用的功能就是测试某一个寄存器的值是不是0

指令:cmp

操作数个数:2

操作数1:reg

操作数2:reg/mem/imm

指令结构:CMP 源操作数,源操作数

执行操作:用操作数1减去操作数2,并根据结果设置EFLAGS寄存器中的状态标志

例子:

        cmp eax,1; 如果eax=0,比较之后由于最高位为1.因此符号位SF为1;

        cmp eax,0; 如果eax=0,比较之后由于结果为零,因此零标志位ZF为1

指令:test

操作数个数:2

操作数1:reg

操作数2:reg/mem/imm

指令结构:TEST 源操作数,源操作数

执行操作:将操作数1和操作数2进行按位与运算,并根据结果设置SF ZF PF状态标志,然后丢弃结果

例子:

        test eax,eax;

        jz XXX

        如果eax为零,设置ZF零标志为1,jz跳转。

字符串操作

要把内存中的一块区域复制从一个地方复制到另外一个地方。这种 操作我们称为串操作指令。

串操作指令用到的寄存器都是EDI和ESI,不能使用其他寄存器。ESI存储的是源地址,EDI存储的是目标 地址。

MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI];------------------>简写:MOVSB
MOVS WORD PTR ES:[EDI],WORD PTR DS:[ESI];------------------>简写:MOVSW
MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI];----------------->简写:MOVSD

以C语言为例,EDI就相当于是dest,ESI就相当于是src,size,BYTE/WERD/DWORD就相当于是size

strcpy(dest,src,size);
  • MOVSB 一次复制一个字节
  • MOVSW 一次复制两个字节
  • MOVSD 一次复制四个字节
     
MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]

movsb

常见汇编指令整理_第7张图片

当这条指令执行完成之后,从源地址复制了一个字节到目标地址;并且ESI和EDI的指针自动增加了1, 所以这种用来复制内存的方式是非常方便的。

如果想一次复制4个字节,可以用下面的指令

MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI];

关于DF标志位

  • 方向标志位,如果DF标志位为0,那么使用movs指令时,ESI和EDI的地址都会增加。
  • 相反,如果DF标志位为1,那么ESI和EDI的地址都会相减,MOVSB会减1,MOVSW会减2,MOVSD会 减4.

测试DF为0时

常见汇编指令整理_第8张图片

从esi开始向后4个字节复制给edi,并且esi,edi都加4

测试DF为1时

常见汇编指令整理_第9张图片

从esi开始向后4个字节复制给edi,并且esi,edi都减4

EDI,ESI都是指向内存空间的一个地址

STOS

将AL/AX/EAX的值存储到EDI里。

和MOVS指令对比,STOS少了一个源寄存器,这个源寄存器EAX是默认省略的。

执行完成之后,EDI的值也会加或者减,加或者减取决于DF标志位。加多少取决于复制的操作数大小。

STOS BYTE PTR ES:[EDI]----->简写为STOSB

STOS WORD PTR ES:[EDI]----->简写为STOSW

STOS DWORD PTR ES:[EDI]---->简写为STOSD

常见汇编指令整理_第10张图片

此时DF标志位为1,所以地址减1,然后EAX的值复制了一个字节,也就是44。复制44的原因是因为小 端存储。

REP

按ECX寄存器中指定的次数重复执行字符串指令

MOV ECX,0x10
REP MOVSD
REP STOSD

上面这些指令会让MOVSD和STOSD执行16次。这三条指令结合起来,就可以实现字符串拷贝的操作

movss指令

用于将单精度浮点数(32 位)从源操作数移动到目标操作数

如果目标操作数是一个寄存器,那么该寄存器的低 32 位将被赋值。

在给浮点数赋值时,往往会这样操作

movss   xmm0, ds:dword_417BE0
movss   [ebp+var_C], xmm0

xmm0 是一个 128 位的 XMM 寄存器,ds 是一个段寄存器,指示要访问的内存段,dword_417BE0 是一个表示内存地址的符号引用,它指向存储单精度浮点数的位置,由417BE0h - 417BE4h这段内存空间(由低向高)取这段空间的值,这是小段存储,低位存地位,高位存高位

小数往往存储在内存某一位置,通过xmm0寄存器给到函数局部变量的位置

eax 与 [eax] 区别

常见汇编指令整理_第11张图片

eax,就是往这个寄存器中写东西

[eax]:把eax存储的值视为地址,往这个地址写东西

test指令

"test" 指令是一种按位逻辑运算指令,其操作数是两个寄存器或内存单元的数据。两个操作数进行逐位逻辑与运算,并根据运算结果更新标志寄存器中的相应标志位,而不修改操作数的值;

对标志寄存器的影响:

  • 零标志位(ZF):如果运算结果为零,则 ZF 置位(ZF = 1);否则复位(ZF = 0)。

  • 符号标志位(SF):根据运算结果的最高位来设置 SF 的值。如果最高位为 1,则 SF 置位(SF = 1);否则复位(SF = 0)。

  • 奇偶标志位(PF):根据运算结果中包含的二进制 1 的个数来设置 PF 的值。如果运算结果中包含偶数个 1,则 PF 置位(PF = 1);否则复位(PF = 0)。

 cmp指令

"cmp" (Compare)指令是 x86 汇编语言中的比较指令,用于比较两个操作数的大小关系,并根据比较结果更新标志寄存器中的相应标志位。

cmp operand1, operand2

其中,operand1operand2 是待比较的操作数。

cmp 指令执行时,会进行以下步骤:

  1. 将 operand1 的值与 operand2 的值进行比较。
  2. 根据比较结果设置相应的标志位,包括零标志位(ZF)、进位标志位(CF)、符号标志位(SF)等。

常见的比较指令结果和对应的标志位设置如下:

  • 如果 operand1 等于 operand2,则 ZF 被置为 1;否则,ZF 被置为 0。
  • 如果 operand1 小于 operand2,则 SF 被置为 1;否则,SF 被置为 0。
  • 如果无符号整数的减法导致产生了借位(即 operand1 小于 operand2),则 CF 被置为 1;否则,CF 被置为 0。

需要注意的是,cmp 指令只进行比较操作,不会修改操作数的值。它主要用于在条件分支或循环中进行条件判断,根据比较结果来确定程序的执行路径。

jle指令

"jle" 是 x86 汇编语言中的跳转指令,它根据标志寄存器中的 SF、ZF 和 OF 标志位的组合进行条件跳转。

"jle" 的含义是 "Jump if Less Than or Equal",即如果小于等于关系成立,则进行跳转。

具体的跳转条件如下:

  • 当 SF = 1 (负数) 且 ZF = 0 (不为零) 时,进行跳转。
  • 当 SF = 0 (非负数) 且 ZF = 1 (为零) 时,进行跳转。
  • 当 OF = 1 (溢出) 时,进行跳转。

jnz指令

"jnz" 是 x86 汇编语言中的条件跳转指令,它根据标志寄存器中的零标志位 (ZF) 进行跳转判断。

"jnz" 的含义是 "Jump if Not Zero",即如果零标志位为 0,则进行跳转。

具体的跳转条件如下:

  • 当 ZF = 0 (不为零) 时,进行跳转。
  • 当 ZF = 1 (为零) 时,不进行跳转,继续执行下一条指令。

cmovnz指令

"cmovnz" 的含义是 "Conditional Move if Not Zero",即如果零标志位为非零值,则执行移动操作。

"cmovnz" 是 x86 汇编语言中的条件移动指令,它根据标志寄存器中的零标志位 (ZF) 进行条件判断,并将数据从一个操作数移动到另一个操作数。

该指令将检查 ZF 标志位的值。如果 ZF = 0,则将 source 中的数据移动到 destination 中;如果 ZF = 1,则不进行移动,保持 destination 不变。

"cmovnz" 用于根据零标志位的状态来选择性地将数据从一个位置移动到另一个位置。它常用于简化逻辑或避免条件分支的情况。

你可能感兴趣的:(C与汇编,汇编,c++)