Доброе время! Задача: определить ImageBase 64-битного процесса из 32-битного. Для решения я попытался использовать NtWow64ReadVirtualMemory64, но получил ошибку STATUS_PARTIAL_COPY. Исходя из дизасма 32-битной ntdll.dll (из папки Wow64), можно понять что два параметра являются 64-битными: Код (Text): .text:7DE8FE80 public ZwReadVirtualMemory .text:7DE8FE80 ZwReadVirtualMemory proc near ; CODE XREF: sub_7DEE31F9+28p .text:7DE8FE80 ; sub_7DF2F608+2C8p .text:7DE8FE80 .text:7DE8FE80 arg_0 = byte ptr 4 .text:7DE8FE80 .text:7DE8FE80 mov eax, 3Ch ; NtReadVirtualMemory .text:7DE8FE85 xor ecx, ecx .text:7DE8FE87 lea edx, [esp+arg_0] .text:7DE8FE8B call large dword ptr fs:0C0h .text:7DE8FE92 add esp, 4 .text:7DE8FE95 retn 14h .text:7DE920F4 public ZwWow64ReadVirtualMemory64 .text:7DE920F4 ZwWow64ReadVirtualMemory64 proc near .text:7DE920F4 .text:7DE920F4 arg_0 = byte ptr 4 .text:7DE920F4 .text:7DE920F4 mov eax, 1A0h ; NtWow64ReadVirtualMemory64 .text:7DE920F9 xor ecx, ecx .text:7DE920FB lea edx, [esp+arg_0] .text:7DE920FF call large dword ptr fs:0C0h .text:7DE92106 add esp, 4 .text:7DE92109 retn 1Ch .text:7DE92109 ZwWow64ReadVirtualMemory64 endp ; sp-analysis failed Прототип я определил так: Код (Text): typedef NTSTATUS (NTAPI *NTWOW64READVIRTUALMEMORY)( IN HANDLE ProcessHandle, IN ULONG64 BaseAddress, OUT ULONG64 Buffer, IN SIZE_T BufferLength, OUT PULONG ReturnLength OPTIONAL ); Исходя из того, что параметры BaseAddress & Buffer являются 64-битными. Методом исключения, т.к. ProcessHandle процесса в 32-битном коде явно 4 байта, а BufferLength и ReturnLength не имеет смысла делать 64-битными, так как 32-битное приложение не может иметь размер виртуальной памяти свыше 4ГБ. Итак, я написал примерно такой код: Код (Text): ULONG64 GetProcessBase (IN HANDLE hProcess, IN BOOL x64) { //#ifndef WIN64 PROCESS_BASIC_INFORMATION pbi; PEB peb; //#else //PROCESS_BASIC_INFORMATION64 pbi64; PEB64 peb64; //#endif NTSTATUS st; if (x64) { st = NtQueryInformationProcess (hProcess, ProcessBasicInformation, &pbi, sizeof (pbi), NULL); if (NT_SUCCESS(st)) { DebugWrite("pbi.PebBaseAddress == 0x%p", pbi.PebBaseAddress); #ifndef WIN64 NTWOW64READVIRTUALMEMORY lpNtWow64ReadVirtualMemory64 = (NTWOW64READVIRTUALMEMORY)_GetProcAddressThroughHash(GetNtdllBase(), 0x50968A4A); ULONG64 PebAddress = (ULONG64)pbi.PebBaseAddress; ULONG64 BufferAddress = (ULONG64)&peb64; ULONG RerurnLength; st = lpNtWow64ReadVirtualMemory64 (hProcess, PebAddress, BufferAddress, sizeof (peb64), &RerurnLength); #else st = NtReadVirtualMemory (hProcess, pbi.PebBaseAddress, &peb64, sizeof (peb64), NULL); #endif if (NT_SUCCESS(st)) { _WriteFile("C:\\pebdump.bin", (PBYTE)&peb64, sizeof(peb64), 0); return peb64.ImageBaseAddress; } } } else { st = NtQueryInformationProcess (hProcess, ProcessBasicInformation, &pbi, sizeof (pbi), NULL); if (NT_SUCCESS(st)) { DebugWrite("[ERROR] : pbi.PebBaseAddress == 0x%p", pbi.PebBaseAddress); st = NtReadVirtualMemory (hProcess, pbi.PebBaseAddress, &peb, sizeof (peb), NULL); if (NT_SUCCESS(st)) { _WriteFile("C:\\pebdump.bin", (PBYTE)&peb, sizeof(peb), 0); return (ULONG64)peb.ImageBaseAddress; } } } return NULL; } Но чёто lpNtWow64ReadVirtualMemory64 возвращает STATUS_PARTIAL_COPY, а RerurnLength == 0. PEB64 описывал так: http://www.everfall.com/paste/id.php?bh8ptyyc3sow Не могу понять что-то почему не работает данный код. Как приблизиться к решению в данном случае? Нужно брать ядерный отладчик и смотреть что не так с сервисом NtWow64ReadVirtualMemory64 ?
Хотя если PEB (именно PEB, а не PEB64) читать просто через NtReadVirtualMemory по тому же адресу, то ImageBase будет равен 0x40000000. Притом что оригинальный ImageBase вроде как равен 0x0000000140000000, это видно из PE-заголовка. Ничего похожего на адрес ImageBase в дампе нет: Почему?
Хотя вот сейчас попытался прочитать что-нибудь из точки входа: Код (Text): NTWOW64READVIRTUALMEMORY lpNtWow64ReadVirtualMemory64 = (NTWOW64READVIRTUALMEMORY)_GetProcAddressThroughHash(GetNtdllBase(), 0x50968A4A); ULONG64 SrcAddress = (ULONG64)0x0000000140000000; BYTE smth[0x1000]; ULONG64 BufferAddress = (ULONG64)smth; ULONG RerurnLength; st = lpNtWow64ReadVirtualMemory64 (hProcess, SrcAddress, BufferAddress, sizeof (smth), &RerurnLength); И нифига. STATUS_ACCESS_VIOLATION Вообще, надо добавить что все эти операции я совершаю до вызова NtResumeThread. И что тогда всё это значит? Процесс ещё не "проинициализирован"? Загрузчик Windows не промапил секции PE-файла в память? Как быть?
А. Ну вроде понятно. http://drdobbs.com/high-performance-computing/184401966 То есть надо использовать ntdll!NtWow64QueryInformationProcess64() просто. В этом случае адрес PEB'а получается 0x000007fffffda000. Однако что-то не могу заставить NtWow64ReadVirtualMemory64 читать по этому адресу.
Хз. NtWow64ReadVirtualMemory64 возвращает STATUS_INFO_LENGTH_MISMATCH ( если destination-буфер сделать бОльшим, то будет возвращать STATUS_ACCESS_VIOLATION ). Причём процесс инициализирован, память по адресу, откуда я пытаюсь читать выделена и права соответствуют:
Всё. Разобрался. Оказывается прототип должен быть такой: Код (Text): typedef NTSTATUS (NTAPI *NTWOW64READVIRTUALMEMORY)( IN HANDLE ProcessHandle, IN ULONG64 BaseAddress, OUT PVOID Buffer, IN ULONG64 BufferLength, OUT PULONG ReturnLength OPTIONAL );
по поводу прототипа если параметр ULONG64 BufferLength - 64 то логично предположить что PULONG ReturnLength должно быть тоже 64 - PULONG_PTR ReturnLength Еще насколько я знаю в windows xp 64 нету NtWow64 функций.