本文主要介绍破解中的汇编基础,并不能取代汇编教程,也不能作为汇编教程学习,只能作为破解过程中对指令的参考

寄存器

1.通用寄存器

通用寄存器包括了816/32位的寄存器:AX/EAX,BX/EBX,CX/ECX,DX/EDX,SP/ESP,BP/EBP,DI/EDISI/ESI.其中AX/EAX,BX/EBX,CX/ECX,DX/EDX在一般情况下作为通用的数据寄存器,用来暂时存放计算过程中所用到的操作数,结果或其他信息.它们还可分为两个独立的8位寄存器使用,命名为AL,AH,BL,BH,CL,CH,DLDH.4个通用数据寄存器除通用功能外,还有如下专门用途:

1.    AX/EAX作为累加器用,所以它是算术运算的主要寄存器.在乘除指令中指定用来存放操作数.另外,所有的I/O指令都使用AXAL与外部设备传送信息.

2.    BX/EBX在计算存储器地址时,可作为基址寄存器使用.

3.    CX/ECX常用来保存计数值,如在移位指令,循环指令和串处理指令中用作隐含的计数器.DX在作双字长运算时,可把DXAX组合在一起存放一个双字长数,DX用来存放高16位数据.此外,对某些I/O操作,DX可用来存放I/O的端口地址.

4.    SP/ESP,BP/EBP,SI/ESI,DI/EDI四个16/32位寄存器可以象数据寄存器一样在运算过程中存放操作数,但它们只能以字(16/32位)为单位使用.此外,它们更经常的用途是在存储器寻址时,提供偏移地址.因此,它们可称为指针或变址寄存器.

5.    SP/ESP称为堆栈指针寄存器,用来指出栈顶的偏移地址.

6.    BP/EBP称为基址指针寄存器,在寻址时作为基地址寄存器使用,但它必须与堆栈段寄存器SS联用来确定堆栈段中的存储单元地址.

2. 标志寄存器FLAG

条件码标志用来记录程序中运行结果的状态信息,它们是根据有关指令的运行结果由(CPU)自动设置的.由于这些状态信息往往作为后续条件转移指令的转移控制条件,所以称为条件码.

1.    进位标志 CF,记录运算时最高有效位产生的进位值.

2.    符号标志 SF,记录运算结果的符号.结果为负时置1,否则置0.

3.    零标志 ZF,运算结果为0ZF位置1,否则置0.

4.    溢出标志 OF,在运算过程中,如操作数超出了机器可表示数的范围称为溢出.溢出时OF位置1,否则置0.

5.    辅助进位标志 AF,记录运算时第3位(半个字节)产生的进位值.

6.    奇偶标志 PF,用来为机器中传送信息时可能产生的代码出错情况提供检验条件.当结果操作数中1的个数为偶数时置1,否则置0.

数据传送指令

1. 传送指令MOV(move)

传送指令是使用最频繁的指令,它相对于高级语言里的赋值语句.指令的格式如下:

1.  MOV  Reg/Mem, Reg/Mem/Imm

其中:Reg—Register(寄存器),Mem—Memory(存储器),Imm—Immediate(立即数),它们可以是8,16位或32(特别指出其位数的除外).

2.传送填充指令

传送填充指令是把位数短的源操作数传送给位数长的目的操作数。指令格式如下:

1.  MOVSX/MOVZX  Reg/Mem, Reg/Mem/Imm 

其中:80386+表示80386及其之后的CPU,其它类似符号含义类同,不再说明。
指令的主要功能和限制与MOV指令类似,不同之处是:在传送时,对目的操作数的高位进行填充。根据其填充方式,又分为:符号填充和零填充。

1.    符号填充指令MOVSX
MOVSX
的填充方式是:用源操作数的符号位来填充目的操作数的高位数据位

