向EXE注入代码致程序APPCRASH崩溃,求排查方向
针对你遇到的情况——首次注入偶然成功,后续运行test.exe触发APPCRASH(错误码c0000005,内存访问违规),结合你的代码和PE文件结构知识,给你几个核心排查点:
1. Shellcode硬编码跳转地址是致命问题
你的shellcode末尾是B8 F0 50 45 00 FF D0,这是直接跳转到固定地址0x004550F0,但你并没有把**原入口点(OEP)**的值动态写入shellcode,而是硬编码了一个固定地址!
首次成功大概率是因为当时test.exe的原入口点刚好是这个地址,但修改PE节区后,原入口点的相对内存位置已经变化,或者后续运行时PE加载的基址偏移导致这个地址不再是合法的代码区域,直接触发内存访问违规。
修复思路:
把记录的oep值(原入口点)写入shellcode的跳转位置,而不是用固定值。比如你可以在shellcode末尾留一个占位符(比如0xDEADBEEF),然后用pe.set_dword_at_offset(raw_offset + len(shellcode) - 4, oep)来替换成真实的原入口点地址。
2. 对齐函数的整数除法错误
你的align函数用了普通除法/,在Python 2中这会返回浮点数,导致计算出的对齐值出现精度问题(比如(0x1000 + 0x200 -1)/0x200会得到5.995,再乘0x200就会变成错误的数值)。
修复思路:
把函数改成整数除法:
def align(val_to_align, alignment): return ((val_to_align + alignment - 1) // alignment) * alignment
3. PE节区大小与Shellcode长度不匹配
你给新节区分配了0x1000的对齐大小,但要确认你的shellcode长度是否超过这个值。如果shellcode长度大于SizeOfRawData,写入时会溢出到其他节区的空间,破坏原PE结构,导致崩溃。
排查方法:
在注入前打印len(shellcode),确保它小于等于你设置的raw_size(即align(0x1000, file_alignment)的结果)。
4. PE头校验和与镜像大小的完整性问题
- 修改节区数量和镜像大小后,你没有更新PE的校验和(
CheckSum)。虽然Windows对普通程序不强制校验,但部分场景下会触发验证失败,导致崩溃。可以添加pe.OPTIONAL_HEADER.CheckSum = pe.generate_checksum()后再写入文件。 - 检查
SizeOfImage的计算:pe.OPTIONAL_HEADER.SizeOfImage = virtual_size + virtual_offset是否正确?正确的计算应该是最后一个节区的VirtualAddress + 该节区的Misc_VirtualSize,然后对齐到SectionAlignment。你当前的写法逻辑是对的,但可以用PE查看工具(比如LordPE)验证修改后的镜像大小是否合理。
5. Shellcode与PE位数不兼容
确认你的test.exe是32位还是64位:
- 32位PE的
Machine值是0x14C,64位是0x8664,可以通过print(hex(pe.FILE_HEADER.Machine))查看。 - 如果
test.exe是64位,但你的shellcode是32位的,必然会触发崩溃;反之亦然。
另外,你的弹窗shellcode如果用了硬编码的API地址(而非通过PEB动态获取),在不同补丁版本的Windows 7上可能地址不匹配,导致首次成功只是巧合。
6. PE文件结构的合法性验证
用PE查看工具打开修改后的test.exe,检查以下几点:
- 新节区的
PointerToRawData和VirtualAddress是否与其他节区重叠? - 新节区的属性是否正确设置为
EXECUTE_READWRITE? - 原入口点是否被正确记录,shellcode是否正确写入新节区的起始位置?
内容的提问来源于stack exchange,提问作者Lavonen

