您的位置:首页 > 产品设计 > UI/UE

(转)ZwQuerySystemInformation枚举内核模块及简单应用

2015-11-10 14:21 573 查看
http://hi.baidu.com/_achillis/item/8b33ead8ccac28ea3cc2cb17

简单说,即调用第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信息等等,以后再玩~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: