用Visual C++实现CPU特权指令操作

原创 2005年02月28日 10:29:00
开发者网络 > 开发工具 > 开发专栏 > VC > 正文

一、引言

  80x86系列CPU具有四级保护机制。在Windows 9X操作系统只使用0级和3级,以便于移植到精简指令集的计算机上,如RS4000等,这些处理器一般只有两个特权级,即系统级和用户级。在Windows 9X系统环境,应用程序运行在Ring3(3级),如果要运行特权指令就必须进入Ring0(0级)。在同一任务内,实现特权级从外层到内层变换的普通途径是使用段间调用指令CALL,通过调用门进行转移;实现特权级从内层向外层变换的普通途径是使用段间返回指令RET。注意,不能用JMP指令实现任务内不同特权级的变换。调用门描述符转移的入口点包含目标地址的段及偏移量的48位全指针。在执行通过任务门的段间转移指令JMP或段间调用指令CALL时,指令所含指针内的选择子用于确定调用门,而偏移被丢弃;把调用门内的48位全指针作为目标地址指针进行转移。

  二、基本思路

  取得全局描述符表,搜索该表找到一个暂时为空的描述符,安装调用门,进行远程调用即可实现特权指令操作。

  三、所用到的数据结构

  ①全局描述符GDT的格式:

252692.gif

  在VC中定义全局描述符如下:

struct GDT_DESCRIPTOR{
 WORD LimitL;//段界限低16位
 WORD BaseL;//基地址低16位
 BYTE BaseM;//基地址中间8位
 BYTE AttriB;//段属性
 BYTE LimitH;//段界限的高4位(包括段属性的高4位)
 BYTE BaseH;//基地址的高8位
}

  ②门描述符的一般格式:

252693.gif

  当TYPE的低4位值为0xC时,这是一个386调用门(CallGate)。在VC中定义"门"如下:struct GATE{ //门结构类型定义

WORD OffsetL; // 32位偏移的低16位
WORD Selector; //选择子
BYTE Dcount; //双字计数字段
BYTE Gtype; //当低4位值为0xC是,这是一个调用门
WORD LimitH; //32位偏移的高16位
}

  ③全局描述符表寄存器GDTR

  GDTR长48位,其中高32位为基地址,低16位为界限,GDTR中的段界限以字节为单位。在VC中定义如下:

struct GDTR{
 WORD wGDTLimit;
 DWORD dwGDTBase;
};

  四、具体实现

  使用MFC AppWizard新建一个基于对话框的应用程序,工程名为MyRing0。在对话框中添加一个按钮,修改ID为ID_GETCR0,修改Caption为取CR0的值,同时添加该按钮的消息处理函数void CMyRing0Dlg::OnGetcr0()。新建一个头文件Ring0.h并添加到工程中,添加下面的代码到Ring0.h中。

#pragma pack(1)
struct GDT_DESCRIPTOR{
 WORD LimitL; //段界限低16位
 WORD BaseL; //基地址低16位
 BYTE BaseM; //基地址中间8位
 BYTE AttriB; //段属性
 BYTE LimitH; //段界限的高4位(包括段属性的高4位)
 BYTE BaseH; //基地址的高8位
};
struct GATE_DESCRIPTOR{
 WORD OffsetL; // 32位偏移的低16位
 WORD Selector; //选择子
 BYTE Dcount; //双字计数字段
 BYTE Gtype; //当低4位值为0xC是,这是一个调用门
 WORD LimitH; //32位偏移的高16位
};

struct GDTR{
 WORD wGDTLimit;
 DWORD dwGDTBase;
};
#pragma pack()

  在MyRing0Dlg.cpp中最后一个include语句后添加#include "Ring0.h",在按钮的消息处理函数void CMyRing0Dlg::OnGetcr0()前面添加下面两个函数:

__declspec(naked) void GetCR0_Ring0()
{
 _asm{
 mov ebx,cr0 //特权指令
 mov [EAX],ebx
 retf
}
}

bool CallRing0(PVOID pvRing0FuncAddr,PWORD pVal)
{
 struct GDT_DESCRIPTOR *pGDTDescriptor;
 struct GDTR gdtr;
 WORD CallgateAddr[3];
 WORD wGDTIndex = 1;
 //取得全局描述符表GDT
 _asm Sgdt [gdtr]

 // 空选择子有特殊用途,跳过它,从第二个选择子开始搜索
 pGDTDescriptor = (struct GDT_DESCRIPTOR *)(gdtr.dwGDTBase + 8);
 for (wGDTIndex = 1; wGDTIndex < (gdtr.wGDTLimit / 8); wGDTIndex++)
 {
  if (pGDTDescriptor->AttriB == 0)
  {
   struct GATE_DESCRIPTOR *pGate;

   pGate = (struct GATE_DESCRIPTOR *) pGDTDescriptor;
   pGate->OffsetL = LOWORD(pvRing0FuncAddr);
   //选择子0x28总是指向Ring0的代码段
   pGate->Selector = 0x28;
   pGate->Dcount = 0;
   pGate->Gtype = 0xEC;
   pGate->OffsetH = HIWORD(pvRing0FuncAddr);
   //准备远程调用参数
   CallgateAddr[0] = 0x0;
   CallgateAddr[1] = 0x0;
   CallgateAddr[2] = (wGDTIndex << 3) | 3;
   //进入Ring0
   _asm Mov EAX,[pVal]
   _asm call FWORD PTR [CallgateAddr]
   //归还刚才使用的全局描述符
   memset(pGDTDescriptor, 0, 8);
   return true;
  }
  //下一个全局描述符
  pGDTDescriptor++;
 }
 //没有空闲的全局描述符
 return false;
}

  为按钮的消息处理函数void CMyRing0Dlg::OnGetcr0()添加代码如下:

