用Visual C++實現CPU特權指令操作

來源:互聯網
上載者:User

轉自天極

一、引言

  80x86系列CPU具有四級保護機制。在Windows 9X作業系統只使用0級和3級,以便於移植到精簡指令集的電腦上,如RS4000等,這些處理器一般只有兩個特權級,即系統級和使用者級。在Windows 9X系統內容,應用程式運行在Ring3(3級),如果要運行特權指令就必須進入Ring0(0級)。在同一任務內,實現特權級從外層到內層變換的普通途徑是使用段間調用指令CALL,通過調用門進行轉移;實現特權級從內層向外層變換的普通途徑是使用段間返回指令RET。注意,不能用JMP指令實現任務內不同特權級的變換。調用門描述符轉移的進入點包含目標地址的段及位移量的48位全指標。在執行通過任務門的段間轉移指令JMP或段間調用指令CALL時,指令所含指標內的選擇子用於確定調用門,而位移被丟棄;把調用門內的48位全指標作為目標地址指標進行轉移。

  二、基本思路

  取得通用描述元表,搜尋該表找到一個暫時為空白的描述符,安裝調用門,進行遠程調用即可實現特權指令操作。

  三、所用到的資料結構

  ①全域描述符GDT的格式:

  在VC中定義全域描述符如下:

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

  ②門描述符的一般格式:

  當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);
}

  程式在VC6下編譯通過,作業系統為Windows98。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.