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中还曾经有过这个文件(至少NT4ResourceKit的支持文档里面是这样说的),但现在似乎微软只提供给它的合作伙伴。好在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 这样,SeSinglePrivilege
复制本页网址和标题,发送给你QQ/Msn的好友一起分享
上一篇:攻击新方法:利用PStore接口获取帐号信息
下一篇:入侵检测系统的优点和缺点深入分析