IMAGE_FILE_MACHINE_UNKNOWN = 0x0 IMAGE_FILE_MACHINE_AM33 = 0x1D3 IMAGE_FILE_MACHINE_AMD64 = 0x8664 IMAGE_FILE_MACHINE_ARM = 0x1C0 IMAGE_FILE_MACHINE_ARMNT = 0x1C4 IMAGE_FILE_MACHINE_ARM64 = 0xAA64 IMAGE_FILE_MACHINE_EBC = 0xEBC IMAGE_FILE_MACHINE_I386 = 0x14C IMAGE_FILE_MACHINE_IA64 = 0x200 IMAGE_FILE_MACHINE_M32R = 0x9041 IMAGE_FILE_MACHINE_MIPS16 = 0x266 IMAGE_FILE_MACHINE_MIPSFPU = 0x366 IMAGE_FILE_MACHINE_MIPSFPU16 = 0x466 IMAGE_FILE_MACHINE_POWERPC = 0x1F0 IMAGE_FILE_MACHINE_POWERPCFP = 0x1F1 IMAGE_FILE_MACHINE_R4000 = 0x166 IMAGE_FILE_MACHINE_SH3 = 0x1A2 IMAGE_FILE_MACHINE_SH3DSP = 0x1A3 IMAGE_FILE_MACHINE_SH4 = 0x1A6 IMAGE_FILE_MACHINE_SH5 = 0x1A8 IMAGE_FILE_MACHINE_THUMB = 0x1C2 IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x169 IMAGE_FILE_RELOCS_STRIPPED = 0x0001 IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002 IMAGE_FILE_LINE_NUMS_STRIPPED = 0x0004 IMAGE_FILE_LOCAL_SYMS_STRIPPED = 0x0008 IMAGE_FILE_AGGRESSIVE_WS_TRIM = 0x0010 IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020 IMAGE_FILE_BYTES_REVERSED_LO = 0x0080 IMAGE_FILE_32BIT_MACHINE = 0x0100 IMAGE_FILE_DEBUG_STRIPPED = 0x0200 IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = 0x0400 IMAGE_FILE_NET_RUN_FROM_SWAP = 0x0800 IMAGE_FILE_SYSTEM = 0x1000 IMAGE_FILE_DLL = 0x2000 IMAGE_FILE_UP_SYSTEM_ONLY = 0x4000 IMAGE_FILE_BYTES_REVERSED_HI = 0x8000 IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA = 0x0020 IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 0x0040 IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY = 0x0080 IMAGE_DLLCHARACTERISTICS_NX_COMPAT = 0x0100 IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = 0x0200 IMAGE_DLLCHARACTERISTICS_NO_SEH = 0x0400 IMAGE_DLLCHARACTERISTICS_NO_BIND = 0x0800 IMAGE_DLLCHARACTERISTICS_APPCONTAINER = 0x1000 IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = 0x2000 IMAGE_DLLCHARACTERISTICS_GUARD_CF = 0x4000 IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000 IMAGE_SUBSYSTEM_UNKNOWN = 0 IMAGE_SUBSYSTEM_NATIVE = 1 IMAGE_SUBSYSTEM_WINDOWS_GUI = 2 IMAGE_SUBSYSTEM_WINDOWS_CUI = 3 IMAGE_SUBSYSTEM_POSIX_CUI = 7 IMAGE_SUBSYSTEM_WINDOWS_CE_GUI = 9 IMAGE_SUBSYSTEM_EFI_APPLICATION = 10 IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER = 11 IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER = 12 IMAGE_SUBSYSTEM_EFI_ROM = 13 IMAGE_SUBSYSTEM_XBOX = 14 IMAGE_SCN_TYPE_NO_PAD = 0x00000008 IMAGE_SCN_CNT_CODE = 0x00000020 IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040 IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080 IMAGE_SCN_LNK_OTHER = 0x00000100 IMAGE_SCN_LNK_INFO = 0x00000200 IMAGE_SCN_LNK_REMOVE = 0x00000800 IMAGE_SCN_LNK_COMDAT = 0x00001000 IMAGE_SCN_GPREL = 0x00008000 IMAGE_SCN_MEM_PURGEABLE = 0x00020000 IMAGE_SCN_MEM_16BIT = 0x00020000 IMAGE_SCN_MEM_LOCKED = 0x00040000 IMAGE_SCN_MEM_PRELOAD = 0x00080000 IMAGE_SCN_ALIGN_1BYTES = 0x00100000 IMAGE_SCN_ALIGN_2BYTES = 0x00200000 IMAGE_SCN_ALIGN_4BYTES = 0x00300000 IMAGE_SCN_ALIGN_8BYTES = 0x00400000 IMAGE_SCN_ALIGN_16BYTES = 0x00500000 IMAGE_SCN_ALIGN_32BYTES = 0x00600000 IMAGE_SCN_ALIGN_64BYTES = 0x00700000 IMAGE_SCN_ALIGN_128BYTES = 0x00800000 IMAGE_SCN_ALIGN_256BYTES = 0x00900000 IMAGE_SCN_ALIGN_512BYTES = 0x00A00000 IMAGE_SCN_ALIGN_1024BYTES = 0x00B00000 IMAGE_SCN_ALIGN_2048BYTES = 0x00C00000 IMAGE_SCN_ALIGN_4096BYTES = 0x00D00000 IMAGE_SCN_ALIGN_8192BYTES = 0x00E00000 IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000 IMAGE_SCN_MEM_DISCARDABLE = 0x02000000 IMAGE_SCN_MEM_NOT_CACHED = 0x04000000 IMAGE_SCN_MEM_NOT_PAGED = 0x08000000 IMAGE_SCN_MEM_SHARED = 0x10000000 IMAGE_SCN_MEM_EXECUTE = 0x20000000 IMAGE_SCN_MEM_READ = 0x40000000 IMAGE_SCN_MEM_WRITE = 0x80000000 IMAGE_REL_BASED_ABSOLUTE = 0 IMAGE_REL_BASED_HIGH = 1 IMAGE_REL_BASED_LOW = 2 IMAGE_REL_BASED_HIGHLOW = 3 IMAGE_REL_BASED_HIGHADJ = 4 IMAGE_REL_BASED_DIR64 = 10 calminstruction align? boundary,value:? check $ relativeto 0 | ( $ relativeto PE.RELOCATION & PE.SECTION_ALIGNMENT mod boundary = 0 ) jyes allowed err 'section not aligned enough' exit allowed: compute boundary, (boundary-1)-((0 scaleof $)+boundary-1) mod boundary arrange value, =db boundary =dup value assemble value end calminstruction PE:: namespace PE if defined Settings.Magic MAGIC = Settings.Magic else MAGIC = 0x10B end if if defined Settings.Machine MACHINE = Settings.Machine else MACHINE = IMAGE_FILE_MACHINE_I386 end if if defined Settings.Characteristics CHARACTERISTICS = Settings.Characteristics else CHARACTERISTICS = IMAGE_FILE_EXECUTABLE_IMAGE or IMAGE_FILE_32BIT_MACHINE end if if defined Settings.DllCharacteristics DLL_CHARACTERISTICS = Settings.DllCharacteristics else DLL_CHARACTERISTICS = 0 end if if defined Settings.Subsystem SUBSYSTEM = Settings.Subsystem else SUBSYSTEM = IMAGE_SUBSYSTEM_WINDOWS_CUI end if if defined Settings.MajorSubsystemVersion MAJOR_SUBSYSTEM_VERSION = Settings.MajorSubsystemVersion else MAJOR_SUBSYSTEM_VERSION = 3 end if if defined Settings.MinorSubsystemVersion MINOR_SUBSYSTEM_VERSION = Settings.MinorSubsystemVersion else MINOR_SUBSYSTEM_VERSION = 10 end if if defined Fixups element RELOCATION DLL_CHARACTERISTICS = DLL_CHARACTERISTICS or IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE else RELOCATION := 0 CHARACTERISTICS = CHARACTERISTICS or IMAGE_FILE_RELOCS_STRIPPED end if if defined Settings.ImageBase IMAGE_BASE := RELOCATION + Settings.ImageBase else IMAGE_BASE := RELOCATION + 400000h end if if defined Settings.SectionAlignment SECTION_ALIGNMENT := Settings.SectionAlignment else SECTION_ALIGNMENT := 1000h end if if defined Settings.FileAlignment FILE_ALIGNMENT := Settings.FileAlignment else FILE_ALIGNMENT := 512 end if if defined Settings.LegacyHeaders LEGACY_HEADERS := Settings.LegacyHeaders else LEGACY_HEADERS := 1 end if NUMBER_OF_DIRECTORIES := 16 if defined Settings.Stub virtual at 0 file Settings.Stub if $ >= 1Ch load SIGNATURE : word from 0 if SIGNATURE = "MZ" | SIGNATURE = "ZM" StubTemplate:: end if end if end virtual if defined StubTemplate load .BYTES_IN_LAST_PAGE : word from StubTemplate:2 load .NUMBER_OF_PAGES : word from StubTemplate:4 .TEMPLATE_LENGTH = .NUMBER_OF_PAGES shl 9 - (-.BYTES_IN_LAST_PAGE) and 1FFh load .RELOCATIONS_OFFSET : word from StubTemplate:18h if .RELOCATIONS_OFFSET >= 40h file Settings.Stub,.TEMPLATE_LENGTH else load .NUMBER_OF_RELOCATIONS : word from StubTemplate:6 .RELOCATIONS_LENGTH = .NUMBER_OF_RELOCATIONS shl 2 load .NUMBER_OF_HEADER_PARAGRAPHS : word from StubTemplate:8 .TEMPLATE_HEADER_LENGTH = .NUMBER_OF_HEADER_PARAGRAPHS shl 4 file Settings.Stub,1Ch rb 40h - $ file Settings.Stub:.RELOCATIONS_OFFSET,.RELOCATIONS_LENGTH align 16 .HEADER_LENGTH = $ file Settings.Stub:.TEMPLATE_HEADER_LENGTH,.TEMPLATE_LENGTH-.TEMPLATE_HEADER_LENGTH .LENGTH = $ store 40h : word at 18h store .HEADER_LENGTH shr 4 : word at 8 store .LENGTH and 1FFh : word at 2 store (.LENGTH-1) shr 9 + 1 : word at 4 end if store Header : dword at 3Ch else Stub: .signature dw "MZ" .bytes_in_last_page dw .LENGTH and 1FFh .number_of_pages dw (.LENGTH-1) shr 9 + 1 .number_of_relocations dw 0 .number_of_header_paragraphs dw .HEADER_LENGTH shr 4 .minimum_heap dw (10000h - (.LENGTH-.HEADER_LENGTH)) shr 4 .maximum_heap dw 0FFFFh .initial_ss dw (-100h) shr 4 .initial_sp dw 0FFFEh .checksum dw 0 .initial_ip dw 100h .initial_cs dw (-100h) shr 4 .relocations_offset dw 40h .overlay_number dw 0 rb 3Ch - $ .new_header_offset dd Header .HEADER_LENGTH = $ file Settings.Stub .LENGTH = $ end if else Stub: .signature dw "MZ" .bytes_in_last_page dw .LENGTH and 1FFh .number_of_pages dw (.LENGTH-1) shr 9 + 1 .number_of_relocations dw 0 .number_of_header_paragraphs dw .HEADER_LENGTH shr 4 .minimum_heap dw .STACK_LENGTH shr 4 .maximum_heap dw 0FFFFh .initial_ss dw 0 .initial_sp dw .LENGTH - .HEADER_LENGTH + .STACK_LENGTH .checksum dw 0 .initial_ip dw 0 .initial_cs dw 0 .relocations_offset dw 40h .overlay_number dw 0 rb 3Ch - $ .new_header_offset dd Header .HEADER_LENGTH = $ .STACK_LENGTH = 100h namespace Stub include '../8086.inc' start: push cs pop ds mov dx,message - start mov ah,9 int 21h mov ax,4C01h int 21h message db 'This program cannot be run in DOS mode.',0Dh,0Ah,24h end namespace align 16 .LENGTH = $ end if if defined Settings.Stamp TIMESTAMP := Settings.Stamp else TIMESTAMP := __TIME__ end if align 8 Header: .Signature dw "PE",0 .Machine dw MACHINE .NumberOfSections dw NUMBER_OF_SECTIONS .TimeDateStamp dd TIMESTAMP .PointerToSymbolTable dd 0 .NumberOfSymbols dd 0 .SizeOfOptionalHeader dw SectionTable - OptionalHeader .Characteristics dw CHARACTERISTICS OptionalHeader: .Magic dw MAGIC .MajorLinkerVersion db 0 .MinorLinkerVersion db 0 .SizeOfCode dd 0 .SizeOfInitializedData dd 0 .SizeOfUninitializedData dd 0 .AddressOfEntryPoint dd 0 .BaseOfCode dd 0 if MAGIC <> 0x20B .BaseOfData dd 0 .ImageBase dd IMAGE_BASE - RELOCATION else .ImageBase dq IMAGE_BASE - RELOCATION end if .SectionAlignment dd SECTION_ALIGNMENT .FileAlignment dd FILE_ALIGNMENT .MajorOperatingSystemVersion dw 1 .MinorOperatingSystemVersion dw 0 .MajorImageVersion dw 0 .MinorImageVersion dw 0 .MajorSubsystemVersion dw MAJOR_SUBSYSTEM_VERSION .MinorSubsystemVersion dw MINOR_SUBSYSTEM_VERSION .Win32VersionValue dd 0 .SizeOfImage dd SIZE_OF_IMAGE .SizeOfHeaders dd SIZE_OF_HEADERS .CheckSum dd 0 .Subsystem dw SUBSYSTEM .DllCharacteristics dw DLL_CHARACTERISTICS if MAGIC <> 0x20B .SizeOfStackReserve dd 1000h .SizeOfStackCommit dd 1000h .SizeOfHeapReserve dd 10000h .SizeOfHeapCommit dd 0 else .SizeOfStackReserve dq 1000h .SizeOfStackCommit dq 1000h .SizeOfHeapReserve dq 10000h .SizeOfHeapCommit dq 0 end if .LoaderFlags dd 0 .NumberOfRvaAndSizes dd NUMBER_OF_DIRECTORIES RvaAndSizes: .Rva dd 0 .Size dd 0 .ENTRY_LENGTH = $ - RvaAndSizes db (NUMBER_OF_DIRECTORIES-1)*RvaAndSizes.ENTRY_LENGTH dup 0 SectionTable: .Name dq '.flat' .VirtualSize dd 0 .VirtualAddress dd 0 .SizeOfRawData dd 0 .PointerToRawData dd 0 .PointerToRelocations dd 0 .PointerToLineNumbers dd 0 .NumberOfRelocations dw 0 .NumberOfLineNumbers dw 0 .Characteristics dd IMAGE_SCN_MEM_EXECUTE + IMAGE_SCN_MEM_READ + IMAGE_SCN_MEM_WRITE .ENTRY_LENGTH = $ - SectionTable db (NUMBER_OF_SECTIONS-1)*SectionTable.ENTRY_LENGTH dup 0 HeadersEnd: define CheckSumBlocks PE,0,HeadersEnd SECTION_INDEX = 0 RELOCATION_INDEX = 0 DEFINED_SECTION = 0 SECTION_DIRECTORIES = 0 align SECTION_ALIGNMENT FIRST_SECTION_RVA: section $%% align FILE_ALIGNMENT,0 SIZE_OF_HEADERS = $% FILE_OFFSET = $% SECTION_BASE = IMAGE_BASE + FIRST_SECTION_RVA org SECTION_BASE store SECTION_BASE-IMAGE_BASE at PE:OptionalHeader.AddressOfEntryPoint store SECTION_BASE-IMAGE_BASE at PE:SectionTable.VirtualAddress store FILE_OFFSET at PE:SectionTable.PointerToRawData virtual at 0 relocated_addresses:: rd NUMBER_OF_RELOCATIONS end virtual virtual at 0 relocation_types:: rw NUMBER_OF_RELOCATIONS end virtual end namespace RVA? equ -PE.IMAGE_BASE + macro entry? address* namespace PE store address-IMAGE_BASE at PE:OptionalHeader.AddressOfEntryPoint end namespace end macro macro stack? reserve*,commit:1000h namespace PE store reserve at PE:OptionalHeader.SizeOfStackReserve store commit at PE:OptionalHeader.SizeOfStackCommit end namespace end macro macro heap? reserve*,commit:0 namespace PE store reserve at PE:OptionalHeader.SizeOfHeapReserve store commit at PE:OptionalHeader.SizeOfHeapCommit end namespace end macro calminstruction calminstruction?.initsym? var*, val& publish var, val end calminstruction calminstruction calminstruction?.asm? line& local name, i initsym name, name.0 match name.i, name compute i, i+1 arrange name, name.i publish name, line arrange line, =assemble name assemble line end calminstruction macro section? namespace PE repeat SECTION_DIRECTORIES end data end repeat local AREA,DATA_START,DATA_END AREA:: DATA_START = $$ DATA_END = $-($%-$%%) CheckSumBlocks reequ CheckSumBlocks,AREA,DATA_START,DATA_END SECTION_SIZE = $ - SECTION_BASE store SECTION_SIZE at PE:SectionTable.VirtualSize+SECTION_INDEX*SectionTable.ENTRY_LENGTH align SECTION_ALIGNMENT SECTION_BASE = $ section $%% align FILE_ALIGNMENT,0 RAW_DATA_SIZE = $% - FILE_OFFSET store RAW_DATA_SIZE at PE:SectionTable.SizeOfRawData+SECTION_INDEX*SectionTable.ENTRY_LENGTH FILE_OFFSET = $% org SECTION_BASE load SECTION_CHARACTERISTICS from PE:SectionTable.Characteristics+SECTION_INDEX*SectionTable.ENTRY_LENGTH if SECTION_SIZE > 0 & RAW_DATA_SIZE = 0 SECTION_CHARACTERISTICS = SECTION_CHARACTERISTICS or IMAGE_SCN_CNT_UNINITIALIZED_DATA store SECTION_CHARACTERISTICS at PE:SectionTable.Characteristics+SECTION_INDEX*SectionTable.ENTRY_LENGTH end if if LEGACY_HEADERS if SECTION_CHARACTERISTICS and IMAGE_SCN_CNT_CODE & RAW_DATA_SIZE > 0 load CODE_SIZE from PE:OptionalHeader.SizeOfCode if CODE_SIZE = 0 load CODE_BASE from PE:SectionTable.VirtualAddress+SECTION_INDEX*SectionTable.ENTRY_LENGTH store CODE_BASE at PE:OptionalHeader.BaseOfCode end if CODE_SIZE = CODE_SIZE + RAW_DATA_SIZE store CODE_SIZE at PE:OptionalHeader.SizeOfCode end if if SECTION_CHARACTERISTICS and IMAGE_SCN_CNT_INITIALIZED_DATA & RAW_DATA_SIZE > 0 load DATA_SIZE from PE:OptionalHeader.SizeOfInitializedData if DATA_SIZE = 0 & MAGIC <> 0x20B load DATA_BASE from PE:SectionTable.VirtualAddress+SECTION_INDEX*SectionTable.ENTRY_LENGTH store DATA_BASE at PE:OptionalHeader.BaseOfData end if DATA_SIZE = DATA_SIZE + RAW_DATA_SIZE store DATA_SIZE at PE:OptionalHeader.SizeOfInitializedData end if if SECTION_CHARACTERISTICS and IMAGE_SCN_CNT_UNINITIALIZED_DATA load BSS_SIZE from PE:OptionalHeader.SizeOfUninitializedData BSS_SIZE = BSS_SIZE + SECTION_SIZE store BSS_SIZE at PE:OptionalHeader.SizeOfUninitializedData end if end if if DEFINED_SECTION | SECTION_SIZE > 0 SECTION_INDEX = SECTION_INDEX + 1 end if end namespace end macro macro section? declaration* namespace PE section DEFINED_SECTION = 1 store SECTION_BASE-IMAGE_BASE at PE:SectionTable.VirtualAddress+SECTION_INDEX*SectionTable.ENTRY_LENGTH store FILE_OFFSET at PE:SectionTable.PointerToRawData+SECTION_INDEX*SectionTable.ENTRY_LENGTH SECTION_DIRECTORIES = 0 match name attributes, declaration store name:qword at PE:SectionTable.Name+SECTION_INDEX*SectionTable.ENTRY_LENGTH SECTION_CHARACTERISTICS = 0 local seq define seq attributes: while 1 match :, seq break else match =readable? tail, seq redefine seq tail SECTION_CHARACTERISTICS = SECTION_CHARACTERISTICS or IMAGE_SCN_MEM_READ else match =writeable? tail, seq redefine seq tail SECTION_CHARACTERISTICS = SECTION_CHARACTERISTICS or IMAGE_SCN_MEM_WRITE else match =writable? tail, seq redefine seq tail SECTION_CHARACTERISTICS = SECTION_CHARACTERISTICS or IMAGE_SCN_MEM_WRITE else match =executable? tail, seq redefine seq tail SECTION_CHARACTERISTICS = SECTION_CHARACTERISTICS or IMAGE_SCN_MEM_EXECUTE else match =discardable? tail, seq redefine seq tail SECTION_CHARACTERISTICS = SECTION_CHARACTERISTICS or IMAGE_SCN_MEM_DISCARDABLE else match =shareable? tail, seq redefine seq tail SECTION_CHARACTERISTICS = SECTION_CHARACTERISTICS or IMAGE_SCN_MEM_SHARED else match =import? tail, seq redefine seq tail SECTION_DIRECTORIES = SECTION_DIRECTORIES + 1 data import else match =export? tail, seq redefine seq tail SECTION_DIRECTORIES = SECTION_DIRECTORIES + 1 data export else match =resource? =from? path tail, seq redefine seq tail SECTION_DIRECTORIES = SECTION_DIRECTORIES + 1 data resource from path else match =resource? tail, seq redefine seq tail SECTION_DIRECTORIES = SECTION_DIRECTORIES + 1 data resource else match =fixups? tail, seq redefine seq tail SECTION_DIRECTORIES = SECTION_DIRECTORIES + 1 data fixups else match =code? tail, seq redefine seq tail SECTION_CHARACTERISTICS = SECTION_CHARACTERISTICS or IMAGE_SCN_CNT_CODE else match =data? tail, seq redefine seq tail SECTION_CHARACTERISTICS = SECTION_CHARACTERISTICS or IMAGE_SCN_CNT_INITIALIZED_DATA else match =udata? tail, seq redefine seq tail SECTION_CHARACTERISTICS = SECTION_CHARACTERISTICS or IMAGE_SCN_CNT_UNINITIALIZED_DATA else match attribute tail, seq err 'unknown attribute "',`attribute,'"' redefine seq : end match end while store SECTION_CHARACTERISTICS at PE:SectionTable.Characteristics+SECTION_INDEX*SectionTable.ENTRY_LENGTH else store declaration:qword at PE:SectionTable.Name+SECTION_INDEX*SectionTable.ENTRY_LENGTH end match end namespace end macro macro data? type* namespace PE local number,content define content match =export?, type number = 0 else match =import?, type number = 1 else match =resource? =from? path, type number = 2 define content resource_from path else match =resource?, type number = 2 else match =fixups?, type number = 5 define content fixups else number = type end match define DATA_DIRECTORY number load DATA_BASE:dword from PE:RvaAndSizes.Rva+DATA_DIRECTORY*RvaAndSizes.ENTRY_LENGTH if DATA_BASE = 0 store $-IMAGE_BASE:dword at PE:RvaAndSizes.Rva+DATA_DIRECTORY*RvaAndSizes.ENTRY_LENGTH match instruction, content instruction end match else err 'data already defined' end if end namespace end macro macro end?.data? namespace PE load DATA_BASE:dword from PE:RvaAndSizes.Rva+DATA_DIRECTORY*RvaAndSizes.ENTRY_LENGTH store $-IMAGE_BASE-DATA_BASE:dword at PE:RvaAndSizes.Size+DATA_DIRECTORY*RvaAndSizes.ENTRY_LENGTH restore DATA_DIRECTORY end namespace end macro macro PE.resource_directory? namespace PE Resource: rb RESOURCE_HEADERS_LENGTH Resource.counter = 0 define RESOURCE_DIRECTORIES_LIST Resource_root Resource_root.counter = 0 end namespace end macro macro PE.resource_data? type*,id*,lang*,codepage:0 namespace PE local _type,_id,_lang _type = type _id = id _lang = lang if ~ type eqtype 0 _type = _type shl 32 end if if ~ id eqtype 0 _id = id shl 32 end if if ~ lang eqtype 0 _lang = lang shl 32 end if repeat 1, %type:_type, %id:_id, %lang:_lang if ~ defined Resource_#%type#_#%id.counter if ~ defined Resource_#%type.counter repeat 1, i:Resource_root.counter Resource_root.entry#i = type Resource_root.offset#i = (Resource_#%type - Resource) or 80000000h end repeat Resource_root.counter = Resource_root.counter + 1 match list, RESOURCE_DIRECTORIES_LIST define RESOURCE_DIRECTORIES_LIST list,Resource_#%type end match Resource_#%type.counter = 0 end if repeat 1, i:Resource_#%type.counter Resource_#%type.entry#i = id Resource_#%type.offset#i = (Resource_#%type#_#%id - Resource) or 80000000h end repeat Resource_#%type.counter = Resource_#%type.counter + 1 match list, RESOURCE_DIRECTORIES_LIST define RESOURCE_DIRECTORIES_LIST list,Resource_#%type#_#%id end match Resource_#%type#_#%id.counter = 0 end if repeat 1, i:Resource_#%type#_#%id.counter Resource_#%type#_#%id.entry#i = lang Resource_#%type#_#%id.offset#i = Resource_#%type#_#%id#_#%lang - Resource end repeat Resource_#%type#_#%id.counter = Resource_#%type#_#%id.counter + 1 repeat 1, i:Resource.counter Resource_#%type#_#%id#_#%lang := Resource.entry#i Resource.cp#i := codepage Resource.data#i: end repeat end repeat end namespace end macro macro PE.end_resource_data? namespace PE repeat 1, i:Resource.counter Resource.size#i := $ - Resource.data#i end repeat Resource.counter = Resource.counter + 1 align 4 end namespace end macro macro PE.end_resource_directory? namespace PE RESOURCE_HEADERS_POINTER = 0 match list, RESOURCE_DIRECTORIES_LIST iterate dir, list dir := Resource + RESOURCE_HEADERS_POINTER RESOURCE_HEADERS_POINTER = RESOURCE_HEADERS_POINTER + 16 + dir.counter * 8 local x,y,z,a,b x = dir.counter shr 1 while x > 0 y = x while y < dir.counter z = y while z-x >= 0 repeat 1, i:z, j:z-x if dir.entry#i eqtype 0 if ~ dir.entry#j eqtype 0 | dir.entry#i >= dir.entry#j z = 0 end if else if ~ dir.entry#j eqtype 0 a = dir.entry#i bswap lengthof dir.entry#i b = dir.entry#j bswap lengthof dir.entry#j if ( lengthof a >= lengthof b & a shr ((lengthof a - lengthof b)*8) >= b ) | ( lengthof a < lengthof b & a > b shr ((lengthof b - lengthof a)*8) ) z = 0 end if end if if z > 0 a = dir.entry#i b = dir.offset#i dir.entry#i = dir.entry#j dir.offset#i = dir.offset#j dir.entry#j = a dir.offset#j = b z = z - x end if end repeat end while y = y + 1 end while x = x shr 1 end while end iterate iterate dir, list store __TIME__ : 4 at dir + 4 dir.names_counter = 0 repeat dir.counter, i:0 if dir.entry#i eqtype 0 store dir.entry#i : 4 at dir + 16 + i * 8 else dir.names_counter = dir.names_counter + 1 repeat 1, %id:dir.entry#i if ~ defined Resource_string#%id restore Resource_string#%id Resource_string#%id = Resource + RESOURCE_HEADERS_POINTER if lengthof dir.entry#i and 1 err 'a word-aligned string is expected as a name' end if RESOURCE_HEADERS_POINTER = RESOURCE_HEADERS_POINTER + lengthof dir.entry#i + 2 store (lengthof dir.entry#i)/2 : 2 at Resource_string#%id store dir.entry#i : lengthof dir.entry#i at Resource_string#%id + 2 end if store (Resource_string#%id - Resource) or 80000000h : 4 at dir + 16 + i * 8 end repeat end if store dir.offset#i : 4 at dir + 16 + i * 8 + 4 end repeat store dir.names_counter : 2 at dir + 12 store dir.counter - dir.names_counter : 2 at dir + 14 end iterate end match if RESOURCE_HEADERS_POINTER and 11b RESOURCE_HEADERS_POINTER = RESOURCE_HEADERS_POINTER + 4 - RESOURCE_HEADERS_POINTER and 11b end if repeat Resource.counter, i:0 Resource.entry#i := Resource + RESOURCE_HEADERS_POINTER RESOURCE_HEADERS_POINTER = RESOURCE_HEADERS_POINTER + 16 store RVA(Resource.data#i) : 4 at Resource.entry#i store Resource.size#i : 4 at Resource.entry#i + 4 store Resource.cp#i : 4 at Resource.entry#i + 8 end repeat RESOURCE_HEADERS_LENGTH = RESOURCE_HEADERS_POINTER end namespace end macro macro PE.resource_from path* local res_file,res_size,res_header_size,res_data_size,res_data local offset,char,type,id,lang virtual at 0 res_file:: file path res_size := $ end virtual PE.resource_directory offset = 0 while offset < res_size load res_header_size : 4 from res_file : offset + 4 load res_data_size : 4 from res_file : offset + 0 if res_data_size > 0 offset =: offset + 8 load char : 2 from res_file : offset if char = 0FFFFh load char : 2 from res_file : offset + 2 type = +char offset = offset + 4 else while 1 if char = 0 load type : (%-1)*2 from res_file : offset offset = offset + (% + % and 1)*2 break end if load char : 2 from res_file : offset + %*2 end while end if load char : 2 from res_file : offset if char = 0FFFFh load char : 2 from res_file : offset + 2 id = +char offset = offset + 4 else while 1 if char = 0 load id : (%-1)*2 from res_file : offset offset = offset + (% + % and 1)*2 break end if load char : 2 from res_file : offset + %*2 end while end if load char : 2 from res_file : offset + 6 lang = +char restore offset PE.resource_data type,id,lang load res_data : res_data_size from res_file : offset + res_header_size db res_data PE.end_resource_data end if offset = offset + res_header_size + res_data_size if offset and 11b offset = offset + 4 - offset and 11b end if end while PE.end_resource_directory end macro macro PE.fixups namespace PE Fixups: calminstruction BuildFixups local PAGE_RVA, BLOCK_HEADER, BLOCK_SIZE local INDEX, ADDRESS, TYPE, FIXUP compute PAGE_RVA, -1 compute BLOCK_HEADER, 0 compute BLOCK_SIZE, 0 compute INDEX,0 process: check INDEX = NUMBER_OF_RELOCATIONS jyes close_block asm load ADDRESS:4 from relocated_addresses:INDEX shl 2 check PAGE_RVA >= 0 & ADDRESS and not 0FFFh = PAGE_RVA jyes append_to_block close_block: check BLOCK_HEADER jno start_new_block check BLOCK_SIZE and 11b jno finish_block asm dw 0 compute BLOCK_SIZE, BLOCK_SIZE + 2 finish_block: asm store BLOCK_SIZE:4 at BLOCK_HEADER+4 start_new_block: check INDEX = NUMBER_OF_RELOCATIONS jyes done compute PAGE_RVA, ADDRESS and not 0FFFh compute BLOCK_HEADER, $ asm dd PAGE_RVA, 0 compute BLOCK_SIZE, 8 append_to_block: asm load TYPE:2 from relocation_types:INDEX shl 1 compute FIXUP, (ADDRESS and 0FFFh) or (TYPE shl 12) asm dw FIXUP compute BLOCK_SIZE, BLOCK_SIZE + 2 compute INDEX, INDEX + 1 jump process done: end calminstruction BuildFixups end namespace end macro if defined PE.Fixups calminstruction dword? value* compute value, value check value relativeto 0 | ~ value relativeto PE.RELOCATION jyes plain local offset compute offset, $% emit 4, value - PE.RELOCATION check $% > offset jno done asm store $-4-PE.IMAGE_BASE:4 at PE.relocated_addresses:PE.RELOCATION_INDEX shl 2 asm store IMAGE_REL_BASED_HIGHLOW:2 at PE.relocation_types:PE.RELOCATION_INDEX shl 1 compute PE.RELOCATION_INDEX, PE.RELOCATION_INDEX + 1 done: exit plain: emit 4, value end calminstruction calminstruction qword? value* compute value, value check value relativeto 0 | ~ value relativeto PE.RELOCATION jyes plain local offset compute offset, $% emit 8, value - PE.RELOCATION check $% > offset jno done asm store $-8-PE.IMAGE_BASE:4 at PE.relocated_addresses:PE.RELOCATION_INDEX shl 2 asm store IMAGE_REL_BASED_DIR64:2 at PE.relocation_types:PE.RELOCATION_INDEX shl 1 compute PE.RELOCATION_INDEX, PE.RELOCATION_INDEX + 1 done: exit plain: emit 8, value end calminstruction iterate , dd,dword, dq,qword calminstruction dd? definitions& local value, n start: match value=,definitions, definitions, () jyes recognize match value, definitions arrange definitions, recognize: match n =dup? value, value, () jyes duplicate match ?, value jyes reserve call dword, value next: match , definitions jno start take , definitions take definitions, definitions jyes next exit reserve: emit dword jump next duplicate: match (value), value stack: check n jno next take definitions, value arrange value, definitions compute n, n - 1 jump stack end calminstruction calminstruction (label) dd? definitions& local cmd arrange cmd, =label label : =dword assemble cmd arrange cmd, =dd definitions assemble cmd end calminstruction end iterate end if postpone purge section? section namespace PE SIZE_OF_IMAGE := SECTION_BASE - IMAGE_BASE NUMBER_OF_SECTIONS := SECTION_INDEX NUMBER_OF_RELOCATIONS := RELOCATION_INDEX end namespace end postpone postpone ? namespace PE CHECKSUM = 0 calminstruction CheckSum local AREA, DATA_START, DATA_END, POS, H get_block: match AREA=,DATA_START=,DATA_END=,CheckSumBlocks, CheckSumBlocks jyes block_ready match AREA=,DATA_START=,DATA_END, CheckSumBlocks jyes last_block exit last_block: arrange CheckSumBlocks, block_ready: compute POS, DATA_START process_block: check POS + 2 <= DATA_END jno finish_block asm load H:2 from AREA:POS compute CHECKSUM, CHECKSUM + H compute POS, POS + 2 jump process_block finish_block: check POS + 1 = DATA_END jno reduce_checksum asm load H:1 from AREA:POS compute CHECKSUM, CHECKSUM + H reduce_checksum: check CHECKSUM shr 16 jno get_block compute CHECKSUM, CHECKSUM shr 16 + CHECKSUM and 0FFFFh jump reduce_checksum done: end calminstruction CheckSum CHECKSUM = CHECKSUM + $% store CHECKSUM at PE:OptionalHeader.CheckSum end namespace end postpone