2.    零填充指令MOVZX
MOVZX
的填充方式是:恒用0来填充目的操作数的高位数据位
例如,AL=87H,指令MOVSX CX,
AL;MOVZX DX, AL
执行后,问CXDX的值是什么?
根据传送-填充指令的填充方式可知:
指令MOVSX
CX, AL
执行后,(CX)=0FF87H,指令MOVZX DX, AL执行后,(DX)=0087H
从上例可看出,两条指令的源操作数完全一样,但因为它们的填充方式不同,所得到的结果而就不同。

3. 交换指令XCHG

交换指令XCHG是两个寄存器,寄存器和内存变量之间内容的交换指令,两个操作数的数据类型要相同。其指令格式如下:

1.  XCHG  Reg/Mem, Reg/Mem

例如,AX=5678HBX=1234H,指令XCHG AX, BX执行后,AXBX的值是什么?
这是两个寄存器内容进行交换,指令执行后,有:(AX)=1234H(BX)=5678H

4. 取有效地址指令LEA(Load)

指令LEA是把一个内存变量的有效地址送给指定的寄存器。其指令格式如下:

1.  LEA Reg, Mem

5. 取段寄存器指令

该组指令的功能是把内存单元的一个低字传送给指令中指定的16位寄存器,把随后的一个高字传给相应的段寄存器(DSESFSGSSS)。其指令格式如下:

1.  LDS/LES/LFS/LGS/LSS Reg, Mem

堆栈操作指令

堆栈是一个重要的数据结构,它具有先进后出的特点,通常用来保存程序的返回地址。它主要有两大类操作:进/压栈操作和出/弹栈操作。

1. 进栈操作

PUSH

指令格式:

1.  PUSH Reg/Mem

一个字进栈,系统自动完成两步操作:SP←SP-2(SP)←操作数;
一个双字进栈,系统自动完成两步操作:ESP←ESP-4(ESP)←操作数。

PUSHA

指令格式:

1.  PUSHA

其功能是依次把寄存器AXCXDXBXSPBPSIDI等压栈。

PUSHAD

指令格式:

1.  PUSHAD 

其功能是把寄存器EAXECXEDXEBXESPEBPESIEDI等压栈。

2. 出栈操作

POP

指令格式:

1.  POP Reg/Mem

弹出一个字,系统自动完成两步操作:操作数←(SP)SP←SP-2
弹出一个双字,系统自动完成两步操作:操作数←(ESP)ESP←ESP-4

POPA

指令格式:

1.  POPA 

其功能是依次把寄存器DISIBPSPBXDXCXAX等弹出栈。其实,程序员不用记住它们的具体顺序,只要与指令PUSHA对称使用就可以了。

POPAD

指令格式:POPAD
其功能是依次把寄存器EDIESIEBPESPEBXEDXECXEAX等弹出栈,它与PUSHAD对称使用即可.

算术运算指令

算术运算指令是反映CPU计算能力的一组指令,也是编程时经常使用的一组指令。它包括:加、减、乘、除及其相关的辅助指令。
该组指令的操作数可以是8位、16位和32(80386+)。当存储单元是该类指令的操作数时,该操作数的寻址方式可以是任意一种存储单元寻址方式。

1. 加法指令

指令的格式:

1.  ADD  Reg/Mem, Reg/Mem/Imm

受影响的标志位:AFCFOFPFSFZF
指令的功能是把源操作数的值加到目的操作数中。

带进位加指令ADC(见得较少)

指令的格式:

1.  ADC  Reg/Mem, Reg/Mem/Imm

受影响的标志位:AFCFOFPFSFZF
指令的功能是把源操作数和进位标志位CF的值(0/1)一起加到目的操作数中。

1指令INC

指令的格式:

1.  INC  Reg/Mem

受影响的标志位:AFOFPFSFZF,不影响CF
指令的功能是把操作数的值加1

交换加指令XADD(见得较少)

指令的格式:

1.  XADD  Reg/Mem, Reg 

受影响的标志位:AFCFOFPFSFZF
指令的功能是先交换两个操作数的值,再进行算术法操作

2. 减法指令

减法指令SUB

指令的格式:

1.  SUB  Reg/Mem, Reg/Mem/Imm

受影响的标志位:AFCFOFPFSFZF
指令的功能是从目的操作数中减去源操作数。

