汇编基础指令

ADD (加)

语法: ADD 被加数, 加数

加法指令将一个数值加在一个寄存器上或者一个内存地址上。

add eax,123 = eax=eax+123;

加法指令对ZF、OF、CF都会有影响。

AND (逻辑与)

语法: AND 目标数, 原数

AND运算对两个数进行逻辑与运算。

AND指令会清空OF,CF标记,设置ZF标记。

为了更好地理解AND,这里有两个二进制数:

1001010110 0101001101

如果对它们进行AND运算,结果是0001000100

即同真为真(1),否则为假(0),你可以用计算器验证。

 

CALL (调用)

语法:CALL something

CALL指令将当前的相对地址(IP)压入栈中,并且调用CALL 后的子程序

CALL 可以这样使用:

CALL 404000           最常见: CALL 地址CALL EAX          

CALL 寄存器 - 如果寄存器存的值为404000,那就等同于第一种情况

CALL DWORD PTR [EAX]       CALL [EAX]偏移量所指向的地址

CALL DWORD PTR [EAX+5]     ;; CALL [EAX+5]偏移量所指向的地址

 

CDQ

Syntax: CDQ

CDQ指令第一次出现时通常不好理解。它通常出现在除法前面,作用是将EDX的所有位变成EAX最高位的值,

比如当EAX>=80000000h时,其二进制最高位为1,则EDX被32位全赋值为1,即FFFFFFFF

若EAX<80000000,则其二进制最高位为0,EDX为00000000。

然后将EDX:EAX组成新数(64位):FFFFFFFF 80000000

 

CMP (比较)

语法: CMP 目标数, 原数

CMP指令比较两个值并且标记CF、OF、ZF:

CMP     EAX, EBX               比较eax和ebx是否相等,如果相等就设置ZF为1

CMP     EAX,[404000]         比较eax和偏移量为[404000]的值是否相等

CMP    [404000],EAX          比较[404000]是否与eax相等

 

DEC (自减)

语法: DEC something

dec用来自减1,相当于c中的–

dec可以有以下使用方式:

dec eax                          eax自减1

dec [eax]                          偏移量为eax的值自减1

dec [401000]                    偏移量为401000的值自减1

dec [eax+401000]             偏移量为eax+401000的值自减1

dec指令可以标记ZF、OF

DIV (除)

语法: DIV 除数

DIV指令用来将EAX除以除数(无符号除法),被除数通常是EAX,结果也储存在EAX中,而被除数对除数取的模存在除数中。

例:

mov eax,64       EAX = 64h = 100mov ecx,9        ECX = 9div ecx         EAX除以ECX

在除法之后 EAX = 100/9 = 0B(十进制:11) 并且 ECX = 100 MOD 9 = 1

例如1001/100:

 mov ax,1001         //ax为被除数,1001位十进制,对应十六进制为03E9H
 mov bl,100				//bl为除数,100对应十六进制为64H
 div  bl						//ax/bl,商存放在al,余数存放在ah
 程序执行结束,al=0AH(即商为10),ah=1(余数为1)

div指令可以标记CF、OF、ZF

IDIV (整除)

语法: IDIV 除数

IDIV执行方式同div一样,不过IDIV是有符号的除法

idiv指令可以标记CF、OC、ZF

 

IMUL (整乘)

语法:IMUL 数值

IMUL 目标寄存器、数值、数值

IMUL 目标寄存器、数值

IMUL指令可以把让EAX乘上一个数(INUL 数值)或者让两个数值相乘并把乘积放在目标寄存器中(IMUL 目标寄存器, 数值,数值)或者将目标寄存器乘上某数值(IMUL 目标寄存器, 数值)

如果乘积太大目标寄存器装不下,那OF、CF都会被标记,ZF也会被标记

INC (自加)

语法: INC something

INC同DEC相反,它是将值加1

INC指令可以标记ZF、OF

 

INT

语法: int 目标数

INT 的目标数必须是产生一个整数(例如:int 21h),类似于call调用函数,INT指令是调用程序对硬件控制,不同的值对应着不同的功能。

 

JUMPS

这些都是最重要的跳转指令和触发条件(重要用*标记,最重要用**标记):

指令                条件                    条件JA*        

  -    如果大于就跳转(无符号)      - CF=0 and ZF=0JAE         

 -    如果大于或等于就跳转(无符号)- CF=0JB*         

 -    如果小于就跳转(无符号)   - CF=1JBE         

 -    如果小于或等于就跳转(无符号)- CF=1 or ZF=1JC          

 -    如果CF被标记就了跳转       - CF=1JCXZ         

-    如果CX等于0就跳转      - CX=0JE**         

-    如果相等就跳转        - ZF=1JECXZ        

-    如果ECX等于0就跳转       - ECX=0JG*          

-    如果大于就跳转(有符号)   - ZF=0 and SF=OF (SF = Sign Flag)JGE*         

-    如果大于或等于就跳转(有符号) - SF=OFJL*         

 -    如果小于就跳转(有符号)    - SF != OF (!= is not)JLE*         

