任意用户模式下执行 ring 0 代码分类:
内核驱动C/C++2011-05-03 22:3616人阅读
评论(0)
收藏举报众所周知在非 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
- *****************************************************************/
- #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
- #include
- 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
- *****************************************************************/
- #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;
- }