函数存在于NTDLL.DLL动态链接库中。NTDLL.DLL负责ring3与ring0之间的通信。当使用子系统方式进行系统调用的时候,ntdll.dll和SSDT会配合使用。
关于ZwQuerySystemInformation这个函数可以用来查询进程信息、内核信息、硬件信息(例如CPU数目)、句柄信息、时间信息等54个系统信息。
该函数的原型是

NTSTATUS WINAPI ZwQuerySystemInformation(__in          SYSTEM_INFORMATION_CLASSSystemInformationClass,__in_out     PVOIDSystemInformation,__in          ULONGSystemInformationLength,__out_opt    PULONGReturnLength);

至于第一个参数SYSTEM_INFORMATION_CLASS是一个枚举结构。枚举了所有的54个系统信息。该结构在最后将会列举出来。

一、用户模式下的ZwQuerySystemInformation
在用户模式下必须用LoadLibrary与GetProcAddress来获取该函数地址。
代码如下,

先声明一个函数。
typedef NTSTATUS (WINAPI *NTQUERYSYSTEMINFORMATION)(INSYSTEM_INFORMATION_CLASS,IN OUT PVOID,INULONG,OUTPULONG);加载NTDLL.DLL,获取函数地址。NTQUERYSYSTEMINFORMATIONZwQuerySystemInformation = NULL;ZwQuerySystemInformation =(NTQUERYSYSTEMINFORMATION)GetProcAddress(ntdll.dll,"ZwQuerySystemInfromation");

举例:枚举进程信息
要想获取进程信息,必须使用第二个参数,第二个参数指向一块内存。必须使用参数1中每个系统信息对应的结构体来将该内存进行转换。
假设我们要枚举进程信息,必须使用下列结构,该结构描述了进程名,线程数,指向下一个模块的指针,创建时间等等。结构描述如下:

typedef struct _SYSTEM_PROCESSES
{  ULONG          NextEntryDelta;          //构成结构序列的偏移量;  ULONG          ThreadCount;             //线程数目;  ULONG          Reserved1[6];             LARGE_INTEGER  CreateTime;              //创建时间;  LARGE_INTEGER  UserTime;                //用户模式(Ring 3)的CPU时间;  LARGE_INTEGER  KernelTime;              //内核模式(Ring 0)的CPU时间;  UNICODE_STRING ProcessName;             //进程名称;  KPRIORITY      BasePriority;            //进程优先权;  HANDLE         ProcessId;               //进程标识符;  HANDLE         InheritedFromProcessId;  //父进程的标识符;  ULONG          HandleCount;             //句柄数目;  ULONG          Reserved2[2];  VM_COUNTERS    VmCounters;              //虚拟存储器的结构;  IO_COUNTERS    IoCounters;              //IO计数结构;  SYSTEM_THREADS Threads[1];              //进程相关线程的结构数组;
}SYSTEM_PROCESSES,*PSYSTEM_PROCESSES; 

循环程序如下:

 PSYSTEM_PROCESSES psp=NULL; //先为参数2设为空,dwNeedSize获取保存该结构体的内存大小
status = ZwQuerySystemInformation(SystemProcessesAndThreadsInformation, NULL, 0, &dwNeedSize); //若用户提供的缓冲区大小不够,则返回STATUS_INFO_LENGTH_MISMATCH,并返回实际需要的缓冲区大小
if ( status ==STATUS_INFO_LENGTH_MISMATCH ) {   pBuffer = new BYTE[dwNeedSize];  status =ZwQuerySystemInformation(SystemProcessesAndThreadsInformation, (PVOID)pBuffer,dwNeedSize, NULL);  if ( status ==STATUS_SUCCESS )  {  psp = (PSYSTEM_PROCESSES)pBuffer; //强制转换printf("PID  线程数工作集大小进程名\n");do {  printf("%-4d",psp->ProcessId);printf(" %3d",psp->ThreadCount);  printf(" %8dKB",psp->VmCounters.WorkingSetSize/1024);wprintf(L" %s\n",psp->ProcessName.Buffer);psp = (PSYSTEM_PROCESSES)((ULONG)psp +psp->NextEntryDelta );  }while ( psp->NextEntryDelta != 0 );//循环遍历}delete []pBuffer;  pBuffer =NULL; }

二、内核模式下的ZwQuerySystemInformation
内核模式下的ZwQuerySystemInformation的地址的获取没有应用层那么麻烦。直接声明一下该函数即可。

NTSYSAPINTSTATUSNTAPI ZwQuerySystemInformation(IN ULONG SystemInformationClass,IN OUT PVOID SystemInformation,IN ULONG SystemInformationLength,OUT PULONG ReturnLength);

注意这里的开头使用了一个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);
}

