问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

《逆向工程核心原理》第三~五章知识整理

创作时间:
作者:
@小白创作中心

《逆向工程核心原理》第三~五章知识整理

引用
CSDN
1.
https://m.blog.csdn.net/helin2020/article/details/145414851

本文整理了《逆向工程核心原理》一书的第三到五章内容,主要涵盖了小端序标记法、IA-32寄存器以及栈的相关知识。这些内容对于理解计算机底层原理具有重要意义。

小端序标记法

  • 字节序:多字节数据在计算机内存中存放的字节顺序,分为小端序和大端序两大类。

  • 大端序与小端序

BYTE b = 0x12;
WORD w = 0x1234;
DWORD dw = 0x12345678;
char str[] = "abcde";
TYPE
Name
字节
大端序
小端序
BYTE
b
1
[12]
[12]
WORD
w
2
[12][34]
[34][12]
DWORD
dw
4
[12][34][56][78]
[78][56][34][12]
char[]
str
6
[61][62][63][64][65][00]
[61][62][63][64][65][00]
  • 1字节:在二进制是8位,在十六进制是2位。

  • 内存地址:从低到高增长(如0x1000 → 0x1001 → 0x1002)。

  • 数据的高/低位:数值的权重高低。例如,0x12345678中:

  • 高位字节是0x12(权重最大,像数字的“千位”),

  • 低位字节是0x78(权重最小,像数字的“个位”)。

  • 大端序:内存的低地址存储数据的高位字节。

  • 人类视角:从左到右(地址递增)阅读,数值顺序不变,符合直觉。

  • 应用场景:网络传输(网络字节序)、某些文件格式(如JPEG)。

  • 优点:保存多字节数据很直观。

  • 小端序:低位字节在低地址,高位字节在高地址。

  • 硬件视角:低地址存低位字节,方便逐字节处理(如加法从低位开始)。

  • 应用场景:x86/x64架构CPU,内存中直接处理低位数据更高效。

  • 字符串:最后是以NULL结尾,a的ASCII码十六进制是0x61。

  • 存储特点:字符串被保存在一个字符数组中,字符数组在内存中是连续的,无论采用大端序还是小端序,存储顺序都相同。

在OllyDbg中查看LittleEndian.exe文件:

#include "windows.h"
BYTE b = 0x12;
WORD w = 0x1234;
DWORD dw = 0x12345678;
char str[] = "abcde";
int main(int argc, char *argv[])
{
    byte lb = b;
    WORD lw = w;
    DWORD ldw = dw;
    char *lstr = str;
    return 0;
}

直接给出main()函数的地址,按Ctrl+G跳转到401000地址处,可以看到定义的变量0x12地址应该是40AC40,可以发现这些数据使用小端序存储。

IA-32寄存器

寄存器概述

  • 寄存器:CPU内部用来存储数据的一些小型存储区域,有非常高的读写速度。
  • 与RAM的区别:CPU访问RAM中的数据时要经过较长的物理路径,花费时间长。
  • 学习目标:学习调试器解析出的汇编指令。

IA-32寄存器

IA-32是英特尔推出的32位架构,属于复杂的指令集架构,支持多种寄存器。

基本程序运行寄存器

E表示扩展,表示该寄存器在16位CPU(IA-16)时已存在,并且其大小在IA-32下由原16位扩展为32位。

通用寄存器
  • 4字节32位:保存常量与地址。

  • 功能:传送和暂存数据,参与算术逻辑运算,保存运算结果。

  • 各寄存器

  • EAX:累加器(针对操作数和结果数据)。

  • 应用:用在函数返回值中,所有Win32 API函数都会先把返回值保存到EAX再返回。

  • EBX:基址寄存器(DS段中的数据指针)。

  • ECX:计数器(字符串和循环操作)。

  • 应用:也可以用在循环命令(LOOP)中循环计数,每执行一次循环,ECX减1。

  • EDX:数据寄存器(I/O指针)。

以上4个寄存器主要用在算法运算(ADD、SUB、XOR、OR)指令中,常用来保存常量与变量的值。某些汇编指令(MUL、DIV、LODS)直接操作特定寄存器,执行这些命令,仅改变特定寄存器的值。

  • EBP:扩展基址指针寄存器(SS段中栈内数据指针)。
  • 应用:表示栈区域的基地址,函数被调用时保存ESP的值,函数返回时再把值返回ESP,保证栈不会崩溃(即栈帧技术)。
  • ESI:源变址寄存器(字符串操作源指针)。
  • EDI:目的变址寄存器(字符串操作目标指针)。
  • ESP:栈指针寄存器(SS段中栈指针)。
  • 应用:指示栈区域的栈顶地址,某些指令(PUSH、POP、CALL、PET)可以直接用来操作ESP。

