跳转到帖子

游客您好,欢迎来到黑客世界论坛!您可以在这里进行注册。

赤队小组-代号1949(原CHT攻防小组)在这个瞬息万变的网络时代,我们保持初心,创造最好的社区来共同交流网络技术。您可以在论坛获取黑客攻防技巧与知识,您也可以加入我们的Telegram交流群 共同实时探讨交流。论坛禁止各种广告,请注册用户查看我们的使用与隐私策略,谢谢您的配合。小组成员可以获取论坛隐藏内容!

TheHackerWorld官方

保护模式笔记二 段寄存器

精选回复

发布于

保护模式笔记二 段寄存器

6073892f43ece.png

前言

所有保护模式索引链接:保护模式笔记一 保护模式介绍

先前提到了保护模式下的两大特点:段的机制和页的机制

先从段的机制开始学习,而要学习段的机制,首先要了解的便是段寄存器


段寄存器

什么是段寄存器

在先前的逆向基础笔记五 标志寄存器中,有提到过段寄存器的概念

当使用汇编来操作一个内存地址时,就会涉及到段寄存器,只不过先前并没有太过在意

如:

 复制代码 隐藏代码
mov dword ptr ds:[0x123456],eax

注意汇编语句中的 ds,它就是一个段寄存器

实际上真正读取的内存地址为:ds.base+0x123456


段寄存器有哪些

段寄存器共8个: CS DS ES SS  FS GS LDTR TR

CS

代码段寄存器,用于存放代码段的段基址

DS

数据段寄存器,用于存放数据段的段基址

ES

附加段寄存器,用于存放附加段的段基址

SS

堆栈段寄存器,用于存放堆栈段的段基址,指示堆栈段区域的位置

FS

附加段寄存器,F为上一个附加段寄存器字母E后的字母,没有对应的名称

指向一种被称为线程信息块(TIB)的结构,这种结构是由内核在创建线程时创建的,用于支持操作系统相关功能、服务和API

GS

附加段寄存器,G为上一个附加段寄存器字母F后的字母,没有对应的名称

在32位Windows上GS保留供将来使用

在x64模式下,FSGS段寄存器已交换

Win64使用GS的原因是该FS寄存器用于32位兼容性层(称为Wow64)

32位应用程序永远不会导致GS更改,而64位应用程序永远不会导致FS更改

注意,在Win64和Wow64中GS是非零的,这可以用来检测一个32位应用程序是否在64位Windows中运行,在一个“真正“的32位Windows中GS总是零

IDTR

中断描述符表寄存器,用于存放中断描述符表IDT的32位线性基地址和16位表长度值

TR

任务寄存器,用于存放当前任务TSS段的16位段选择符、32位基地址、16位段长度和描述符属性值


段寄存器的结构

组成BaseLimitAttributeSelector
数据宽度32位32位16位16位
是否可见不可见不可见不可见可见
描述基地址(当前段的起始地址)大小限制(当前段的整个长度)属性(当前段是否可读可写可执行)段选择子

 复制代码 隐藏代码
struct Segment{     WORD Selector;     WORD Attribute;     DWORD Base;     DWORD Limit; }

段寄存器的属性

拿OD随便载入一个程序,观察寄存器窗口:

image-20210411163725387

得到了当前的计算机的段寄存器信息(不同计算机段寄存器信息不一定相同)


段寄存器SelectorAttributeBaseLimit
ES0023可读、可写00xFFFFFFFF
CS001B可读、可执行00xFFFFFFFF
SS0023可读、可写00xFFFFFFFF
DS0023可读、可写00xFFFFFFFF
FS003B可读、可写0x7FFDE0000xFFF
GS----

段寄存器的读写

对于段寄存器可以使用MOV指令进行读写(LDTR和TR除外)

读段寄存器

 复制代码 隐藏代码
#include <stdio.h> #include <windows.h> int main(){         WORD selector=0;         _asm{                 mov selector, es         }         printf("%x\n",selector);         return 0; }

