段探测的研究

在介绍今天的内容之前,我们先要知道一些前置的知识

跳过繁琐的介绍,我们单刀直入,介绍一个划时代的CPU 8086

8086

从8086开始,CPU扩展到了16位,地址的位宽扩展到了20位,自此之后我们现在所熟知的计算机结构大体确定了,包括各个寄存器

在这里插入图片描述

80386

在8086问世后,唯一有比较大飞跃的就是80386,其首先将位宽扩展到了32位,地址也扩展到了32位,最重要的是,它加入了分页的虚拟内存机制

CPU的两种架构

Risc

定长机器码

Cisc

变长机器码,指令长度由解析的Opcode来决定、

两种架构里面,按理来说应该是不需要解析的Risc性能较好,但是实际中,由于耗电量和CPU振动频率,Cisc的性能更好。

由此,嵌入式设备,手机这种电子设备大多使用的Risc,因为省电,稳定;相反来说,Cisc性能更好,被用于我们的PC机中

段和页

现在回到我们一开始所介绍的划时代的8086上面,在8086中,我们的系统是直接运行在物理地址上的,并且内核和用户并没有严格区分

在这里插入图片描述

而我们知道对于汇编来说寻址就是段地址*0x10+段内逻辑地址 = 线性地址

就以最普通的寻址为例

mov ax ,word ptr ds:[0x12345]

这种没有任何隔离的访问方式可以导致在用户层面的代码可以在知道对于段的情况下,直接访问内核的地址,这显然是不利于我们的安全的

这时候我们就可以引入了上面说的80386,它引入了段页的划分

页这种方式就可以轻松的用虚拟地址来将我们的内存隐藏起来避免了我们对物理地址的直接访问

核心就是两点:段是权限的划分,页是物理地址的隐藏

之后我们本节也是会围绕

1.段 如何利用权限的规则

2.页 如何找到真正的物理地址

段寄存器

CS(Code Segment)

  • 用途指向当前正在执行的代码所在的内存段。
  • 描述:CS寄存器包含了当前代码段的基地址。处理器使用CS寄存器来确定指令的获取位置。当处理器执行跳转或调用指令时,CS寄存器的值可能会改变。

DS(Data Segment)

  • 用途指向数据所在的内存段。
  • 描述:DS寄存器通常用于访问全局变量或静态数据。在许多情况下,编译器会将数据段的选择子加载到DS寄存器中,以便程序能够访问这些数据。

SS(Stack Segment)

  • 用途:指向当前使用的栈所在的内存段。
  • 描述:SS寄存器包含了当前栈段的基地址。栈用于存储函数调用的返回地址、局部变量以及其他临时数据。当执行压栈或弹栈操作时,处理器会使用SS和SP(栈指针)寄存器来访问栈。

ES(Extra Segment)

  • 用途:指向额外的数据段,常用于字符串操作。
  • 描述:ES寄存器通常用于某些特定的字符串操作指令,如MOVS(移动字符串)和STOS(存储字符串)。它允许程序访问不同的数据段,而不需要修改DS寄存器。

FS

  • 用途:指向额外的数据段,通常用于线程本地存储(Thread Local Storage, TLS)也是本地上下问环境的存储,在R3中存储的TEB,在R0中存储的KPCR
  • 描述:FS寄存器常用于访问线程特定的数据,特别是在多线程环境中。操作系统可能会使用FS段来存储线程局部变量。

段寄存器的权限

不同段寄存器指向的段,权限是不同的

我们以一段简单的代码为例(x86)

#include "stdafx.h"
#include <Windows.h>int val = 0x100;
int val2 = 0x200;int _tmain(int argc,_TCHAR* argv[]){__asm{mov ax ,cs;mov ds , ax;mov eax ,dword ptr [val];mov dword ptr [val2],eax;}printf("%x\r\n",val2);system("pause");return 0;
}

可以看见,我们将cs的值移到了ds里面

当我们继续运行时,出现了0xC00005,这说明我们权限出了问题

在这里插入图片描述

上面图中的报错表示,我们出错正是在向段所指内存中写值时报错,这证明

