第一天学逆向,从x86汇编开始QAQ(第一次写博客,也没有什么特殊内容)
X86汇编简介
什么是x86
x86泛指一系列基于Intel 8086且向后兼容的中央处理器指令集架构。最早的8086处理器于1978年由intel推出,为16位微处理器,x86架构是重要的可变指令长度的CISC。
什么是汇编?
汇编语言区别于高级语言和机器语言,简单来说就是把机器语言的指令用一些易于理解和记忆的单词、字母代替。
寄存器
寄存器是CPU内部的组成部分,是具有存储容量的高速存储部件,可以暂存指令,数据和地址
可以分为通用寄存器、指令指针寄存器、段寄存器、标志寄存器、控制寄存器、浮点寄存器
通用寄存器
r开头的是8-byte,e开头/d结尾的是4-byte,ax、cx、dx、bx/r开头w结尾的是2-byte,l/b结尾的是1-byte
rax、rcx、rdx、rbx还有_h部分,代表低字节的高字节
指令指针寄存器
程序运行时,CPU会读取该寄存器中一条指令的地址,将指令传送到指令缓冲区后,改寄存器的值自动增加,CPU每次执行完一条指令,就会通过该寄存器读取并执行下一条指令。
不能直接修改指令指针寄存器的值,只能通过其他指令间接修改。
eg:jmp、retn、call
标志寄存器
*常用的状态标志
OF(Overflow Flag)溢出标志位
如果指令运算结果发生溢出则OF=1,反之OF=0
SF(Sign Flag)符号标志位
如果指令运算结果是负数,SF=1,反之SF=0
ZF(Zero Flag)零标志位
如果指令运算结果是零则ZF=1,反之=0
CF(Carry Flag)进位标志位
如果指令运算发生进位或者借位则CF=1,反之CF=0
常见指令
数据传送指令可以将数据、地址立即数传送到寄存器或存储单元中
mov:把源操作数传送到目的操作数
格式:MOV dest, src
变化:
MOVSX:符号扩展的move指令
MOVZX:零扩展的move指令
数据传送指令-栈操作
栈是向低地址增长的
PUSH:把操作数进栈
同类指令:
PUSHA[D]:仅32位,64位不支持,将所有通用寄存器压栈
PUSHA[D|Q]:将寄存器的低16bits压栈,32位后可加d表示32bits,64位后可加q表示64bits,注意x86_64不支持PUSHFD
POP:将栈顶数据出栈到操作数
格式:POP dest
同类指令:
POPA[D]:仅32位,64位不支持,将所有通用寄存器出栈到各自寄存器
POPA[D|Q]:将标志寄存器的低16bits出栈,32位后可加d表示32bits,64位后可加q表示64bits,注意x86_不支持POPFD
LEA:将源操作数的有效地址传送到通用寄存器
格式:LEA reg, men
CMOV 系列指令,在一定条件下执行MOV
格式:CMOVXX dest, src
其中XX为不同的条件
XCHG:交换两操作数
格式:XCHG op1,op2
算数运算指令-加法指令
ADD:将源操作数和目的操作数相加,结果送到目的操作数。
ADC:将源操作数与目的操作数以及CF值相加,结果传送到目的操作数,即带进位的加法。
eg:Dest = dest + src
指令格式:ADD/ADC dest, src
INC(increase):目的操作数加一,结果送入目的操作数。
指令格式:INC dest
dest ++
算数运算指令-减法指令
SUB:将目的操作数减去源操作数,结果送入目的操作数。
CMP:将目的操作数减去源操作数,只修改状态标志位,不回送结果。
eg:CMP rax, 1,rax-1操作,但不会把rax-1的值赋给rax
SBB:将目的操作数减去源操作数,再减去CF值,结果送入目的操作数,即带错位的减法
指令格式:SUB/CMP/SBB dest, src
eg:sub rax, 1
rax -= 1
DEC:目的操作数减一,结果送入目的操作数
指令格式:DEC dest
dest - -
算数运算指令-乘法指令
MUL:无符号数乘法指令
指令格式:MUL src
解释:RDX:RAX = src * RAX
eg:mull rbx
rdx:rax = rbx * rax
IMUL:有符号数乘法指令
指令格式:IMUL [dest,] src
解释:dest = src *dest, dest 可以省略,省略时与MUL指令格式一致。
或者,IMUL dest, src1, src2
算数运算指令-除法指令
DIV:无符号除法指令
指令格式:DIV src
解释:RDX:RAX / src把商保存到RAX,余数保存到RDX
IDIV:有符号除法指令
指令格式:IDIV src
解释:RDX:RAX / src把商保存到RAX,余数保存到RDX
位运算指令
AND:与运算
TEST:与运算(只影响状态标志位,不回送结果)
OR:或运算
XOR:异或运算
指令格式:
AND/TEST/OR/XOR dest, src
NOT:非运算
对目标操作数按位取反
**指令格式 **:NOT dest
逻辑移位
右移位后最高位补0
SHL 逻辑左移
每移一位,最低位补0,最高位移入标志位CF中
SHR
每移一位,最低位移入标志位CF,最高位补0
算数移位
右移位后最高位补符号位
SAL
与SHL完全一致
SAR
每移一位,最低位移入标志位CF,最高位补符号位
位运算指令
循环移位
ROL 循环左移
ROR 循环右移
流程控制指令
无条件转移指令
JMP 无条件转移
指令格式:JMP dest
解释:RIP = “dest”
CALL 过程调用
指令格式:CALL dest
解释:PUSH(RIP)、RIP = “dest”
CALL 0x1111
RET
指令格式:RET
解释:RIP = Pop()
指令指针寄存器
程序运行时,CPU会读取该寄存器中一条指令的地址,将指令传送到指令缓冲区后,该寄存器的值自动增加,CPU每次执行完一条指令,就会通过该寄存器读取并执行下一条指令。
不能直接修改指令指针寄存器的值,只能通过其他指令间接修改。
比如:jmp、retn、call
其他指令
NOP:空指令
指令格式:NOP
什么都不做,除了让RIP++外,不做任何操作
INT:中断指令
指令格式:INT n
其中n为中断类型号,比如INT3断点中断
寻址方式
处理器中寻找指令和操作数的方式
在x86_64架构中,有效地址(Effective Address)的计算公式如下:
Base + (Index * Scale) + Displacement
其中:
Base:任何一个通用寄存器
Index:任何一个通用寄存器
Scale:一个参数因子,可以为1、2、4、8
Displacement:偏移量,一般来说可以是 8bits、16bits 或者 32bits 的一个有符号整数
.png)
函数调用约定-x86 – 32位
stdcall调用(标准调用)
stdcall约定通常用于Windows API
参数从右向左入栈(即最后一个参数首先入栈)
调用者不需要清理堆栈,被调用函数负责清理堆栈
cdecl(C声明)
cdecl约定通常用于c语言标准库函数
参数从右向左入栈
调用者负责清理堆栈
fastcall(快速调用)
通过使用寄存器传递部分参数来优化函数调用优化性能
前两个整数参数通过寄存器(在x86架构下,通常是 ‘ecx’ 和 ‘edx’)传递,剩余参数从右向左入栈
被调用函数负责清理堆栈
![外链图片转存失败,源站可能有防盗链机制,建议
汇编代码 - if 语句/switch语句/while语句/for语句(没学太明白QAQ)