这是一个C代码程序,该程序是在ring3层写的,主要内容是获取CPU个数,枚举进程,枚举内核模块。该代码是从网上下载的,因为要用到这个函数,所以小小地研究了一下。

------------------------------------------------------------------------------------------------------------------------------------------

简单说,即调用第11号功能,枚举一下内核中已加载的模块。
部分代码如下:
//功能号为11,先获取所需的缓冲区大小
ZwQuerySystemInformation(SystemModuleInformation,NULL,0,&needlen);
//申请内存
ZwAllocateVirtualMemory(NtCurrentProcess(),(PVOID*)&pBuf,0,&needlen,MEM_COMMIT,PAGE_READWRITE);
//再次调用
ZwQuerySystemInformation(SystemModuleInformation,(PVOID)pBuf,truelen,&needlen);
......
//最后,释放内存
ZwFreeVirtualMemory(NtCurrentProcess(),(PVOID*)&pBuf,&needlen,MEM_RELEASE);

突出过程,省略了错误判断,和调用其它的功能时操作并没有什么区别。
关键在返回的内容中,缓冲区pBuf的前四个字节是已加载的模块总数,记为ModuleCnt,接下来就是共有ModuleCnt个元素的模块信息数组了。

//该结构如下:
typedef struct _SYSTEM_MODULE_INFORMATION {
ULONG Count;
SYSTEM_MODULE_INFORMATION_ENTRY Module[1];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;//模块详细信息结构如下:
typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY {
HANDLE Section;
PVOID MappedBase;
PVOID Base;
ULONG Size;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT PathLength;
CHAR ImageName[256];
} SYSTEM_MODULE_INFORMATION_ENTRY, *PSYSTEM_MODULE_INFORMATION_ENTRY;

一个for循环,循环ModuleCnt次就OK了。
基于此,写了三个简单的函数。

void ShowAllModules(char *pBuf)
{
//函数功能:输出所有模块信息
//参数pBuf:ZwQuerySystemInformation返回的缓冲区首址
PSYSTEM_MODULE_INFORMATION_ENTRY pSysModuleInfo;
DWORD Modcnt=0;
Modcnt=*(DWORD*)pBuf;
pSysModuleInfo=(PSYSTEM_MODULE_INFORMATION_ENTRY)(pBuf+sizeof(DWORD));
for (DWORD i=0;i<Modcnt;i++)
{
   printf("%d\t0x%08X 0x%08X %s\n",pSysModuleInfo->LoadOrderIndex,pSysModuleInfo->Base,pSysModuleInfo->Size,pSysModuleInfo->ImageName);
   pSysModuleInfo++;
}

}
void GetOSKrnlInfo(char *pBuf,DWORD *KernelBase,char *szKrnlPath)
{
//函数功能:返回系统内核(ntoskrnl.exe或ntkrnlpa.exe)的基址和路径
//参数pBuf:ZwQuerySystemInformation返回的缓冲区首址
//参数KernelBase:接收返回的系统内核的基址
//参数szKrnlPath:接收返回的内核文件的路径
PSYSTEM_MODULE_INFORMATION_ENTRY pSysModuleInfo;
DWORD Modcnt=0;
*KernelBase=0;
Modcnt=*(DWORD*)pBuf;
pSysModuleInfo=(PSYSTEM_MODULE_INFORMATION_ENTRY)(pBuf+sizeof(DWORD));
//其实第一个模块就是了,还是验证一下吧
if (strstr((strlwr(pSysModuleInfo->ImageName),pSysModuleInfo->ImageName),"nt"))
{
   *KernelBase=(DWORD)pSysModuleInfo->Base;
   GetSystemDirectory(szKrnlPath,MAX_PATH);
   lstrcat(szKrnlPath,strrchr(pSysModuleInfo->ImageName,'\\'));
}
}

void DetectModule(char *pBuf,DWORD dwAddress,char *ModulePath)
{
//函数功能:找出给定地址所在的模块
//参数pBuf:缓冲区地址,同上
//参数dwAddress:要查询的内核地址
//参数ModulePath:接收返回的模块路径
PSYSTEM_MODULE_INFORMATION_ENTRY pSysModuleInfo;
DWORD Modcnt=0;
Modcnt=*(DWORD*)pBuf;
pSysModuleInfo=(PSYSTEM_MODULE_INFORMATION_ENTRY)(pBuf+sizeof(DWORD));
for (DWORD i=0;i<Modcnt;i++)
{
   if ((dwAddress>=(DWORD)pSysModuleInfo->Base)&&(dwAddress<(DWORD)pSysModuleInfo->Base+pSysModuleInfo->Size))
   {
    lstrcpy(ModulePath,pSysModuleInfo->ImageName);
   }
   pSysModuleInfo++;
}
}

该功能是通过遍历PsLoadedModuleList实现的,所以要隐藏的话,最简单的方法还是断链~~
更高级的方法比如抹DriveObject,抹PE信息等等,以后再玩~

函数ZwQuerySystemInformation小结相关推荐

  1. php 自动处理小图的代码,php对图像的各种处理函数代码小结

    导语:PHP中图像处理是一个比较容易的事情,不知道你对了没有?下面的是百分网小编为大家搜集的php对图像的各种处理函数代码小结供大家参考. 一.创建图片资源 imagecreatetruecolor( ...

  2. php图像销毁_php对图像的各种处理函数代码小结

    php对图像的各种处理函数代码小结 导语:PHP中图像处理是一个比较容易的事情,不知道你对了没有?下面的是百分网小编为大家搜集的php对图像的各种处理函数代码小结供大家参考. 一.创建图片资源 ima ...

  3. 指针、数组、函数阶段小结

    引子:数据在内存中是如何存储的,又是如何读取的?内存编号就是内存的地址(内存中每个字节都有一个编号,即地址) 1.概念: 地址:内部存储器的编号,称为地址.如变量a的位置编号,变量b的位置都是指针. ...

  4. Matlab imcrop函数功能小结(20190123)

    最近因为公司研发在准备深度学习,所以在截图的工作需求测试了诸多版本的效果,CImage/OpenCV没有深入研究,Imagemagick类有安装使用,很方便:Matlab截图配置起来尤其简单,操作也很 ...

  5. gettimeofday() 和 clock_gettime()函数 分析小结

    在上一篇文章<struct timeval 和 struct timespec 应用小结>我们分析了与linux系统时间相关的结构体定义,在linux系统C编程中,获取系统时间的api函数 ...

  6. scala函数自我小结(待更新)

    这周进行了Scala函数的学习,我对这周学习的函数进行了自我小结. ++ 这个函数用来执行合并集合操作,会有返回值,返回一个新数组,新数组包含左右两个集合对象的内容. scala> val a ...

  7. python函数进阶小结_Python-进阶-functools模块小结

    文档 地址 functools.partial 作用: functools.partial 通过包装手法,允许我们 "重新定义" 函数签名 用一些默认参数包装一个可调用对象,返回结 ...

  8. php常用操作数组函数,PHP常见数组函数用法小结

    本文实例讲述了PHP常见数组函数用法.分享给大家供大家参考,具体如下: 1.array array_merge(array $array1 [, array  $array2 [, $array]]) ...

  9. scala 方法、函数定义小结

    2019独角兽企业重金招聘Python工程师标准>>> package scalapackage.testmethod/*** Created by Germmy on 2018/4 ...

最新文章

  1. 为什么LINUX不需要碎片整理
  2. 人工智能会取代科学家吗
  3. 【6】青龙面板系列教程之xdd-plus与nolanjdc的对接
  4. C语言strchr()函数(字符串中查找子字符)
  5. Boost:将自定义占位符_1复制到arg <1>的测试程序
  6. Form表单中的button导致页面刷新而无法进入Ajax请求回调函数
  7. IOS基础之UIDynamicAnimator动力学入门-01
  8. 安卓APP_ Fragment(5)—— Fragment + ViewPager2 模拟微信首页 (2)两者联动翻页
  9. python 如何匹配列表中某个单词_Python中部分指定单词的最佳匹配项
  10. 对象 对象 java 1615134277
  11. 【算法】剑指 Offer 63. 股票的最大利润
  12. element tree树组件default-expand-all属性设置默认展开的节点
  13. 简单代码大全_VBA爱好者请进:VBA代码宝概述
  14. .net 中的DllImport
  15. 【转】在CentOS 6.4中编译安装GCC 4.8.1 + GDB 7.6.1
  16. MySQL讲义第49讲——select 查询之查询练习(七):使用多种方法添加排名
  17. SAP 采购定价日期控制
  18. 二叉树的结构特点及性质
  19. qt中socket编程
  20. Vue生命周期,axios及动画

热门文章

  1. @RequestBody, @ResponseBody 注解详解
  2. WINDOWS渗透与提权总结(1)
  3. 软件版本命名规范(转载)
  4. 在linux中教你通过NFS实现文件共享
  5. nonatomic,assign,copy,retain的区别
  6. CPU步进号(版本号)
  7. 在vs2005中使用loki的方法
  8. Go 语言并发模型 Context
  9. 一文读懂:完整的支付系统整体架构
  10. bootstrap layui 两种分页的实现