<< index Android/Java/x86/... opcodes tables PDF tricks Portable Executable x86 oddities PEThis page deals with the PE format, or more specifically, x86/x64 Windows (from XP to W7) binaries (ie, not other OSes or systems, not OBJ format, etc...) if you're not familiar with this format, check PE 101 - a Windows executable walkthrough. It deals with the reality of the loader, not the theory of the format itself, as specified in Microsoft PE and COFF Specification. Many malwares or packers actually run without a problem, while they theoretically shouldn't. All proof of concepts are included with source:
required elementsa standard (high aligments, sections, imports) PE such as normal can be defined with only the following structure elements: at IMAGE_DOS_HEADER.e_magic, db 'MZ' at IMAGE_DOS_HEADER.e_lfanew, dd NT_Signature - IMAGEBASE ... at IMAGE_NT_HEADERS.Signature, db 'PE', 0, 0 ... at IMAGE_FILE_HEADER.Machine, dw IMAGE_FILE_MACHINE_I386 at IMAGE_FILE_HEADER.NumberOfSections, dw NUMBEROFSECTIONS at IMAGE_FILE_HEADER.SizeOfOptionalHeader, dw SIZEOFOPTIONALHEADER at IMAGE_FILE_HEADER.Characteristics, dw IMAGE_FILE_EXECUTABLE_IMAGE ... istruc IMAGE_OPTIONAL_HEADER32 at IMAGE_OPTIONAL_HEADER32.Magic, dw IMAGE_NT_OPTIONAL_HDR32_MAGIC at IMAGE_OPTIONAL_HEADER32.AddressOfEntryPoint, dd EntryPoint - IMAGEBASE at IMAGE_OPTIONAL_HEADER32.ImageBase, dd IMAGEBASE at IMAGE_OPTIONAL_HEADER32.SectionAlignment, dd SECTIONALIGN at IMAGE_OPTIONAL_HEADER32.FileAlignment, dd FILEALIGN at IMAGE_OPTIONAL_HEADER32.MajorSubsystemVersion, dw 4 at IMAGE_OPTIONAL_HEADER32.SizeOfImage, dd 2 * SECTIONALIGN at IMAGE_OPTIONAL_HEADER32.SizeOfHeaders, dd SIZEOFHEADERS at IMAGE_OPTIONAL_HEADER32.Subsystem, dw IMAGE_SUBSYSTEM_WINDOWS_CUI at IMAGE_OPTIONAL_HEADER32.NumberOfRvaAndSizes, dd 16 ... at IMAGE_DATA_DIRECTORY_16.ImportsVA, dd Import_Descriptor - IMAGEBASE ... at IMAGE_SECTION_HEADER.VirtualSize, dd 1 * SECTIONALIGN at IMAGE_SECTION_HEADER.VirtualAddress, dd 1 * SECTIONALIGN at IMAGE_SECTION_HEADER.SizeOfRawData, dd 1 * FILEALIGN at IMAGE_SECTION_HEADER.PointerToRawData, dd 1 * FILEALIGN at IMAGE_SECTION_HEADER.Characteristics, dd IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE so everything else is not required. a more extreme PE can rely on even less elements:
at IMAGE_NT_HEADERS.Signature, db 'PE', 0, 0 ... at IMAGE_FILE_HEADER.Machine, dw IMAGE_FILE_MACHINE_I386 at IMAGE_FILE_HEADER.Characteristics, dw IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_32BIT_MACHINE ... at IMAGE_OPTIONAL_HEADER32.Magic, dw IMAGE_NT_OPTIONAL_HDR32_MAGIC at IMAGE_OPTIONAL_HEADER32.AddressOfEntryPoint, dd EntryPoint - IMAGEBASE ; not strictly required at IMAGE_OPTIONAL_HEADER32.ImageBase, dd IMAGEBASE ; not required under XP at IMAGE_OPTIONAL_HEADER32.SectionAlignment, dd SECTIONALIGN at IMAGE_OPTIONAL_HEADER32.FileAlignment, dd FILEALIGN at IMAGE_OPTIONAL_HEADER32.MajorSubsystemVersion, dw 4 at IMAGE_OPTIONAL_HEADER32.SizeOfImage, dd SIZEOFIMAGE at IMAGE_OPTIONAL_HEADER32.SizeOfHeaders, dd SIZEOFIMAGE - 1 ; required for XP at IMAGE_OPTIONAL_HEADER32.Subsystem, dw IMAGE_SUBSYSTEM_WINDOWS_CUI as most elements are actually unused, they can be used for other reasons.
32b and 64b differences
structure by structureDOS Header ('MZ Header')
DOS_HEADER: ... .e_cparhdr dw (dos_stub - DOS_HEADER) >> 4 ; defines MZ stub entry point ... align 010h, db 0 dos_stub: bits 16 push cs pop ds mov dx, dos_msg - dos_stub mov ah, 9 int 21h mov ax, 4c01h int 21h dos_msg db 'This program cannot be run in DOS mode.', 0dh, 0dh, 0ah, '$' exe2pethis file is a broken 32b PE that is fixed (on disk), then launched by its (16b) dos stub. What's the most surprising is that a 16b process can launch the 32b part of a PE: if you were in a DOS environment, the 16b stub would be executed. e_magic
at IMAGE_DOS_HEADER.e_magic, db 'ZM' e_cparhrd
e_lfanew
DOS_HEADER: .e_magic dw 'MZ' align 4, db 0 istruc IMAGE_NT_HEADERS at IMAGE_NT_HEADERS.Signature, db 'PE',0,0 ... at IMAGE_OPTIONAL_HEADER32.SectionAlignment, dd 4 ; also sets e_lfanew at IMAGE_OPTIONAL_HEADER32.FileAlignment, dd 4 Rich header
align 16, db 0 RichHeader: RichKey EQU 092033d19h dd "DanS" ^ RichKey , 0 ^ RichKey, 0 ^ RichKey , 0 ^ RichKey dd 0131f8eh ^ RichKey , 7 ^ RichKey, 01220fch ^ RichKey, 1 ^ RichKey dd "Rich", 0 ^ RichKey , 0, 0 align 16, db 0 NT Headers ('PE Header')
Machine
NumberOfSections
TimeDateStamp
PointerToSymbolTable/NumberOfSymbolsno importance whatsoever for the loader SizeOfOptionalHeader
Thus, it can be null (the section table will overlap the Optional Header, or can be null when no sections are present), or bigger than the file (the section table will be in virtual space, full of zeroes), but can't be negative.
Characteristics
... at IMAGE_FILE_HEADER.Characteristics, dw IMAGE_FILE_EXECUTABLE_IMAGE ... at IMAGE_OPTIONAL_HEADER32.AddressOfEntryPoint, dd 31415926h ... Optional Header
Magic
MajorLinkerVersion/MinorLinkerVersionno particular importance whatsoever if LinkerVersion < 2.5, Microsoft AppLocker might wrongly report is not a valid Win32 application. (Exception from HRESULT: 0x800700C1) for no apparent reason. Changing these fields might fix the problem. SizeOfCode/SizeOfInitializedData/SizeOfUninitializedDatano particular importance whatsoever AddressOfEntryPoint
EntryPoint: istruc IMAGE_DOS_HEADER at IMAGE_DOS_HEADER.e_magic, db 'MZ' push Msg call [__imp__printf] add esp, 1 * 4 push 0 call [__imp__ExitProcess] at IMAGE_DOS_HEADER.e_lfanew, dd NT_Signature - IMAGEBASE
at IMAGE_OPTIONAL_HEADER32.AddressOfEntryPoint, dd EntryPoint - IMAGEBASE - 1 ; -1 to start in virtual space ... ; actual EntryPoint starts here... ; there will be a virtual 00 before, so 00 C0 will be executed as `add al, al` EntryPoint: db 0c0h ...
BaseOfCode/BaseOfDatano particular importance whatsoever ImageBase
SectionAlignment/FileAlignment
MajorOperatingSystemVersion/MinorOperatingSystemVersion/MajorImageVersion/MinorImageVersionno particular importance whatsoever MajorSubsystemVersion/MinorSubsystemVersion
... at IMAGE_OPTIONAL_HEADER32.MajorSubsystemVersion, dw 6 ; <= at IMAGE_OPTIONAL_HEADER32.MinorSubsystemVersion, dw 3 ; <= ... at IMAGE_DATA_DIRECTORY_16.Load, dd LoadConfig - IMAGEBASE, LOADCONFIGSIZE ... at IMAGE_LOAD_CONFIG_DIRECTORY32.Size, dd IMAGE_LOAD_CONFIG_DIRECTORY32_size at IMAGE_LOAD_CONFIG_DIRECTORY32.SecurityCookie, dd cookie ... ... istruc IMAGE_LOAD_CONFIG_DIRECTORY32 at IMAGE_LOAD_CONFIG_DIRECTORY32.Size, dd IMAGE_LOAD_CONFIG_DIRECTORY32_size at IMAGE_LOAD_CONFIG_DIRECTORY32.GuardFlags, dd IMAGE_GUARD_SECURITY_COOKIE_UNUSED iend ... Reserved1 (Win32VersionValue)
OSMAJOR equ 31 OSMINOR equ 41 BUILD equ 5926 ID equ 3 ; [0;3] at IMAGE_OPTIONAL_HEADER32.Win32VersionValue, dd OSMAJOR | (OSMINOR << 8) | ((BUILD & 03fffh) << 16) | (((ID & 3) ^ 02h) << 30) SizeOfImage
SizeOfHeaders
CheckSum
SubsystemFrom a technical perspective, drivers and gui/console PEs are identical, except that:
DllCharacteristics
SizeOfStackReserve/SizeOfStackCommit/SizeOfHeapReserve/SizeOfHeapCommit
LoaderFlagsNumberOfRvaAndSizes
data directoriesexports
at IMAGE_DATA_DIRECTORY_16.ExportsVA, dd Exports_Directory - IMAGEBASE ... Exports_Directory: Characteristics dd 0 TimeDateStamp dd 0 MajorVersion dw 0 MinorVersion dw 0 Name dd aDllName - IMAGEBASE Base dd 0 NumberOfFunctions dd NUMBER_OF_FUNCTIONS NumberOfNames dd NUMBER_OF_NAMES AddressOfFunctions dd address_of_functions - IMAGEBASE AddressOfNames dd address_of_names - IMAGEBASE AddressOfNameOrdinals dd address_of_name_ordinals - IMAGEBASE ... aDllName db 'dll.dll', 0 ... address_of_functions: dd __exp__Export - IMAGEBASE NUMBER_OF_FUNCTIONS equ ($ - address_of_functions) / 4 ... address_of_names: dd a__exp__Export - IMAGEBASE NUMBER_OF_NAMES equ ($ - address_of_names) / 4 ... address_of_name_ordinals: dw 0 ... a__exp__Export db 'export', 0
Exports_Directory: ... Name dd VDELTA + aDllName - IMAGEBASE ... aDllName db 'completely unrelated dll name', 1, 2, 3, 4, 0
... push a_export ... call [__imp__GetProcAddress] jmp eax ... push a_export2 ... call [__imp__GetProcAddress] ; we assume EAX==0 because it should fail add eax, end_ - 07fh ; expected error code: 7fh ... address_of_names: dd a_export - IMAGEBASE dd a_zz - IMAGEBASE dd a_export2 - IMAGEBASE
EntryPoint: ownexports.exe_iat: dd 80000000h ; => dd 000101468h => 68 14100010 push 10001014 dd 80000001h ; => dd 04015FF10h => FF15 40100010 call [10001040] dd 80000002h ; => dd 083100010h => 83C4 04 add esp,4 dd 80000003h ; => dd 0CCC304C4h => C3 retn dd 0 ... Exports_Directory: ... address_of_functions: dd 000101468h - IMAGEBASE dd 04015FF10h - IMAGEBASE dd 083100010h - IMAGEBASE dd 0CCC304C4h - IMAGEBASE NBFUNCTIONS equ ($ - address_of_functions) / 4 ...
dll.dll_iat: __imp__export: dd 1 << 31 | 314h ; highest bit set to indicate imports by ordinal Exports_Directory: ... Base dd 313h ... AddressOfFunctions dd address_of_functions - IMAGEBASE ... address_of_functions: dd -1 ; bogus entry that will be 313h dd __exp__Export - IMAGEBASE
address_of_functions: dd amsvcrt_printf - IMAGEBASE ... address_of_names: dd a__exp__Export - IMAGEBASE ... amsvcrt_printf db "msvcrt.printf", 0 ; forwarding string can only be within the official export directory bounds a__exp__Export db 'ExitProcess', 0 EXPORTS_SIZE equ $ - Exports_Directory
... address_of_functions: dd adllfwloop_loophere - IMAGEBASE dd adllfwloop_looponceagain - IMAGEBASE dd amsvcrt_printf - IMAGEBASE dd adllfwloop_GroundHogDay - IMAGEBASE dd adllfwloop_Yang - IMAGEBASE dd adllfwloop_Ying - IMAGEBASE NUMBER_OF_FUNCTIONS equ ($ - address_of_functions) / 4 _d address_of_names: dd a__exp__ExitProcess - IMAGEBASE dd a__exp__LoopHere - IMAGEBASE dd a__exp__LoopOnceAgain - IMAGEBASE dd a__exp__GroundHogDay - IMAGEBASE dd a__exp__Ying - IMAGEBASE dd a__exp__Yang - IMAGEBASE NUMBER_OF_NAMES equ ($ - address_of_names) / 4 ... imports
at IMAGE_DATA_DIRECTORY_16.ImportsVA, dd Import_Descriptor - IMAGEBASE ... EntryPoint: call [__imp__export] ... Import_Descriptor: ... dll.dll_DESCRIPTOR: dd dll.dll_hintnames - IMAGEBASE dd 0, 0 dd dll.dll - IMAGEBASE dd dll.dll_iat - IMAGEBASE ;terminator dd 0, 0, 0, 0, 0 ... dll.dll_hintnames: dd hndllexport - IMAGEBASE dd 0 ... hndllexport: dw 0 db 'export', 0 ... dll.dll_iat: __imp__export: dd hndllexport - IMAGEBASE dd 0 ... dll.dll db 'dll.dll', 0
kernel32.dll db 'kernel32', 0 msvcrt.dll db 'msvcrt', 0
kernel32.dll db 'kernel32.dll...', 0 msvcrt.dll db 'msvcrt.dll.', 0
kernel32.dll db 'KernEl32', 0 msvcrt.dll db 'mSVCrT', 0
... Import_Descriptor: kernel32.dll_DESCRIPTOR: dd kernel32.dll_iat - IMAGEBASE dd 0, 0 dd kernel32.dll - IMAGEBASE dd kernel32.dll_iat - IMAGEBASE ...
;terminator is partially in virtual space dd msvcrt.dll_hintnames - IMAGEBASE dd 0, 0 <EOF>
... ;disguised terminator - dll address is 0 dd msvcrt.dll_hintnames - IMAGEBASE dd 0, 0 dd 0 ;msvcrt.dll - IMAGEBASE dd msvcrt.dll_iat - IMAGEBASE ...
Import_Descriptor: ;kernel32.dll_DESCRIPTOR: dd 0 ; can't put the IAT over this one msvcrt.dll_iat: __imp__printf: dd hnprintf - IMAGEBASE dd 0 dd kernel32.dll - IMAGEBASE dd kernel32.dll_iat - IMAGEBASE ;msvcrt.dll_DESCRIPTOR: dd 0 kernel32.dll_iat: __imp__ExitProcess: dd hnExitProcess - IMAGEBASE dd 0 dd msvcrt.dll - IMAGEBASE dd msvcrt.dll_iat - IMAGEBASE
Import_Descriptor: ;kernel32.dll_DESCRIPTOR: dd 0 msvcrt.dll_iat: __imp__printf: dd 80000000h + 742 ; printf dd 0 dd kernel32.dll - IMAGEBASE dd kernel32.dll_iat - IMAGEBASE ;msvcrt.dll_DESCRIPTOR: dd 0 kernel32.dll_iat: __imp__ExitProcess: dd 80000000h + 183 ; ExitProcess dd 0 dd msvcrt.dll - IMAGEBASE dd msvcrt.dll_iat - IMAGEBASE ;terminator kernel32.dll db 'kernel32' ,0 ; not W2k compatible msvcrt.dll: dd 'msvcrt',0 align 4, db 0 ; <= imports terminator NULL
It doesn't accept to import to mscoree (without extension). resources
... at IMAGE_DATA_DIRECTORY_16.ResourceVA, dd Directory_Entry_Resource - IMAGEBASE ... push SOME_TYPE ; lpType push SOME_NAME ; lpName push 0 ; hModule call [__imp__FindResourceA] ... Directory_Entry_Resource: ; root directory istruc IMAGE_RESOURCE_DIRECTORY at IMAGE_RESOURCE_DIRECTORY.NumberOfIdEntries, dw 1 iend istruc IMAGE_RESOURCE_DIRECTORY_ENTRY at IMAGE_RESOURCE_DIRECTORY_ENTRY.NameID, dd SOME_TYPE ; .. resource type of that directory at IMAGE_RESOURCE_DIRECTORY_ENTRY.OffsetToData, dd (1<<31) | (resource_directory_type - Directory_Entry_Resource) iend resource_directory_type: istruc IMAGE_RESOURCE_DIRECTORY at IMAGE_RESOURCE_DIRECTORY.NumberOfIdEntries, dw 1 iend istruc IMAGE_RESOURCE_DIRECTORY_ENTRY at IMAGE_RESOURCE_DIRECTORY_ENTRY.NameID, dd SOME_NAME ; name of the underneath resource at IMAGE_RESOURCE_DIRECTORY_ENTRY.OffsetToData, dd (1<<31) | (resource_directory_language - Directory_Entry_Resource) iend resource_directory_language: istruc IMAGE_RESOURCE_DIRECTORY at IMAGE_RESOURCE_DIRECTORY.NumberOfIdEntries, dw 1 iend istruc IMAGE_RESOURCE_DIRECTORY_ENTRY at IMAGE_RESOURCE_DIRECTORY_ENTRY.OffsetToData, dd resource_entry - Directory_Entry_Resource iend resource_entry: istruc IMAGE_RESOURCE_DATA_ENTRY at IMAGE_RESOURCE_DATA_ENTRY.OffsetToData, dd resource_data - IMAGEBASE at IMAGE_RESOURCE_DATA_ENTRY.Size1, dd RESOURCE_SIZE iend resource_data: Msg db " * message stored in resources", 0ah, 0 RESOURCE_SIZE equ $ - resource_data
resource_directory_type: ... at IMAGE_RESOURCE_DIRECTORY_ENTRY.OffsetToData, dd (1<<31) | (resource_directory_loop - Directory_Entry_Resource) ... resource_directory_loop: ... ; double level recursivity ... at IMAGE_RESOURCE_DIRECTORY_ENTRY.OffsetToData, dd (1<<31) | (resource_directory_type - Directory_Entry_Resource) ... ; direct recursivity ... at IMAGE_RESOURCE_DIRECTORY_ENTRY.OffsetToData, dd (1<<31) | (resource_directory_loop - Directory_Entry_Resource)
SOME_TYPE equ 315h SOME_NAME equ 7354h ... push SOME_TYPE ; lpType push SOME_NAME ; lpName push 0 ; hModule call [__imp__FindResourceA] ... at IMAGE_RESOURCE_DIRECTORY_ENTRY.NameID, dd SOME_TYPE ; .. resource type of that directory ... at IMAGE_RESOURCE_DIRECTORY_ENTRY.NameID, dd SOME_NAME ; name of the underneath resource push atype ; lpType push ares ; lpName push 0 ; hModule call [__imp__FindResourceA] ... atype db '#315', 0 ares db "#7354", 0 ... SOME_TYPE equ 315 SOME_NAME equ 7354 ... at IMAGE_RESOURCE_DIRECTORY_ENTRY.NameID, dd SOME_TYPE ; .. resource type of that directory ... at IMAGE_RESOURCE_DIRECTORY_ENTRY.NameID, dd SOME_NAME ; name of the underneath resource ... push arestype ; lpType push aresname ; lpName push 0 ; hModule call [__imp__FindResourceA] ... aresname db 'RES', 0 arestype db 'TYPE', 0 ... .NumberOfNamedEntries dw 0 .NumberOfIdEntries dw 1 .ID dd (1 << 31) | (alrestype - resource_directory) ; .. resource type of that directory ... .NumberOfNamedEntries dw 0 .NumberOfIdEntries dw 1 .ID dd (1 << 31) | (alresname - resource_directory) ; name of the underneath resource ... ; length + widestring alresname dw 3, "R", "E", "S", 0 alrestype dw 4, "T", "Y", "P", "E", 0
at IMAGE_DOS_HEADER.e_magic, db 'MZ' at IMAGE_DOS_HEADER.e_lfanew, dd NT_Signature - IMAGEBASE ... resource_data: Msg db " * resource stored in header and shuffled resource structure", 0ah, 0 RESOURCE_SIZE equ $ - resource_data
Version information
version_cust contains minimal version informations, which generates the version tab but doesn't show any information... at IMAGE_RESOURCE_DIRECTORY_ENTRY.NameID, dd RT_VERSION ; .. resource type ... resource_data: VS_VERSION_INFO: .wLength dw VERSIONLENGTH .wValueLength dw VALUELENGTH .wType dw 0 ; 0 = bin, 1 = text WIDE 'VS_VERSION_INFO' align 4, db 0 Value: istruc VS_FIXEDFILEINFO at VS_FIXEDFILEINFO.dwSignature, dd 0FEEF04BDh iend VALUELENGTH equ $ - Value align 4, db 0 ; no children VERSIONLENGTH equ $ - VS_VERSION_INFO RESOURCE_SIZE equ $ - resource_data ; children StringFileInfo: dw STRINGFILEINFOLEN dw 0 ; no value dw 0 ; type WIDE 'StringFileInfo' align 4, db 0 ; children StringTable: dw STRINGTABLELEN dw 0 ; no value dw 0 WIDE '040904b0' ; required correct align 4, db 0 ;children ; required or won't be displayed by explorer __string 'FileVersion', '' STRINGTABLELEN equ $ - StringTable STRINGFILEINFOLEN equ $ - StringFileInfo istruc VS_FIXEDFILEINFO at VS_FIXEDFILEINFO.dwSignature, dd 0FEEF04BDh times 6 dd 0ffffffffh iend __string 'FileVersion', 'compulsory for version tab' __string 'LegalCopyright', 'corkami.com' __string 'StringFileInfo', '' __string 'Comments', '' __string 'CompanyName', '' __string 'InternalName', '' __string 'LegalTrademarks', '' __string 'OriginalFilename', '' __string 'PrivateBuild', '' __string 'ProductName', '' __string 'ProductVersion', '' __string 'SpecialBuild', '' __string '', '' __string ' ', '' __string ' ** EAT AT JOE"S **', 'best hamburger in town' __string 'FileVersion', 'duplicates are authorized' Manifest
... MYMAN equ 3 ; incorrect - this file wouldn't run if it's set to 1 or 2 ... at IMAGE_RESOURCE_DIRECTORY_ENTRY.NameID, dd MYMAN ... resource_data: db "<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>" ; broken end RESOURCE_SIZE equ $ - resource_data ... exception
security
relocations
Directory_Entry_Basereloc: ... dw (IMAGE_REL_BASED_HIGHLOW << 12) | 0ffh dw 0 dw (IMAGE_REL_BASED_HIGHLOW << 12) | (here - reloc01) here: dw (IMAGE_REL_BASED_HIGHLOW << 12) | (here - reloc01) ... at IMAGE_DATA_DIRECTORY_16.FixupsVA, dd Directory_Entry_Basereloc - IMAGEBASE at IMAGE_DATA_DIRECTORY_16.FixupsSize, dd DIRECTORY_ENTRY_BASERELOC_SIZE ... reloc01: push detach reloc22: call [__imp__printf] ... Directory_Entry_Basereloc: block_start0: .VirtualAddress dd reloc01 - IMAGEBASE .SizeOfBlock dd BASE_RELOC_SIZE_OF_BLOCK0 dw (IMAGE_REL_BASED_HIGHLOW << 12) | (reloc01 + 1 - reloc01) dw (IMAGE_REL_BASED_HIGHLOW << 12) | (reloc22 + 2 - reloc01) BASE_RELOC_SIZE_OF_BLOCK0 equ $ - block_start0 ... DIRECTORY_ENTRY_BASERELOC_SIZE equ $ - Directory_Entry_Basereloc
... reloc40: AddressOfIndex dd SizeOfZeroFill reloc50: AddressOfCallBacks dd CallBacks ... CallBacks: reloc60: dd tls
... block_start: .VirtualAddress dd VDELTA + relocated_reloc - IMAGEBASE ... dw (IMAGE_REL_BASED_MIPS_JMPADDR << 12) ... relocated_reloc: .SizeOfBlock dd (BASE_RELOC_SIZE_OF_BLOCK0 - 40002h - (0fc000000h + (20000h >> 2))) & 0ffffffffh
EntryPoint: reloc01: ;68h push VDELTA + msg crypt168 db 0 dd VDELTA + msg ... Directory_Entry_Basereloc: ; this block will fix the SizeOfBlock of the next block block_start: .VirtualAddress dd VDELTA + relocated_reloc - IMAGEBASE .SizeOfBlock dd BASE_RELOC_SIZE_OF_BLOCK dw (IMAGE_REL_BASED_HIGHLOW << 12) ; + 10000h dw (IMAGE_REL_BASED_ABSOLUTE << 12) dw (IMAGE_REL_BASED_HIGHLOW << 12) ; + 10000h dw (IMAGE_REL_BASED_HIGHADJ << 12) dw (IMAGE_REL_BASED_HIGH << 12) ; + 00001h dw (IMAGE_REL_BASED_LOW << 12) ; + 0 dw (IMAGE_REL_BASED_SECTION << 12) dw (IMAGE_REL_BASED_REL32 << 12) ... ;this block is actually the genuine relocations block_start0: .VirtualAddress dd VDELTA + reloc01 - IMAGEBASE relocated_reloc: .SizeOfBlock dd BASE_RELOC_SIZE_OF_BLOCK0 - 40002h ... %macro cryptblock 2 block_start%1: .VirtualAddress dd VDELTA + %1 - IMAGEBASE .SizeOfBlock dd BASE_RELOC_SIZE_OF_BLOCK%1 dw (IMAGE_REL_BASED_ABSOLUTE << 12) times %2 / 2 dw (IMAGE_REL_BASED_HIGH << 12) BASE_RELOC_SIZE_OF_BLOCK%1 equ $ - block_start%1 %endmacro ;these blocks are the ones to implement the decryption cryptblock crypt168, 068h ...
IMAGEBASE equ 0fffffffffff0000h ... lea ecx, [rel Msg] call [rel __imp__printf] IMAGEBASE equ 0FFFF0000h ... push msg + 20000h call [__imp__printf + 20000h] ... ... IMAGEBASE equ 0FFFF0000h DELTA equ 20000h ... at IMAGE_OPTIONAL_HEADER32.AddressOfEntryPoint, dd EntryPoint - IMAGEBASE + DELTA reloc00: at IMAGE_OPTIONAL_HEADER32.ImageBase, dd IMAGEBASE ... Directory_Entry_Basereloc: block_start1: .VirtualAddress dd reloc00 - IMAGEBASE .SizeOfBlock dd BASE_RELOC_SIZE_OF_BLOCK1 dw (IMAGE_REL_BASED_HIGHLOW << 12) | 0 BASE_RELOC_SIZE_OF_BLOCK1 equ $ - block_start1 ...
debug
copyright
GlobalPtr
TLS
at IMAGE_DATA_DIRECTORY_16.TLSVA, dd Image_Tls_Directory32 - IMAGEBASE ... Image_Tls_Directory32: StartAddressOfRawData dd 0 EndAddressOfRawData dd 0 AddressOfIndex dd some_value AddressOfCallBacks dd CallBacks SizeOfZeroFill dd 0 Characteristics dd 0 ... some_value dd 012345h CallBacks: dd tls dd 0 ... tls: <...>
This is true even under Windows 7, however libraries such as user32.dll might be already unloaded, preventing code using it to work normally.
tls: ... mov dword [CallBacks + 4], tls2 retn ... tls2: ... ... at IMAGE_OPTIONAL_HEADER32.AddressOfEntryPoint, dd 0 - IMAGEBASE ... tls: ... mov dword [CallBacks], tls2 ... call [__imp__ExitProcess] ... tls2: push TLSEnd call [__imp__printf]
AddressOfIndex equ $ + 1 jmp long $
LoadConfig
at IMAGE_DATA_DIRECTORY_16.Load, dd LoadConfig - IMAGEBASE, 40h ; fixed XP value? ... LoadConfig: istruc IMAGE_LOAD_CONFIG_DIRECTORY32 at IMAGE_LOAD_CONFIG_DIRECTORY32.Size, dd IMAGE_LOAD_CONFIG_DIRECTORY32_size ... at IMAGE_LOAD_CONFIG_DIRECTORY32.SecurityCookie, dd cookie at IMAGE_LOAD_CONFIG_DIRECTORY32.SEHandlerTable, dd HandlerTable at IMAGE_LOAD_CONFIG_DIRECTORY32.SEHandlerCount, dd HANDLERCOUNT iend HandlerTable: ... HANDLERCOUNT equ ($ - HandlerTable) / 4
... mov dword [HandlerTable], Handler - IMAGEBASE int3 ...
... call [__imp__RtlGetNtGlobalFlags] ... at IMAGE_LOAD_CONFIG_DIRECTORY32.GlobalFlagsSet, dd FLG_SHOW_LDR_SNAPS ... Bound imports
at IMAGE_DATA_DIRECTORY_16.BoundImportsVA, dd BoundImports - IMAGEBASE ... BoundImports: dd 31415925h ; timestamp of the bound DLL dw bounddll - BoundImports ; it's a WORD relative offset :( dw 0 ... bounddll db 'dllbound.dll', 0 ; we have to duplicate locally this string... :( ... dll.dll_iat: __imp__export: dd 01001008h ;VA of the export of the loaded DLL
dll.dll_iat: __imp__export: dd 01001018h ; corrupted VA of the import
BoundImports: dd 27182818h ; timestamp of the hijacking DLL dw bounddll - BoundImports dw 0 ;terminator dd 0, 0 bounddll db 'dllbound2.dll', 0 ; hijacking DLL name Import table
delay imports
with a 'frontend' in the data directories, with a structure similar to standard imports (adress table + name table) so that external tools can still indicate that imports calls are present. ... at IMAGE_DATA_DIRECTORY_16.DelayImportsVA, dd delay_imports - IMAGEBASE at IMAGE_DATA_DIRECTORY_16.DelayImportsSize, dd DELAY_IMPORTS_SIZE ... delay_imports: istruc _IMAGE_DELAY_IMPORT_DESCRIPTOR at _IMAGE_DELAY_IMPORT_DESCRIPTOR.rvaDLLName, dd msvcrt.dll at _IMAGE_DELAY_IMPORT_DESCRIPTOR.rvaIAT, dd delay_iat - IMAGEBASE at _IMAGE_DELAY_IMPORT_DESCRIPTOR.rvaINT, dd msvcrt_int iend istruc _IMAGE_DELAY_IMPORT_DESCRIPTOR iend delay_iat: __imp__printf: dd __delay__printf dd 0 ... delay_imports: istruc _IMAGE_DELAY_IMPORT_DESCRIPTOR iend ... COM Runtime
reserved
section table
Name
Misc_VirtualSize
... extravirtualspace equ 010000h at IMAGE_OPTIONAL_HEADER32.SizeOfImage, dd (2 + extravirtualspace) * SECTIONALIGN ... at IMAGE_SECTION_HEADER.VirtualSize, dd (1 + extravirtualspace) * SECTIONALIGN ... EntryPoint: VirtualStart equ (extravirtualspace - 1) * SECTIONALIGN + IMAGEBASE mov edi, VirtualStart ; 68 xxxxxxxx push Msg mov al, 68h stosb mov eax, Msg stosd ... jmp VirtualStart
VirtualAddress
SectionHeader: istruc IMAGE_SECTION_HEADER at IMAGE_SECTION_HEADER.VirtualSize, dd 1 * SECTIONALIGN at IMAGE_SECTION_HEADER.VirtualAddress, dd 1 * SECTIONALIGN at IMAGE_SECTION_HEADER.SizeOfRawData, dd 3 * FILEALIGN at IMAGE_SECTION_HEADER.PointerToRawData, dd 1 * FILEALIGN iend istruc IMAGE_SECTION_HEADER at IMAGE_SECTION_HEADER.VirtualSize, dd 1 * SECTIONALIGN at IMAGE_SECTION_HEADER.VirtualAddress, dd 2 * SECTIONALIGN at IMAGE_SECTION_HEADER.SizeOfRawData, dd 1 * FILEALIGN at IMAGE_SECTION_HEADER.PointerToRawData, dd 2 * FILEALIGN iend
SizeOfRawData
at IMAGE_SECTION_HEADER.SizeOfRawData, dd 1 * FILEALIGN + 0ffff0000h PointerToRawData
SectionHeader: istruc IMAGE_SECTION_HEADER at IMAGE_SECTION_HEADER.VirtualSize, dd 1 * SECTIONALIGN at IMAGE_SECTION_HEADER.VirtualAddress, dd 1 * SECTIONALIGN at IMAGE_SECTION_HEADER.SizeOfRawData, dd 1 * FILEALIGN at IMAGE_SECTION_HEADER.PointerToRawData, dd 1 * FILEALIGN at IMAGE_SECTION_HEADER.Characteristics, dd IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE iend istruc IMAGE_SECTION_HEADER at IMAGE_SECTION_HEADER.VirtualSize, dd 1 * SECTIONALIGN at IMAGE_SECTION_HEADER.VirtualAddress, dd 2 * SECTIONALIGN at IMAGE_SECTION_HEADER.SizeOfRawData, dd 1 * FILEALIGN at IMAGE_SECTION_HEADER.PointerToRawData, dd 1 * FILEALIGN at IMAGE_SECTION_HEADER.Characteristics, dd IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE iend at IMAGE_SECTION_HEADER.PointerToRawData, dd 1ffh ; upper limit of the down-rounding trick SectionHeader: istruc IMAGE_SECTION_HEADER at IMAGE_SECTION_HEADER.VirtualSize, dd 1 * SECTIONALIGN at IMAGE_SECTION_HEADER.VirtualAddress, dd 1 * SECTIONALIGN at IMAGE_SECTION_HEADER.SizeOfRawData, dd FILEALIGN at IMAGE_SECTION_HEADER.PointerToRawData, dd 2 * FILEALIGN ... iend istruc IMAGE_SECTION_HEADER at IMAGE_SECTION_HEADER.VirtualSize, dd 1 * SECTIONALIGN at IMAGE_SECTION_HEADER.VirtualAddress, dd 2 * SECTIONALIGN at IMAGE_SECTION_HEADER.SizeOfRawData, dd FILEALIGN at IMAGE_SECTION_HEADER.PointerToRawData, dd 1 * FILEALIGN ... SectionHeader: istruc IMAGE_SECTION_HEADER at IMAGE_SECTION_HEADER.VirtualSize, dd SECTIONALIGN at IMAGE_SECTION_HEADER.VirtualAddress, dd SECTIONALIGN at IMAGE_SECTION_HEADER.SizeOfRawData, dd FILEALIGN at IMAGE_SECTION_HEADER.PointerToRawData, dd FILEALIGN ... iend istruc IMAGE_SECTION_HEADER at IMAGE_SECTION_HEADER.VirtualSize, dd SECTIONALIGN at IMAGE_SECTION_HEADER.VirtualAddress, dd SECTIONALIGN * 2 at IMAGE_SECTION_HEADER.SizeOfRawData, dd FILEALIGN at IMAGE_SECTION_HEADER.PointerToRawData, dd 3 * FILEALIGN ... PointerToRelocations/PointerToLinenumbers/NumberOfRelocations/NumberOfLinenumbers
Characteristics
extra64ba 64b PE (PE32+) is like a 32b PE, except that the FILE HEADER's Machine and the OPTIONAL HEADER's Magic have AMD specific values, and the Imports's INT, as well as the ImageBase, and the Stack and Heap info are QWORD (which drops a few fields from the Optional header as a consequence
... at IMAGE_FILE_HEADER.Machine, dw IMAGE_FILE_MACHINE_AMD64 ... at IMAGE_OPTIONAL_HEADER64.Magic, dw IMAGE_NT_OPTIONAL_HDR64_MAGIC ... .ImageBase resq 1 ... .SizeOfStackReserve resq 1 .SizeOfStackCommit resq 1 .SizeOfHeapReserve resq 1 .SizeOfHeapCommit resq 1 .LoaderFlags resd 1 ... kernel32.dll_hintnames: dq hnExitProcess - IMAGEBASE dq 0 minimal sizesthe minimal size for a PE is:
so, 268 bytes is the smallest size for a universal tiny PE. specific casesfolded header
thus, the actual data directories used for imports resolving will not be the contiguous ones on the disk. ... section progbits vstart=IMAGEBASE + SECTIONALIGN align=FILEALIGN ;---------------------------------------------- CUT and FOLD here ---------------------------------- ; ok here we're at RVA 1000h (start of 1st section), ; so this data will overwrite the PE headers originally loaded from offset F80h, physically further in the file. dd Import_Descriptor - IMAGEBASE, 0 ... times 0f80h - FILEALIGN * 2 db 0 ; to make the header overlap on address offset/rva 1000h NT_Signature: istruc IMAGE_NT_HEADERS at IMAGE_NT_HEADERS.Signature, db 'PE', 0, 0 iend ... istruc IMAGE_DATA_DIRECTORY_16 dd 88660001h,010009988h ;---------------------------------------------- CUT and FOLD here ---------------------------------- ; we cut the header here, and we're right at offset 1000h ;---------------------------------------------- CUT and FOLD here ---------------------------------- dd 86600010h,001000998h dd 66000100h,000100099h dd 6000100Fh,0F0010009h ... PE + PDF + ZIP
So it's possible to make a ZIP containing a PDF that also works as the PDF itself.
so it's possible to make a PE containing a ZIP containing a uncompressed PDF, that works as both a document (PDF), an archive (ZIP), and an executable (PE), like pdf_zip_pe.exe. File formats should have enforce their signature at offset 0. file walkthrough
00000000: 4D 5A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 MZ.............. 00000030: 50 4B 03 04 0A 00 00 00 00 00 74 01 00 00 PK???.....t?..\ 00000030: 74 01 00 00 t?.. 00000050: 25 50 %P 00000060: 44 46 2D 31.2E 0A 31 20.30 20 6F 62.6A 3C 3C 2F DF-1.?1 0 obj<</ 00000150: 50 4B PK 00000160: 05 06 00 00.00 00 01 00.01 00 3C 00.00 00 F0 00 ??....?.?.<...=. 00000170: 50 45 00 00.4C 01 00 00.00 00 00 00 PE L?...... quine
quine.exe has its own source directly accessible via the type command. after the source, an EOF character is inserted.db 'MZ' align 3bh, db 0dh dd nt_header - IMAGEBASE db 0dh incbin 'quine.asm' db 1ah
op db "open", 0 fn db "cmd", 0 param db "/K type quine.exe", 0 ... EntryPoint: push 1 push 0 push param push fn push op push 0 call [ShellExecuteA] tls_aoiOSDET
so, depending on the OS that is running, tls_aoiOSDET behaves differently by checking its own imports ... mov eax, [__imp__MessageBoxA] cmp eax, hnMessageBoxA - IMAGEBASE jz W7 ... ;user32.dll_DESCRIPTOR: dd user32.dll_hintnames - IMAGEBASE dd 0, 0 AddressOfIndex: dd user32.dll - IMAGEBASE dd user32.dll_iat - IMAGEBASE ...
manyimportsW7
Image_Tls_Directory32: ... AddressOfIndex dd zero_here_plz ... zero_here_plz: %rep 40000h dd fake_imports - IMAGEBASE + i * 4 ...
no0code
db 'MZ' align 3bh, db 90h dd nt_header - IMAGEBASE db 90h EntryPoint: bits 32 ... times 01010000h db ' ' ... nt_header: istruc IMAGE_NT_HEADERS at IMAGE_NT_HEADERS.Signature, db 'PE',0,0 data PEssome specific cases require PE files with less elements than otherwise mentioned Data Filesloading a file via LoadLibraryEx with LOAD_LIBRARY_AS_DATAFILE needs a PE file with only a very few defined elements: not even the Subsystem or the Machine needs to be defined for such a ''library''.
yet even if nothing is defined, its code can still be ran. This allows us to make a non-null PE with code.
resourcesA standard use for code-less PEs is to store resources. In this case, more fields are required (Machine, SizeOfOptionalHeader, SizeOfHeaders), but most fields can contain bogus values.
conclusion
acknowledgements
extra resourcesBinary Art - byte-ing the PE that fails you, presented at Hashdays, Luzern, on the 3rd November 2012 external resources
<< index Android/Java/x86/... opcodes tables PDF tricks Portable Executable x86 oddities | |||||||||||||||||||||||||||||||||||