您的位置:首页 > 编程语言

任意用户模式下执行 ring 0 代码

2008-03-25 12:53 267 查看
任意用户模式下执行 ring 0 代码

Author : sinister
Email : sinister@whitecell.org
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/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: