利用调用门从Ring 3进入Ring 0[转]

☆ 利用调用门从Ring 3进入Ring 0

观察用户空间程序memdump.exe执行时CS、DS、FS所对应的段描述符:

--------------------------------------------------------------------------
> memdump -l 8
GDTR.base             = 0x8003F000
GDTR.limit            = 0x03FF
CURRENT_CS            = 0x001B
CURRENT_DS            = 0x0023
CURRENT_ES            = 0x0023
CURRENT_SS            = 0x0023
CURRENT_FS            = 0x0038
PageSize              = 0x00001000
AllocationGranularity = 0x00010000
byteArray [ 8 bytes ] ->
00000000  00 00 00 00 00 00 00 00                            ........

> memdump -l 8 -a 0x8003F018
PageSize              = 0x00001000
AllocationGranularity = 0x00010000
byteArray [ 8 bytes ] ->
00000000  FF FF 00 00 00 FB CF 00                            ........

> memdump -l 8 -a 0x8003F020
PageSize              = 0x00001000
AllocationGranularity = 0x00010000
byteArray [ 8 bytes ] ->
00000000  FF FF 00 00 00 F3 CF 00                            ........

> memdump -l 8 -a 0x8003F038
PageSize              = 0x00001000
AllocationGranularity = 0x00010000
byteArray [ 8 bytes ] ->
00000000  FF 0F 00 E0 FD F3 40 7F                            ......@.
--------------------------------------------------------------------------

代码段、数据段描述符的DPL都是3,均覆盖整个4G空间。选择子等于0x001B,并非对
应第0x001B个(从0计)描述符,有时候容易忘了这茬,其对应的描述符所在线性地址
为:

GDTR.base + ( CURRENT_CS & 0xfff8 ) -> 0x8003F018

再比如FS对应的是GDT中第7个描述符:

0x0038 >> 3 -> 0x0007

可能有人奇怪了,数据段描述符覆盖整个4G空间并且DPL等于3,那岂非任一用户空间
程序都可读写访问整个4G空间,包括高2G的内核空间。微软没这么傻,事实上除段级
保护外,IA-32还同时提供页级保护,Windows内核启用了分页机制,其页级保护将阻
止Ring 3代码访问内核空间。页级保护只对Ring 3代码有意义,对Ring 2、1、0代码
没有任何意义,后者对页级保护来说统称为系统特权级,而前者称为用户特权级。系
统特权级代码对任意页拥有读、写、执行权限。

本小节的目标很简单,在不写驱动程序的情况下读访问任意线性地址,而不是局限在
[0x80000000, 0xa0000000)区间上。为达目标,现在有两条路,一是修改页级保护,
二是让自己的代码拥有系统特权级。页目录、页表在0xc0300000、0xc0000000,就前
几节所演示的技术而言,没法简单修改页级保护,就算有办法,也太过麻烦并且冒很
大风险。事实上我们只有一条路,让自己的代码拥有Ring 0权限。

crazylord演示了一种技术([3])。他利用/Device/PhysicalMemory在GDT中搜索P位为
0的空闲描述符,然后将这个空闲描述符设置成DPL等于3的调用门,用户空间Ring 3
代码通过这个调用门获取Ring 0权限,于是内核空间完全暴露在我们面前。

前面有一节中已经看到内核中代码段选择子等于0x0008,其对应的描述符如下:

--------------------------------------------------------------------------
> memdump -l 8 -a 0x8003F008
PageSize              = 0x00001000
AllocationGranularity = 0x00010000
byteArray [ 8 bytes ] ->
00000000  FF FF 00 00 00 9B CF 00                            ........
--------------------------------------------------------------------------

与0x8003F018相比,仅仅是DPL不同,0x8003F008的DPL是0。Windows内核采用基本平
坦模式,一个函数在这两种代码段选择子下对应一样的段内偏移,这样就很容易设置
调用门。

如果调用门导致向内层特权级跃迁,必然发生堆栈切换。压栈的形参将从Ring 3的堆
栈复制到Ring 0的堆栈中,并且CS随EIP一起压栈,我们不能依赖编译器处理形参。