后四个寄存器主要用作保存内存地址的指针。

  • 对低16位兼容
  • EAX:(0~31)32位
  • AX:(0~15)EAX的低16位
  • AH:(8~15)AX的高8位
  • AL:(0~7)AX的低8位

段寄存器

  • 段的概念:段是一种内存保护技术。它把内存划分为多个区段,并为每个区段赋予起始地址、范围、访问权限等,以保护内存。

  • 段寄存器的作用:段寄存器持有SDT(段描述符表)的索引。

  • 组成:由6种寄存器组成,每个寄存器大小为2字节16位,存放相应所在段的段基址。

  • CS:代码段寄存器

  • SS:栈段寄存器

  • DS:数据段寄存器

  • ES:附加(数据)段寄存器

  • FS:数据段寄存器

  • 应用:用于计算SEH(结构化异常处理机制)、TEB(线程环境块)、PEB(进程环境块)等地址。

  • GS:数据段寄存器

每个段寄存器指向的段描述符与虚拟内存结合,形成一个线性地址,借助分页技术,线性地址最终被转换为实际的物理地址。在不使用分页技术的操作系统中,线性地址直接变为物理地址。

程序状态与控制寄存器

  • EFLAGS:标志寄存器
  • 大小:4字节32位,由原来16位FLAGS寄存器扩展而来。
  • 每位的值:1或0。
  • 标志位
  • ZF:零标志,若运算结果为0,则值为1,否则为0。
  • OF:溢出标志,有符号整数溢出时,OF值被设置为1。MSB(最高有效位)改变时,其值也被设为1。
  • CF:进位标志,无符号整数溢出时,其值也被设置为1。

指令指针寄存器

  • EIP:指令指针寄存器
  • 大小:4字节32位,由原16位IP寄存器扩展而来。
  • 功能:保存着CPU要执行的指令地址。
  • 执行过程:程序执行时,CPU会读取EIP中一条指令的地址,传送指令到指令缓冲区后,EIP寄存器的值自动增加,增加的大小即是读取指令的字节大小。
  • 特点:CPU每次执行完一条指令,就会通过EIP寄存器读取并执行下一条指令。
  • 修改方式:与通用寄存器不同,不能直接修改EIP的值,只能通过其他指令间接修改,比如JMP、Jcc、CALL、RET,还可以通过中断或异常修改EIP的值。

栈内存在进程中的作用如下:

  • 暂时保存函数内的局部变量
  • 调用函数时传递参数
  • 保存函数返回后的地址

栈是一种数据结构,按照FILO(后进先出)的原则存储数据。

栈的特征

一个进程中,栈顶指针(ESP)初始状态指向栈底端。执行PUSH命令将数据压入栈时,栈顶指针就会上移到栈顶端。执行POP命令从栈中弹出数据时,若栈为空,则栈顶指针重新移动到栈底端。栈是一种由高地址向低地址扩展的数据结构,栈是由下往上扩展的,逆向扩展。

栈操作示例

打开Stack.exe(调试过程中,寄存器的初始值与栈的初址会随运行环境的不同而不同)。

可以看到栈顶指针的值为19FF74,观察右下角的栈窗口,可以看到ESP指向的地址及其值。

在代码窗口按F7,执行401000地址处的PUSH 100命令,ESP的值变为了19FF70,比原来减少了4个字节,并且当前栈顶指针指向了19FF20地址,该地址保存的值就是100。也就是说,执行PUSH命令时,数值100被压入栈,ESP随之向上移动,值减少4个字节。

再次按F7,执行401005地址的POP EAX命令,可以发现,ESP的值增加了4个字节,变为了19FF74,变为了一开始的状态。也就是说,从栈中弹出数据后,ESP随之向下移动。

总结:栈顶指针在初始状态指向栈底。向栈压入数据时,栈顶指针减小,向低地址移动;从栈中弹出数据时,栈顶指针增加,向高地址移动。

总结

第3到5章初看时可能感觉很多都是记忆类的知识,不太容易理解,尤其是寄存器相关,可以大概先留个印象,初步学习时,知道这个术语在这里出现过就可以了。关键的点是栈的理解,可以结合实例去弄明白栈的特征。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号