任意用戶模式下執行 ring 0 代碼
Author : sinister
Email : [email protected]
HomePage: http://www.whitecell.org
衆所周知在非 Admin 用戶模式下,是不允許加載驅動執行 RING 0 代碼的。
本文提供了一種方法,通過修改系統 GDT,IDT 來添加自己的 CALLGATE 和
INTGATE 這樣便在系統中設置了一個後門。我們就可以利用這個後門
在任意用戶模式下執行 ring 0 代碼了。爲了保證我們添加的 CALLGATE 和 INT
GATE 永久性。可以在第一次安裝時利用 SERVICE API 或 INF 文件設置成隨
系統啓動。不過此方法也有個缺陷,就是在第一次安裝 CALLGATE 或 INTGATE
時仍然需要 ADMIN 權限。下面分別給出了添加 CALLGATE 與 INTGATE 的具體
代碼。
一、通過添加調用門實現
爲了可以讓任意用戶來調用我們的 CALLGATE 需要解決一個小問題。因爲
需要知道 CALLGATE 的 SELECTOR 後纔可以調用。而在 RING 3 下除了能
得到 GDT 的 BASE ADDRESS 和 LIMIT 外是無法訪問 GDT 內容的。我本想
在 RING 0 把 SELECTOR 保存到文件裏。在 RING 3 下讀取出來再調用。
後經過跟 wowocock 探討。他提出的思路是在 RING 0 下通過
ZwQuerySystemInformation 得到 NTDLL.DLL 的 MODULE BASE 然後根據
PE HEADER 中的空閒處存放 SELECTOR。這樣在 RING 3 的任意用戶模式下
就很容易得到了。在這裏要特別感謝 wowocock。下面的代碼爲了演示
方便,用了在我機器上 GDT 中第一個空閒描述符的 SELECTOR 。
驅動程序:
/*****************************************************************
文件名 : WssAddCallGate.c
描述 : 添加調用門
作者 : sinister
最後修改日期 : 2002-11-02
*****************************************************************/
#include "ntddk.h"
#include "string.h"
#ifndef DWORD
#define DWORD unsigned int
#endif
#ifndef WORD
#define WORD unsigned short
#endif
#define LOWORD(l) ((unsigned short)(unsigned int)(l))
#define HIWORD(l) ((unsigned short)((((unsigned int)(l)) >> 16) & 0xFFFF))
typedef unsigned long ULONG;
static NTSTATUS MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
VOID DriverUnload (IN PDRIVER_OBJECT pDriverObject);
#pragma pack(push,1)
typedef struct tagGDTR{
WORD wLimit;
DWORD *dwBase;
}GDTR, *PGDTR;
typedef struct tagGDT_DESCRIPTOR{
unsigned limit : 16;
unsigned baselo : 16;
unsigned basemid : 8;
unsigned type : 4;
unsigned system : 1;
unsigned dpl : 2;
unsigned present : 1;
unsigned limithi : 4;
unsigned available : 1;
unsigned zero : 1;
unsigned size : 1;
unsigned granularity : 1;
unsigned basehi : 8;
}GDT_DESCRIPTOR, *PGDT_DESCRIPTOR;
typedef struct tagCALLGATE_DESCRIPTOR{
unsigned short offset_0_15;
unsigned short selector;
unsigned char param_count : 4;
unsigned char some_bits : 4;
unsigned char type : 4;
unsigned char app_system : 1;
unsigned char dpl : 2;
unsigned char present : 1;
unsigned short offset_16_31;
} CALLGATE_DESCRIPTOR, *PCALLGATE_DESCRIPTOR;
#pragma pack(pop)
void __declspec(naked) Ring0Call()
{
PHYSICAL_ADDRESS PhyAdd;
__asm {
pushad
pushfd
cli
}
DbgPrint("WSS - My CallGate /n");
//
// 這裏可以添加你想要執行的 ring 0 代碼。
//
__asm {
popfd
popad
retf
}
}
VOID AddCallGate( ULONG FuncAddr )
{
GDTR gdtr;
PGDT_DESCRIPTOR gdt;
PCALLGATE_DESCRIPTOR callgate;
WORD wGDTIndex = 1;
__asm {
sgdt gdtr // 得到 GDT 基地址與界限
}
gdt = (PGDT_DESCRIPTOR) ( gdtr.dwBase + 8 ); // 跳過空選擇子
while ( wGDTIndex < ( gdtr.wLimit / 8 ) )
{
if ( gdt->present == 0 ) //從 GDT 中找到空描述符
{
callgate = (PCALLGATE_DESCRIPTOR)gdt;
callgate->offset_0_15 = LOWORD(FuncAddr);
callgate->selector = 8; // 內核段選擇子
callgate->param_count = 0; // 參數複製數量
callgate->some_bits = 0;
callgate->type = 0xC; // 386調用門
callgate->app_system = 0; // 系統描述符
callgate->dpl = 3; // RING 3 可調用
callgate->present = 1; // 設置存在位
callgate->offset_16_31 = HIWORD(FuncAddr);
DbgPrint("Add CallGate/n");
return;
}
gdt ++;
wGDTIndex ++;
}
}
// 驅動入口
NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath )
{
UNICODE_STRING nameString, linkString;
PDEVICE_OBJECT deviceObject;
NTSTATUS status;
HANDLE hHandle;
int i;
//卸載驅動
DriverObject->DriverUnload = DriverUnload;
//建立設備
RtlInitUnicodeString( &nameString, L"//Device//WssAddCallGate" );
status = IoCreateDevice( DriverObject,
0,
&nameString,
FILE_DEVICE_UNKNOWN,
0,
TRUE,
&deviceObject
);
if (!NT_SUCCESS( status ))
return status;
RtlInitUnicodeString( &linkString, L"//DosDevices//WssAddCallGate" );
status = IoCreateSymbolicLink (&linkString, &nameString);
if (!NT_SUCCESS( status ))
{
IoDeleteDevice (DriverObject->DeviceObject);
return status;
}
AddCallGate((ULONG)Ring0Call);
for ( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {
DriverObject->MajorFunction[i] = MydrvDispatch;
}
DriverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
//處理設備對象操作
static NTSTATUS MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0L;
IoCompleteRequest( Irp, 0 );
return Irp->IoStatus.Status;
}
VOID DriverUnload (IN PDRIVER_OBJECT pDriverObject)
{
UNICODE_STRING nameString;
RtlInitUnicodeString( &nameString, L"//DosDevices//WssAddCallGate" );
IoDeleteSymbolicLink(&nameString);
IoDeleteDevice(pDriverObject->DeviceObject);
return;
}
應用程序:
#include <windows.h>
#include <stdio.h>
void main()
{
WORD farcall[3];
farcall[0] = 0x0;
farcall[1] = 0x0;
farcall[2] = 0x4b; //在我機器上,添加 CALLGATE 的選擇子爲 4BH
_asm call fword ptr [farcall]
}
二、通過添加中斷門實現
添加中斷門沒有什麼需要解決的問題。直接在 RING 3 利用 int x
即可切換。想想系統調用 INT 2E 就很容易理解了。
/*****************************************************************
文件名 : WssMyInt.c
描述 : 添加中斷門
作者 : sinister
最後修改日期 : 2002-11-02
*****************************************************************/
#include "ntddk.h"
#pragma pack(1)
typedef struct tagIDTR {
short Limit;
unsigned int Base;
}IDTR, *PIDTR;
typedef struct tagIDTENTRY {
unsigned short OffsetLow;
unsigned short Selector;
unsigned char Reserved;
unsigned char Type:4;
unsigned char Always0:1;
unsigned char Dpl:2;
unsigned char Present:1;
unsigned short OffsetHigh;
} IDTENTRY, *PIDTENTRY;
#pragma pack()
#define MYINT 0x76
extern VOID _cdecl MyIntFunc();
CHAR IDTBuffer[6];
IDTENTRY OldIdt;
PIDTR idtr = (PIDTR)IDTBuffer;
static NTSTATUS MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
VOID DriverUnload (IN PDRIVER_OBJECT pDriverObject);
// 我們得中斷處理函數
VOID _cdecl MyIntFunc()
{
PHYSICAL_ADDRESS PhyAdd;
unsigned int dwCallNum;
unsigned int dwVAddr;
_asm mov dwCallNum,eax
//
// 這裏可以添加你想要執行的 ring 0 代碼
//
switch ( dwCallNum )
{
case 0x01:
DbgPrint("MyIntGate eax = 0x01/n");
break;
case 0x02:
DbgPrint("MyIntGate eax = 0x02/n");
break;
default:break;
}
_asm iretd; //中斷返回
}
NTSTATUS AddMyInt()
{
PIDTENTRY Idt;
//得到 IDTR 中得段界限與基地址
_asm sidt IDTBuffer
Idt = (PIDTENTRY)idtr->Base; //得到IDT表基地址
//保存原有得 IDT
RtlCopyMemory(&OldIdt, &Idt[MYINT], sizeof(OldIdt));
//禁止中斷
_asm cli
//設置 IDT 表各項添加我們得中斷
Idt[MYINT].OffsetLow = (unsigned short)MyIntFunc; //取中斷處理函數低16位
Idt[MYINT].Selector = 8; //設置內核段選擇子
Idt[MYINT].Reserved = 0; //系統保留
Idt[MYINT].Type = 0xE; //設置0xE表示是中斷門
Idt[MYINT].Always0 = 0; //系統保留必須爲0
Idt[MYINT].Dpl = 3; //描述符權限,設置爲允許 RING 3 進程調用
Idt[MYINT].Present = 1; //存在位設置爲1表示有效
Idt[MYINT].OffsetHigh = (unsigned short)((unsigned int)MyIntFunc>>16); //取中斷處理函數高16位
//開中斷
_asm sti
return STATUS_SUCCESS;
}
//刪除中斷
void RemoveMyInt()
{
PIDTENTRY Idt;
Idt = (PIDTENTRY)idtr->Base;
_asm cli
//恢復 IDT
RtlCopyMemory(&Idt[MYINT], &OldIdt, sizeof(OldIdt));
_asm sti
}
// 驅動入口
NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath )
{
UNICODE_STRING nameString, linkString;
//UNICODE_STRING deviceString;
PDEVICE_OBJECT deviceObject;
NTSTATUS status;
WCHAR wBuffer[200];
nameString.Buffer = wBuffer;
nameString.MaximumLength = 200;
//卸載驅動
DriverObject->DriverUnload = DriverUnload;
//建立設備
RtlInitUnicodeString( &nameString, L"//Device//WSSINT" );
status = IoCreateDevice( DriverObject,
0,
&nameString,
FILE_DEVICE_UNKNOWN,
0,
TRUE,
&deviceObject
);
if (!NT_SUCCESS( status ))
return status;
RtlInitUnicodeString( &linkString, L"//??//WSSINT" );
//使WIN32應用程序可見
status = IoCreateSymbolicLink (&linkString, &nameString);
if (!NT_SUCCESS( status ))
{
IoDeleteDevice (DriverObject->DeviceObject);
return status;
}
AddMyInt();
DriverObject->MajorFunction[IRP_MJ_CREATE] = MydrvDispatch;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = MydrvDispatch;
return STATUS_SUCCESS;
}
static NTSTATUS MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
NTSTATUS status;
UNREFERENCED_PARAMETER( DeviceObject );
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0L;
status = STATUS_SUCCESS;
IoCompleteRequest( Irp, 0 );
return status;
}
VOID DriverUnload (IN PDRIVER_OBJECT pDriverObject)
{
UNICODE_STRING nameString;
UNICODE_STRING deviceString,driveString;
NTSTATUS ntStatus;
RemoveMyInt();
//刪除WIN32可見
IoDeleteSymbolicLink(&nameString);
//刪除設備
IoDeleteDevice(pDriverObject->DeviceObject);
return;
}
關於我們:
WSS(Whitecell Security Systems),一個非營利性民間技術組織,致力於各種系統安全技術的研究。堅持傳統的hacker精神,追求技術的精純。
WSS 主頁:http://www.whitecell.org/
任意用戶模式下執行 ring 0 代碼
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章
VS2005 對話框如何屏蔽回車鍵
sjf1234
2018-08-27 17:42:06
在PropertyPage窗口下修改父窗口PropertySheet上的4個按鈕
sjf1234
2018-08-27 17:42:05
windows不規則窗體的編程實現
luoweigangyuqin
2018-08-27 12:15:44
MFC多文檔框架
luoweigangyuqin
2018-08-27 12:15:42
CEdit重繪垂直居中顯示
luoweigangyuqin
2018-08-27 12:15:40
CloseHandle()函數的使用
luoweigangyuqin
2018-08-27 12:15:40
vc 2003 Release 版本添加調試功能
stuarts740
2018-08-27 06:58:31
檢查MFC程序的內存泄露
stuarts740
2018-08-27 06:58:24
今天解決了一個問題:GDI庫版本不一致
stuarts740
2018-08-27 06:58:24
SQL Server存儲圖像數據的策略與方法
icebergly
2018-08-27 00:33:04
一個關於多對話框和CListCtrl控件的問題(棘手)。
icebergly
2018-08-27 00:32:54
CString 操作指南
icebergly
2018-08-27 00:32:51