dump.c演示了如何在用户空间编程中调用内核函数nt!MmGetPhysicalAddress。因为
现在进入Ring 0已不成问题,如果能获取nt!MmGetPhysicalAddress的线性地址就搞
定。crazylord对LoadLibrary()理解有问题,他在Phrack Magazine 59-0x10([3])中
这部分代码是错误的,后来为了让他的代码跑起来,他硬性定义了一个ntoskrnl.exe
基址:

/*
* default base address for ntoskrnl.exe on win2k
*
#define BASEADD 0x7FFE0000

ntoskrnl.exe的基址不可能低于0x80000000。dump.c中LocateNtoskrnlEntry()才是
正确的实现。

顺带在这里验证线性地址0xc0300000的确指向页目录,办法就是先取CR3的物理地址,
然后调用nt!MmGetPhysicalAddress( 0xc0300000 ),看返回的物理地址是否与CR3一
致。

h0ck0r@smth可能是要搞破解吧,他折腾过将内核中的驱动dump出来。当时提问如何
访问[0x80000000, 0xa0000000)以外的内核空间线性地址。后来他的实现就是直接在
Ring 0代码中访问这些线性地址。我当时想绕了,先调用nt!MmGetPhysicalAddress
再利用/Device/PhysicalMemory,事实上h0ck0r@smth的办法更直接。dump.c演示了
他的办法。

dump.c没有考虑太多边界情形,可能会导致不可预知的后果,比如[-a Address]指定
0,结果dump.exe在Ring 0中立即终止,没有回到Ring 3来,于是所征用的空闲描述
符得不到释放,此时我用kd手工释放,最简单的办法将相应描述符的第6字节(从1计)
清为0x00即可。

演示程序是为Unix程序员小闹Windows而写,注释冗长可以理解,Windows程序员勿怪。
Unix程序员如无IA-32基础,万勿执行dump.exe!

--------------------------------------------------------------------------
/*
* For x86/EWindows XP SP1 & VC 7
* cl dump.c /Os /G6 /W3 /Fadump.asm
*
* Usage: dump [-h] [-g Gdtrbase] [-a Address] [-l Length]
*/

/*
* 名为dump.c,实则与dump非紧藕合,dump功能仅为其中一种演示而已。
*
* 该程序仅为演示用途,其潜在的危险由使用者本人承担,否则请勿执行之。
*
* 由于参考太多源代码,我不是太清楚该将哪些作者的名字列于此处:
*
* crazylord <crazylord@minithins.net>
* Gary Nebbett
* h0ck0r@smth
* Mark E. Russinovich
* tsu00 <tsu00@263.net>
*
* 这是此番学习笔记中惟一列举源作者的C程序。总之,该程序与我没有太大关系,
* 就不贪天功为己有了,顺带少些风险,上场当念下场时。
*/

/************************************************************************
*                                                                      *
*                               Head File                              *
*                                                                      *
************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <windows.h>
#include <aclapi.h>
#include <memory.h>

/************************************************************************
*                                                                      *
*                               Macro                                  *
*                                                                      *
************************************************************************/

#pragma comment( linker, "/subsystem:console" )
#pragma comment( lib,    "advapi32.lib"       )

typedef LONG NTSTATUS;

#define NT_SUCCESS(status)      ((NTSTATUS)(status)>=0)

#define RING0_CODE_SELECTOR     ((unsigned short int)0x0008)

