函数ZwQuerySystemInformation小结
来源:互联网 发布:人才招聘源码 码农网 编辑:程序博客网 时间:2024/06/05 21:49
关于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的地址的获取没有应用层那么麻烦。直接声明一下该函数即可。
- NTSYSAPI
- NTSTATUS
- NTAPI ZwQuerySystemInformation(
- IN ULONG SystemInformationClass,
- IN OUT PVOID SystemInformation,
- IN ULONG SystemInformationLength,
- OUT PULONG ReturnLength);
- #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;
基于此,写了三个简单的函数。
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小结
- 函数ZwQuerySystemInformation小结
- 函数ZwQuerySystemInformation小结
- 函数ZwQuerySystemInformation小结
- ZwQuerySystemInformation函数的用法
- ZwQuerySystemInformation函数查询SystemModuleInformation
- ZwQuerySystemInformation函数的用法
- ZwQuerySystemInformation函数[msdn文档]
- ZwQuerySystemInformation
- ZwQuerySystemInformation
- ZwQuerySystemInformation
- ZwQuerySystemInformation 函数查看进程列表
- 列举进程的内核函数ZwQuerySystemInformation _asm
- 列举进程的内核函数ZwQuerySystemInformation _asm
- 关于未公开函数ZwQuerySystemInformation的使用
- //关于函数ZwQuerySystemInformation的第一个参数 SystemInformationClass
- 关于ZwQuerySystemInformation
- 函数小结
- 15第九周项目二——Time类中的运算符的重载(续)
- POJ 2349 Arctic Network
- runtime运行机制
- 虚拟设备创建多分区虚拟磁盘(软盘,硬盘)
- R软件学习笔记-1
- 函数ZwQuerySystemInformation小结
- 递归的应用实战一
- stm8 蜂鸣器BEEP
- 检查被修改的参数-被修改的时间及前后值
- VS中的路径宏 vc++中OutDir、ProjectDir、SolutionDir各种路径
- 解决myeclipse10.x的Servers产生的at com.genuitec.eclipse.ast.deploy.core.Deployment.<init>(Unknown Source)错
- 【mybatis】完全解读mybatis JDBC事务
- iOS UICollectionView实现瀑布流(3)
- 社区发现算法(二)