进制
- 二进制
- 八进制
- 十六进制
- 六十进制
转换
二进制和十六进制的转换
数据宽度
位、字节、字是计算机数据存储的单位。位是最小的存储单位,每一个位存储一个1位的二进制码,一个字节由8位组成。而字通常为16、32或64个位组成
位 (Bit):
- 定义: 位是计算机中最小的存储单位,表示二进制数中的一个数字,可以是0或1。
- 用途: 用于表示和存储数据的基本单位,计算机内部所有的数据都由位组成。
字节 (Byte):
- 定义: 字节是由8个位组成的存储单位。
- 用途: 字节是计算机处理中常用的数据单位,常用于表示一个字符(如字母或符号)。例如,一个字母“A”在计算机中通常占用一个字节。
字 (Word):
- 定义: 字是计算机架构中一次处理的数据长度,可以由多个字节组成。字的长度通常是计算机的位数(例如,16位、32位或64位)。
- 用途: 字的长度决定了计算机在一次操作中可以处理的最大数据量。不同计算机架构的字长可能不同。
关系:
- 1 位 (bit) = 0 或 1
- 1 字节 (byte) = 8 位 (bits)
- 1 字 (word) = 若干字节,根据计算机架构而定 (通常是2字节、4字节、或8字节)。
通用寄存器
通用寄存器(General-Purpose Registers, GPRs)是计算机处理器中的一种高速存储单元,用于暂时存储数据和地址,方便 CPU 在执行指令时快速访问这些数据。通用寄存器的数量和用途可能因处理器架构的不同而有所差异,但它们通常具有以下特点:
特点:
- 高速访问:通用寄存器位于 CPU 内部,访问速度远快于内存。
- 多用途:可以存储操作数、临时数据、内存地址等,支持算术、逻辑运算、数据传送等操作。
- 短期存储:主要用于存储在运算过程中需要快速访问的数据,而不是长期存储。
常见的通用寄存器(以 x86 架构为例):
32位寄存器(x86架构)
在32位x86架构下,有以下通用寄存器:
- 数据寄存器:
EAX
(Extended Accumulator Register): 累加寄存器,用于算术和逻辑操作的默认寄存器。EBX
(Extended Base Register): 基址寄存器,通常用于存储数据的基地址。(通过基地址和偏移量(Offset),可以计算出具体的内存地址(有效地址))ECX
(Extended Counter Register): 计数寄存器,通常用于循环计数或字符串操作中的计数。EDX
(Extended Data Register): 数据寄存器,通常用于I/O操作(I/O操作包括从外部设备获取数据(输入)和将数据发送到外部设备(输出))、乘法和除法。
- 指针寄存器:
ESI
(Extended Source Index): 源索引寄存器,常用于字符串操作中的源地址。(源地址(Source Address)通常指在数据传输或操作过程中,数据的原始位置,即数据最初存储的位置。源地址用于标识从哪里读取数据。)EDI
(Extended Destination Index): 目标索引寄存器,常用于字符串操作中的目标地址。EBP
(Extended Base Pointer): 基址指针寄存器,通常用于指向栈帧的基址。(栈底)ESP
(Extended Stack Pointer): 栈指针寄存器,指向当前栈顶。
- 指令指针寄存器:
EIP
(Extended Instruction Pointer): 指令指针寄存器,指向当前执行的指令地址。
- 标志寄存器:
EFLAGS
(Extended Flags Register): 存储各种状态和控制标志,如进位、溢出、零、符号等。
64位寄存器(x86-64架构)
在64位x86-64架构下,寄存器的名称和大小进行了扩展,同时增加了一些新的寄存器:
- 数据寄存器:
RAX
(64-bit Accumulator Register): 扩展的累加寄存器,64位宽度。RBX
(64-bit Base Register): 扩展的基址寄存器,64位宽度。RCX
(64-bit Counter Register): 扩展的计数寄存器,64位宽度。RDX
(64-bit Data Register): 扩展的数据寄存器,64位宽度。
- 指针寄存器:
RSI
(64-bit Source Index): 扩展的源索引寄存器,64位宽度。RDI
(64-bit Destination Index): 扩展的目标索引寄存器,64位宽度。RBP
(64-bit Base Pointer): 扩展的基址指针寄存器,64位宽度。RSP
(64-bit Stack Pointer): 扩展的栈指针寄存器,64位宽度。
- 指令指针寄存器:
RIP
(64-bit Instruction Pointer): 扩展的指令指针寄存器,指向当前执行的指令地址,64位宽度。
- 标志寄存器:
RFLAGS
(64-bit Flags Register): 扩展的标志寄存器,功能类似32位的EFLAGS。
- 额外的通用寄存器:
- 在64位架构下,新增了8个通用寄存器:
R8
、R9
、R10
、R11
、R12
、R13
、R14
、R15
,每个寄存器均为64位宽度。
- 在64位架构下,新增了8个通用寄存器:
兼容性
在64位模式下,寄存器可以根据需要访问不同的部分:
- 访问低32位:使用
EAX
、EBX
、ECX
等。 - 访问低16位:使用
AX
、BX
、CX
等。 - 访问低8位:使用
AL
、BL
、CL
等(对应寄存器的低8位),以及AH
、BH
、CH
等(对应寄存器的高8位,在R8-R15中不存在)。
总结
- 32位架构:使用
EAX
、EBX
等32位寄存器。 - 64位架构:扩展了32位寄存器为64位(
RAX
等),并增加了更多的寄存器(R8-R15
),适应更复杂和高效的64位运算需求。
高低位图解
X32
根据颜色标号1,2,3,4,5
有以下数据
1010 1011
- 1号:1010
- 2号:1011 (AX)
- 3号:1011(AX)低16位
- 4号:10(AH)高八位
- 5号:11(AL)低八位
常用汇编指令
1. MOV
- 功能: 数据传送指令,用于将数据从一个位置传送到另一个位置。
- 语法:
MOV 目标, 源
- 解释: 将
源
的值复制到目标
中,不影响标志寄存器。
2. ADD
- 功能: 加法指令,用于将两个操作数相加,并将结果存储在第一个操作数中。
- 语法:
ADD 目标, 源
- 解释: 将
源
的值加到目标
中,结果存储在目标
中,可能会影响标志寄存器(如进位标志、溢出标志等)。
3. SUB
- 功能: 减法指令,用于从第一个操作数中减去第二个操作数,并将结果存储在第一个操作数中。
- 语法:
SUB 目标, 源
- 解释: 从
目标
中减去源
的值,结果存储在目标
中,可能会影响标志寄存器。
4. AND
- 功能: 位与运算指令,用于对两个操作数进行按位与运算,并将结果存储在第一个操作数中。
- 语法:
AND 目标, 源
- 解释: 对
目标
和源
的每个位执行与操作(1 与 1 得 1,其余得 0),结果存储在目标
中,可能会影响零标志。
5. OR
- 功能: 位或运算指令,用于对两个操作数进行按位或运算,并将结果存储在第一个操作数中。
- 语法:
OR 目标, 源
- 解释: 对
目标
和源
的每个位执行或操作(只要有一个 1,结果就是 1),结果存储在目标
中,可能会影响零标志。
6. XOR
- 功能: 位异或运算指令,用于对两个操作数进行按位异或运算,并将结果存储在第一个操作数中。
- 语法:
XOR 目标, 源
- 解释: 对
目标
和源
的每个位执行异或操作(相同为 0,不同为 1),结果存储在目标
中,可能会影响零标志。
7. NOT
- 功能: 按位取反指令,用于将操作数的每一位取反。
- 语法:
NOT 目标
- 解释: 将
目标
的每一位取反(0 变 1,1 变 0),结果存储在目标
中。
语法总结表
使用@代替位,取值可为8,16,32,64,在表中除了特别标注多少位以外其余皆前后对应
r:通用寄存器
m:内存中的数据
imm:立即数(也就是十六进制的数据)
内存表示语句解释
举例;dword ptr ds:[0x12345678]
1. dword
dword
是 “double word” 的缩写,表示 32 位(4 字节)的数据类型。- 在 x86 汇编中,
word
是 16 位(2 字节),byte
是 8 位(1 字节),而dword
是 32 位。 - 所以
dword
表示要访问或操作的是 32 位的数据。
2. ptr
ptr
是 “pointer” 的缩写,表示这是一个指针操作,指向内存中的某个地址。dword ptr
结合在一起表示这个指针指向的是一个 32 位(4 字节)的内存数据。
3. ds
ds
是数据段寄存器 (Data Segment Register) 的缩写。- 在 x86 实模式下,内存是通过段寄存器(如
ds
,cs
,ss
,es
等)和偏移地址的组合来访问的。 - 这里
ds
表示使用数据段寄存器ds
来确定访问数据的段地址。
4. [0x12345678]
[0x12345678]
表示一个内存地址,0x12345678
是一个具体的内存地址值。- 方括号
[]
表示对这个内存地址进行解引用,也就是访问该地址处存储的数据。
5. 整体解释
dword ptr ds:[0x12345678]
可以解释为:- 访问位于数据段
ds
中偏移地址0x12345678
处的 32 位数据。 - 换句话说,这个表达式的意思是在数据段内的内存地址
0x12345678
处,读取或写入一个 32 位的值。
- 访问位于数据段
实际用法
这个表达式通常出现在汇编语言中,用于内存访问操作。可能是从指定地址读取 32 位数据,也可能是将某个值写入这个地址。在具体的指令中,它可能像这样出现:
mov eax, dword ptr ds:[0x12345678] ; 从内存地址 0x12345678 处读取32位值到EAX寄存器
或者
mov dword ptr ds:[0x12345678], eax ; 将EAX寄存器中的32位值写入到内存地址 0x12345678 处
MOV(赋值) | ADD(加法) | SUB(减法) | AND(按位与) | OR(按位或) | XOR(按位异或) | NOT(按位取反) |
---|---|---|---|---|---|---|
MOV r@,imm@ | ADD r@,imm@ | SUB r@,imm@ | AND r@,imm@ | OR r@,imm@ | XOR r@,imm@ | NOT r@ |
MOV r@,r@ | ADD m@,imm@ | SUB m@,imm@ | AND m@,imm@ | OR m@,imm@ | XOR m@,imm@ | NOT m@ |
MOV r@,m@ | ADD r16@,imm8@ | SUB r16@,imm8@ | AND r16@,imm8@ | OR r16@,imm8@ | XOR r16@,imm8@ | |
MOV m@,r@ | ADD r32@,imm8@ | SUB r32@,imm8@ | AND r32@,imm8@ | OR r32@,imm8@ | XOR r32@,imm8@ | |
ADD r@,r@ | SUB r@,r@ | AND r@,r@ | OR r@,r@ | XOR r@,r@ | ||
ADD m@,r@ | SUB m@,r@ | AND m@,r@ | OR m@,r@ | XOR m@,r@ | ||
ADD r@,m@ | SUB r@,m@ | AND r@,m@ | OR r@,m@ | XOR r@,m@ |
特别的;MOV不能内存之间相互赋值,此操作需要借助通用寄存器作为中间量进行操作
3环用户层和0环内核层
- Ring 0(内核层):最高权限,操作系统内核及核心驱动程序在此层运行,能够直接控制硬件和内存。
- Ring 3(用户层):最低权限,普通应用程序运行在此层,需要通过系统调用来请求操作系统内核执行特定任务,受限于硬件和内存的直接访问。
内存寻址
1. 内存寻址基础
- 内存与寄存器:寄存器位于CPU内部,访问速度非常快,但存储容量有限。相比之下,内存容量大得多,但访问速度相对较慢。尽管寄存器和内存的速度不同,它们的本质都是用于存储数据的定宽容器。
2. 数据单位与寻址范围
- 数据的基本单位包括字节(BYTE, 8位),字(WORD, 16位),双字(DWORD, 32位),和四字(QWORD, 64位)。
- 在32位系统中,内存的寻址范围为00000000到FFFFFFFF,共计4GB。
3. 寻址方式
文档中列出了几种内存寻址方式:
-
立即数寻址:直接使用常数作为地址。
mov eax,dword ptr ds:[0x19FF84] mov ebx,dword ptr ds:[0x19FF88] mov dword ptr ds:[0x19FF84],eax mov dword ptr ds:[0x19FF88],ebx lea eax,dword ptr ds:[0x19FF84] lea eax,dword ptr ds:[ESP+8]
-
寄存器寻址:使用寄存器的内容作为地址。
MOV ECX,0x19FF84 MOV EAX,DWORD PTR DS:[ECX] MOV EDX,0x13FFD8 MOV DWORD PTR DS:[EDX],0x87654321 LEA EAX,DWORD PTR DS:[EDX] MOV EAX,DWORD PTR DS:[EDX]
-
立即数+寄存器:将常数与寄存器的内容相加得到地址。
-
寄存器+寄存器×比例因子:寄存器的内容加上另一个寄存器的内容乘以1/2/4/8作为地址。
-
寄存器+寄存器×比例因子+立即数:寄存器的内容加上另一个寄存器的内容乘以1/2/4/8,再加上一个常数得到地址。
堆栈与内存管理
- 堆栈(Stack):用于存储函数的参数、局部变量等,由编译器自动管理。
- 堆(Heap):由程序员手动管理,存储动态分配的内存块。
- 全局区:用于存储全局变量和静态变量,程序结束时由系统释放。
- 常量区:存储程序中的常量,程序结束后由系统释放。
- 代码区:存储程序的二进制代码。
EFLAGS寄存器
EFLAGS寄存器有32位,EFLAGS 寄存器的标志位可以通过各种指令进行操作和判断,例如条件分支指令、算术指令和控制指令等。程序可以根据标志位的值来进行条件判断和控制流程,从而实现不同的逻辑和功能。
EFLAGS 寄存器的各个位和标志位含义如下:
- CF (Carry Flag):进/借位标志位。用于表示某些算术操作或移位操作是否产生了进位或借位。
- PF (Parity Flag):奇偶标志位。用于表示结果中 1 的个数的奇偶性。
- AF (Auxiliary Carry Flag):辅助进位标志位。用于表示低 4 位的进位或借位情况。
- ZF (Zero Flag):零标志位。用于表示操作结果是否为零。
- SF (Sign Flag):符号标志位。用于表示操作结果的最高有效位(符号位)。
- TF (Trap Flag):陷阱标志位。用于控制单步执行调试功能。
- IF (Interrupt Flag):中断标志位。用于控制是否允许中断响应。
- DF (Direction Flag):方向标志位。用于控制字符串传输指令的方向(正向或反向)。
- OF (Overflow Flag):溢出标志位。用于表示有符号算术操作是否发生溢出。
- IOPL (I/O Privilege Level):I/O 特权级。用于管理对 I/O 端口的访问权限。
- NT (Nested Task Flag):嵌套任务标志位。用于表示当前是否处于嵌套任务的执行环境。
- RF (Resume Flag):恢复标志位。用于控制中断返回时是否进入恢复处理器状态的过程。
- VM (Virtual Mode Flag):虚拟模式标志位。用于指示处理器是否处于虚拟模式。
- AC (Alignment Check):对齐检查标志位。用于控制是否进行内存对齐检查。
- VIF (Virtual Interrupt Flag):虚拟中断标志位。用于指示当前是否处于虚拟 8086 模式的中断响应中。
- VIP (Virtual Interrupt Pending):虚拟中断等待标志位。用于指示是否有虚拟中断正在等待响应。
- ID (ID Flag):识别标志位。用于指示是否支持 CPUID 指令。
目前我们只需要关注下面9个就可以了
CF 进位标志:当算术结果产生进位或者借位的时候被置1
PF 奇偶标志:当算术结果为偶数时被置1
AF 辅助进位标志:算术操作在结果的第三位发生进位或借位则将该标志置1
ZF 零标志:当结果为0时被置1
SF 符号标志:当算术结果为负数时被置1
TF 单步标志 :和调试原理相关
IF 中断标志:和内核有关系
DF 方向标志:会影响MOVS STOS两个串操作指令中EDI和ESI的值
OF 溢出标志:当有符号数的数值超过最大范围时被置1
jcc指令
经常使用的也就是JZ,JE
JZ/JE:如果ZF=0,也就是两个值相等,就跳转
一些指令
LEA指令
- LEA(Load Effective Address)指令用于计算有效地址而不实际访问内存。这在处理复杂的内存操作时非常有用。
jmp
JMP
(Jump):
- 无条件跳转指令。
- 不论任何条件,程序执行到
JMP
指令时,总是会跳转到指定的目标地址。 - 用于直接改变程序的执行流,比如跳转到一个函数、一个代码块的开头等。
- 硬编码:E9
本质就是操作EIP,不涉及堆栈
call
- 保存返回地址:
CALL
指令将当前程序计数器(PC, Program Counter)指向的下一条指令的地址压入堆栈。 - 跳转到子程序:
CALL
指令将程序跳转到指定的子程序地址。 - 执行子程序:程序开始执行子程序中的代码。
- 返回到调用点:子程序执行完毕后,通过执行
RET
指令,从堆栈中弹出先前保存的返回地址,并跳转回调用CALL
指令后的下一条指令。
返回下一行地址,涉及到堆栈改变
硬编码:
- 近跳转:E8
- 原跳转:FF15
call的配套指令ret
行为:
- 取出对应地址里面的值返回给eip(也就是保证call执行完了继续从下一行执行)
- esp降低四字节也就是压栈(esp+4)
堆栈平衡
在call执行中esp,ebp都会变,但是执行完了以后esp,ebp都会回到之前的对应值,也就体现了堆栈平衡
NOP
指令
- 全称: No Operation
- 作用: 执行这条指令时,CPU 什么都不做,仅仅消耗一个时钟周期。
- 用途:
- 代码对齐: 在汇编代码中,
NOP
通常用于对齐代码段,以满足某些优化需求或特定的内存对齐要求。 - 占位符: 在开发和调试时,
NOP
可以作为占位符,方便以后替换成其他指令。 - 时间延迟: 虽然不常用,但多个连续的
NOP
指令可以用来产生一个微小的时间延迟。
- 代码对齐: 在汇编代码中,
INT3
指令
- 全称: Interrupt 3
- 作用: 触发一个中断信号,通常用于调试目的。
- 用途:
- 断点设置: 在调试程序时,
INT3
指令用来设置断点。当程序执行到INT3
时,控制权会转交给调试器,方便开发人员检查程序状态。 - 异常处理: 调试器捕获到
INT3
中断后,可以对程序进行分析和诊断。
- 断点设置: 在调试程序时,
PUSH
指令
-
作用: 将数据压入堆栈顶部。
-
语法:
PUSH source
-
source: 可以是一个寄存器、内存地址或立即数。
-
用途:
- 保存寄存器值: 在调用子程序前,将当前寄存器值保存到堆栈中,以免子程序修改它们。
- 传递函数参数: 在函数调用前,将参数压入堆栈,以便子程序使用。
- 保存返回地址: 在执行函数调用 (
CALL
) 时,返回地址会自动压入堆栈。
POP
指令
-
作用: 从堆栈顶部弹出数据,并存储到指定的目标寄存器或内存位置。
-
语法:
POP destination
-
destination: 可以是一个寄存器或内存地址。
-
用途:
- 恢复寄存器值: 在子程序执行完毕后,通过
POP
恢复之前保存的寄存器值。 - 函数返回: 函数返回时,通过
POP
弹出堆栈中的返回地址,以便恢复到调用点继续执行。 - 参数恢复: 在函数调用结束后,使用
POP
清理堆栈中的参数。
- 恢复寄存器值: 在子程序执行完毕后,通过
堆栈
提栈
从下往上减少地址值
修改ESP —> ESP-4
压栈
从上往下增加地址值
修改ESP —> EBP+4