|
另一种枚举进程模块的方法
在ntdll里有一张表,叫作LdrpHashTable,这张hash表中保存了进程已经的模块列表,函数GetModuleHandle就是通过查找这张句返回模块句柄的。
这张hash表也指向LDR_DATA_TABLE_ENTRY,作为HashLinks字段:
typedef struct _LDR_DATA_TABLE_ENTRY
{
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
union
{
LIST_ENTRY HashLinks;
struct
{
PVOID SectionPointer;
ULONG CheckSum;
};
};
union
{
ULONG TimeDateStamp;
PVOID LoadedImports;
};
PVOID EntryPointActivationContext;
PVOID PatchInformation;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
当然这张表的内容也可以被抹掉,但是那个模块就不能使用函数GetModuleHandle了。此方法对直接Map Dll dump文件的方法无效。另外使用此方法在定位表时可能需要一些特征搜索,硬编码啊。。。。
关键代码:
//LdrpHashTable
LIST_ENTRY *GetHashTableAddress()
{
HANDLE hModule=GetModuleHandle("ntdll.dll");
BYTE *p=NULL;
LIST_ENTRY *retval;
CONST BYTE *pSign=NULL;
DWORD SignLen;
DWORD dwVersion,dwMajorVersion,dwMinorVersion;
dwVersion=GetVersion();
dwMajorVersion= LOBYTE(LOWORD(dwVersion));
dwMinorVersion= HIBYTE(LOWORD(dwVersion));
if(dwMajorVersion==5 && dwMinorVersion==0)//2k
{
pSign=(CONST BYTE *)"\x89\x01\x89\x56\x40\x89\x0a\x89\x48\x04\x8b\x4f\x10\x8d\x47\x0c";
SignLen=16;
}
else if(dwMajorVersion==5 && dwMinorVersion==1)//xp
{
pSign=(CONST BYTE *)"\x8B\x48\x04\x89\x07\x89\x4F\x04\x89\x39\x89";
SignLen=11;
}
else if(dwMajorVersion==6 && dwMinorVersion==0)//vista
{
pSign=(CONST BYTE *)"\x89\x45\x88\x8b\x18\x3b\xd8";
SignLen=7;
}
else
{
printf("不支持的系统");
return NULL;
}
//__asm{int 3}
__try
{
for(DWORD i=0;i<0x70***00;i++)
{
if(memcmp((BYTE *)hModule+i,pSign,SignLen)==0)
{
p=(BYTE *)hModule+i-4;
retval=(LIST_ENTRY *)(*(DWORD *)p);
if((ULONG)retval>(ULONG)hModule && (ULONG)retval<0x800****0000)
break;
else
retval=NULL;
}
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{}
return retval;
}
void PrintDll(HANDLE hProcess,LIST_ENTRY *LdrpHashTable)
{
LIST_ENTRY *LdrpHashTableTemp=NULL,*pListEntry,*pListHead;
UNICODE_STRING *pDllFullPath;
void *pTemp;
DWORD size;
LDR_DATA_TABLE_ENTRY LdrDataEntry;
size=sizeof(LIST_ENTRY)*32;
pTemp=malloc(size);
//读Hash表
if(!ReadProcessMemory(hProcess,LdrpHashTable,pTemp,size,&size))
goto END;
LdrpHashTableTemp=(LIST_ENTRY *)pTemp;
for(DWORD i=0;i<32;i++)
{
pListEntry=LdrpHashTableTemp+i;
pListEntry=pListEntry->Flink;
pListHead=LdrpHashTable+i;
while(pListEntry!=pListHead)
{
size=sizeof(LIST_ENTRY);
pTemp=malloc(size);
if(!ReadProcessMemory(hProcess,(BYTE *)pListEntry -0x3c,&LdrDataEntry,sizeof(LdrDataEntry),&size))
goto END;
//读模块路径保存在pTemp中
pDllFullPath=&LdrDataEntry.FullDllName;
pTemp=malloc(pDllFullPath->MaximumLength);
memset(pTemp,0,pDllFullPath->MaximumLength);
if(!ReadProcessMemory(hProcess,pDllFullPath->Buffer,pTemp,pDllFullPath->Length,&size))
goto END;
wprintf(L"%ws \n",pTemp);
free(pTemp);
pListEntry=LdrDataEntry.HashLinks.Flink;
}
}
END:
if(!LdrpHashTableTemp)
free(LdrpHashTableTemp);
}
int _tmain(int argc, _TCHAR* argv[])
{
LIST_ENTRY *LdrpHashTable;
HANDLE hProcess;
DWORD Pid;
LdrpHashTable=GetHashTableAddress();
if(!LdrpHashTable)
{
printf("找不到Hash表");
getchar();
return 0;
}
printf("输入进程ID:");
scanf("%d",&Pid);
hProcess=OpenProcess(PROCESS_VM_READ,FALSE,Pid);
if(hProcess==NULL)
{
printf("打开进程出错");
getchar();
return 0;
}
PrintDll(hProcess,LdrpHashTable);
return 0;
} |
|