保护模式 2讲 -段 -段寄存器结构
保护模式 -段 -段寄存器结构
一丶保护模式学习
保护模式,主要学习的就是段 与 页 的关系. 学习段的时候先学习段寄存器
-
何为段
根据Intel 手册第三卷所属. 分段和分页是操作系统提供的机制. 这种机制可以为每个
程序或者任务提供单独的代码. 数据 和栈. 也就是我们 常常所说的进程隔离
保证了多个任务何以运行在一个处理器之上,且不会互相影响. 这就是分段.
-
何为页
分页机制 是实现了传统的请求 调用 页虚拟机内存系统. 简单来说就是内存是如何管理的.
分页机制同样可以实现任务隔离. 在保护模式下. 分段机制 是必须的 而分页是可选的.
所以先从段开始学.
二丶段寄存器
2.1 什么是段寄存器
先看一段汇编 代码如下
mov eax,fs:[0]
mov eax,fs:[eax + 0x30]
上面的代码学过 TEB PEB 结构的人应该知道.是在做什么. 而我么你这里所说不讲 PEB TEB
看汇编代码.我们操作了FS; FS就是段寄存器 我们这里操作的地址分别就是 FS:[0] 与 fs:[0x30]
而其实展开来说. 我们真正的操作的地址是 FS.base + 0 或者 FS.base + 0x30 这样来操作的.
出了FS寄存器.还有 ES CS SS DS GS LDTR TR等段寄存器
我们上面所说的 段.base 其实是段寄存器的一个成员. 可以理解为段寄存器就是一个结构体
PS: 在inter手册中也称为段寄存器为段描述符
2.2 段寄存器结构
在我们x86平台下.我们知道一个寄存器是 4个字节. 32位. 可以表达一个32位的数据. 但是我们的段
却很少有人关注 其实我们的段 是有96位的.是一个结构体.
结构如下:
struct Segment
{
WORD Selecter; //16位段选择子 可见部分. 使用OD 或者X64dbg看段寄存器只会显示16位的段选择子可见部分.
WORD Attribute; //16位表示的段属性, 表示了当前段寄存器是可读的可写的还是可执行的
DWORD Base; //32位表示的基址,表示段从哪里开始
DWORD limit; //32位表示,表示的是基址的长度. base + limit 可以确定一个段的大小
}
2.3 段寄存器的读写
使用汇编可以对段寄存器进行读写.
读取
mov ax,ss 段寄存器的可见部分只有16位.所以读出来之后只能放到16位寄存器中
写入
mov ss,ax 读寄存器只是读了可见部分的16位.而写入寄存器则是写入了96位
inter手册对段寄存器的操作寄存器指令有以下
- 直接载入的指令
mov pop LDS LES LSS LGS LFS L是Load的意思
-
其它隐含改变的指令
Call JMP RET Sysenter sysExit iret intn int0 int3
2.4 段寄存器的探测
2.4.1 段寄存器结构
在x86下.我们可以看如下寄存器表示图.
| 寄存器名称 | 段选择子(Select) | 段属性(Attributes) | 段基址(Base) | 段长(Limit) |
|---|---|---|---|---|
| ES(附加扩展段) | 0x0023 | 可读,可写 | 0x0000000 | 0xFFFFFFFF |
| CS(代码段) | 0x001B | 可读,可执行 | 0x00000000 | 0xFFFFFFFF |
| SS(堆栈段) | 0x0023 | 可读,可写 | 0x00000000 | 0xFFFFFFFF |
| DS(数据段) | 0x0023 | 可读,可写 | 0x00000000 | 0xFFFFFFFF |
| FS(分段机制) | 0x003B | 可读,可写 | 0x7FFDF000 | 0xFFF |
| GS | 未使用 | 未使用 | 未使用 | 未使用 |
2.4.2 段寄存器中的 段属性探测
我们可以巧妙的利用汇编.来探测一下段属性 是否存在的. 依靠段寄存器结构所知. 出了CS段 不能写之外.其余段都是可以写的.
那么看一下内敛汇编代码.
-
CS代码段 段属性探测
int Var = 0; int main() { __asm { mov ax,cs mov ds,ax mov dword ptr ds:[Var],eax ;等价于 mov dword ptr cs:[Var],eax } }将CS赋值到AX中. AX赋值给DS. 此时DS就代表CS了. 如果以把eax之给 CS.则会出现错误.
可以将代码放到VS2019中.直接编译生成. 运行之后会崩溃. 而下方的则不会崩溃.
说明权限确实是不可写.
-
其它代码段段属性探测
int Var = 0; int main() { __asm { mov ax,ss mov ds,ax mov dword ptr ds:[Var],eax } }
2.4.3 段基地址探测
根据上面我们可以轻而一举的探测出 CS段 带有不可写的属性. 那么同样我们可以探测一下基地址.
在上图我们得知. 有基地址的只有FS. 看如下代码.
int main()
{
__asm
{
mov ax,fs
mov gs,ax
mov eax,gs:[0]
}
}
看汇编我们可以看到. 为啥访问 gs:[0]不会出错那. 有基础的都应该知道. 0地址是不可读的. 其实我们说过. 我们对任何一个地址的操作,操作的都是它的 段.base + 偏移的方式. 在实模式下.这个概念应该知道.到了保护模式下. 段base为0了. 所以偏移就是我们看到的虚拟地址.
上面的汇编是一样的. FS是有基地址的. 当其赋值给gs的时候. gs代表的就是fs. 所以用 gs去操作[0]地址是有效的. 等价于操作 fs:[0]
而FS:[0] 就是我们的TEB结构.
2.4.4 段长探测
在段地址探测中,我们学习到了 访问有效地址 都等价于 段.base + 偏移地址 x86下.偏移地址就是我们所看到的虚拟地址. 也称为逻辑地址.
那么我们如何探测 段长? 根据段寄存器表格得知. FS的 limit 只有0xFFF大小. 我们可以写汇编代码验证一下
int main()
{
__asm
{
mov ax, fs
mov gs, ax
mov eax, gs: [0] //fs.base + 0 读取
mov eax,gs:[0x1000]//fs.base + 0x1000
mov eax, dword ptr ds : [eax + 0xFFF] ;
// mov eax,gs:[0x1000] //fs.base + 0x1000 读取
}
}
可能是我们win764上测试的. 读取长度.越界读取.都会导致程序崩溃.
坚持两字,简单,轻便,但是真正的执行起来确实需要很长很长时间.当你把坚持两字当做你要走的路,那么你总会成功. 想学习,有问题请加群.群号:725864912(收费)群名称: 逆向学习小分队 群里有大量学习资源. 以及定期直播答疑.有一个良好的学习氛围. 涉及到外挂反外挂病毒 司法取证加解密 驱动过保护 VT 等技术,期待你的进入。
详情请点击链接查看置顶博客 https://www.cnblogs.com/iBinary/p/7572603.html
本文来自博客园,作者:iBinary,未经允许禁止转载 转载前可联系本人.对于爬虫人员来说如果发现保留起诉权力.https://www.cnblogs.com/iBinary/p/13155281.html
欢迎大家关注我的微信公众号.不定期的更新文章.更新技术. 关注公众号后请大家养成 不白嫖的习惯.欢迎大家赞赏. 也希望在看完公众号文章之后 不忘 点击 收藏 转发 以及点击在看功能.
QQ群:

浙公网安备 33010602011771号