void CMyRing0Dlg::OnGetcr0()
{
 // TODO: Add your control notification handler code here
 WORD Val=0;
 char str[16];
 if(!CallRing0((PVOID)GetCR0_Ring0,&Val)){
  AfxMessageBox("系统资源不够!");
  return;
 };
 sprintf(str,"CR0=%3d",Val);
 AfxMessageBox(str);
}

关于“特权解除、陷入模拟”的理解

一直想不通这两句话的含义,今天查了点资料、对着源码分析了一下,不一定对,写下来,分享: x86 CPU支持ring0-3 共4种不同的特权级别,下面分正常和虚拟化两种情况叙述、分析: 1.正常情况下:...
  • sdulibh
  • sdulibh
  • 2015年09月16日 17:09
  • 3443

全虚拟化与半虚拟化的实现方式

目录目录 全虚拟化 软件辅助的全虚拟化 硬件辅助的全虚拟化 KVM虚拟机 半虚拟化全虚拟化不需要对GuestOS操作系统软件的源代码做任何的修改,就可以运行在这样的VMM中在全虚拟化的虚拟平台中,Gu...
  • Jmilk
  • Jmilk
  • 2016年07月05日 01:47
  • 6841

内核态,用户态,目态,管态

目态,管态大多数计算机系统将CPU执行状态分为目态与管态。CPU的状态属于程序状态字PSW的一位。CPU交替执行操作系统程序和用户程序。管态又叫特权态,系统态或核心态。CPU在管态下可以执行指令系统的...
  • msdnwolaile
  • msdnwolaile
  • 2016年09月26日 16:14
  • 1433

用Visual C++实现注册表简单操作

对注册表的编程要用到句柄,我们需要通过一个句柄访问注册表键值,当打开或创建一个键值的时候,会返回一个该键的句柄,并且调用和分析键和创建键值, 在分析和创建的同时需要传递句柄到函数。WINDOWS提供预...
  • zyrr159487
  • zyrr159487
  • 2011年12月05日 13:29
  • 462

Visual C++利用Intel C++ 编译器提升多核性能与多媒体指令支持获取更高的程序效率与缩小程序体积

Intel c++编译器有下列优点,建议VC++项目开发采用intel c++编译器取代VS自带c++编译器: 与 Microsoft Visual C++ 相兼容,可以嵌入 Microsoft V...
  • szu030606
  • szu030606
  • 2013年07月25日 17:39
  • 2624

Visual C++利用Intel C++ 编译器提升多核性能与多媒体指令支持获取更高的程序效率与缩小程序体积

Intel c++编译器有下列优点,建议VC++项目开发采用intel c++编译器取代VS自带c++编译器:   与 Microsoft Visual C++ 相兼容,可以嵌入 Microsof...
  • pizi0475
  • pizi0475
  • 2014年01月02日 20:27
  • 825

COM组件技术操作技巧(Visual C++代码参考与技巧大全 )

第12章 COM组件技术操作技巧 COM是开发组件的一种方法,组件是一些小的二进制程序,它可以为操作系统或者应用程序提供服务。COM技术的发展进一步加强了程序的模块化编程的思想,使应用程序在更容易扩...
  • shigaopb
  • shigaopb
  • 2013年06月12日 22:52
  • 1431

基于Visual C++6.0的声音文件操作

一、前言   当前Visual C++相关的编程资料中,无论是大部头的参考书,还是一些计算机杂志,对声音文件的处理都是泛泛的涉及一下,许多编程爱好者都感到对该部分的内容了解不是很透彻,本文希望能...
  • qutadi
  • qutadi
  • 2014年07月17日 17:37
  • 410

Visual C++剪贴板操作不完全攻略

在Visual C++中如何实现对剪贴板的操作,其实在VC++/MFC中是相当简单的。本文主要介绍了如下内容: 1、文本内容的操作 2、WMF数据的操作 3、位图的操作 4、设置使用自定义格式...
  • tian_110
  • tian_110
  • 2015年01月09日 10:20
  • 278

Visual C++中用MFC ODBC操作Access数据库(1)

本实例是某项目中的一部分,目的是实现MFC ODBC数据库与Access数据表格之间的相互操作。包括用Visual C++中的MFC ODBC技术实现对Access数据表格的内容的显示、添加、修改和删...
  • phenixyf
  • phenixyf
  • 2012年08月14日 10:40
  • 926
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:用Visual C++实现CPU特权指令操作
举报原因:
原因补充:

(最多只允许输入30个字)