【旧文章搬运】ZwQuerySystemInformation枚举内核模块及简单应用
原文发表于百度空间,2008-10-24
==========================================================================
简单说,即调用第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信息等等,以后再玩~