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.
GetLastError()
is called right afterVirtualProtect
– Odontoblast