1.ds段寄存器和cs段寄存器有着不同的权限,至少有一个没有写权限,通过查阅知道,cs段是代码段是没有写权限的

2.默认去取全局变量的地址时,编译器会智能的将我们的赋值指向ds段,这里我们在上面的代码中交换了cs和ds的值,所以ds里面的值实际上是cs的值

这里我们修改回去,es里面的值与ds相同,这是微软的规定,重新编译

#include "stdafx.h"
#include <Windows.h>int val = 0x100;
int val2 = 0x200;int _tmain(int argc,_TCHAR* argv[]){__asm{mov ax ,cs;mov ds , ax;mov ax,es;mov ds,ax;//Win系统中es和ds值是一样的mov eax ,dword ptr [val];mov dword ptr [val2],eax;}printf("%x\r\n",val2);system("pause");return 0;
}

在这里插入图片描述

我们继续实验,如果将两个被定义的变量移入main函数中,看汇编,这时候,段寄存器又变为了ss,也就是栈段。这里就是用实验证明的,如果是局部变量,那么就会用ss寻址

在这里插入图片描述

段选择符

我们继续往下,这时候我们可以选择记住目前段寄存器的值

在这里插入图片描述

从网上查阅资料可以知道,此时寄存器中存着的就是段选择子

在这里插入图片描述

就以CS为例,1B的16位二进制表示为0000 0001 1011

按照上图所示,CS的TI位为0,所以指向的是GDT,结构如下

在这里插入图片描述

回到我们的段选择符,前面3到15的index号表明,我们要去找GDT表中的序号为3的项

打开Windbg,用r gdtr命令来看当前GDT表的指向,可以看见这里指向了807d4c20

1: kd> r gdtr
gdtr=807d4c20

我们可以使用dq命令来看内存,d是看内存,q是qword

1: kd> dq 807d4c20
ReadVirtual: 807d4c20 not properly sign extended
807d4c20  00000000`00000000 00cf9b00`0000ffff
807d4c30  00cf9300`0000ffff 00cffb00`0000ffff
807d4c40  00cff300`0000ffff 80008b7c`f75020ab
807d4c50  8040937c`c0003748 0040f300`00004000
807d4c60  0000f200`0400ffff 00000000`00000000
807d4c70  8000897d`1ac00068 8000897d`1b300068
807d4c80  00000000`00000000 00000000`00000000
807d4c90  800092b9`900003ff 00000000`00000000

序号为三,也就是第四项,值为00cffb00`0000ffff

首先我们从低位看起

根据上面的图,0到15位是段的限长,值为ffff,再加上48-51的4位限长还是f,所以最后是fffff

而base的值为 00 0000,再添加上两段分开的00,最后还是0

继续向下解析,39-42为b也就是1011,type就是b,S位(这里图有误,也就是红色的那个1)为1,所以是代码段或者数据段,对应的type如下

在这里插入图片描述

如果s为0,那么type则为system段,这里暂时不涉及

在这里插入图片描述

DPL为11,也就是3,p为1

最后的52-55为值为c,也就是1100,G位为1,D/B位为1,def位为0,AVL位为0

到此为止,我们已经看完了段描述符的所有信息

一股脑解析完这些信息,我们要知道它的作用

首先,G位为1

那么就表明我们现在以页为单位,再intel中,一个页是4096字节,也就是0x1000

页数也是从0开始所以有(fffff+1)页,每页大小0x1000,因为我们在计算机中算总长度的时候,是从0开始的所以最后要减一

写成公式就是((ffff+1) x 0x1000 )-1 = 0xffffffff

这个值,我们用十六进制看不熟悉,但是如果换成十进制

在这里插入图片描述

地址的下标范围到4294967295,长度是4294967296

这个值我们除1024^3,结果就是4,也就是4GB

到此为止,我们得出结论,这个段,最多管理着4GB的内存

段长度的验证

学习到这里,我们怎么去验证我们段描述符所规定的段范围是正确的呢

为了不影响我们程序最后的正常运行,我们将GDT表中的一段标为0的字节作为我们待会放置新GDT

的位置,按照序号来说,它就是9,结合 我们之前的知识,我们ds的值应该替换为4b,也就是0100 1011,index位对应为9

1: kd> dq 807d4c20
ReadVirtual: 807d4c20 not properly sign extended
807d4c20  00000000`00000000 00cf9b00`0000ffff
807d4c30  00cf9300`0000ffff 00cffb00`0000ffff
807d4c40  00cff300`0000ffff 80008b7c`f75020ab
807d4c50  8040937c`c0003748 0040f300`00004000
807d4c60  0000f200`0400ffff 00000000`00000000//在这里
807d4c70  8000897d`1ac00068 8000897d`1b300068
807d4c80  00000000`00000000 00000000`00000000
807d4c90  800092b9`900003ff 00000000`00000000

我们修改我们之前的代码,先将4b这个描述符对应的值送入对应的寄存器中(我这里vmtool暂时除了问题,就偷懒贴个图片了)

在这里插入图片描述

写好上面的代码之后,我们先把原段选择子23位置的值,移入到4b里面,这里通过windbg实现

0: kd> eq 80b99048 00cff300`0000ffff
WriteVirtual: 80b99048 not properly sign extended
0: kd> dq 80b99000
ReadVirtual: 80b99000 not properly sign extended
80b99000  00000000`00000000 00cf9b00`0000ffff
80b99010  00cf9300`0000ffff 00cffb00`0000ffff
80b99020  00cff300`0000ffff 80008b1e`400020ab
80b99030  834093f7`8c003748 0040f300`00000fff
80b99040  0000f200`0400ffff 00cff300`0000ffff//可以看见这里已经被写进去了
80b99050  830089f7`60000068 830089f7`60680068
80b99060  00000000`00000000 00000000`00000000
80b99070  800092b9`900003ff 00000000`00000000

这时候我们回去运行我们的程序,验证是否真的将这个4b移入了ds,Val2的结果在最后被赋予了0x100

在这里插入图片描述

这以上的一切都是建立在我们的base为0的情况下,那么如果让我们的base为1呢

1: kd> dq 80b99000
ReadVirtual: 80b99000 not properly sign extended
80b99000  00000000`00000000 00cf9b00`0000ffff
80b99010  00cf9300`0000ffff 00cffb00`0000ffff
80b99020  00cff300`0000ffff 80008b1e`400020ab
80b99030  834093f7`8c003748 0040f300`00000fff
80b99040  0000f200`0400ffff 00cff300`0000ffff
80b99050  830089f7`60000068 830089f7`60680068
80b99060  00000000`00000000 00000000`00000000
80b99070  800092b9`900003ff 00000000`00000000
1: kd> eq 80b99048 00cff300`0001ffff
WriteVirtual: 80b99048 not properly sign extended
1: kd> dq 80b99000
ReadVirtual: 80b99000 not properly sign extended
80b99000  00000000`00000000 00cf9b00`0000ffff
80b99010  00cf9300`0000ffff 00cffb00`0000ffff
80b99020  00cff300`0000ffff 80008b1e`400020ab
80b99030  834093f7`8c003748 0040f300`00000fff
80b99040  0000f200`0400ffff 00cff300`0001ffff//在把这里对应base为改为1
80b99050  830089f7`60000068 830089f7`60680068
80b99060  00000000`00000000 00000000`00000000
80b99070  800092b9`900003ff 00000000`00000000

通过汇编得知,得到以下结果

在这里插入图片描述

我们原本的存储的dword4个字节,在base为0的情况下出来的是 00 01 00 00,也就是0x100,但是现在我们的base不为0,为1,所以整个读取向右移了一字节,所以实际上读的是 01 00 00 00也就是1,最后的实验结果也和我们预测的相等

在这里插入图片描述

所以我们利用段寄存器进行调用,例如ds:[val]

真正的式子应该是**(base + val )+ ds 0x10*,需要加上我们的base

在知道了这个基础知识之后,我们就可以继续向前了

在上面的截图中,我们知道fs的值是3b,对应到我们GDT表中的值里面,我们可以知道它的限长是fff,所以我们写两句asm,来访问一下

在这里插入图片描述

不出所料,访问冲突

在这里插入图片描述

但是如果我们改为0xffc,这样就是刚好将最后四个字节移入eax中

在这里插入图片描述

最后也是能够正确访问到

在这里插入图片描述

这就证明了,段限长是确实存在的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/61007.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux:进程的优先级 进程切换

文章目录 前言一、进程优先级1.1 基本概念1.2 查看系统进程1.3 PRI和NI1.4 调整优先级1.4.1 top命令1.4.2 nice命令1.4.3 renice命令 二、进程切换2.1 补充概念2.2 进程的运行和切换步骤&#xff08;重要&#xff09; 二、Linux2.6内核进程O(1)调度队列&#xff08;重要&#x…

【学习心得】算力云平台上的大模型部署并实现远程调用

以AutoDL算力云平台为例&#xff0c;部署国产开源ChatGLM3b模型。 一、准备工作 &#xff08;1&#xff09;准备一台算力服务器 首先&#xff0c;进入AutoDL官网的算力时长选择算力服务器资源。 创建好后会自动跳转控制台的“容器实例”界面&#xff0c;稍等片刻后选择“快捷…

【Linux】—进程地址空间

大家好呀&#xff0c;我是残念&#xff0c;希望在你看完之后&#xff0c;能对你有所帮助&#xff0c;有什么不足请指正&#xff01;共同学习交流哦 本文由&#xff1a;残念ing原创CSDN首发&#xff0c;如需要转载请通知 个人主页&#xff1a;残念ing-CSDN博客&#xff0c;欢迎各…

leetcode-44-通配符匹配

题解&#xff1a; 代码&#xff1a; 参考&#xff1a; (1)牛客华为机试HJ71字符串通配符 (2)leetcode-10-正则表达式匹配

低成本出租屋5G CPE解决方案:ZX7981PG/ZX7981PM WIFI6千兆高速网络

刚搬进新租的房子&#xff0c;没有网络&#xff0c;开个热点&#xff1f;续航不太行。随身WIFI&#xff1f;大多是百兆级网络。找人拉宽带&#xff1f;太麻烦&#xff0c;退租的时候也不能带着走。5G CPE倒是个不错的选择&#xff0c;插入SIM卡就能直接连接5G网络&#xff0c;千…

学习日记_20241117_聚类方法(高斯混合模型)

前言 提醒&#xff1a; 文章内容为方便作者自己后日复习与查阅而进行的书写与发布&#xff0c;其中引用内容都会使用链接表明出处&#xff08;如有侵权问题&#xff0c;请及时联系&#xff09;。 其中内容多为一次书写&#xff0c;缺少检查与订正&#xff0c;如有问题或其他拓展…

列出D3的所有交互方法,并给出示例

D3.js 提供了丰富的交互方法&#xff0c;可以用来增强图表的用户交互体验。以下是一些常用的交互方法及其示例&#xff1a; 1. 鼠标事件 on("mouseover", function) 用途: 当鼠标悬停在元素上时触发。示例:svg.selectAll(".bar").on("mouseover&qu…

设计模式-参考的雷丰阳老师直播课

一般开发中使用的模式为模版模式策略模式组合&#xff0c;模版用来定义骨架&#xff0c;策略用来实现细节。 模版模式 策略模式 与模版模式特别像&#xff0c;模版模式会定义好步骤定义好框架&#xff0c;策略模式定义小细节 入口类 使用模版模式策略模式开发支付 以上使用…

模拟实现STL中的list

目录 1.设计list的结点 2.设计list的迭代器 3.list类的设计总览 4.list类的迭代器操作 5.list类的四个特殊的默认成员函数 无参的默认构造函数 拷贝构造函数 赋值运算符重载函数 析构函数 6.list类的插入操作 7.list类的删除操作 8.list.hpp源代码 1.设计list的结点…

.NET SDK 各操作系统开发环境搭建

一、Win10&#xff08;推荐&#xff09; 1、VS 2022 社区版 # 下载地址 https://visualstudio.microsoft.com/zh-hans/downloads/ 2、.NET 6 SDK # 下载地址 https://dotnet.microsoft.com/zh-cn/download/dotnet/6.0 3、Hello World 如果需要使用旧程序样式时&#xff0c;则…

IDEA怎么定位java类所用maven依赖版本及引用位置

在实际开发中&#xff0c;我们可能会遇到需要搞清楚代码所用依赖版本号及引用位置的场景&#xff0c;便于排查问题&#xff0c;怎么通过IDEA实现呢&#xff1f; 可以在IDEA中打开项目&#xff0c;右键点击maven的pom.xml文件&#xff0c;或者在maven窗口下选中项目&#xff0c;…

【Golang】——Gin 框架中的模板渲染详解

Gin 框架支持动态网页开发&#xff0c;能够通过模板渲染结合数据生成动态页面。在这篇文章中&#xff0c;我们将一步步学习如何在 Gin 框架中配置模板、渲染动态数据&#xff0c;并结合静态资源文件创建一个功能完整的动态网站。 文章目录 1. 什么是模板渲染&#xff1f;1.1 概…

力扣 LeetCode 144. 二叉树的前序遍历(Day6:二叉树)

解题思路&#xff1a; 方法一&#xff1a;递归&#xff08;中左右&#xff09; class Solution {List<Integer> res new ArrayList<>();public List<Integer> preorderTraversal(TreeNode root) {recur(root);return res;}public void recur(TreeNode roo…

高级 SQL 技巧讲解

​ 大家好&#xff0c;我是程序员小羊&#xff01; 前言&#xff1a; SQL&#xff08;结构化查询语言&#xff09;是管理和操作数据库的核心工具。从基本的查询语句到复杂的数据处理&#xff0c;掌握高级 SQL 技巧不仅能显著提高数据分析的效率&#xff0c;还能解决业务中的复…

pom中无法下载下来的类外部引用只给一个jar的时候

比如jar在桌面上放着,操作步骤如下&#xff1a; 选择桌面&#xff0c;输入cmd ,执行mvn install:install-file -DgroupIdcom -DartifactIdaspose-words -Dversion15.8.0 -Dpackagingjar -Dclassifierjdk11 -Dfilejar包名称 即可把jar包引入成功。

【软件测试】设计测试用例的万能公式

文章目录 概念设计测试用例的万能公式常规思考逆向思维发散性思维万能公式水杯测试弱网测试如何进行弱网测试 安装卸载测试 概念 什么是测试用例&#xff1f; 测试⽤例&#xff08;Test Case&#xff09;是为了实施测试⽽向被测试的系统提供的⼀组集合&#xff0c;这组集合包…

在连通无向图中寻找欧拉回路(Eulerian Circuit)

在连通无向图中寻找欧拉回路(Eulerian Circuit) 问题描述解决方案概述算法步骤伪代码C代码示例如何在迷宫中找出一条路示例:在简单迷宫中应用欧拉回路结论问题描述 给定一个连通无向图 $ G = (V, E) $,我们需要找到一条路径,该路径正向和反向通过 $ E $ 中的每条边恰好一…

ANSYS Maxwell:3PH 感应电机 - 第 1 部分 - 力与热耦合

在此博客中&#xff0c;我们使用 Ansys RMxprt 创建了 3PH 感应电机的 1D 模型&#xff0c;并从设计中自动开发具有所有设置、边界条件和激励的麦克斯韦模型。 ANSYS RMxprt 1D 模型 - 3PH 感应电机设计 请参阅上一篇博客下面的链接&#xff0c;了解如何设置电机设计的 RMxp…

【linux】网络基础 ---- 数据链路层

用于两个设备(同一种数据链路节点)之间进行传递 数据链路层解决的问题是&#xff1a;直接相连的主机之间&#xff0c;进行数据交付 1. 认识以太网 "以太网" 不是一种具体的网络, 而是一种技术标准&#xff1a; 既包含了数据链路层的内容, 也包含了一些物理层的内容…