• 【驱动笔记7】再谈ZwQuerySystemInformation

    2009-01-07

    分类:内核编程

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://nokyo.blogbus.com/logs/33542878.html

    文章作者: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);
    }