Files
Deshab-OS/CODE/tools/pe-samples/gen_pe.py
T
2026-07-28 21:11:10 +08:00

631 lines
25 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
gen_pe.py — Deshab PE 兼容层测试 PE 程序生成器(无需 MinGW/MSVC)
用途: 当宿主机无 MinGW/MSVC 时,用纯 Python 构造最小 PE32+ 和 PE32 二进制,
验证 pe_loader 解析与 pe_shim/x86emu32 执行路径。
构造的 PE 特征:
- PE32+ (64位): machine=0x8664, entry=main, image_base=0x140000000
- PE32 (32位): machine=0x014c, entry=main, image_base=0x00400000
- 单 section (.text), 4KB 对齐
- IAT 仅 2 项: msvcrt.dll!printf + kernel32.dll!ExitProcess
- main 函数: 调用 printf("Hello from PE32+/PE32!\\r\\n") → 调用 ExitProcess(0)
输出:
hello64.exe - PE32+ 二进制 (供 HELLO64 EXE 测试用)
hello32.exe - PE32 二进制 (供 HELLO32 EXE 测试用)
用法:
python gen_pe.py
# 生成 hello64.exe / hello32.exe 到当前目录
# 之后复制到 SYSTEM/system/deshab64/tools/ 并重新运行 build.bat
"""
import struct
import sys
import os
# ============================================================================
# PE32+ (64位) 构造
# ============================================================================
IMAGE_DOS_SIGNATURE = 0x5A4D # 'MZ'
IMAGE_NT_SIGNATURE = 0x00004550 # 'PE\0\0'
IMAGE_FILE_MACHINE_I386 = 0x014c
IMAGE_FILE_MACHINE_AMD64 = 0x8664
IMAGE_FILE_MACHINE_I386_CHARACTERISTICS = 0x0102 # EXECUTABLE_IMAGE | 32BIT_MACHINE
IMAGE_FILE_MACHINE_AMD64_CHARACTERISTICS = 0x0022 # EXECUTABLE_IMAGE | LARGE_ADDRESS_AWARE
IMAGE_SUBSYSTEM_WINDOWS_CUI = 3
IMAGE_SCN_CNT_CODE = 0x20
IMAGE_SCN_MEM_EXECUTE = 0x20000000
IMAGE_SCN_MEM_READ = 0x40000000
IMAGE_DIRECTORY_ENTRY_IMPORT = 1
def build_pe32_plus():
"""构造 PE32+ (64位) 测试程序。"""
image_base = 0x140000000
section_align = 0x1000
file_align = 0x200
# DOS header (64 bytes) + e_lfanew
dos_header = bytearray(64)
struct.pack_into('<H', dos_header, 0, IMAGE_DOS_SIGNATURE) # e_magic
dos_header[2:60] = b'\x00' * 58
struct.pack_into('<I', dos_header, 60, 64) # e_lfanew = 64 (PE header at offset 64)
# PE signature
pe_sig = struct.pack('<I', IMAGE_NT_SIGNATURE)
# COFF file header (20 bytes)
num_sections = 1
time_stamp = 0
sym_table_ptr = 0
num_symbols = 0
optional_header_size = 240 # PE32+ optional header size
characteristics = IMAGE_FILE_MACHINE_AMD64_CHARACTERISTICS
coff_header = struct.pack('<HHIIIHH',
IMAGE_FILE_MACHINE_AMD64,
num_sections,
time_stamp,
sym_table_ptr,
num_symbols,
optional_header_size,
characteristics)
# PE32+ Optional header (240 bytes)
# 布局:
# Magic (2) = 0x20b (PE32+)
# MajorLinkerVersion (1) = 0
# MinorLinkerVersion (1) = 0
# SizeOfCode (4) = .text 大小
# SizeOfInitializedData (4) = 0
# SizeOfUninitializedData (4) = 0
# AddressOfEntryPoint (4) = main RVA
# BaseOfCode (4) = 0x1000
# ImageBase (8) = 0x140000000
# SectionAlignment (4) = 0x1000
# FileAlignment (4) = 0x200
# MajorOperatingSystemVersion (2) = 6
# MinorOperatingSystemVersion (2) = 0
# MajorImageVersion (2) = 0
# MinorImageVersion (2) = 0
# MajorSubsystemVersion (2) = 6
# MinorSubsystemVersion (2) = 0
# Win32VersionValue (4) = 0
# SizeOfImage (4) = 0x3000
# SizeOfHeaders (4) = 0x200
# CheckSum (4) = 0
# Subsystem (2) = IMAGE_SUBSYSTEM_WINDOWS_CUI = 3
# DllCharacteristics (2) = 0
# SizeOfStackReserve (8) = 0x100000
# SizeOfStackCommit (8) = 0x1000
# SizeOfHeapReserve (8) = 0x100000
# SizeOfHeapCommit (8) = 0x1000
# LoaderFlags (4) = 0
# NumberOfRvaAndSizes (4) = 16
# DataDirectory[16] (8*16 = 128 bytes)
# .text 段机器码(x86_64):
# main:
# lea rcx, [rip + msg] ; 48 8D 0D XX XX XX XX (printf arg1 = msg)
# call [rip + printf_iat] ; FF 15 XX XX XX XX (call IAT[printf])
# xor ecx, ecx ; 31 C9 (ExitProcess arg1 = 0)
# call [rip + exitproc_iat] ; FF 15 XX XX XX XX (call IAT[ExitProcess])
# ret ; C3
# msg: "Hello from PE32+!\r\n\0"
msg = b"Hello from PE32+!\r\n\0"
# 占位用,后面填正确偏移
code = bytearray()
code += b'\x48\x8D\x0D' + b'\x00\x00\x00\x00' # lea rcx, [rip+0] (placeholder)
code += b'\xFF\x15' + b'\x00\x00\x00\x00' # call [rip+0] (placeholder)
code += b'\x31\xC9' # xor ecx, ecx
code += b'\xFF\x15' + b'\x00\x00\x00\x00' # call [rip+0] (placeholder)
code += b'\xC3' # ret
code += msg
code_rva = 0x1000 # .text RVA
main_rva = code_rva
printf_iat_rva = code_rva + 0x200 # IAT 在 .text 后(同一 section 内,简化)
exitproc_iat_rva = printf_iat_rva + 8
# 修正 lea rcx, [rip + msg]: msg 在 code[19] 之后(lea 7字节 + call 6 + xor 2 + call 6 + ret 1 = 22)
msg_offset_in_code = 22
lea_rip_offset = msg_offset_in_code - len(code) + len(code) # 偏移=22-0=22(lea 后下一指令的 RIP)
# lea rcx, [rip + disp32]: disp32 = msg - (next_instr_rip)
# next_instr_rip = main_rva + 7
# msg = main_rva + 22
# disp32 = 22 - 7 = 15
struct.pack_into('<i', code, 3, 15)
# 修正 call [rip + printf_iat]: printf IAT 在 printf_iat_rva, call 后下一指令 RIP = main_rva + 13
# disp32 = printf_iat_rva - (main_rva + 13) = 0x200 - 13 = 499
struct.pack_into('<i', code, 10, 0x200 - 13)
# 修正 call [rip + exitproc]: ExitProcess IAT 在 exitproc_iat_rva, call 后下一指令 RIP = main_rva + 21
# disp32 = exitproc_iat_rva - (main_rva + 21) = 0x208 - 21 = 491
struct.pack_into('<i', code, 17, 0x208 - 21)
# IAT 8字节对齐填充
while len(code) < 0x200:
code += b'\x00'
# IAT 内容(指向 import 函数名 RVA)
iat_data = bytearray()
iat_data += struct.pack('<Q', 0x300) # printf function name RVA (hint+name 表)
iat_data += struct.pack('<Q', 0x320) # ExitProcess function name RVA
code += iat_data
# Import descriptor 数据
import_desc_rva = 0x400 # 在 IAT 后
while len(code) < 0x300:
code += b'\x00'
# Hint/Name 表
# "msvcrt.dll\0" + printf name "printf\0"
# "kernel32.dll\0" + ExitProcess name "ExitProcess\0"
printf_name_rva = 0x300
exitproc_name_rva = 0x320
printf_hint_name = struct.pack('<H', 0) + b'printf\0' # hint=0
exitproc_hint_name = struct.pack('<H', 0) + b'ExitProcess\0'
while len(code) < printf_name_rva - code_rva:
code += b'\x00'
code += printf_hint_name
while len(code) < exitproc_name_rva - code_rva:
code += b'\x00'
code += exitproc_hint_name
# DLL 名(放在 import descriptor 之后)
msvcrt_dll_rva = 0x350
kernel32_dll_rva = 0x360
while len(code) < msvcrt_dll_rva - code_rva:
code += b'\x00'
code += b'msvcrt.dll\0'
while len(code) < kernel32_dll_rva - code_rva:
code += b'\x00'
code += b'kernel32.dll\0'
# Import descriptor (5 * 4 + 4 = 24 bytes for original thunk 这里简化)
while len(code) < import_desc_rva - code_rva:
code += b'\x00'
import_desc = struct.pack('<IIIII',
printf_iat_rva, # OriginalFirstThunk
0, # TimeDateStamp
0, # ForwarderChain
msvcrt_dll_rva, # Name
printf_iat_rva) # FirstThunk
code += import_desc
import_desc2 = struct.pack('<IIIII',
exitproc_iat_rva,
0, 0,
kernel32_dll_rva,
exitproc_iat_rva)
code += import_desc2
# NULL 终止 import desc 数组
code += b'\x00' * 20
# 对齐到 file_align
while len(code) % file_align != 0:
code += b'\x00'
size_of_code = len(code)
size_of_image = code_rva + size_of_code
# 修正 size_of_image 到 section_align
while size_of_image % section_align != 0:
size_of_image += 1
opt_header = bytearray(240)
struct.pack_into('<H', opt_header, 0, 0x20b) # Magic = PE32+
opt_header[2] = 0 # MajorLinkerVersion
opt_header[3] = 0 # MinorLinkerVersion
struct.pack_into('<I', opt_header, 4, size_of_code) # SizeOfCode
struct.pack_into('<I', opt_header, 8, 0) # SizeOfInitializedData
struct.pack_into('<I', opt_header, 12, 0) # SizeOfUninitializedData
struct.pack_into('<I', opt_header, 16, main_rva) # AddressOfEntryPoint
struct.pack_into('<I', opt_header, 20, code_rva) # BaseOfCode
struct.pack_into('<Q', opt_header, 24, image_base) # ImageBase
struct.pack_into('<I', opt_header, 32, section_align)
struct.pack_into('<I', opt_header, 36, file_align)
struct.pack_into('<H', opt_header, 40, 6) # MajorOperatingSystemVersion
struct.pack_into('<H', opt_header, 42, 0)
struct.pack_into('<H', opt_header, 44, 0) # MajorImageVersion
struct.pack_into('<H', opt_header, 46, 0)
struct.pack_into('<H', opt_header, 48, 6) # MajorSubsystemVersion
struct.pack_into('<H', opt_header, 50, 0)
struct.pack_into('<I', opt_header, 52, 0) # Win32VersionValue
struct.pack_into('<I', opt_header, 56, size_of_image)
struct.pack_into('<I', opt_header, 60, 0x200) # SizeOfHeaders
struct.pack_into('<I', opt_header, 64, 0) # CheckSum
struct.pack_into('<H', opt_header, 68, IMAGE_SUBSYSTEM_WINDOWS_CUI) # Subsystem
struct.pack_into('<H', opt_header, 70, 0) # DllCharacteristics
struct.pack_into('<Q', opt_header, 72, 0x100000) # SizeOfStackReserve
struct.pack_into('<Q', opt_header, 80, 0x1000) # SizeOfStackCommit
struct.pack_into('<Q', opt_header, 88, 0x100000) # SizeOfHeapReserve
struct.pack_into('<Q', opt_header, 96, 0x1000) # SizeOfHeapCommit
struct.pack_into('<I', opt_header, 104, 0) # LoaderFlags
struct.pack_into('<I', opt_header, 108, 16) # NumberOfRvaAndSizes
# DataDirectory[16] = 16 entries * 8 bytes = 128 bytes
data_dir_offset = 112
# DataDirectory[1] = Import (RVA, Size)
struct.pack_into('<II', opt_header, data_dir_offset + 8, import_desc_rva, 48)
# Section header (.text)
section_header = bytearray(40)
section_header[0:8] = b'.text\0\0\0' # Name
struct.pack_into('<I', section_header, 8, size_of_code) # VirtualSize
struct.pack_into('<I', section_header, 12, code_rva) # VirtualAddress
struct.pack_into('<I', section_header, 16, size_of_code) # SizeOfRawData
struct.pack_into('<I', section_header, 20, file_align) # PointerToRawData
struct.pack_into('<I', section_header, 24, 0) # PointerToRelocations
struct.pack_into('<I', section_header, 28, 0) # PointerToLinenumbers
struct.pack_into('<H', section_header, 32, 0) # NumberOfRelocations
struct.pack_into('<H', section_header, 34, 0) # NumberOfLinenumbers
struct.pack_into('<I', section_header, 36,
IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ)
# 组装文件
headers = bytearray()
headers += dos_header
headers += pe_sig
headers += coff_header
headers += opt_header
headers += section_header
# 头部对齐到 file_align
while len(headers) % file_align != 0:
headers += b'\x00'
return bytes(headers) + bytes(code)
def build_pe32():
"""构造 PE32 (32位) 测试程序(x86emu32 解释器执行)。
与 build_pe32_plus 的区别:
- Machine = 0x014c (i386), Characteristics = 0x0102
- Optional Header magic = 0x10b, 大小 224 字节
- 有 BaseOfData 字段;ImageBase 为 4 字节
- Stack/Heap Reserve/Commit 为 4 字节
- IAT thunk 为 4 字节(struct '<I')
- 机器码为 x86-32,使用 call [abs] 绝对寻址(FF 25 disp32)
"""
image_base = 0x00400000
section_align = 0x1000
file_align = 0x200
# DOS header (64 bytes) + e_lfanew
dos_header = bytearray(64)
struct.pack_into('<H', dos_header, 0, IMAGE_DOS_SIGNATURE)
dos_header[2:60] = b'\x00' * 58
struct.pack_into('<I', dos_header, 60, 64) # e_lfanew
pe_sig = struct.pack('<I', IMAGE_NT_SIGNATURE)
# COFF file header (20 bytes) — PE32 optional header = 224 字节
num_sections = 1
optional_header_size = 224
characteristics = IMAGE_FILE_MACHINE_I386_CHARACTERISTICS # 0x0102
coff_header = struct.pack('<HHIIIHH',
IMAGE_FILE_MACHINE_I386,
num_sections,
0, 0, 0,
optional_header_size,
characteristics)
# .text 段机器码(x86-32):
# main:
# push msg_addr ; 68 XX XX XX XX (5) printf 参数
# call [printf_iat_abs] ; FF 25 XX XX XX XX (6) 通过 IAT 调用
# add esp, 4 ; 83 C4 04 (3) cdecl 清栈
# push 0 ; 6A 00 (2) ExitProcess 参数
# call [exit_iat_abs] ; FF 25 XX XX XX XX (6) 通过 IAT 调用
# ret ; C3 (1)
# msg: "Hello from PE32!\r\n\0"
msg = b"Hello from PE32!\r\n\0"
code_rva = 0x1000
main_rva = code_rva
printf_iat_rva = code_rva + 0x200 # 0x1200
exitproc_iat_rva = printf_iat_rva + 4 # 0x1204 (4-byte thunk)
printf_name_rva = 0x1300
exitproc_name_rva = 0x1320
msvcrt_dll_rva = 0x1350
kernel32_dll_rva = 0x1360
import_desc_rva = 0x1400
msg_offset = 5 + 6 + 3 + 2 + 6 + 1 # = 23
msg_addr = image_base + code_rva + msg_offset # 0x401017
printf_iat_abs = image_base + printf_iat_rva # 0x401200
exitproc_iat_abs = image_base + exitproc_iat_rva # 0x401204
code = bytearray()
code += b'\x68' + struct.pack('<I', msg_addr) # push msg_addr
code += b'\xFF\x25' + struct.pack('<I', printf_iat_abs) # call [printf_iat]
code += b'\x83\xC4\x04' # add esp, 4
code += b'\x6A\x00' # push 0
code += b'\xFF\x25' + struct.pack('<I', exitproc_iat_abs) # call [exitproc_iat]
code += b'\xC3' # ret
code += msg
# 对齐到 IAT (0x200)
while len(code) < 0x200:
code += b'\x00'
# IAT (4-byte thunks,初始值 = hint/name RVA)
code += struct.pack('<I', printf_name_rva)
code += struct.pack('<I', exitproc_name_rva)
# 对齐到 hint/name 表 (0x300)
while len(code) < printf_name_rva - code_rva:
code += b'\x00'
code += struct.pack('<H', 0) + b'printf\0' # hint=0
while len(code) < exitproc_name_rva - code_rva:
code += b'\x00'
code += struct.pack('<H', 0) + b'ExitProcess\0'
# DLL 名
while len(code) < msvcrt_dll_rva - code_rva:
code += b'\x00'
code += b'msvcrt.dll\0'
while len(code) < kernel32_dll_rva - code_rva:
code += b'\x00'
code += b'kernel32.dll\0'
# Import descriptors
while len(code) < import_desc_rva - code_rva:
code += b'\x00'
code += struct.pack('<IIIII',
printf_iat_rva, # OriginalFirstThunk (INT)
0, 0,
msvcrt_dll_rva, # Name
printf_iat_rva) # FirstThunk (IAT)
code += struct.pack('<IIIII',
exitproc_iat_rva, # OriginalFirstThunk
0, 0,
kernel32_dll_rva, # Name
exitproc_iat_rva) # FirstThunk
code += b'\x00' * 20 # NULL 终止
# 对齐到 file_align
while len(code) % file_align != 0:
code += b'\x00'
size_of_code = len(code)
size_of_image = code_rva + size_of_code
while size_of_image % section_align != 0:
size_of_image += 1
# PE32 Optional Header (224 字节)
opt_header = bytearray(224)
struct.pack_into('<H', opt_header, 0, 0x10b) # Magic = PE32
opt_header[2] = 0 # MajorLinkerVersion
opt_header[3] = 0 # MinorLinkerVersion
struct.pack_into('<I', opt_header, 4, size_of_code) # SizeOfCode
struct.pack_into('<I', opt_header, 8, 0) # SizeOfInitializedData
struct.pack_into('<I', opt_header, 12, 0) # SizeOfUninitializedData
struct.pack_into('<I', opt_header, 16, main_rva) # AddressOfEntryPoint
struct.pack_into('<I', opt_header, 20, code_rva) # BaseOfCode
struct.pack_into('<I', opt_header, 24, 0) # BaseOfData (PE32 only)
struct.pack_into('<I', opt_header, 28, image_base) # ImageBase (32-bit)
struct.pack_into('<I', opt_header, 32, section_align)
struct.pack_into('<I', opt_header, 36, file_align)
struct.pack_into('<H', opt_header, 40, 6) # MajorOperatingSystemVersion
struct.pack_into('<H', opt_header, 42, 0)
struct.pack_into('<H', opt_header, 44, 0) # MajorImageVersion
struct.pack_into('<H', opt_header, 46, 0)
struct.pack_into('<H', opt_header, 48, 6) # MajorSubsystemVersion
struct.pack_into('<H', opt_header, 50, 0)
struct.pack_into('<I', opt_header, 52, 0) # Win32VersionValue
struct.pack_into('<I', opt_header, 56, size_of_image)
struct.pack_into('<I', opt_header, 60, 0x200) # SizeOfHeaders
struct.pack_into('<I', opt_header, 64, 0) # CheckSum
struct.pack_into('<H', opt_header, 68, IMAGE_SUBSYSTEM_WINDOWS_CUI) # Subsystem
struct.pack_into('<H', opt_header, 70, 0) # DllCharacteristics
struct.pack_into('<I', opt_header, 72, 0x100000) # SizeOfStackReserve (4字节)
struct.pack_into('<I', opt_header, 76, 0x1000) # SizeOfStackCommit
struct.pack_into('<I', opt_header, 80, 0x100000) # SizeOfHeapReserve
struct.pack_into('<I', opt_header, 84, 0x1000) # SizeOfHeapCommit
struct.pack_into('<I', opt_header, 88, 0) # LoaderFlags
struct.pack_into('<I', opt_header, 92, 16) # NumberOfRvaAndSizes
# DataDirectory[1] = Import (RVA, Size)
data_dir_offset = 96
struct.pack_into('<II', opt_header, data_dir_offset + 8, import_desc_rva, 60)
# Section header (.text)
section_header = bytearray(40)
section_header[0:8] = b'.text\0\0\0'
struct.pack_into('<I', section_header, 8, size_of_code) # VirtualSize
struct.pack_into('<I', section_header, 12, code_rva) # VirtualAddress
struct.pack_into('<I', section_header, 16, size_of_code) # SizeOfRawData
struct.pack_into('<I', section_header, 20, file_align) # PointerToRawData
struct.pack_into('<I', section_header, 24, 0)
struct.pack_into('<I', section_header, 28, 0)
struct.pack_into('<H', section_header, 32, 0)
struct.pack_into('<H', section_header, 34, 0)
struct.pack_into('<I', section_header, 36,
IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ)
# 组装文件
headers = bytearray()
headers += dos_header
headers += pe_sig
headers += coff_header
headers += opt_header
headers += section_header
while len(headers) % file_align != 0:
headers += b'\x00'
return bytes(headers) + bytes(code)
def build_cmd_exe():
"""构造 cmd.exe — PE32+ (64位) 命令行测试程序。
与 build_pe32_plus() 类似,仅修改消息文本为 "Hello from cmd.exe!"
"""
image_base = 0x140000000
section_align = 0x1000
file_align = 0x200
dos_header = bytearray(64)
struct.pack_into('<H', dos_header, 0, IMAGE_DOS_SIGNATURE)
dos_header[2:60] = b'\x00' * 58
struct.pack_into('<I', dos_header, 60, 64)
pe_sig = struct.pack('<I', IMAGE_NT_SIGNATURE)
num_sections = 1
optional_header_size = 240
characteristics = IMAGE_FILE_MACHINE_AMD64_CHARACTERISTICS
coff_header = struct.pack('<HHIIIHH',
IMAGE_FILE_MACHINE_AMD64,
num_sections,
0, 0, 0,
optional_header_size,
characteristics)
msg = b"Hello from cmd.exe!\r\n\0"
code = bytearray()
code += b'\x48\x8D\x0D' + b'\x00\x00\x00\x00' # lea rcx, [rip+0]
code += b'\xFF\x15' + b'\x00\x00\x00\x00' # call [rip+0]
code += b'\x31\xC9' # xor ecx, ecx
code += b'\xFF\x15' + b'\x00\x00\x00\x00' # call [rip+0]
code += b'\xC3' # ret
code += msg
code_rva = 0x1000
main_rva = code_rva
printf_iat_rva = code_rva + 0x200
exitproc_iat_rva = printf_iat_rva + 8
msg_offset_in_code = 22
struct.pack_into('<i', code, 3, 15)
struct.pack_into('<i', code, 10, 0x200 - 13)
struct.pack_into('<i', code, 17, 0x208 - 21)
while len(code) < 0x200:
code += b'\x00'
code += struct.pack('<Q', 0x300)
code += struct.pack('<Q', 0x320)
import_desc_rva = 0x400
while len(code) < 0x300:
code += b'\x00'
printf_name_rva = 0x300
exitproc_name_rva = 0x320
printf_hint_name = struct.pack('<H', 0) + b'printf\0'
exitproc_hint_name = struct.pack('<H', 0) + b'ExitProcess\0'
while len(code) < printf_name_rva - code_rva:
code += b'\x00'
code += printf_hint_name
while len(code) < exitproc_name_rva - code_rva:
code += b'\x00'
code += exitproc_hint_name
msvcrt_dll_rva = 0x350
kernel32_dll_rva = 0x360
while len(code) < msvcrt_dll_rva - code_rva:
code += b'\x00'
code += b'msvcrt.dll\0'
while len(code) < kernel32_dll_rva - code_rva:
code += b'\x00'
code += b'kernel32.dll\0'
while len(code) < import_desc_rva - code_rva:
code += b'\x00'
code += struct.pack('<IIIII', printf_iat_rva, 0, 0, msvcrt_dll_rva, printf_iat_rva)
code += struct.pack('<IIIII', exitproc_iat_rva, 0, 0, kernel32_dll_rva, exitproc_iat_rva)
code += b'\x00' * 20
while len(code) % file_align != 0:
code += b'\x00'
size_of_code = len(code)
size_of_image = code_rva + size_of_code
while size_of_image % section_align != 0:
size_of_image += 1
opt_header = bytearray(240)
struct.pack_into('<H', opt_header, 0, 0x20b)
opt_header[2] = 0
opt_header[3] = 0
struct.pack_into('<I', opt_header, 4, size_of_code)
struct.pack_into('<I', opt_header, 8, 0)
struct.pack_into('<I', opt_header, 12, 0)
struct.pack_into('<I', opt_header, 16, main_rva)
struct.pack_into('<I', opt_header, 20, code_rva)
struct.pack_into('<Q', opt_header, 24, image_base)
struct.pack_into('<I', opt_header, 32, section_align)
struct.pack_into('<I', opt_header, 36, file_align)
struct.pack_into('<H', opt_header, 40, 6)
struct.pack_into('<H', opt_header, 42, 0)
struct.pack_into('<H', opt_header, 44, 0)
struct.pack_into('<H', opt_header, 46, 0)
struct.pack_into('<H', opt_header, 48, 6)
struct.pack_into('<H', opt_header, 50, 0)
struct.pack_into('<I', opt_header, 52, 0)
struct.pack_into('<I', opt_header, 56, size_of_image)
struct.pack_into('<I', opt_header, 60, 0x200)
struct.pack_into('<I', opt_header, 64, 0)
struct.pack_into('<H', opt_header, 68, IMAGE_SUBSYSTEM_WINDOWS_CUI)
struct.pack_into('<H', opt_header, 70, 0)
struct.pack_into('<Q', opt_header, 72, 0x100000)
struct.pack_into('<Q', opt_header, 80, 0x1000)
struct.pack_into('<Q', opt_header, 88, 0x100000)
struct.pack_into('<Q', opt_header, 96, 0x1000)
struct.pack_into('<I', opt_header, 104, 0)
struct.pack_into('<I', opt_header, 108, 16)
data_dir_offset = 112
struct.pack_into('<II', opt_header, data_dir_offset + 8, import_desc_rva, 48)
section_header = bytearray(40)
section_header[0:8] = b'.text\0\0\0'
struct.pack_into('<I', section_header, 8, size_of_code)
struct.pack_into('<I', section_header, 12, code_rva)
struct.pack_into('<I', section_header, 16, size_of_code)
struct.pack_into('<I', section_header, 20, file_align)
struct.pack_into('<I', section_header, 24, 0)
struct.pack_into('<I', section_header, 28, 0)
struct.pack_into('<H', section_header, 32, 0)
struct.pack_into('<H', section_header, 34, 0)
struct.pack_into('<I', section_header, 36,
IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ)
headers = bytearray()
headers += dos_header
headers += pe_sig
headers += coff_header
headers += opt_header
headers += section_header
while len(headers) % file_align != 0:
headers += b'\x00'
return bytes(headers) + bytes(code)
def main():
out_dir = os.path.dirname(os.path.abspath(__file__))
pe32_plus = build_pe32_plus()
out_path = os.path.join(out_dir, 'hello64.exe')
with open(out_path, 'wb') as f:
f.write(pe32_plus)
print(f"[gen] Generated PE32+: {out_path} ({len(pe32_plus)} bytes)")
pe32 = build_pe32()
out_path = os.path.join(out_dir, 'hello32.exe')
with open(out_path, 'wb') as f:
f.write(pe32)
print(f"[gen] Generated PE32: {out_path} ({len(pe32)} bytes)")
cmd_exe = build_cmd_exe()
out_path = os.path.join(out_dir, 'cmd.exe')
with open(out_path, 'wb') as f:
f.write(cmd_exe)
print(f"[gen] Generated cmd.exe: {out_path} ({len(cmd_exe)} bytes)")
print("[gen] 完成。复制到 SYSTEM/system/deshab64/tools/ 并重新运行 build.bat")
if __name__ == '__main__':
main()