/*
*************************************************************************
* ntdef.h
*/
typedef struct _UNICODE_STRING
{
    USHORT Length;
    USHORT MaximumLength;
    PWSTR  Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

/*
* Valid values for the Attributes field
*/
#define OBJ_INHERIT             0x00000002L
#define OBJ_PERMANENT           0x00000010L
#define OBJ_EXCLUSIVE           0x00000020L
#define OBJ_CASE_INSENSITIVE    0x00000040L
#define OBJ_OPENIF              0x00000080L
#define OBJ_OPENLINK            0x00000100L
#define OBJ_KERNEL_HANDLE       0x00000200L
#define OBJ_FORCE_ACCESS_CHECK  0x00000400L
#define OBJ_VALID_ATTRIBUTES    0x000007F2L

typedef struct _OBJECT_ATTRIBUTES
{
    ULONG           Length;
    HANDLE          RootDirectory;
    PUNICODE_STRING ObjectName;
    ULONG           Attributes;
    PVOID           SecurityDescriptor;
    PVOID           SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;

typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;
/*
* ntdef.h
*************************************************************************
*/

/*
*************************************************************************
* <<Windows NT/2000 Native API Reference>> by Gary Nebbett
*/
typedef enum _SECTION_INHERIT
{
    ViewShare = 1,
    ViewUnmap = 2
} SECTION_INHERIT;

/*
* 虽然本程序用不到这么多枚举值,还是列出一份最完整的。这个程序本身不求完
* 美,尽可能多地保留一些未文档化的参考资料。
*/
typedef enum _SYSTEM_INFORMATION_CLASS     //    Q S
{
    SystemBasicInformation,                // 00 Y N
    SystemProcessorInformation,            // 01 Y N
    SystemPerformanceInformation,          // 02 Y N
    SystemTimeOfDayInformation,            // 03 Y N
    SystemNotImplemented1,                 // 04 Y N
    SystemProcessesAndThreadsInformation,  // 05 Y N
    SystemCallCounts,                      // 06 Y N
    SystemConfigurationInformation,        // 07 Y N
    SystemProcessorTimes,                  // 08 Y N
    SystemGlobalFlag,                      // 09 Y Y
    SystemNotImplemented2,                 // 10 Y N
    SystemModuleInformation,               // 11 Y N
    SystemLockInformation,                 // 12 Y N
    SystemNotImplemented3,                 // 13 Y N
    SystemNotImplemented4,                 // 14 Y N
    SystemNotImplemented5,                 // 15 Y N
    SystemHandleInformation,               // 16 Y N
    SystemObjectInformation,               // 17 Y N
    SystemPagefileInformation,             // 18 Y N
    SystemInstructionEmulationCounts,      // 19 Y N
    SystemInvalidInfoClass1,               // 20
    SystemCacheInformation,                // 21 Y Y
    SystemPoolTagInformation,              // 22 Y N
    SystemProcessorStatistics,             // 23 Y N
    SystemDpcInformation,                  // 24 Y Y
    SystemNotImplemented6,                 // 25 Y N
    SystemLoadImage,                       // 26 N Y
    SystemUnloadImage,                     // 27 N Y
    SystemTimeAdjustment,                  // 28 Y Y
    SystemNotImplemented7,                 // 29 Y N
    SystemNotImplemented8,                 // 30 Y N
    SystemNotImplemented9,                 // 31 Y N
    SystemCrashDumpInformation,            // 32 Y N
    SystemExceptionInformation,            // 33 Y N
    SystemCrashDumpStateInformation,       // 34 Y Y/N
    SystemKernelDebuggerInformation,       // 35 Y N
    SystemContextSwitchInformation,        // 36 Y N
    SystemRegistryQuotaInformation,        // 37 Y Y
    SystemLoadAndCallImage,                // 38 N Y
    SystemPrioritySeparation,              // 39 N Y
    SystemNotImplemented10,                // 40 Y N
    SystemNotImplemented11,                // 41 Y N
    SystemInvalidInfoClass2,               // 42
    SystemInvalidInfoClass3,               // 43
    SystemTimeZoneInformation,             // 44 Y N
    SystemLookasideInformation,            // 45 Y N
    SystemSetTimeSlipEvent,                // 46 N Y
    SystemCreateSession,                   // 47 N Y
    SystemDeleteSession,                   // 48 N Y
    SystemInvalidInfoClass4,               // 49
    SystemRangeStartInformation,           // 50 Y N
    SystemVerifierInformation,             // 51 Y Y
    SystemAddVerifier,                     // 52 N Y
    SystemSessionProcessesInformation      // 53 Y N
} SYSTEM_INFORMATION_CLASS;

typedef struct _SYSTEM_MODULE_INFORMATION  // Information Class 11
{
    ULONG  Reserved[2];
    PVOID  Base;
    ULONG  Size;
    ULONG  Flags;
    USHORT Index;
    USHORT Unknown;
    USHORT LoadCount;
    USHORT ModuleNameOffset;
    CHAR   ImageName[256];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
/*
* <<Windows NT/2000 Native API Reference>> by Gary Nebbett
*************************************************************************
*/

/*
*************************************************************************
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值