Windows内核基础知识-5-调用门(32-Bit Call Gate)
Windows内核基础知识-5-调用门(32-Bit Call Gate)
调用门有一个关键的作用,就是用来提权。调用门其实就是一个段。
调用门:

这是段描述符的结构体,里面的s字段用来标记是代码段还是数据段还是系统段,前面解析的时候讲的是 S==1的情况,也就是Code or data的情况,这次的调用门就是当s==0时的情况。
当s==0时,type的内容如下:

那么调用门其实就是 type为12的情况下的一个段寄存器。
32-Bit Call Gate。32位情况下的一个调用门。
就是一个 段描述符下且S==0 && type==12的一个段。
调用门的段描述符:

利用调用门提权
我们可以通过构造段选择子和段描述符来自己添加一个调用门也就是添加一个段来自己使用。
因为段寄存器无非就是拥有一个起始地址然后作为一个段的内容来让你使用。用汇编写过代码的肯定知道如果构造一个段:
sample PROC
ret
sample ENDP
那么我们自己构造一个系统段来执行我们的代码这不就行了吗。段寄存器只是系统默认的方便我们使用,我们自己通过 segment:eip这样来跳转使用不就完事了吗。
段寄存器比如说 ss(stack segment)无法也就是把栈段的内容通过段选择子和段描述符来集成了而已。
所以这里我们直接添加自己的段,也就是这里所谓的调用门。
解析调用门描述符:
我们要自己配一个调用们,肯定需要知道怎么配,段选择子我们知道了,这里还需要知道段描述符:

这个和前面的段寄存器的段描述符大相径庭,只是有一些不一样。
和前面的段描述符一样,上面的是高32位地址,下面的是低32位地址。
| 字段 | 内容 |
|---|---|
| offset in segment | 要跳转的函数的地址,或者是要跳转的地址 |
| segment selector | 段选择子,要变成的段选择子(提权的关键) |
| Param Count | 函数参数个数 |
| 高位5-7 | 固定的三个0 |
| Type | 系统段只能是1100(10进制的12) |
| 高12地址 | 就是段描述符的S字段,就系统调用的必须是0 |
| DPL | 肯定赋值为3呀,这样ring3才能。 |
| p | 和段描述符一样表示该段是否有效,当P为0时无效,1时有效。 |
构造段描述符:
segment selector段描述符字段,可以通过WinDbg附加Windows双机调试时查看cs段寄存器的值就行了,因为此时系统正在启动肯定是在r0的情况下的:

所以这里的段选择子就构造为: 0008(因为段选择子是两个字节16位)
然后再根据前面的解析我们目前的构造是这样的:
高32位:
0-3:
0(十六进制)
4-7:
0(十六进制)
8-11:
C(十六进制)
12-15:
E(十六进制)
16-31:
函数地址的高地址:xxxx
低32:
0-15:
函数地址的低地址:xxxx
16-31:
0008
合集:
xxxxEC000008xxxx
目前就是函数地址需要解决,这个函数地址的话其实就是我们的代码的起始地址,然后就处理这个函数的内容了。
我们可以写一个函数不就完了嘛,但是需要修改成固定基址,这样函数地址就不会改变了。需要采用release版本,因为debug版本有个jmp,然后还得修改优化和随机基址:


#include<iostream>
#include<Windows.h>
using namespace std;
void _declspec(naked) test()
{
_asm
{
//这里我们访问一个0环才能访问的地址
//这样就知道是否是拿到了0环的权限
push eax
mov eax,0x80b95040
mov eax,[eax]
pop eax
ret
}
}
int main()
{
printf("%x\n", test);//输出函数的地址
system("pause");
return 0;
}
这里我的函数地址是:00401080。
所以完整的段描述符值为:
0040EC0000081080
将段描述符添加到gdt表:

