调用NtAllocateVirtualMemory系统调用触发0xc0000005错误求助
解决直接调用NtAllocateVirtualMemory系统调用触发0xc0000005错误的方案
核心问题分析
触发访问违规的主要原因是参数传递非法和系统调用号硬编码不兼容目标系统,同时编译命令存在格式冲突问题。
具体修复步骤
1. 修复RegionSize参数的非法传递
NtAllocateVirtualMemory的RegionSize是输入输出参数,要求传入指向ULONG变量的指针——系统会在这个地址写入实际分配的内存大小。你当前直接将0x1000强制转换为PULONG,相当于让系统调用去写入地址0x1000,而这个地址在用户态进程中通常不可访问,直接触发访问违规。
修改evasion.c的main函数:
int main(int argc, char* argv[]) { LPVOID rb; ULONG size = 0x1000; // 定义合法变量存储内存大小 NTSTATUS res = myNtAllocateVirtualMemory(GetCurrentProcess(), &rb, 0, &size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); printf("STATUS: %x\n", res); return 0; }
2. 避免硬编码系统调用号
Windows不同版本的系统调用号不固定,硬编码0x18h仅适用于旧版本(如Windows 7),Windows 10及以后版本中NtAllocateVirtualMemory的syscall号已变更。正确做法是从ntdll.dll中动态提取:
修改后的evasion.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <windows.h> #include <stdint.h> extern "C" NTSTATUS myNtAllocateVirtualMemory( HANDLE ProcessHandle, PVOID *BaseAddress, ULONG ZeroBits, PULONG RegionSize, ULONG AllocationType, ULONG Protect, uint32_t syscall_num // 添加syscall号参数 ); // 从ntdll.dll中提取NtAllocateVirtualMemory的syscall号 uint32_t get_ntallocate_syscall() { FARPROC func = GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtAllocateVirtualMemory"); if (!func) return 0; uint8_t* code = (uint8_t*)func; // 跳过mov r10, rcx指令(字节码:4C 8B D9) if (code[0] == 0x4C && code[1] == 0x8B && code[2] == 0xD9) { // 读取mov eax, XX指令中的syscall号(字节码:B8 XX XX XX XX) if (code[3] == 0xB8) { return *(uint32_t*)(code + 4); } } return 0; } int main(int argc, char* argv[]) { LPVOID rb; ULONG size = 0x1000; uint32_t syscall_num = get_ntallocate_syscall(); if (!syscall_num) { printf("Failed to get syscall number\n"); return 1; } NTSTATUS res = myNtAllocateVirtualMemory(GetCurrentProcess(), &rb, 0, &size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE, syscall_num); printf("STATUS: %x\n", res); return 0; }
修改后的syscall.asm
section .text global myNtAllocateVirtualMemory myNtAllocateVirtualMemory: mov r10, rcx mov eax, r8d ; 使用传入的syscall号(第7个参数对应r8寄存器) syscall ret
3. 修正编译命令中的错误选项
你当前用g++编译时添加了-shared选项,这会生成动态链接库格式的目标文件,后续链接成exe会导致格式冲突。去掉该选项:
# 编译汇编文件 nasm -f win64 -o syscall.o syscall.asm # 编译C文件(去掉-shared) x86_64-w64-mingw32-g++ -m64 -c evasion.c -I/usr/share/mingw-w64/include/ -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc -Wall -fpermissive # 链接生成exe x86_64-w64-mingw32-gcc evasion.o syscall.o -o evasion.exe
内容的提问来源于stack exchange,提问作者user3467471
相关产品推荐
相关产品推荐