1. 带借位减SBB(见得较少)

指令的格式:

1.  SBB  Reg/Mem, Reg/Mem/Imm

受影响的标志位:AFCFOFPFSFZF
指令的功能是把源操作数和标志位CF的值从目的操作数中一起减去。

1. 1指令DEC

指令的格式:

1.  DEC  Reg/Mem

受影响的标志位:AFOFPFSFZF,不影响CF
指令的功能是把操作数的值减去1

2. 求补指令NEG

指令的格式:

1.  NEG  Reg/Mem

受影响的标志位:AFCFOFPFSFZF
指令的功能:操作数=0-操作数,即改变操作数的正负号

3. 乘法指令

计算机的乘法指令分为无符号乘法指令和有符号乘法指令,它们的唯一区别就在于:数据的最高位是作为数值参与运算,还是作为符号位参与运算。
乘法指令的被乘数都是隐含操作数,乘数在指令中显式地写出来。CPU会根据乘数是8位、16位,还是32位操作数,来自动选用被乘数:ALAXEAX
指令的功能是把显式操作数和隐含操作数相乘,并把乘积存入相应的寄存器中。

1. 无符号数乘法指令MUL/FMUL

指令的格式:

1.  MUL  Reg/Mem

受影响的标志位:CFOF(AFPFSFZF无定义)
指令的功能是把显式操作数和隐含操作数(都作为无符号数)相乘

2. 有符号数乘法指令IMUL/FIMUL

指令的格式:

1.  IMUL Reg/Mem 
2.  IMUL Reg, Imm
3.  IMUL Reg, Reg, Imm 
4.  IMUL Reg, Reg/Mem

4. 除法指令

除法指令的被除数是隐含操作数,除数在指令中显式地写出来。CPU会根据除数是8位、16位,还是32位,来自动选用被除数AXDX-AX,还是EDX-EAX
除法指令功能是用显式操作数去除隐含操作数,可得到商和余数。当除数为0,或商超出数据类型所能表示的范围时,系统会自动产生0号中断。

1. 无符号数除法指令DIV/FDIV

指令的格式:

1.  DIV  Reg/Mem

指令的功能是用显式操作数去除隐含操作数(都作为无符号数)。指令对标志位的影响无定义.

2. 有符号数除法指令IDIV/FIDIV

指令的格式:

1.  IDIV  Reg/Mem

受影响的标志位:AFCFOFPFSFZF

逻辑运算指令

逻辑运算指令是另一组重要的指令,它包括:逻辑与(AND)、逻辑或(OR)、逻辑非(NOT)和异或指令(XOR),逻辑运算指令也是经常使用的指令。

1. 逻辑与操作指令AND

指令的格式:

1.  AND Reg/Mem, Reg/Mem/Imm

受影响的标志位:CF(0)OF(0)PFSFZF(AF无定义)
指令的功能是把源操作数中的每位二进制与目的操作数中的相应二进制进行逻辑与操作,操作结果存入目标操作数中。

2. 逻辑或操作指令OR

指令的格式:

1.  OR Reg/Mem, Reg/Mem/Imm

受影响的标志位:CF(0)OF(0)PFSFZF(AF无定义)
指令的功能是把源操作数中的每位二进制与目的操作数中的相应二进制进行逻辑或操作,操作结果存入目标操作数中。

1. 逻辑非操作指令NOT

指令的格式:

1.  NOT Reg/Mem

其功能是把操作数中的每位变反,即:1←00←1。指令的执行不影响任何标志位。

2. 逻辑异或操作指令XOR

指令的格式:

1.  XOR Reg/Mem, Reg/Mem/Imm

受影响的标志位:CF(0)OF(0)PFSFZF(AF无定义)
指令的功能是把源操作数中的每位二进制与目的操作数中的相应二进制进行逻辑异或操作,操作结果存入目标操作数中。

1.  mov....--->00402536
2.  call...
3.    ....
4.    ....
5.    xor eax,eax--->返回为0//or eax,eax
6.    retn
7.  je/jz..--->0040253C

