Что не так с моим использованием ReadProcessMemory? - PullRequest
0 голосов
/ 03 мая 2018

У меня есть два процесса, A и B.
A загружает DLL с кодом, который считывает некоторые области памяти, в то время как B пытается прочитать те же области памяти в памяти A, используя ReadProcessMemory.

Я получаю те же значения, пока в какой-то момент не получу, что весьма озадачивает. Я что-то упустил, но я не знаю что. Я надеюсь, вы поможете мне найти его.

(В обоих кодах процессов IMPORT_TABLE_OFFSET - это 1, а processBaseAdress - начальный адрес заголовка MZ A в памяти процесса).

Код DLL

A:

printf("processBaseAddress: %p\n", processBaseAddress);
PIMAGE_DOS_HEADER dosHeaderP = processBaseAddress;
printf("ntHeaderP = %p\n", (PBYTE)dosHeaderP + dosHeaderP->e_lfanew);
PIMAGE_NT_HEADERS ntHeader = ((PBYTE)dosHeaderP + dosHeaderP->e_lfanew);
printf("optHeaderP = %p\n", &ntHeader->OptionalHeader);
IMAGE_OPTIONAL_HEADER optionalHeader = (ntHeader->OptionalHeader);
printf("oh.aoep = %p\n", optionalHeader.AddressOfEntryPoint);
printf("oh.cs = %x\n", optionalHeader.CheckSum);
printf("DataDirectory: %p\n", optionalHeader.DataDirectory);
IMAGE_DATA_DIRECTORY dataDirectory = (optionalHeader.DataDirectory[IMPORT_TABLE_OFFSET]);

код B: (hHandle - это ручка к A)

#define VERIFY_RPM(CALL_ID, RPM_CALL) {
    if(RPM_CALL==0){
        printf("Error! ReadProcessMemory(): %d. Call id: %d.\n",GetLastError(),CALL_ID);
        exit(1);
    }
}
SIZE_T bytesRead;
printf("processBaseAddress: %p\n", processBaseAddress);
VERIFY_RPM(0, ReadProcessMemory(hProcess, processBaseAddress, &dosHeader, sizeof(dosHeader), &bytesRead));
PIMAGE_NT_HEADERS ntHeaderP = processBaseAddress + dosHeader.e_lfanew;
printf("ntHeaderP = %p\n", ntHeaderP);
VERIFY_RPM(1, ReadProcessMemory(hProcess, ntHeaderP, &ntHeader, sizeof(ntHeader), &bytesRead));
IMAGE_OPTIONAL_HEADER optionalHeader = ntHeader.OptionalHeader;
printf("oh.aoep = %p\n", optionalHeader.AddressOfEntryPoint);
printf("oh.cs = %x\n", optionalHeader.CheckSum);
printf("DataDirectory: %p\n", optionalHeader.DataDirectory);
VERIFY_RPM(2, ReadProcessMemory(hProcess, optionalHeader.DataDirectory + IMPORT_TABLE_OFFSET, &dataDirectory, sizeof(dataDirectory), &bytesRead));

Выход A:

processBaseAddress: 1C530000
ntHeaderP = 1C5300F0
optHeaderP = 1C530108
oh.aoep = 00001327
oh.cs = d6c7
DataDirectory: 0322F8E8

B вывод:

processBaseAddress: 1C530000
ntHeaderP = 1C5300F0
oh.aoep = 00001327
oh.cs = d6c7
DataDirectory: 001AEE3C
Error! ReadProcessMemory(): 299. Call id: 2.

Это все то же самое, пока DataDirectory.

1 Ответ

0 голосов
/ 03 мая 2018

ошибка (по смыслу) следующая строка:

IMAGE_OPTIONAL_HEADER optionalHeader = (ntHeader->OptionalHeader);

с этим вы делаете копию из IMAGE_OPTIONAL_HEADER. как результат:

optionalHeader.DataDirectory

- это адрес внутри этой копии, но не внутри оригинала IMAGE_OPTIONAL_HEADER внутри изображения. вам нужно использовать

PIMAGE_OPTIONAL_HEADER poptionalHeader = &ntHeader->OptionalHeader;
PIMAGE_DATA_DIRECTORY dataDirectory = 
    &poptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];

и строка

ReadProcessMemory(hProcess, optionalHeader.DataDirectory + ..))

конечно ошибка, потому что optionalHeader.DataDirectory - адрес внутри локальной копии - не имеет смысла в удаленном процессе. и DataDirectory является частью IMAGE_NT_HEADERS - после прочтения - вам не нужно отдельное чтение для DataDirectory - у вас уже есть эти данные внутри ntHeader

также нужно понимать, что IMAGE_NT_HEADERS - это макросы, расширенные до IMAGE_NT_HEADERS32 или IMAGE_NT_HEADERS64 в зависимости от разрядности вашего кода. но когда вы читаете другое изображение - оно может иметь другую битность. поэтому вам всегда нужно проверять Magic член IMAGE_OPTIONAL_HEADER для определения - используйте 32- или 64-битную структуру.

правильный код для чтения этого пульта может выглядеть так:

union {
    IMAGE_DOS_HEADER dosHeader;
    IMAGE_NT_HEADERS ntHeader;
    IMAGE_NT_HEADERS32 ntHeader32;
    IMAGE_NT_HEADERS64 ntHeader64;
};

if (ReadProcessMemory(hProcess, ImageBase, &dosHeader, sizeof(dosHeader), 0) &&
    dosHeader.e_magic == IMAGE_DOS_SIGNATURE)
{
    if (ReadProcessMemory(hProcess, (PBYTE)ImageBase + dosHeader.e_lfanew, 
        &ntHeader64, sizeof(ntHeader64), 0) &&
        ntHeader.Signature == IMAGE_NT_SIGNATURE)
    {
        PIMAGE_DATA_DIRECTORY dataDirectory = 0;

        switch (ntHeader.OptionalHeader.Magic)
        {
        case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
            dataDirectory = ntHeader32.OptionalHeader.DataDirectory;
            break;
        case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
            dataDirectory = ntHeader64.OptionalHeader.DataDirectory;
            break;
        }

        if (dataDirectory)
        {
            PIMAGE_DATA_DIRECTORY ImpDataDirectory = &dataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
            DbgPrint("[%x, %x]\n", ImpDataDirectory->Size, ImpDataDirectory->VirtualAddress);
        }
    }
}
...