最近看到一篇文章介绍IAT HOOK实现,用ImageDirectoryEntryToData函数直接获取IID表,然后一顿操作。我当时对下面这个函数比较困惑。
pImportDescript = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(hModuleToRead, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize);
函数原型:
PVOID WINAPI ImageDirectoryEntryToData(_In_ PVOID Base,_In_ BOOLEAN MappedAsImage,_In_ USHORT DirectoryEntry,_Out_ PULONG Size);
hModuleToRead是要HOOK模块的基址,但是文章里并没有讲如何获取基址。大概有以下几种办法获取到模块基址:
1.hModuleToRead
2.定位远程进程的PEB
DWORD FindRemotePEB(HANDLE hProcess){ HMODULE hNTDLL = LoadLibraryA("ntdll"); if (!hNTDLL) return 0; FARPROC fpNtQueryInformationProcess = GetProcAddress ( hNTDLL, "NtQueryInformationProcess" ); if (!fpNtQueryInformationProcess) return 0; NtQueryInformationProcess ntQueryInformationProcess = (NtQueryInformationProcess)fpNtQueryInformationProcess; PROCESS_BASIC_INFORMATION* pBasicInfo = new PROCESS_BASIC_INFORMATION(); DWORD dwReturnLength = 0; ntQueryInformationProcess ( hProcess, 0, pBasicInfo, sizeof(PROCESS_BASIC_INFORMATION), &dwReturnLength ); return pBasicInfo->PebBaseAddress;}
3.EnumProcessModulesEx可以枚举出远程进程所有的模块信息。我下面用的就是这个方法。
为了搞清楚我打算写个程序打印出远程进程的INT表,就不HOOK了。代码如下:
DWORD dwPID = 0; HWND hd = ::FindWindow(NULL, L"Zenmap"); printf("正在打开窗口句柄\n"); ::GetWindowThreadProcessId(hd,&dwPID); HANDLE hPID = ::OpenProcess(PROCESS_ALL_ACCESS, false, dwPID); printf("dwPID=%d,hPID=%d\n", dwPID, hPID); //开始打印所有模块基址 DWORD pro_base = NULL; HMODULE hModule[100] = { 0 }; DWORD dwRet = 0; int num = 0; int bRet = EnumProcessModulesEx(hPID, (HMODULE *)(hModule), sizeof(hModule), &dwRet, NULL); if (bRet == 0) { printf("EnumProcessModules");} // 总模块个数 num = dwRet / sizeof(HMODULE); //printf("总模块个数: %d\n", num); 打印每一个模块加载基址 //char lpBaseName[100]; //for (int i = 0; i < num; i++) { //GetModuleBaseNameA(hPID, hModule[i], lpBaseName, sizeof(lpBaseName)); //printf("%-2d %-25s基址: 0x%p\n", i, lpBaseName, hModule[i]); //} pro_base = (DWORD)hModule[0];//Zenmap.exe的基址 ULONG ulSize; PIMAGE_IMPORT_DESCRIPTOR pImportDescript; PIMAGE_THUNK_DATA pThunkData; PIMAGE_IMPORT_BY_NAME pImportByName; char *sMoldeName; pImportDescript = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(hModuleToRead, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize); while (pImportDescript->OriginalFirstThunk){ sMoldeName = (char *)((PBYTE)hModuleToRead + pImportDescript->Name); printf("模块名为:%s\n", sMoldeName); pThunkData = (PIMAGE_THUNK_DATA)((BYTE *)hModuleToRead + pImportDescript->OriginalFirstThunk); while (pThunkData->u1.AddressOfData) { pImportByName = (PIMAGE_IMPORT_BY_NAME)((BYTE *)hModuleToRead + pThunkData->u1.AddressOfData); printf("导入函数,HIT:%d,NAME:%s\n", pImportByName->Hint, pImportByName->Name); pThunkData++; } pImportDescript++;}
大家可能一眼就看出问题来了,Zenmap.exe是远程进程,而ImageDirectoryEntryToData读取的是本地进程的IID。要如何拿到远程进程的INT(IAT)表信息呢,我没有找到现成的函数,只能用ReadProcessMemory一点点地把IID找出来。思路如下:
1.通过进程名找到窗口句柄
HWND hd = ::FindWindow(NULL, L"Zenmap");
2.通过窗口句柄找到进程id
::GetWindowThreadProcessId(hd,&dwPID);
3.通过进程id获得进程句柄
HANDLE hPID = ::OpenProcess(PROCESS_ALL_ACCESS, false, dwPID);
4.拿到各模块基址:
int bRet = EnumProcessModulesEx(hPID, (HMODULE *)(hModule), sizeof(hModule), &dwRet, NULL);
5.读取ImageDosHeader
::ReadProcessMemory(hPID,hModule[0],&ImageDosHeader,sizeof(IMAGE_DOS_HEADER),&dwRead);
6.读取ImageOptionalHeader
IMAGE_OPTIONAL_HEADER ImageOptionalHeader = {}; IMAGE_NT_HEADERS ImageNTHeader = {}; LPCVOID ImageOptionalHeader_addr = (BYTE *)hModule[0] + ImageDosHeader.e_lfanew + sizeof(ImageNTHeader.Signature) + sizeof(ImageNTHeader.FileHeader); ::ReadProcessMemory(hPID, ImageOptionalHeader_addr, &ImageOptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dwRead);
7.读取IID,ThunkData,OriginalFirstThunk等。
效果图:
完整代码:
{ DWORD dwPID = 0; HWND hd = ::FindWindow(NULL, L"Zenmap"); printf("正在打开窗口句柄\n"); ::GetWindowThreadProcessId(hd,&dwPID); HANDLE hPID = ::OpenProcess(PROCESS_ALL_ACCESS, false, dwPID); printf("dwPID=%d,hPID=%d\n", dwPID, hPID); //开始打印所有模块基址 DWORD pro_base = NULL; HMODULE hModule[100] = { 0 }; DWORD dwRet = 0; int num = 0; int bRet = EnumProcessModulesEx(hPID, (HMODULE *)(hModule), sizeof(hModule), &dwRet, NULL); if (bRet == 0) { printf("EnumProcessModules");} // 总模块个数 num = dwRet / sizeof(HMODULE); //printf("总模块个数: %d\n", num); 打印每一个模块加载基址 //char lpBaseName[100]; //for (int i = 0; i < num; i++) { //GetModuleBaseNameA(hPID, hModule[i], lpBaseName, sizeof(lpBaseName)); //printf("%-2d %-25s基址: 0x%p\n", i, lpBaseName, hModule[i]); //} pro_base = (DWORD)hModule[0]; IMAGE_DOS_HEADER ImageDosHeader = {}; DWORD dwRead = 0; ::ReadProcessMemory(hPID,hModule[0],&ImageDosHeader,sizeof(IMAGE_DOS_HEADER),&dwRead); printf("MZ:%p\n",ImageDosHeader.e_magic); printf("DOS_HEADER_OFFSET:0x%p\n", ImageDosHeader.e_lfanew); IMAGE_OPTIONAL_HEADER ImageOptionalHeader = {}; IMAGE_NT_HEADERS ImageNTHeader = {}; LPCVOID ImageOptionalHeader_addr = (BYTE *)hModule[0] + ImageDosHeader.e_lfanew + sizeof(ImageNTHeader.Signature) + sizeof(ImageNTHeader.FileHeader); ::ReadProcessMemory(hPID, ImageOptionalHeader_addr, &ImageOptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dwRead); printf("IID:%p\n", ImageOptionalHeader.DataDirectory[1]); IMAGE_IMPORT_DESCRIPTOR ImageImportDirectory = {}; PIMAGE_IMPORT_DESCRIPTOR ImageImportDirectory_addr = (PIMAGE_IMPORT_DESCRIPTOR)((BYTE *)hModule[0] + ImageOptionalHeader.DataDirectory[1].VirtualAddress); ::ReadProcessMemory(hPID, ImageImportDirectory_addr,&ImageImportDirectory,sizeof(IMAGE_IMPORT_DESCRIPTOR),&dwRead); PIMAGE_IMPORT_DESCRIPTOR pImportDescript; PIMAGE_THUNK_DATA pThunkData_addr; IMAGE_THUNK_DATA ThunkData; PIMAGE_IMPORT_BY_NAME pImportByName_addr; PIMAGE_IMPORT_BY_NAME ImportByName = {}; char sMoldeName[30] = {}; int a = 1; while (ImageImportDirectory.FirstThunk){ LPCVOID sMoldeName_addr = (BYTE *)hModule[0] + ImageImportDirectory.Name; ::ReadProcessMemory(hPID, sMoldeName_addr, sMoldeName, 29, &dwRead); printf("导入模块%d,名为:%s\n",a++, sMoldeName); pThunkData_addr = (PIMAGE_THUNK_DATA)((BYTE *)hModule[0] + ImageImportDirectory.OriginalFirstThunk); ::ReadProcessMemory(hPID, pThunkData_addr, &ThunkData, sizeof(IMAGE_THUNK_DATA), &dwRead); int i = 1; while (ThunkData.u1.AddressOfData) { pImportByName_addr = (PIMAGE_IMPORT_BY_NAME)((BYTE *)hModule[0] + ThunkData.u1.AddressOfData); void *p = malloc(15); ::ReadProcessMemory(hPID, pImportByName_addr, p, 15, &dwRead); //int HIT = ((int)*p); ImportByName = (PIMAGE_IMPORT_BY_NAME)p; printf("导入函数%d,HIT:%d,NAME:%s\n", i++, ImportByName->Hint,ImportByName->Name); ::ReadProcessMemory(hPID, ++pThunkData_addr, &ThunkData, sizeof(IMAGE_THUNK_DATA), &dwRead); } ::ReadProcessMemory(hPID, ++ImageImportDirectory_addr, &ImageImportDirectory, sizeof(IMAGE_IMPORT_DESCRIPTOR), &dwRead);}}