I'm analyzing various modules loaded by the process. Unfortunately I'm not able to create the kernel32.dll
memory snapshot although the function works properly with other modules (e.g. ntddl.dll
). The problem is with the following code:
/* Copy code from memory */
if (VirtualProtect((BYTE*)virtualAddress, sizeOfCode, PAGE_EXECUTE_READWRITE, &flags) == 0) {
std::cout << "VirtualProtect failed!" << std::endl;
std::cout << "Virtual address: " << virtualAddress << std::endl;
std::cout << "Size of code: " << sizeOfCode << std::endl;
std::cout << "Error code: " << GetLastError() << std::endl;
}
The result of calling this code for kernel32.dll
is:
Virtual address: 747d0000
Size of code: 6a000
Error code: 0x1e7
The error description says that:
ERROR_INVALID_ADDRESS
487 (0x1E7)
Attempt to access invalid address.
I checked the process' memory map and kernel32.dll address is correct. What's the cause?
Pretty hard to verify that you got the address correct, it is unusually low. I just wrote another program to test this. It enumerates the regions in kernel32.dll and calls VirtualProtect() on them:
#include <Windows.h>
#include <assert.h>
#include <iostream>
int main()
{
HMODULE hmod = GetModuleHandle(L"kernel32.dll");
MEMORY_BASIC_INFORMATION info;
// Start at PE32 header
SIZE_T len = VirtualQuery(hmod, &info, sizeof(info));
assert(len > 0);
BYTE* dllBase = (BYTE*)info.AllocationBase;
BYTE* address = dllBase;
for (;;) {
len = VirtualQuery(address, &info, sizeof(info));
assert(len > 0);
if (info.AllocationBase != dllBase) break;
std::cout << "Address: " << std::hex << info.BaseAddress;
std::cout << " (" << std::hex << info.RegionSize << ") ";
std::cout << " protect = " << std::hex << info.Protect;
DWORD oldprotect;
if (info.Protect == 0) std::cout << ", VirtualProtect skipped" << std::endl;
else {
BOOL ok = VirtualProtect(info.BaseAddress, info.RegionSize, PAGE_EXECUTE_READWRITE, &oldprotect);
std::cout << ", VirtualProtect = " << (ok ? "okay" : "Failed!") << std::endl;
}
address = (BYTE*)info.BaseAddress + info.RegionSize;
}
return 0;
}
Output of this program on my machine, running Windows 8.1 x64:
Address: 77470000 (1000) protect = 2, VirtualProtect = okay
Address: 77471000 (f000) protect = 0, VirtualProtect skipped
Address: 77480000 (62000) protect = 20, VirtualProtect = okay
Address: 774E2000 (e000) protect = 0, VirtualProtect skipped
Address: 774F0000 (7e000) protect = 2, VirtualProtect = okay
Address: 7756E000 (2000) protect = 0, VirtualProtect skipped
Address: 77570000 (1000) protect = 4, VirtualProtect = okay
Address: 77571000 (f000) protect = 0, VirtualProtect skipped
Address: 77580000 (1000) protect = 2, VirtualProtect = okay
Address: 77581000 (f000) protect = 0, VirtualProtect skipped
Address: 77590000 (1a000) protect = 2, VirtualProtect = okay
Address: 775AA000 (6000) protect = 0, VirtualProtect skipped
Running it in 64-bit mode:
Address: 00007FFC4F870000 (1000) protect = 2, VirtualProtect = okay
Address: 00007FFC4F871000 (112000) protect = 20, VirtualProtect = okay
Address: 00007FFC4F983000 (1000) protect = 4, VirtualProtect = okay
Address: 00007FFC4F984000 (1000) protect = 8, VirtualProtect = okay
Address: 00007FFC4F985000 (24000) protect = 2, VirtualProtect = okay
Clearly you have a different Windows version so be sure to run this program on your machine to get comparable results.
The conclusion I draw is there is no fundamental reason for this kind of code to fail. And if it does on your machine then that's likely to be environmental. With a very obvious candidate to be your anti-malware software, which of course has a great stake in preventing code from messing with kernel32.dll. I'm running minimal protection on my machine.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With