检测位指令TEST

检测位指令是把二个操作数进行逻辑操作,并根据运算结果设置相应的标志位,但并不保存该运算结果,所以,不会改变指令中的操作数。在该指令后,通常用JEJNEJZJNZ等条件转移指令。
指令的格式:

1.  TEST  Reg/Mem, Reg/Mem/Imm

受影响的标志位:CF(0)OF(0)PFSFZF(AF无定义)

1.  call XXXXXXXX
2.  test al,al/eax,eax...
3.  je/jne...

循环指令

循环指令本身的执行不影响任何标志位.

1.循环指令

循环指令LOOP的一般格式:

1.  LOOP 标号
2.  LOOPW 标号  ;CX作为循环计数器
3.  LOOPD 标号  ;ECX作为循环计数器
4.  ....
5.  ....
6.  inc eax
7.  dex ebx
8.  cmp eax,ebx
9.  jne/je XXXX ^

1+2+…+1000之和,并把结果存入AX中。

方法1:因为计数器CX只能递减,所以,可把求和式子改变为:1000+999+…+2+1

1.    
2.         XOR AX, AX 
3.         MOV CX, 1000D 
4.  again: ADD AX, CX ;计算过程:1000+999+…+2+1
5.         DEC CX 
6.         LOOP again 
7.   

方法2:不用循环计数器进行累加,求和式子仍为:1+2+…+999+1000

1.    
2.         XOR AX, AX 
3.         MOV CX, 1000D 
4.         MOV BX, 1 
5.  again: ADD AX, BX ;计算过程:1+2+…+999+1000 
6.         INC BX 
7.         LOOP again 
8.   

从程序段的效果来看:方法1要比方法2.

转移指令

转移指令是汇编语言程序员经常使用的一组指令。在高级语言中,时常有尽量不要使用转移语句的劝告,但如果在汇编语言的程序中也尽量不用转移语句,那么该程序要么无法编写,要么没有多少功能,所以,在汇编语言中,不但要使用转移指令,而且还要灵活运用,因为指令系统中有大量的转移指令。
转移指令分无条件转移指令和有条件转移指令两大类。

1. 无条件转移指令

无条件转移指令包括:JMP、子程序的调用和返回指令、中断的调用和返回指令等。
下面只介绍无条件转移指令JMP
JMP
指令的一般形式:

1.  JMP  标号/Reg/Mem

2. 条件转移指令

条件转移指令是一组极其重要的转移指令,它根据标志寄存器中的一个(或多个)标志位来决定是否需要转移,这就为实现多功能程序提供了必要的手段。微机的指令系统提供了丰富的条件转移指令来满足各种不同的转移需要,在编程序时,要对它们灵活运用。
条件转移指令又分三大类:基于无符号数的条件转移指令、基于有符号数的条件转移指令和基于特殊算术标志位的条件转移指令。
指令的助忆符

1. 无符号数的条件转移指令

指令的助忆符

1.  JE/JZ
2.  ZF=1 Jump Equal or Jump Zero 
3.   
4.  JNE/JNZ
5.  ZF=0 Jump Not Equal or Jump Not Zero 
6.   
7.  JA/JNBE
8.  CF=0 and ZF=0 Jump Above or Jump Not Below or Equal
9.   
10.JAE/JNB
11.CF=0 Jump Above or Equal or Jump Not Below 
12. 
13.JB/JNAE
14.CF=1 Jump Below or Jump Not Above or Equal
15. 
16.JBE/JNA
17.CF=1 or AF=1 Jump Below or Equal or Jump Not Above 

2.有符号数的条件转移指令

指令的助忆符

1.  JE/JZ
2.  ZF=1 Jump Equal or Jump Zero 
3.   
4.  JNE/JNZ
5.  ZF=0 Jump Not Equal or Jump Not Zero 
6.   
7.  JG/JNLE
8.  ZF=0 and SF=OF Jump Greater or Jump Not Less or Equal 
9.   
10.JGE/JNL
11.SF=OF Jump Greater or Equal or Jump Not Less 
12. 
13.JL/JNGE
14.SFOF Jump Less or Jump Not Greater or Equal 
15. 
16.JLE/JNG
17.ZF=1 or SFOF Jump Less or Equal or Jump Not Greater 

