文章作者:grayfox
作者主页:http://nokyo.blogbus.com
原始出处:http://nokyo.blogbus.com/logs/33542878.html
此前在“【科普6】利用NTDLL导出函数枚举进程”一文中我们曾经介绍了在ring3通过动态导出ntdll.dll中的ZwQuerySystemInformation函数来枚举系统进程,那么在ring0能否调用该函数呢?
当然可以,而且在ring0调用会比在ring3更加简单,这样说来我们直接把ring3的代码复制到ring0就可以了?事实证明没有这么简单。
因为这个函数属于未公开文档的函数,所以我们还是不能直接使用的,难道还要像在ring3一样,调用LoadLibrary和GetProcAddress从ntdll.dll中导出?靠,那和ring3还有什么区别?
事实上,在ring0调用未公开文档函数是很容易的,只要在代码的开始声明一下就可以了,注意要这样声明:
NTKERNELAPI
NTSTATUS ZwQuerySystemInformation(
IN ULONG SystemInformationClass,
IN OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength OPTIONAL
);
注意这里的开头使用了一个NTKERNELAPI,这个宏我不知道是干啥的,就到几个群里问了一下,得到了答案,它是在winddk.h这个头文件中声明的,如下:
#if (defined(_NTDRIVER_) || defined(_NTDDK_) || defined(_NTIFS_) || defined(_NTHAL_)) && !defined(_BLDR_)
#define NTKERNELAPI DECLSPEC_IMPORT // wdm
#else
#define NTKERNELAPI
#endif
这个我还真不敢准确地说是干啥用的,经验不够,不敢乱发言,反正就这么用着行了,有大牛路过的时候麻烦给俺们科普一下,扫下盲~~~
函数照上面的方法声明之后就可以直接用了,如下是我的代码,基本和ring3没多大区别:
//////////////////////////////////////////////////////////////////////////
//
// 使用ZwQuerySystemInformation函数枚举进程
//
//////////////////////////////////////////////////////////////////////////
VOID
EnumProcessList1()
{
ULONG cbBuffer = 0x10000;
ULONG dwCount = 0;
PVOID pBuffer = NULL;
PSYSTEM_PROCESS_INFORMATION pInfo;
pBuffer = ExAllocatePool(PagedPool, cbBuffer);
// 获取进程信息
KdPrint(("We Use ZwQuerySystemInformation!"));
ZwQuerySystemInformation( SystemProcessesAndThreadsInformation,
pBuffer,
cbBuffer,
NULL);
pInfo = (PSYSTEM_PROCESS_INFORMATION)pBuffer;
for( ; ; )
{
dwCount++;
if (pInfo->ProcessId == 0)
{
KdPrint(("[%6d] System Idle Process", pInfo->ProcessId));
}
else
{
KdPrint(("[%6d] %wZ", pInfo->ProcessId, pInfo->ProcessName));
}
if (pInfo->NextEntryDelta == 0)
{
break;
}
pInfo = (PSYSTEM_PROCESS_INFORMATION)(((PUCHAR)pInfo) + pInfo->NextEntryDelta);
}
KdPrint(("ProcessCount = %d", dwCount));
ExFreePool(pBuffer);
}