Windows逆向工程入门之汇编数据存储\宽度,内存地址及边界,数据截断处理
- 公开视频 -> 链接点击跳转公开课程
- 博客首页 -> 链接点击跳转博客主页
目录
一、汇编数据存储宽度
1. 常见的数据存储宽度
2. 数据存储宽度在汇编中的应用
3. 数据存储宽度的意义
二、汇编中的内存地址与边界对齐
1. 内存地址
示例:
2. 数据对齐
3. 数据对齐在汇编中的体现
正确对齐
错误对齐
汇编代码示例
三、汇编中的数据宽度截断
1. 数据截断的影响
示例:
2. 数据宽度截断在赋值和运算中的体现
汇编代码:
数据截断溢出示例:
四、技术扩展
1. 结构体内存对齐
示例:
2. 溢出和截断攻击
示例:
3. 操作系统中的对齐机制
在逆向工程和汇编语言中,对内存地址、数据存储宽度及边界对齐的理解是分析程序行为、修复漏洞和优化代码的基础。
一、汇编数据存储宽度
数据存储宽度是指在内存中存储数据时占用的字节范围。不同的存储宽度适合存放不同的数据类型。
1. 常见的数据存储宽度
在 x86/x64 汇编中,存储宽度通常可以是以下几种:
数据类型 | 宽度(字节) | 宽度(位) | 数据范围 | 汇编定义 |
---|---|---|---|---|
字节(Byte) | 1 | 8 | 0 ~ 255 或 -128 ~ 127 | BYTE |
字(Word) | 2 | 16 | 0 ~ 65535 或 -32768 ~ 32767 | WORD |
双字(DWord) | 4 | 32 | 0 ~ 2³²-1 或 -2³¹ ~ 2³¹-1 | DWORD |
四字(QWord) | 8 | 64 | 0 ~ 2⁶⁴-1 或 -2⁶³ ~ 2⁶³-1 | QWORD |
1 字节 (1 byte) = 8 位 (8 bit),存储宽度直接决定了计算机能够处理的数据大小和精度。
2. 数据存储宽度在汇编中的应用
存储宽度在汇编中通常决定了寄存器、指令和数据类型的选择:
-
寄存器与数据存储宽度的关系:
- x86 通常有 8 位、16 位、32 位和 64 位寄存器。
- 如
AL/AH
(8 位),AX
(16 位),EAX
(32 位),RAX
(64 位)。
-
数据指令的宽度:
不同的指令操作不同的数据宽度:mov al, 0xFF ; 1 字节数据 (8-bit) mov ax, 0xFFFF ; 2 字节数据 (16-bit) mov eax, 0xFFFFFFFF; 4 字节数据 (32-bit) mov rax, 0xFFFFFFFFFFFFFFFF; 8 字节数据 (64-bit)
3. 数据存储宽度的意义
- 内存占用:数据宽度决定了变量在内存中占用的空间,直接影响程序的内存使用效率。
- 运算精度:操作数据宽度不匹配可能导致精度丢失或溢出。
- 硬件支持:现代CPU通常优化了对不同数据宽度操作的支持,以提升处理效率。
二、汇编中的内存地址与边界对齐
计算机内存储存数据时,会将数据映射到地址空间的特定位置,而程序的性能与数据的存储方式密切相关。
1. 内存地址
每个内存地址对应 1 字节
的存储单元。数据的存储位置由其起始地址决定,而数据的存储宽度影响其占据的字节范围。
示例:
若数据 WORD
(2字节)存储在地址 0x1000
,其实际范围为 0x1000
~ 0x1001
。
2. 数据对齐
- 定义:数据对齐是为了提升 CPU 对数据的访问效率,将数据存储在可由宽度整除的内存地址上。
- 常见对齐方式:
1 字节对齐
:无需对齐。2 字节对齐
:地址可被 2 整除。4 字节对齐
:地址可被 4 整除。8 字节对齐
:地址可被 8 整除。
3. 数据对齐在汇编中的体现
- 防止越界访问:越界访问可能导致程序崩溃或触发异常。
- 安全性:恶意程序可能利用越界访问来执行任意代码。
- 性能优化:合理的内存访问方式有助于优化程序性能。
正确对齐
若一个 DWORD
(4字节)从对齐地址开始存储,如 0x1000
:
地址 0x1000 | 0x1001 | 0x1002 | 0x1003
数据 XXXX
错误对齐
若 DWORD
从非对齐地址 0x1001
开始存储:
地址 0x1000 | 0x1001 | 0x1002 | 0x1003 | 0x1004
数据 XXXX
- 错误对齐可能导致额外的内存访问操作,降低性能。
汇编代码示例
正确对齐方式:
section .data
align 4 ; 强制 4字节对齐
mydata dd 0x12345678
三、汇编中的数据宽度截断
数据截断(Truncation)是指将宽度较大的数据缩小为占用更少的存储空间。
1. 数据截断的影响
- 高位数据会被丢弃,可能导致溢出或数据丢失。
- 常见于将
DWORD
转换为WORD
或BYTE
。
示例:
mov eax, 0x12345678 ; 将 0x12345678 装载到 eax 中 (32位寄存器)
mov ax, eax ; 仅保留低 16 位 0x5678,截断高位
截断结果为仅保留 0x5678
,高位 0x1234
被丢弃。
2. 数据宽度截断在赋值和运算中的体现
汇编代码:
mov rax, 0xFFFFFFFF12345678 ; 64位寄存器
mov eax, rax ; 截断为低 32 位,结果为 0x12345678
mov al, rax ; 截断为低 8 位,结果为 0x78
数据截断溢出示例:
mov ah, 0xFF ; AH = 高8位,值为 255 (0xFF)
add al, 2 ; AL = 低8位,加上2溢出
; AL 的结果可能导致不可预料的错误
四、技术扩展
1. 结构体内存对齐
C/C++ 中常见问题,影响结构体大小与性能。
示例:
struct Example {
char a; // 1 字节
int b; // 4 字节
};
- 若未对齐,总大小为 5 字节。
- 若对齐规则为 4 字节,结构体大小为 8 字节(
a
后填充3字节)。
应用:优化对齐,提高内存访问效率。
2. 溢出和截断攻击
在逆向工程中的常见场景。攻击者通过数据截断/溢出导致程序行为异常。
示例:
int value = 0x100; // 256
char buffer[8];
snprintf(buffer, value, "Test Overflow");
// 多余的字节可能覆盖函数返回地址
应用:
- 在漏洞挖掘中,分析溢出是否可控。
- 修复关键函数逻辑,避免意外截断。
3. 操作系统中的对齐机制
- 内存分配:堆栈/堆内存页面通常对齐至 4KB(4096字节)。
- 文件结构:
- PE 文件(Portable Executable):各节对齐至 512 字节或 4KB。
- ELF 文件(Linux 下的可执行文件):默认对齐至 4 字节或 8 字节。
代码片段:
// Windows内存分配对齐
void* pAligned = _aligned_malloc(16, 8); // 16 字节分配,8 字节对齐
_aligned_free(pAligned);