-    如果小于或等于就跳转(有符号 - ZF=1 and OF != OFJMP**       

 -    跳转             - 强制跳转JNA          

-    如果不大于就跳转(无符号)   - CF=1 or ZF=1JNAE        

 -    如果不大于等于就跳转(无符号) - CF=1JNB          

-    如果不小于就跳转(无符号)   - CF=0JNBE        

 -    如果不小于等于就跳转(无符号) - CF=0 and ZF=0JNC         

 -    如果CF未被标记就跳转     - CF=0JNE**        

-    如果不等于就跳转       - ZF=0JNG          

-    如果不大于就跳转(有符号)   - ZF=1 or SF!=OFJNGE        

 -    如果不大于等于就跳转(有符号) - SF!=OFJNL         

-    如果不小于就跳转(有符号)   - SF=OFJNLE         

-    如果不小于等于就跳转(有符号) - ZF=0 and SF=OFJNO          

-    如果OF未被标记就跳转     - OF=0JNP          

-    如果PF未被标记就跳转     - PF=0JNS         

 - 如果SF未被标记就跳转      - SF=0JNZ         

 -    如果不等于0就跳转      - ZF=0JO           

-    如果OF被标记就跳转     - OF=1JP           

-    如果PF被标记就跳转     - PF=1JPE          

-    如果是偶数就跳转       - PF=1JPO          

-    如果是奇数就跳转       - PF=0JS           

-    如果SF被标记就跳转     - SF=1JZ           

-    如果等于0就跳转      - ZF=1

LEA (有效地址传送)

语法:LEA 目的数、源数

LEA可以看成和MOV差不多的指令LEA ,它本身的功能并没有被太广泛的使用,反而广泛运用在快速乘法中:

lea eax,dword ptr [4*ecx+ebx]

将eax赋值为 4*ecx+ebx

MOV (传送)

语法: MOV 目的数,源数

这是一个很简单的指令,MOV指令将源数赋值给目的数,并且源数值保持不变

这里有一些MOV的变形:

MOVS/MOVSB/MOVSW/MOVSD EDI, ESI:这些变形能将ESI指向的内容传送到EDI指向的内容中去

MOVSX:MOVSX指令将单字或者单字节扩展为双字或者双字节传送,原符号不变

MOVZX:MOVZX扩展单字节或单字为双字节或双字并且用0填充剩余部分(通俗来说就是将源数取出置于目的数,其他位用0填充)

MUL (乘法)

语法:MUL 数值

这个指令同IMUL一样,不过MUL可以乘无符号数。

NOP (无操作)

语法:NOP

这个指令说明不做任何事

所以它在逆向中运用范围最广

OR (逻辑或)

语法:OR 目的数,源数

OR指令对两个值进行逻辑或运算

这个指令会清空OF、CF标记,设置ZF标记

为了更好的理解OR,思考下面二进制串:

1001010110 0101001101

如果对它们进行逻辑与运算,结果将是1101011111。

只有当两边同为0时其结果为0,否则就为1。你可以用计算器尝试计算。希望你能理解为什么,最好自己动手算一算

POP

语法:POP 目的地址

POP指令将栈顶第一个字传送到目的地址。 每次POP后,ESP(栈指针寄存器)都会增加以指向新栈顶

PUSH

语法:PUSH 值

PUSH是POP的相反操作,它将一个值压入栈并且减小栈顶指针值以指向新栈顶。

REP/REPE/REPZ/REPNE/REPNZ

语法: REP/REPE/REPZ/REPNE/REPNZ ins

重复上面的指令:直到CX=0。ins必须是一个操作符,比如CMPS、INS、LODS、MOVS、OUTS、SCAS 或 STOS

RET (返回)

语法:RET

RET digit

RET指令的功能是从一个代码区域中退出到调用CALL的指令处。

RET digit在返回前会清理栈

SUB (减)

语法:SUB 目的数,源数

SUB与ADD相反,它将源数减去目的数,并将结果储存在目的数中

SUB可以标记ZF、OF、CF

TEST

语法:TEST 操作符、操作符

这个指令99%都是用于”TEST EAX, EAX”,它执行与AND相同的功能,但是并不储存数据。如果EAX=0就会标记ZF,如果EAX不是0,就会清空ZF

XOR

语法:XOR 目的数,源数

XOR指令对两个数进行异或操作

这个指令清空OF、CF,但会标记ZF

为了更好的理解,思考下面的二进制串:

10010101100101001101

如果异或它们,结果将是1100011011

如果两个值相等,则结果为0,否则为1,你可以使用计算器验算。

很多情况下我们会使用”XOR EAX, EAX”,这个操作是将EAX赋值为0,因为当一个值异或其自身,就过都是0。

 

 

 

汇编语言中的标志位:

CF:进位标志位。在无符号运算时,记录了运算结果的最高有效位向更高位的进位值或从更高位借位,产生进位或借位时CF=1,否则CF=0;

 

PF:奇偶标志位。相关指令执行后结果所有bit中1的个数为偶数,那么PF=1,1的个数为奇数则PF=0;

 

AF:辅助进位标志位。运算过程中看最后四位,不论长度为多少。最后四位向前有进位或者借位,AF=1,否则AF=0;

 

ZF:零标志位。相关指令执行后结果为0那么ZF=1,结果不为0则ZF=0;

 

SF:符号标志位。相关指令执行后结果为负那么SF=1,结果非负数则SF=0;

 

TF:调试标志位。当TF=1时,处理器每次只执行一条指令,即单步执行;

 

IF:中断允许标志位。它用来控制8086是否允许接收外部中断请求。若IF=1,8086能响应外部中断,反之则屏蔽外部中断;

 

DF:方向标志位。在串处理指令中,每次操作后,如果DF=0,si、di递增,如果DF=1,si、di递减;注意此处DF的值是由程序员进行设定的 cld命令是将DF设置为0,std命令是将DF设置为1;

 

OF:溢出标志位。记录了有符号运算的结果是否发生了溢出,如果发生溢出OF=1,如果没有OF=0;

 

posted @ 2023-03-08 08:32  yaolingyu1  阅读(805)  评论(0编辑  收藏  举报