对段寄存器的读操作只能读取段寄存器的16位Selector部分(可见部分)


运行结果

image-20210411174259638

能够正确地读出es段寄存器的selector


写段寄存器

 复制代码 隐藏代码
#include <stdio.h> #include <windows.h> int main(){         WORD data;         _asm{                 mov bx,ds                //将段寄存器ds的Selector部分保存到bx(ecx的低16位)                 mov ax,cs                //将段寄存器cs的Selector部分保存到ax(eax的低16位)                 mov ds,ax                //将先前读出来的段寄存器去写ds这个段寄存器,也就是用cs段寄存器覆盖ds段寄存器                 mov cx,word ptr ds:[_data]        //使用cs段寄存器覆盖过的ds段寄存器,读取_data                 mov data,cx                                        //将读出来的数据赋值给变量data                 mov ds,bx                                        //还原被修改的ds段寄存器                 jmp _end                                        //跳过数据部分,继续执行 _data:                 _emit 0x00                 _emit 0x61 _end:         }         printf("%X\n",data);         return 0; }

运行结果

image-20210411170151931

可以看到代码是能够正常执行,并且输出对应的数据段的代码的


说明

为什么明明替换了段寄存器,仍然能够正常运行呢?

首先要注意到,替换和被替换的段寄存器分别是:cs和ds;它们的base是相同的都为0,因此所访问的内存自然也是相同的

再来看权限问题:无论是cs还是ds,它们都具有可读的权限;这里也只对数据进行了读操作,于是可以正常运行

如果这里将读取_data的代码修改为写_data的代码,则会报错:

 复制代码 隐藏代码
mov cx,word ptr ds:[_data]        //使用cs段寄存器覆盖过的ds段寄存器,读取_data //将上面的代码修改为: mov word ptr ds:[data],cx        //修改_data的数据

为什么会报错?因为此时的ds段寄存器已经被覆盖为了cs段寄存器,而cs段寄存器的权限为可读、可执行,没有可写的权限,所以会报错

报错截图:

image-20210411171305883

可以看到,此时的_data的地址明明是有效的,先前也验证了可以正确读取,但是在这里就会报错:Acccess Violation(非法访问)

就这里就是因为段寄存器权限不足导致的,也是为什么先前都是使用ds段寄存器来赋值,而不是用cs段寄存器

 复制代码 隐藏代码
mov dword ptr ds:[address],data        //使用ds段寄存器修改数据,可以正常修改 mov dword ptr cs:[address],data //使用cs段寄存器修改数据,会报错

和前面对段寄存器的读操作不同,写寄存器是对整个96位的段寄存器进行修改

但是这里明明只给出了16位的段选择子Selector,剩下的80位呢?

这个就段描述符有关了,这里暂且不谈,留作之后自会知晓,先记住写寄存器是对整个段寄存器进行修改即可


验证Limit

在前面的读写中,或多或少都验证了段寄存器的几个属性:Base、Selector、Attribute

现在最后验证一下Limit

 复制代码 隐藏代码
#include <stdio.h> #include <windows.h> int main(){         unsigned char base;         _asm{                         mov al,fs:[0x1000]                //超过limit:0xfff,无法正常运行                 mov base,al         }         printf("%x\n",base);         return 0; }

image-20210411190011540


 复制代码 隐藏代码
#include <stdio.h> #include <windows.h> int main(){         unsigned char base;         _asm{                         mov al,fs:[0xfff]                //在临界点可以正常运行                 mov base,al         }         printf("%x\n",base);         return 0; }

image-20210411185454452


总结

  • 段寄存器共96位,其中16位为可见部分,后80位为不可见部分
  • 不同计算机段寄存器信息不一定相同
  • FS和GS两个段寄存器分别在32位程序和64位程序发挥作用

创建帐户或登录后发表意见

最近浏览 0

  • 没有会员查看此页面。