再看nt下无驱执行ring0代码
(在不考虑正误的前提下,胡说八道一番…有点罗嗦…没办法。。。)
Author:icelord@ustb@05/11/19
(这仅是一篇日记而已…)
大二时看网上的“无驱执行ring0代码”看得我一头雾水,今天重新拿起来看了几遍,有点收获,将想法记录一下….
X86平台上,cpu可以工作在三个特权级别下,ring0—ring3,其中ring0具有最高权限,可以执行任何指令而无限制,ring3受到cpu保护机制限制,只能执行非特权指令。当在ring3下执行特权指令如lgdt、iret等时,会触发general protection异常(也就是出错啦,跳转到相应得错误处理程序)。
在nt平台下,普通应用程序运行在ring3下,操作系统运行于ring0。如果在程序中需要执行一些特权指令的话,程序必须转入到ring0。由于用户程序执行特权指令可能会破坏系统资源,故出于保护和稳定的目的,操作系统通过“门”机制向用户态程序提供必要的服务。在x86种有四种门:中断门、陷阱门、调用门、任务门。
先描述一下门的概念,个人认为就是两种不同状态之间的通道,换句话说,也就是不同环(特权级)之间切换的通道。
一般在操作系统初始化时,由real mode进入保护模式(pmode)后,cpu就处于ring0状态,在完成各种初始化后,系统转入用户态并创建用户进程。用户程序需要特权服务时,通过系统调用进入ring0,由系统完成指定的、在提供的服务范围内的请求。这样可以避免恶意程序破坏系统。但是如果我们想执行一些“特殊的”操作时怎么办?
这个问题有几个解决方法,第一种方法是安装驱动;驱动程序作为内核的辅助模块为用户程序提供服务,它与操作系统一样工作在ring0,而且他是可以根据自己需编写。所以可以通过编写一个“自定义的”驱动程序来执行ring0代码,这种方法在nt下和linux下应该都可,(不好意思,本人没实践过,忙着“好好学习”,有时间再说)。第二种限定于nt平台,通过“自定义门”来实现执行ring0代码。
由于nt平台的特性,导致用户可以通过操作Section对象""device"PhysicalMemory来操作物理内存。这样就可通过找到全局描述符表GDT或中断描述符表IDT并修改其内容来构造自己的“门”,甚至使用自定义代码来覆盖内核代码,。。。通过这些方法来达到执行ring0代码的目的。说得有点混乱…下面将一些预备知识,以便为后面理解作基础….
还有几个寄存器,这里就不乱说了….下面给出相应得结构:
/* 中断描述符结构 */
typedef struct IDT_ITEM__
{
unsigned short offset_low ; // 偏移量的0~15位
unsigned short seg_selector ; // 段选择符
unsigned char reserved1 ; // 未使用,须设为全零
unsigned char saved_1_1_0 : 3 ; // 类型/中断门14/陷阱门15
unsigned char d : 1 ; // D 位
unsigned char reserved2 : 1 ; // 保留,需设为0
unsigned char dpl : 2 ; // 特权ring3
unsigned char p : 1 ; // P 位存在/有效
unsigned short offset_high ; // 偏移量的16~31位
}IDT_ITEM ;
/* 调用门结构 */
typedef struct InvokeGate__
{
unsigned short Offset_0_15 ;/* 偏移量的 0~15 位 */
unsigned short SegSelector ;/* 段选择符 */
unsigned char reserved1;
unsigned char Type : 4 ; /* 类型字段,调用门需为 1100 ( 0xC ) */
unsigned char DT_0 : 1 ; /* 需为 0 , 以表明这是一个系统用的描述符 */
unsigned char DPL : 2 ; /* 特权级 */ ring3
unsigned char P : 1 ; /* 存在位 */
unsigned short Offset_16_31 ; /* 偏移量的 16~31 位 */
}INT_GATE;
讲到这里,问题好像还没解决的样子….
预备知识:
1) Windows NT将开始512MB物理内存连续映射到0x8000 0000 开始到0xa000 0000处(暂时不考虑大于/小于512MB)//这里在暂时对winnt 5.0 和 5.1
2) ZwMapViewOfSection()函数可以将物理内存映射到当前进程地址空间,并返回映射的虚拟地址
3) Sidt指令和sgdt指令是非特权及指令,用户态可执行
4) Windows Nt使用平坦模式的内存段,即段基址为0
说到这里,问题的基本可以解决了,这就是网上流传的“无驱执行ring0代码” 的基础。
预备知识:
预备知识:
在ring3“使用”门要求门的描述符特权级=3,这样这个门才能被用户态程序所使用,
也就是上面结构中DPL域的值=3
构造中断门:
将中断描述符指向你的中断处理程序,里面填写你的ring0代码,至于参数可以通过寄存器eax/ebx/ecx…/esi/edi传递,就跟linux系统调用类似
调用时:
Mov eax,param1
Mov ebx,param2
…..
Int 中断向量号
构造陷阱门与中断门类似。。。。。
构造调用门:
将描述符指向你的ring0要执行的函数
word sel[3];
Sel[0]=sel[1]=0;
Sel[2]=调用门选择子
_Asm call fword ptr [sel] //调用调用门,进入ring0
//这里没有试验过
//估计 ushort[3]è
//struct
//{
// Ulong offset;
// Ushort selector;
//};
这里糊涂啊….有待研究….
到这里,你应该基本了解了为什么“无驱执行ring 0”了,流程图如下:
到这里问题因该很简单了,代码我就不贴了,老早以前的东西了…..
本次只是更新一下本人对这这些的认识,上面有很多错误,暂时摆到这里,以后有时间再修改吧,懒啊….
需要代码在百度查:无驱执行ring0代码就可以查到…..