avatar

Catalog
探究段寄存器

被忽视的ds

Code
1
mov dword ptr ds:[0x003f048], eax

在进行ring3逆向时,海哥让我们不去管ds寄存器的作用,只需要理解,这条语句的作用是将eax的值,写入0x003f048这个地址处即可;但是到了保护模式,这种说法就不再准确了,接下来一步步探寻ds的本质

段寄存器

ds 是 CPU 中的一个寄存器,这种寄存器称为段寄存器,除了ds,还有cs、es、ss、fs、gs 、ldtr、tr共八个。

打开OllyDbg,任意附加一个.exe文件,可以在右侧窗口看到如下一块区域

这些是OllyDbg调试器显示出当前程序运行时段寄存器的各部分属性的值。接下来分析这些值的来源和含义。

段寄存器的读写

在后面的部分会经常用到段寄存器的读写,这里先说明一下:

读:

Code
1
mov ax, fs

写:

Code
1
mov ds, ax

段寄存器在的时候,只读了16位,但是的时候会写入96位。

注意:ldtr和tr段寄存器不能用mov指令进行读写

段寄存器结构

Code
1
2
3
4
5
6
struct SegmentReg {
WORD selector;
WORD attribute;
DWORD base;
DWORD limit;
}

由段寄存器的结构可知,段寄存器共96位,由16位的段选择子,16位的段属性,32位的base和32位的limit组成。

打印ds寄存器的值,发现只能显示0x0023,也就是段选择子那16位。不是说好的共96位吗?实际上,剩下来80位是不可见的部分,只不过OD也展示出来了,接下来证明每个属性的存在。

段基址

Code
1
mov eax, dword ptr ds:[0]

理论上,上面这条语句是无法执行成功的,因为零地址是不允许访问的(因为没有给零地址挂物理页)

但是上述程序可以成功执行(这里不使用ds,原因是vc6作者对ds做过优化,写成ds将编译不过去),说明了这里访问的不是零地址,而是其它地址,也就是说,段寄存器修改了写入数据的地址,证明了段基址的存在。

这里真正的将数据写入eax的地址是:

Code
1
gs.base + 0x0

以下是常见段的基址

段寄存器 Base
ES 0
CS 0
SS 0
DS 0
FS 0x7FFDE000
GS -

由于将fs段的值赋给了gs段,因此写入eax寄存器的是0x7FFDE000地址上的值。

段属性

上面两段程序的差别仅仅在于插入的汇编的第一条指令,mov ax, cs 和 mov ax, ss。造成结果不同的原因是,ss段寄存器是可读、可写的,而cs段寄存器是可读、可执行,但是不可写;因此在试图向cs段寄存器所指向的基址+偏移(既[ ]内的值)是会发生访问违例的,这也说明了,不同的段寄存器,属性是不同的,证明了段属性的存在。

段限长

又出现了访问违例的情况,此处var的值为0x1000,超过了fs段寄存器的Limit:0xFFF,所以此时已经不能通过fs段来访问fs.base+0x1000这个地址了,这说明段寄存器也有一定的管辖范围,超出这个范围,就没有权限访问了

总结

这次的笔记主要探究了段寄存器的属性和结构,大致整理如下

段寄存器 段选择子 属性 基址 限长
ES 0x0023 RW 0 0xFFFFFFFF
CS 0x001B RX 0 0xFFFFFFFF
SS 0x0023 RW 0 0xFFFFFFFF
DS 0x0023 RW 0 0xFFFFFFFF
FS 0x003B RW 0x7FFDE000 0xFFF
GS - - - -

参考文章:https://blog.csdn.net/q1007729991/article/details/52537943

参考教程:https://www.bilibili.com/video/av68700135?p=7

Author: cataLoc
Link: http://cataloc.gitee.io/blog/2020/03/06/%E6%8E%A2%E7%A9%B6%E6%AE%B5%E5%AF%84%E5%AD%98%E5%99%A8/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付寶
    支付寶