段探测的研究

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

跳过繁琐的介绍,我们单刀直入,介绍一个划时代的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,一经查实,立即删除!

相关文章

pytorch环境问题以及探索Dataloader的数据格式

1 问题 DataLoader object is not subscriptable No module named matplotlib/torchvision.io 2 方法 针对问题一&#xff1a;“dataloader” object is not subscriptable 是一个 Python 中常见的错误。它通常是由于对 dataloader 取下标而导致的。 在 PyTorch 中&#xff0c;…

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-正则表达式匹配

【redis】redis

1.linux离线安装 解压 redis-6.2.6.tar.gz进入redis-6.2.6执行make编译执行./make install PREFIX/app/soft/redis6安装 2. 使用客户端 redis-cli 启动默认6379 redis-cli -p port指定端口 -h ip -n 仓库号 【redis-cli -p 6379 -h 192.168.23.22】 auth username#passwd 或…

低成本出租屋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;策略模式定义小细节 入口类 使用模版模式策略模式开发支付 以上使用…

基于BERT的情感分析

基于BERT的情感分析 1. 项目背景 情感分析&#xff08;Sentiment Analysis&#xff09;是自然语言处理的重要应用之一&#xff0c;用于判断文本的情感倾向&#xff0c;如正面、负面或中性。随着深度学习的发展&#xff0c;预训练语言模型如BERT在各种自然语言处理任务中取得了…

37.超级简易的计算器 C语言

超级简单&#xff0c;简单到甚至这个计算器输入都比较反人类 但是足够简单 有输入功能有Switch语句支持四种运算还能检查除数是不是0还能打印出完整的式子 #define _CRT_SECURE_NO_WARNINGS// 禁用安全警告 #include <stdio.h>int main() {double num1, num2;// 声明两…

【tokenization分词】WordPiece, Byte-Pair Encoding(BPE), Byte-level BPE(BBPE)的原理和代码

目录 前言 1、word (词粒度) 2、char (字符粒度) 3、subword (子词粒度) WordPiece Byte-Pair Encoding (BPE) Byte-level BPE(BBPE) 总结 前言 Tokenization&#xff08;分词&#xff09; 在自然语言处理(NLP)的任务中是最基本的一步&#xff0c;将文本处理成一串tok…

深入解析 MySQL 数据库:数据库时区问题

在 MySQL 数据库中&#xff0c;时区管理是一个重要且复杂的主题&#xff0c;尤其是在全球化的应用程序中。以下是关于 MySQL 数据库时区问题的深入解析&#xff1a; 1. 时区的概念 时区是指地球表面被分为若干个区域&#xff0c;每个区域的标准时间相对协调世界时 (UTC) 有所…

技术周总结 11.11~11.17 周日(Js JVM XML)

文章目录 一、11.11 周一1.1&#xff09;问题01&#xff1a;js中的prompt弹窗区分出来用户点击的是 确认还是取消进一步示例 1.2&#xff09;问题02&#xff1a;在 prompt弹窗弹出时默认给弹窗中写入一些内容 二、11.12 周二2.1) 问题02: 详解JVM中的本地方法栈本地方法栈的主要…

模拟实现STL中的list

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

spark 设置hive.exec.max.dynamic.partition不生效

spark脚本和程序中设置ive.exec.max.dynamic.partition不生效 正确写法&#xff1a; spark-submit \ --master yarn \ --deploy-mode client \ --driver-memory 1G \ --executor-memory 12G \ --num-executors 8 \ --executor-cores 4 \--conf spark.hadoop.hive.exec.max.dyna…

.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;则…

centos7.9安装mysql社区版

文章目录 场景安装 场景 今天把家里闲置的笔记本安装了centos&#xff0c;设置内网穿透做个人服务器用&#xff0c; 这里记录下安装mysql的过程 安装 安装mysql源 sudo yum install -y wget wget https://dev.mysql.com/get/mysql80-community-release-el7-5.noarch.rpm sudo r…

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

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