3. 特殊算术标志位的条件转移指令

指令的助忆符
检测的转移条件 功能描述

1.  JC
2.  CF=1 Jump Carry 
3.   
4.  JNC
5.  CF=0 Jump Not Carry
6.   
7.  JO
8.  OF=1 Jump Overflow
9.   
10.JNO
11.OF=0 Jump Not Overflow
12. 
13.JP/JPE
14.PF=1 Jump Parity or Jump Parity Even
15. 
16.JNP/JPO
17.PF=0 Jump Not Parity or Jump Parity Odd 
18. 
19.JS
20.SF=1 Jump Sign (negative)
21. 
22.JNS
23.SF=0 Jump No Sign (positive) 

,已知一个字节变量char,试编写一程序段,把其所存的大写字母变成小写字母。
解:

1.  next:  
2.  char DB  'F'   ;变量说明 
3.   
4.  MOV AL, char 
5.  CMP AL, 'A' 
6.  JB next        ;注意:字符是无符号数,不要使用指令JL 
7.  CMP AL, 'Z' 
8.  JA next 
9.  ADD char, 20   

子程序的调用和返回指令

子程序的调用和返回是一对互逆操作,也是一种特殊的转移操作。
一方面,之所以说是转移,是因为当调用一个子程序时,程序的执行顺序被改变,CPU将转而执行子程序中的指令序列,在这方面,调用子程序的操作含有转移指令的功能,子程序的返回指令的转移特性与此类似;
另一方面,转移指令是一种一去不复返的操作,而当子程序完后,还要求CPU能转而执行调用指令之下的指令,它是一种有去有回的操作。
为了满足子程序调用和返回操作的特殊性,在指令系统中设置了相应的特定指令。

1. 调用指令(CALL)

调用子程序指令的格式如下

1.  CALL 子程序名/Reg/Mem

子程序的调用指令分为近(near)调用和远(far)调用。如果被调用子程序的属性是近的,那么,CALL指令将产生一个近调用,它把该指令之后地址的偏移量(用一个字来表示的)压栈,把被调用子程序入口地址的偏移量送给指令指针寄存器IP即可实现执行程序的转移
如果被调用子程序的属性是远的,那么,CALL指令将产生一个远调用。这时,调用指令不仅要把该指令之后地址的偏移量压进栈,而且也要把段寄存器CS的值压进栈。在此之后,再把被调用子程序入口地址的偏移量和段值分别送给IPCS,这样完成了子程序的远调用操作

1.  00405600 call 00406895
2.  00405604 ......

子程序调用指令本身的执行不影响任何标志位,但子程序体中指令的执行会改变标志位,所以,如果希望子程序的执行不能改变调用指令前后的标志位,那么,就要在子程序的开始处保护标志位,在子程序的返回前恢复标志位。
例如:

1.  CALL  DISPLAY ;DISPLAY是子程序名 
2.  CALL  BX ;BX的内容是子程序的偏移量 
3.  CALL  WORD1  ;WORD1是内存字变量,其值是子程序的偏移量 
4.  CALL  DWORD1 ;DWORD1是双字变量,其值是子程序的偏移量和段值 
5.  CALL  word ptr [BX]  ;BX所指内存字单元的值是子程序的偏移量 
6.  CALL  dword ptr [BX]  ;BX所指内存双字单元的值是子程序的偏移量和段值 

2. 返回指令(RET)

当子程序执行完时,需要返回到调用它的程序之中。为实现此功能,指令系统提供了一条专用的返回指令。
其格式如下:

1.  RET/RETN/RETF [Imm]

子程序的返回在功能上是子程序调用的逆操作。为了与子程序的远、近调用相对应,子程序的返回也分:远返回和近返回。返回指令在堆栈操作方面是调用指令的逆过程

打赏