【旧文章搬运】暴搜内存查找PE镜像

原文发表于百度空间,2008-7-28
==========================================================================

前面介绍了修改PEB中已加载模块的双链,来隐藏指定的模块.
不过要对付这样隐藏,一个暴力搜索内存就够了.

实现思路如下:
地址以一个页的大小为单位从0x00000000到0x7FFFFFFF遍历,检查是否具有PE特征.
页的大小可以通过GetSystemInfo()得到,结果在SYSTEM_INFO结构的DWORD dwPageSize一项中,通常是0x1000.遍历时,并不是所有地址都是可以访问的,我们还需要先得到该地址是否可以访问的信息,否则将会引发内存访问错误.获取该信息可以使用函数VirturlQuery(),在得到的MEMORY_BASIC_INFORMATION结构中有足够多的信息.
    MEMORY_BASIC_INFORMATION在WinNT.h中定义如下:

typedef struct _MEMORY_BASIC_INFORMATION {
          PVOID BaseAddress;       // 区域基地址。
            PVOID AllocationBase;    // 分配基地址。
            DWORD AllocationProtect; // 区域被初次保留时赋予的保护属性。
            SIZE_T RegionSize;       // 区域大小(以字节为计量单位)。
            DWORD State;             // 状态(MEM_FREE、MEM_RESERVE或 MEM_COMMIT)。
            DWORD Protect;           // 保护属性。
            DWORD Type;              // 类型。
        } MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;

其中的State指明了该地址所在页的状态,分为MEM_FREE,MEM_COMMIT和MEM_RESERVE三种情况.
仅当页状态为MEM_COMMIT时才可以访问,否则将引发访问错误.
然后就可以检验是否是PE文件了,这个通常检查MZ头和PE头即可.

实现代码如下:

void SearchMemoryForPE(void)
{
IMAGE_DOS_HEADER *dhead;
MEMORY_BASIC_INFORMATION mbi;
DWORD StartAddr=0;
for (;StartAddr<0x7FFF0000;StartAddr+=dwpagesize)
{
   VirtualQuery((PVOID)StartAddr,&mbi,sizeof(MEMORY_BASIC_INFORMATION));
   if (mbi.State==MEM_COMMIT)
   {
    if ((*(char*)StartAddr=='M')&&(*((char*)StartAddr+1)=='Z'))
    {
     dhead=(IMAGE_DOS_HEADER*)StartAddr;
     if (!lstrcmp((char*)dhead+dhead->e_lfanew,"PE"))
     {
      printf("Found PE at 0x%08x!\n",StartAddr);
     }
    
    }
   }
}
}

对付内核中的隐藏驱动也可以使用类似的方法,关键只在于验证地址是否可以访问.
不过对付这种暴力搜索,只需要抹去相应的特征,使检测者无法匹配即可~
附本例结果:

posted @ 2018-12-26 16:27  黑月教主  阅读(492)  评论(0编辑  收藏  举报