这个段描述就到了gdt表偏移9的地方了。
使用调用门
前面调用们的段描述符我们已经配置好了。
现在需要使用调用门了,需要学习两个指令:
call far ;跨段调用 长调用
jmp far ;跨段跳转 长跳转
调用门只能采用call far,jmp far无法,因为jmp far无法做到越级这个作用。
然后还要配一个段选择子:
RPL:
00//采用0环
TI:
0
Index
1001
0100 1011
最终的段选择子就是:0x48
那么应该call far的地址为: 0x48:xxxx
但是在内联汇编里不能这样写,只能这样写:
BYTE code[] = {0,0,0,0,0x48,0};
//0,0,0,0 是eip,然后0x0048是段选择子,采用的是小端字节序
//这里用0000是因为这里不会用到
//因为段描述符里面已经指定了函数的地址了会自动跳转,所以写啥都行
_asm
{
call far fwrod ptr code
}
完整代码:
#include<iostream>
#include<Windows.h>
using namespace std;
void _declspec(naked) test()
{
_asm
{
//这里我们访问一个0环才能访问的地址
//这样就知道是否是拿到了0环的权限
push eax
mov eax,0x80b95040
mov eax,[eax]
pop eax
ret
}
}
int main()
{
//跳转
BYTE code[] = {0,0,0,0,0x48,0};
//段选择子为 0000
_asm
{
call far fwrod ptr code
}
system("pause");
return 0;
}
然后拿到虚拟机里运行一下:


直接系统出错WinDbg捕获了并且蓝屏了,但是至少有一个可以确定,就是我们肯定是跑到内核去执行了,不然怎么会导致系统出错呢,r3的应用层代码肯定不会导致系统的问题的。
就出现问题很正常,打几个断点观察下:
#include<iostream>
#include<Windows.h>
using namespace std;
void _declspec(naked) test()
{
_asm
{
//这里我们访问一个0环才能访问的地址
//这样就知道是否是拿到了0环的权限
int 3
push eax
mov eax, 0x80b95040
mov eax, [eax]
pop eax
ret
}
}
int main()
{
//跳转
BYTE code[6] = {0,0,0,0,0x48,0};
//段选择子为0x0048
__asm
{
call far fword ptr code
}
printf("%x\n", test);
system("pause");
return 0;
}

通过单步调试汇编代码发现是,这个ret的原因,call far或者jmp far,需要采用retf来使用。
改成retf:
#include<iostream>
#include<Windows.h>
using namespace std;
void _declspec(naked) test()
{
_asm
{
//这里我们访问一个0环才能访问的地址
//这样就知道是否是拿到了0环的权限
int 3
push eax
mov eax, 0x80b95040
mov eax, [eax]
pop eax
retf
}
}
int main()
{
//跳转
BYTE code[6] = {0,0,0,0,0x48,0};
//段选择子为0x0048
__asm
{
call far fword ptr code
}
printf("%x\n", test);
system("pause");
return 0;
}
这样之后我们函数内的代码是正常执行了,但是还是蓝屏了,通过我的观察,是段寄存器的问题,这里就通过od的观察看进入前和进入后的问题就可以判断是这个问题了。
所以这里我直接不要这个int 3断点了,可能在r0和r3下的int 3断点执行的东西不一样把:
#include<iostream>
#include<Windows.h>
using namespace std;
void _declspec(naked) test()
{
_asm
{
//这里我们访问一个0环才能访问的地址
//这样就知道是否是拿到了0环的权限
push eax
mov eax, 0x80b93040
mov eax, [eax]
pop eax
retf
}
}
int main()
{
//跳转
BYTE code[6] = {0,0,0,0,0x48,0};
//段选择子为0x0048
__asm
{
call far fword ptr code
}
printf("%x\n", test);
system("pause");
return 0;
}
这样我们的程序就可以美美的执行结束了:

小结
段是一个很重要的概念用来进行内存分割,一个段的描述有很多信息保存在段描述符里面,由于段很多所有就有段描述符表,然后这个表呢由一个段选择子来指向获取表内哪一个段描述符,而段寄存器是CPU为了方便使用的一个寄存器,用来保存的是段选择子这个东西。所以这里我们用的是一个系统调用段来执行我们的指令就是操作系统内部的操作所允许也是intel架构的内容,比较复杂,这里的话我们就明白到这里就可以了想深入的可以阅读本博客后面的参考文献。
参考文献:(3条消息) 段选择符 段寄存器farmwang的专栏-CSDN博客段寄存器
参考文献:(3条消息) 段选择符tasty-CSDN博客段选择符
Windows内核基础知识-5-调用门(32-Bit Call Gate)的更多相关文章
- Windows内核基础知识-1-段寄存器
Windows内核基础知识-1-段寄存器 学过汇编的应该都知道段寄存器,在Windows里段寄存器有很多,之前可能只接触了ds数据段,cs 代码段这种,今天这个博客就介绍Windows一些比较常用的段 ...
- Windows内核基础知识-2-段描述符
Windows内核基础知识-2-段描述符 比如: ES 002B 0(FFFFFFFF) 意思就是es段寄存器,段选择子/段选择符 为002B, 起始地址base为0, 限制范围Limit地址最大能寻 ...
- Windows内核基础知识-8-监听进程、线程和模块
Windows内核基础知识-8-监听进程.线程和模块 Windows内核有一种强大的机制,可以在重大事件发送时得到通知,比如这里的进程.线程和模块加载通知. 本次采用链表+自动快速互斥体来实现内核的主 ...
- windows内核基础与异常处理
前两日碰到了用异常处理来做加密的re题目 所以系统学习一下windows内核相关 windows内核基础 权限级别 内核层:R0 零环 核心态工作区域 大多数驱动程序 应用层:R3 用户态工作区域 只 ...
- 第0章Linux环境到内核基础知识
#include<stdio.h> int main(void) { printf("hello world\n"); return 0; } gcc -g -wall ...
- Windows内核原理-同步IO与异步IO
目录 Windows内核原理-同步IO与异步IO 背景 目的 I/O 同步I/O 异步I/O I/O完成通知 总结 参考文档 Windows内核原理-同步IO与异步IO 背景 在前段时间检查异常连接导 ...
- 学习 FPGA之前的基础知识
在学习一门技术之前往往应该从它的编程语言入手,比如学习单片机时,往往从汇编或者C语言入门.所以不少开始接触FPGA的开发人员,往往是从VHDL或者Verilog开始入手学习的.但小编认为,若能先结合& ...
- Windows内核开发-3-内核编程基础
Windows内核开发-3-内核编程基础 这里会深入讲解kernel内核的API.结构体.和一些定义.考察代码在内核驱动中运行的机制.最后把所有知识合在一起写一个有用的驱动. 本章学习要点: 1:通用 ...
- Windows核心编程 第六章 线程基础知识 (上)
第6章 线程的基础知识 理解线程是非常关键的,因为每个进程至少需要一个线程.本章将更加详细地介绍线程的知识.尤其是要讲述进程与线程之间存在多大的差别,它们各自具有什么作用.还要介绍系统如何使用线程内核 ...
随机推荐
- linux命令(用户)
一.常用命令 1.1 ls ls 命令是 linux 下最常用的命令,ls 命令就是 list 的缩写. ls 用来打印出当前目录的清单.如果 ls 指定其他目录,那么就会显示指定目录里的文件及文件夹 ...
- 根据类拼凑成url参数
/// <summary> /// 根据类拼凑成url参数 /// </summary> /// <typeparam name ...
- Linux命令进阶篇之二
实验内容: cat :由第一行开始显示文件内容 tac:由最后一行开始显示,有没有发现和cat是反过来写的 more:一页一页的显示内容 less:与more相似, ...
- Qt中的ui文件转换为py文件
将pyuic5 -o demo.py demo.ui写入ui-py.bat文件(自定义文件),将ui文件与ui-py.bat文件放在同一文件夹,双击.bat文件即可生成.py文件
- turtle color设置的几种方式
t.colormode() 查看色彩模式,缺省1.0,即RGB范围在0-1 模式切换:参数填1.0或255 t.colormode(1.0) t.colormode(255) 设置颜色,以设置penc ...
- 《手把手教你》系列技巧篇(二十八)-java+ selenium自动化测试-处理模态对话框弹窗(详解教程)
1.简介 在前边的文章中窗口句柄切换宏哥介绍了switchTo方法,这篇继续介绍switchTo中关于处理alert弹窗的问题.很多时候,我们进入一个网站,就会弹窗一个alert框,有些我们直接关闭, ...
- Linux系统自我学习的一些笔记1
远程连接: 1.查看IP地址 ip addr 2.远程登陆linux系统 ssh 主机名@IP地址 文件操作: 新建文件touch 例如:touch test.txt (创建单个文件) 例如:to ...
- asp.net core 中配合响应 html5 的音视频播放流,以及文件下载
一.asp.net core 中配合响应 html5 的音视频播放流,以及文件下载 问题描述: 目前测试了在 Windows(谷歌浏览器).Android(系统浏览器.QQ.微信).iOS 三个系统不 ...
- WebXml文件与SpringMVC的联系
WebXml文件与SpringMVC的联系 无论采用何种框架来进行Java Web的开发,只要是Web项目必须在WEB-INF下有web.xml,这是java规范. 当然,我们最早接触到Java We ...
- 解决VM 与 Device/Credential Guard 不兼容
通过命令关闭Hyper-V(控制面板关闭Hyper-V起不到决定性作用,要彻底关闭Hyper-V) 以管理员身份运行Windows Powershell (管理员)(Windows键+X) 运行下面命 ...
