То есть ReadProcessMemory
с auto address = process_base_address + import_desc.FirstThunk
работает для вас, но не работает с process_base_address + import_desc.FirstThunk
напрямую, я рекомендую использовать (PBYTE)
Conversion.
Согласно вашему описанию sizeof (IMAGE_THUNK_DATA ) = 8, я предполагаю, что вы используете версию x64.
typedef struct _IMAGE_THUNK_DATA64 {
union {
ULONGLONG ForwarderString; // PBYTE
ULONGLONG Function; // PDWORD
ULONGLONG Ordinal;
ULONGLONG AddressOfData; // PIMAGE_IMPORT_BY_NAME
} u1;
} IMAGE_THUNK_DATA64;
typedef IMAGE_THUNK_DATA64 * PIMAGE_THUNK_DATA64;
Когда максимальное значение IMAGE_THUNK_DATA
равно 1, это означает, что функция импортируется в виде серийного номера, в противном случае функция импортируется в форме имени функции, и это RVA, указывающий на структуру IMAGE_IMPORT_BY_NAME
. Мы можем использовать константу IMAGE_ORDINAL_FLAG
, чтобы проверить, равен ли самый старший бит 1.
Для меня работает следующий пример:
#include <Windows.h>
#include <iostream>
#include <psapi.h>
#pragma warning(disable : 4996)
using namespace std;
void main()
{
int i;
HMODULE hModule;
DWORD dwOffset, cbneeded;
SIZE_T dwRet;
DWORD dwPid = 8752; // PID of process to be hooked
TCHAR szModName[MAX_PATH];
TCHAR szHookModName[MAX_PATH] = { "user32.dll" };
TCHAR szFuncName[MAX_PATH] = { "MessageBoxA" };
IMAGE_DOS_HEADER DOSHeader;
IMAGE_OPTIONAL_HEADER OptionalHeader;
IMAGE_DATA_DIRECTORY DataDirectory;
IMAGE_IMPORT_DESCRIPTOR ImportDesc;
IMAGE_THUNK_DATA OrigThunkData;
IMAGE_THUNK_DATA RealThunkData;
PIMAGE_IMPORT_BY_NAME pImportByName = (PIMAGE_IMPORT_BY_NAME)malloc(255); //function name length;
MEMORY_BASIC_INFORMATION mbi;
LPVOID lpBaseAddress;
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, dwPid);
if (hProcess == NULL)
{
printf("Fail to open process!\n");
return;
}
if (!EnumProcessModules(hProcess, &hModule, sizeof(hModule), &cbneeded))
{
printf("Fail to enum process modules!\n");
return;
}
if (!ReadProcessMemory(hProcess, hModule, (void*)&DOSHeader, sizeof(IMAGE_DOS_HEADER), &dwRet))
{
printf("Fail to read memory in remote process!\n");
return;
}
dwOffset = DOSHeader.e_lfanew + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER);
if (!ReadProcessMemory(hProcess, (PBYTE)hModule + dwOffset, (void*)&OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dwRet))
{
printf("Fail to read memory in remote process!\n");
return;
}
DataDirectory = OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
i = 0;
do
{
dwOffset = DataDirectory.VirtualAddress + sizeof(IMAGE_IMPORT_DESCRIPTOR) * i;
if (!ReadProcessMemory(hProcess, (PBYTE)hModule + dwOffset, (void*)&ImportDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR), &dwRet))
{
printf("Fail to read memory in remote process!\n");
return;
}
if (!ReadProcessMemory(hProcess, (PBYTE)hModule + ImportDesc.Name, (void*)szModName, MAX_PATH, &dwRet))
{
printf("Fail to read memory in remote process!\n");
return;
}
if (stricmp(szModName, szHookModName) == 0)
break;
i++;
} while (ImportDesc.Name);
i = 0;
do
{
lpBaseAddress = (PBYTE)hModule + ImportDesc.OriginalFirstThunk + sizeof(IMAGE_THUNK_DATA) * i;
if (!ReadProcessMemory(hProcess, lpBaseAddress, (void*)&OrigThunkData, sizeof(IMAGE_THUNK_DATA), &dwRet))
{
printf("Fail to read memory in remote process!\n");
return;
}
if (!ReadProcessMemory(hProcess, (PBYTE)hModule + ImportDesc.FirstThunk + sizeof(IMAGE_THUNK_DATA) * i, (void*)&RealThunkData, sizeof(IMAGE_THUNK_DATA), &dwRet))
{
printf("Fail to read memory in remote process!\n");
return;
}
std::cout << "Function address :" << std::hex << "0x" << RealThunkData.u1.Function << '\n';
lpBaseAddress = (PBYTE)hModule + ImportDesc.FirstThunk + sizeof(IMAGE_THUNK_DATA) * i;
if (!ReadProcessMemory(hProcess, lpBaseAddress, (void*)&RealThunkData, sizeof(IMAGE_THUNK_DATA), &dwRet))
{
printf("Fail to read memory in remote process!\n");
return;
}
std::cout << "Function address :" << std::hex << "0x" << RealThunkData.u1.Function << '\n';
if ((OrigThunkData.u1.Ordinal & IMAGE_ORDINAL_FLAG) != IMAGE_ORDINAL_FLAG)
{
if (!ReadProcessMemory(hProcess, (PBYTE)hModule + OrigThunkData.u1.AddressOfData, (void*)pImportByName, sizeof(WORD) + strlen(szFuncName) + 1, &dwRet))
{
if (GetLastError() == ERROR_PARTIAL_COPY)
{
i++;
continue;
}
else
{
printf("Fail to read memory in remote process!\n");
return;
}
}
if (pImportByName->Name[0] == '\0')
{
printf("Function not located!\n");
break;
}
if (strcmpi((char*)pImportByName->Name, szFuncName) == 0)
{
printf("Function: %s \n ", pImportByName->Name);
break;
}
}
i++;
} while (OrigThunkData.u1.Function);
free(pImportByName);
}
Следует отметить, что содержимое, на которое указывает OriginalFirstThunk
и FirstThunk
в PE-файле точно такие же, но при загрузке файла в память появляется разница: содержимое OriginalFirstThunk
не изменится, но данные в FirstThunk
изменятся на адрес записи функции.
целевой процесс:
#include <windows.h>
#include <iostream>
int main()
{
printf("child\n");
VOID *p = (VOID*)MessageBoxA;
MessageBoxA(NULL,"TEST","TEST",0);
getchar();
return 0;
}
Результат:
введите описание изображения здесь