关于 IA-32 寄存器——入门逆向工程必备前置知识

基本程序运行寄存器

笔者在上一学期试着通过《逆向工程核心原理》接触逆向工程这一领域,其中寄存器部分作为重要的前置知识,笔者在书中第一次读到时,体验较为痛苦,知识难以下咽。好在在选修了计算机组成这门课以及用OD进行了多次动调之后对寄存器这里的知识有了更为清晰的认识。下面这篇 IA-32 寄存器学习笔记只是在复习计组时突然感受到知识连接起来的畅快感后,整理出的一篇学习笔记。

通用寄存器(General Purpose Register)

image

用途

  • 传送和暂存数据;
  • 参与算数逻辑运算,并保存运算结果。

各寄存器具体用途

EAX(累加器)

  • 用于寄存操作数和结果数据;
  • 用于函数返回值,所有Win32 API函数都会先把返回值保存在EAX再返回。

EBX(基址寄存器)

用于基址寻址

image

一般情况下, CPU 内部有一个专门的基址寄存器。如 Intel 8086 中的 BXBP

若基址是 BX ,则操作数在数据段;若基址是 BP ,则操作数在堆栈段,因此基址寻址方式下,基址寄存器采用隐含寻址的方法,不需要在指令中显式地指出。指令中的形式地址字段给出参与基址寻址的偏移值。如果采用通用寄存器作为基址寄存器,则需要在指令中明确地指出寄存器的编号。

基址寻址面向系统,主要用于程序的重定位。如多道程序设计环境下,需要由系统的管理程序将多道程序装入主存。由于用户编程使用的是逻辑地址,当用户程序装人主存时,为了实现用户程序的再定位,系统程序给每个用户程序分配一个基地址。程序运行时,该基地址装人基地址寄存器,通过基址寻址实现逻辑地址到特定用户物理地址的变换。用户通过改变指令中的形式地址 D 来实现指令或操作数的寻址。基址寄存器的内容是操作系统或管理程序通过特权指令设置的,对用户透明。对每一个用户程序而言,在程序执行过程中基址寄存器的值保持不变。

除解决程序的重定位问题外,基址寻址方式还能扩展寻址空间,这一功能可通过增加基址寄存器的字长来实现 如将基址寄存器的位数从32位增加到34位后,采用基址寻址的寻址范围将从4G扩展到16G。

变址寻址是面向用户的,主要解决程序循环问题,变址寄存器的内容由用户设置,程序执行过程中,用户通过改变变址寄存器的内容实现指令或操作数的寻址。

相对寻址,变址寻址和基址寻址3种寻址方式计算有效地址的方式非常类似,都由某寄存器的内容与指令中形式地址字段之和作为有效地址。通常将这3种寻址方式统称为偏移寻址

ECX(计数器)

一般用于字符串和循环操作,在循环命令(LOOP)中ECX用来循环计数,每循环一次ECX都会减一。

EDX(数据寄存器)

IO指针,也总是被用来放整数除法产生的余数。

注意

Win32 API函数在内部会使用 ECX、EDX,调用API前要先把 ECX、EDX中的重要数据备份到其他寄存器或栈。

EBP(扩展基址指针寄存器)

EBP表示的是栈区域的基地址,是SS段中的数据指针,具体详见栈帧部分。

ESP(栈指针寄存器)

保存栈顶地址。

ESI(源变址寄存器)

字符串操作源指针。

EDI(目的变址寄存器)

字符串操作目标指针。

EDI 和 ESI 与特定指令(LODS、STOS、REP、MOVS等)一起使用,主要用于内存复制。

段寄存器

image

内容

段寄存器是因为对内存的分段管理而设置的。计算机需要对内存分段,以分配给不同的程序使用(类似于硬盘分页)。在描述内存分段时,需要有如下段的信息:

  1. 段的大小;
  2. 段的起始地址;
  3. 段的管理属性(禁止写入/禁止执行/系统专用等)。

IA-32 的保护模式中,段是一种内存保护技术,将内存划分为多个区段,各个段寄存器指向的SDT(段内存描述表)和虚拟内存结合形成一个线性地址,同分页技术(paging)一起将虚拟内存变更为实际物理内存。

需要用8个字节(64位)存储这些信息,但段寄存器只有16位,因此段寄存器中只能存储段号(segment selector,也译作“段选择符”),再由段号映射到存在内存中的GDT(global (segment) descriptor table,全局段号记录表),读取段的信息。

16位CPU有四个16位段寄存器,所以,其程序可同时访问四个不同含义的段。

8086CPU 有20根地址线,最大可寻址内存空间为 1MB。而 8086 的寄存器只有 16 位,指令指针(IP)和变址寄存器(SI、DI)也是16位的。用 16 位的地址寻址 1MB 空间是不可能的。所以就要把内存分段,也就是把1MB空间分为\(2^4\) ,即 16 个段,每段不超过 64KB(\(2^{16}\), 16位数据线就可以寻址)。在8086中设置4个16位的段寄存器,用于管理4种段:CS是代码段,DS是数据段,SS是堆栈段,ES是附加段。把内存分段后,每一个段就有一个段基址,段寄存器保存的就是这个段基址的高16位,这个16位的地址左移四位(后面加上4个0)就可构成20位的段基址。

代码段寄存器CS(Code Segment)

存放当前正在运行的程序代码所在段的段基址,表示当前使用的指令代码可以从该段寄存器指定的存储器段中取得,相应的偏移量则由IP提供。

数据段寄存器DS(Data Segment)

指出当前程序使用的数据所存放段的最低地址,即存放数据段的段基址。

堆栈段寄存器SS(Stack Segment)

指出当前堆栈的底部地址,即存放堆栈段的段基址。

附加段寄存器ES(Extra Segment)

指出当前程序使用附加数据段的段基址,该段是串操作指令中目的串所在的段。

程序状态与控制寄存器

image

EFLAGS,标志寄存器,大小为32位,这32个位元中只需要掌握 ZF、OF、CF。

  • ZF:运算结果是0则置1。
  • OF:MSB(Most significant Bit)改变时置为1,所以有符号整数溢出时会置1。
  • CF:无符号整数溢出时置1。

指令指针寄存器(EIP)

大小为32位,和其他通用寄存器不同,我们不能直接修改 EIP 的值。只能通过JMP、Jcc、CALL、RET 等指令间接修改。

posted @ 2022-01-18 12:15  oneQuiz  阅读(429)  评论(0)    收藏  举报