NtAllocateVirtualMemory调用失败,错误码0xC0000005技术求助
解决NtAllocateVirtualMemory触发0xC0000005错误的问题
错误原因分析
- 类型不匹配导致内存大小错误:NtAllocateVirtualMemory的
RegionSize参数实际要求是PULONG_PTR(32位系统对应ULONG,64位系统对应ULONG_PTR),你使用unsigned int类型的buffer_len强制转换为PULONG,在64位系统下会造成参数截断,导致分配的内存大小不符合预期,后续访问时触发访问违规。 - 内存执行权限问题:分配内存时使用
PAGE_READWRITE权限,然后直接创建线程执行该内存区域,现代Windows的DEP(数据执行保护)会拦截这种无执行权限的内存执行操作,触发访问违规。
修复方案
- 修正参数类型:将
buffer_len的类型改为ULONG_PTR,确保在32/64位系统下都能正确传递内存大小参数。 - 调整内存权限:分配内存时直接使用
PAGE_EXECUTE_READWRITE权限,或者分配后调用NtProtectVirtualMemory修改权限为可执行。 - 修正函数指针定义:确保
NtAllocateVirtualMemory的RegionSize参数类型为PULONG_PTR,避免类型不匹配问题。
修正后的代码
#include <Windows.h> #define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) unsigned char buffer[] = { 0x90, // NOP 0x90, // NOP 0xcc, // INT3 0xc3 // RET }; ULONG_PTR buffer_len = sizeof(buffer); // 使用ULONG_PTR适配32/64位系统 // 修正NtAllocateVirtualMemory的函数指针定义,RegionSize为PULONG_PTR typedef NTSTATUS(NTAPI* pNtAllocateVirtualMemory)( HANDLE ProcessHandle, PVOID* BaseAddress, ULONG ZeroBits, PULONG_PTR RegionSize, ULONG AllocationType, ULONG Protect ); typedef NTSTATUS(NTAPI* pNtWriteVirtualMemory)( HANDLE ProcessHandle, PVOID BaseAddress, PVOID Buffer, SIZE_T BufferSize, PSIZE_T NumberOfBytesWritten ); int main() { PVOID exec_mem = NULL; HANDLE rt = NULL; pNtAllocateVirtualMemory ntAllocateVirtualMemory = (pNtAllocateVirtualMemory)GetProcAddress(GetModuleHandleA("ntdll"), "NtAllocateVirtualMemory"); if (!ntAllocateVirtualMemory) { return -1; } NTSTATUS status = ntAllocateVirtualMemory( GetCurrentProcess(), &exec_mem, 0, &buffer_len, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE // 直接分配带可执行权限的内存 ); if (!NT_SUCCESS(status)) { return -1; } pNtWriteVirtualMemory ntWriteVirtualMemory = (pNtWriteVirtualMemory)GetProcAddress(GetModuleHandleA("ntdll"), "NtWriteVirtualMemory"); if (!ntWriteVirtualMemory) { return -1; } SIZE_T bytesWritten = 0; status = ntWriteVirtualMemory( GetCurrentProcess(), exec_mem, buffer, sizeof(buffer), &bytesWritten ); if (!NT_SUCCESS(status) || bytesWritten != sizeof(buffer)) { return -1; } rt = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)exec_mem, 0, 0, 0); if (rt) { WaitForSingleObject(rt, INFINITE); CloseHandle(rt); } return 0; }
额外说明(可选安全优化)
如果不想直接分配可执行内存,可先分配PAGE_READWRITE权限内存,写入数据后再调用NtProtectVirtualMemory修改为可执行权限,示例代码如下:
// 在写入内存后添加以下代码 typedef NTSTATUS(NTAPI* pNtProtectVirtualMemory)( HANDLE ProcessHandle, PVOID* BaseAddress, PULONG_PTR RegionSize, ULONG NewProtect, PULONG OldProtect ); pNtProtectVirtualMemory ntProtectVirtualMemory = (pNtProtectVirtualMemory)GetProcAddress(GetModuleHandleA("ntdll"), "NtProtectVirtualMemory"); if (ntProtectVirtualMemory) { ULONG oldProtect = 0; ULONG_PTR protectSize = sizeof(buffer); status = ntProtectVirtualMemory( GetCurrentProcess(), &exec_mem, &protectSize, PAGE_EXECUTE_READ, &oldProtect ); if (!NT_SUCCESS(status)) { return -1; } }
内容的提问来源于stack exchange,提问作者unyo
相关产品推荐
相关产品推荐

