/* * Interactive disassembler (IDA). * Version 3.05 * Copyright (c) 1990-95 by Ilfak Guilfanov. (2:5020/209@fidonet) * ALL RIGHTS RESERVED. * */ // // Portable Executable file format (MS Windows 95, MS Windows NT) // #ifndef _PE_H_ #define _PE_H_ #include #include #pragma pack(push, 1) //----------------------------------------------------------------------- // // 32-bit Portable EXE Header // //----------------------------------------------------------------------- struct petab_t { uint32 rva; // relative virtual address uint32 size; // size }; // PE va/size array element template struct peheader_tpl { int32 signature; // 00 Current value is "PE/0/0". #define PEEXE_ID 0x4550 // 'PE' followed by two zeroes #define BPEEXE_ID 0x455042 // Borland's extenson for DPMI'host #define PLEXE_ID 0x4C50 // 'PL', PharLap TNT DOS-Extender Lite file that uses real mode APIs #define TEEXE_ID 0x5A56 // 'VZ', EFI Terse Executable uint16 machine; // 04 This field specifies the type of CPU // compatibility required by this image to run. // The values are: #define PECPU_UNKNOWN 0x0000 // unknown #define PECPU_80386 0x014C // 80386 #define PECPU_80486 0x014D // 80486 #define PECPU_80586 0x014E // 80586 #define PECPU_R3000 0x0162 // MIPS Mark I (R2000, R3000) #define PECPU_R6000 0x0163 // MIPS Mark II (R6000) #define PECPU_R4000 0x0166 // MIPS Mark III (R4000) #define PECPU_R10000 0x0168 // MIPS Mark IV (R10000) #define PECPU_WCEMIPSV2 0x0169 // MIPS little-endian WCE v2 #define PECPU_MIPS16 0x0266 // MIPS16 #define PECPU_MIPSFPU 0x0366 // MIPS with FPU #define PECPU_MIPSFPU16 0x0466 // MIPS16 with FPU #define PECPU_ALPHA 0x0184 // DEC Alpha #define PECPU_ALPHA64 0x0284 // Dec Alpha 64-bit #define PECPU_SH3 0x01A2 // SH3 #define PECPU_SH3DSP 0x01A3 // SH3DSP #define PECPU_SH3E 0x01A4 // SH3E #define PECPU_SH4 0x01A6 // SH4 #define PECPU_SH5 0x01A8 // SH5 #define PECPU_ARM 0x01C0 // ARM #define PECPU_ARMI 0x01C2 // ARM with Thumb #define PECPU_ARMV7 0x01C4 // ARMv7 (or higher) Thumb mode only #define PECPU_AM33 0x01D3 // Matsushita (Panasonic) AM33/MN10300 #define PECPU_PPC 0x01F0 // PowerPC #define PECPU_PPCFP 0x01F1 // PowerPC with floating-point #define PECPU_PPCBE 0x01F2 // PowerPC Big-Endian #define PECPU_M32R 0x9041 // M32R little-endian #define PECPU_IA64 0x0200 // Intel Itanium IA64 #define PECPU_EPOC 0x0A00 // ARM EPOC #define PECPU_AMD64 0x8664 // AMD64 (x64) #define PECPU_ARM64 0xaa64 // ARMv8 in 64-bit mode #define PECPU_M68K 0x0268 // Motorola 68000 series #define PECPU_EBC 0x0EBC // EFI Bytecode #define PECPU_CEF 0x0CEF // ? #define PECPU_CEE 0xC0EE // ? #define PECPU_TRICORE 0x0520 // TRICORE (Infineon) bool is_64bit_cpu(void) const { return machine == PECPU_AMD64 || machine == PECPU_IA64 || machine == PECPU_ARM64; } bool is_pc(void) const { return machine == PECPU_80386 || machine == PECPU_80486 || machine == PECPU_80586 || machine == PECPU_AMD64; } bool is_mips(void) const { return machine == PECPU_R3000 || machine == PECPU_R6000 || machine == PECPU_R4000 || machine == PECPU_R10000 || machine == PECPU_WCEMIPSV2 || machine == PECPU_MIPS16 || machine == PECPU_MIPSFPU || machine == PECPU_MIPSFPU16; } bool is_arm(void) const { return machine == PECPU_ARM || machine == PECPU_ARMI || machine == PECPU_ARMV7; } bool has_code16_bit(void) const { return is_arm() || is_mips(); } uint16 nobjs; // 06 This field specifies the number of entries // in the Object Table. qtime32_t datetime; // 08 Used to store the time and date the file was // created or modified by the linker. uint32 symtof; // 0C Symbol Table Offset uint32 nsyms; // 10 Number of Symbols in Symbol Table uint16 hdrsize; // 14 This is the number of remaining bytes in the NT // header that follow the FLAGS field. uint16 flags; // 16 Flag bits for the image. 0000h Program image. #define PEF_BRVHI 0x8000 // Big endian: MSB precedes LSB in memory #define PEF_UP 0x4000 // File should be run only on a UP machine #define PEF_DLL 0x2000 // Dynamic Link Library (DLL) #define PEF_SYS 0x1000 // System file #define PEF_NSWAP 0x0800 // If the image is on network media, fully load it and copy it to the swap file. #define PEF_SWAP 0x0400 // If image is on removable media, // copy and run from swap file #define PEF_NODEB 0x0200 // Debugging info stripped #define PEF_32BIT 0x0100 // 32-bit word machine #define PEF_BRVLO 0x0080 // Little endian: LSB precedes MSB in memory #define PEF_16BIT 0x0040 // 16-bit word machine #define PEF_2GB 0x0020 // App can handle > 2gb addresses #define PEF_TMWKS 0x0010 // Aggressively trim working set #define PEF_NOSYM 0x0008 // Local symbols stripped #define PEF_NOLIN 0x0004 // Line numbers stripped #define PEF_EXEC 0x0002 // Image is executable #define PEF_NOFIX 0x0001 // Relocation info stripped int32 first_section_pos(int32 peoff) const { return peoff + offsetof(peheader_tpl, magic) + hdrsize; } // COFF fields: uint16 magic; // 18 Magic #define MAGIC_ROM 0x107 // ROM image #define MAGIC_P32 0x10B // Normal PE file #define MAGIC_P32_PLUS 0x20B // 64-bit image bool is_pe_plus(void) const { return magic == MAGIC_P32_PLUS; } uchar vstamp_major; // 1A Major Linker Version uchar vstamp_minor; // 1B Minor Linker Version uint32 tsize; // 1C TEXT size (padded) uint32 dsize; // 20 DATA size (padded) uint32 bsize; // 24 BSS size (padded) uint32 entry; // 28 Entry point uint32 text_start; // 2C Base of text union { struct { uint32 data_start; // 30 Base of data // Win32/NT extensions: uint32 imagebase32; // 34 Virtual base of the image. }; uint64 imagebase64; }; uint64 imagebase() const { if ( is_pe_plus() ) return imagebase64; else return imagebase32; } // This will be the virtual address of the first // byte of the file (Dos Header). This must be // a multiple of 64K. uint32 objalign; // 38 The alignment of the objects. This must be a power // of 2 between 512 and 256M inclusive. The default // is 64K. uint32 filealign; // 3C Alignment factor used to align image pages. // The alignment factor (in bytes) used to align the // base of the image pages and to determine the // granularity of per-object trailing zero pad. // Larger alignment factors will cost more file space; // smaller alignment factors will impact demand load // performance, perhaps significantly. Of the two, // wasting file space is preferable. This value // should be a power of 2 between 512 and 64K inclusive. // Get the file position aligned: #define FILEALIGN 512 // IDA5.1: it seems that for standard object alignment (if 4096) // the Windows kernel does not use filealign // (just checks that it is in the valid range) but uses 512 uint32 get_align_mask(void) const { return ((objalign == 4096 || filealign == 0) ? FILEALIGN : filealign) - 1; } uint32 align_up_in_file(uint32 pos) const { if ( is_efi() ) // apparently EFI images are not aligned return pos; uint32 mask = get_align_mask(); return (pos+mask) & ~mask; } uint32 align_down_in_file(uint32 pos) const { return is_efi() ? pos : (pos & ~get_align_mask()); } uint16 osmajor; // 40 OS version number required to run this image. uint16 osminor; // 42 OS version number required to run this image. uint16 imagemajor; // 44 User major version number. uint16 imageminor; // 46 User minor version number. uint16 subsysmajor; // 48 Subsystem major version number. uint16 subsysminor; // 4A Subsystem minor version number. uint32 subsystem_version(void) const { return (subsysmajor << 16) | subsysminor; } uint32 reserved; // 4C uint32 imagesize; // 50 The virtual size (in bytes) of the image. // This includes all headers. The total image size // must be a multiple of Object Align. uint32 allhdrsize; // 54 Total header size. The combined size of the Dos // Header, PE Header and Object Table. uint32 checksum; // 58 Checksum for entire file. Set to 0 by the linker. uint16 subsys; // 5C NT Subsystem required to run this image. #define PES_UNKNOWN 0x0000 // Unknown #define PES_NATIVE 0x0001 // Native #define PES_WINGUI 0x0002 // Windows GUI #define PES_WINCHAR 0x0003 // Windows Character #define PES_OS2CHAR 0x0005 // OS/2 Character #define PES_POSIX 0x0007 // Posix Character #define PES_NAT9x 0x0008 // image is a native Win9x driver #define PES_WINCE 0x0009 // Runs on Windows CE. #define PES_EFI_APP 0x000A // EFI application. #define PES_EFI_BDV 0x000B // EFI driver that provides boot services. #define PES_EFI_RDV 0x000C // EFI driver that provides runtime services. #define PES_EFI_ROM 0x000D // EFI ROM image #define PES_XBOX 0x000E // Xbox system #define PES_BOOTAPP 0x0010 // Windows Boot Application bool is_efi(void) const { return subsys == PES_EFI_APP || subsys == PES_EFI_BDV || subsys == PES_EFI_RDV || subsys == PES_EFI_ROM; } bool is_console_app(void) const { return subsys == PES_WINCHAR || subsys == PES_OS2CHAR || subsys == PES_POSIX; } bool is_userland(void) const { return subsys == PES_WINGUI || subsys == PES_WINCHAR || subsys == PES_OS2CHAR || subsys == PES_POSIX || subsys == PES_WINCE; } uint16 dllflags; // 5E Indicates special loader requirements. #define PEL_PINIT 0x0001 // Per-Process Library Initialization. #define PEL_PTERM 0x0002 // Per-Process Library Termination. #define PEL_TINIT 0x0004 // Per-Thread Library Initialization. #define PEL_TTERM 0x0008 // Per-Thread Library Termination. #define PEL_HIGH_ENT 0x0020 // Image can handle a high entropy 64-bit virtual address space. #define PEL_DYNAMIC_BASE 0x0040 // The DLL can be relocated at load time. #define PEL_FORCE_INTEGRITY 0x0080 // Code integrity checks are forced. #define PEF_NX 0x0100 // The image is compatible with data execution prevention (DEP). #define PEF_NO_ISOLATION 0x0200 // The image is isolation aware, but should not be isolated. #define PEF_NO_SEH 0x0400 // The image does not use structured exception handling (SEH). No handlers can be called in this image. #define PEL_NO_BIND 0x0800 // Do not bind image #define PEL_APPCONTAINER 0x1000 // Image should execute in an AppContainer #define PEL_WDM_DRV 0x2000 // Driver is a WDM Driver #define PEL_GUARDCF 0x4000 // Image supports Control Flow Guard checking #define PEL_TSRVAWA 0x8000 // Image is Terminal Server aware pointer_t stackres; // 60 Stack size needed for image. The memory is // reserved, but only the STACK COMMIT SIZE is // committed. The next page of the stack is a // 'guarded page'. When the application hits the // guarded page, the guarded page becomes valid, // and the next page becomes the guarded page. // This continues until the RESERVE SIZE is reached. pointer_t stackcom; // 64 Stack commit size. pointer_t heapres; // 68 Size of local heap to reserve. pointer_t heapcom; // 6C Amount to commit in local heap. uint32 loaderflags; // 70 ? uint32 nrvas; // 74 Indicates the size of the VA/SIZE array // that follows. petab_t expdir; // 0 78 Export Directory petab_t impdir; // 1 80 Import Directory petab_t resdir; // 2 88 Resource Directory petab_t excdir; // 3 90 Exception Directory petab_t secdir; // 4 98 Security Directory // The Certificate Table entry points to a table of // attribute certificates. These certificates are not // loaded into memory as part of the image. As such, // the first field of this entry, which is normally // an RVA, is a File Pointer instead petab_t reltab; // 5 A0 Relocation Table petab_t debdir; // 6 A8 Debug Directory petab_t desstr; // 7 B0 Description String petab_t cputab; // 8 B8 Machine Value petab_t tlsdir; // 9 C0 TLS Directory petab_t loddir; // 10 Load Configuration Directory petab_t bimtab; // 11 Bound Import Table address and size. petab_t iat; // 12 Import Address Table address and size. petab_t didtab; // 13 Address and size of the Delay Import Descriptor. petab_t comhdr; // 14 COM+ Runtime Header address and size petab_t x00tab; // 15 Reserved bool is_te() const { return signature == TEEXE_ID; } inline bool has_debdir() const; }; typedef peheader_tpl peheader_t; typedef peheader_tpl peheader64_t; constexpr size_t total_rvatab_size = sizeof(peheader_t) - offsetof(peheader_t, expdir); constexpr size_t total_rvatab_count = total_rvatab_size / sizeof(petab_t); //----------------------------------------------------------------------- struct diheader_t { uint16 signature; // 00 Current value is "DI" #define DBG_ID 0x4944 uint16 flags2; // 02 ?? pedump mentions about this // I've never seen something other than 0 uint16 machine; // 04 This field specifies the type of CPU // compatibility required by this image to run. uint16 flags; // 06 Flag bits for the image. qtime32_t datetime; // 08 Used to store the time and date the file was // created or modified by the linker. uint32 checksum; // 12 Checksum uint32 imagebase; // 16 Virtual base of the image. // This will be the virtual address of the first // byte of the file (Dos Header). This must be // a multiple of 64K. uint32 imagesize; // 20 The virtual size (in bytes) of the image. // This includes all headers. The total image size // must be a multiple of Object Align. uint32 n_secs; // 24 Number of sections uint32 exp_name_size; // 28 Exported Names Size uint32 dbg_dir_size; // 32 Debug Directory Size uint32 reserved[3]; // 36 Reserved fields }; //------------------------------------------------------------------------- // // S E C T I O N S // struct pesection_t { char s_name[8]; /* section name */ uint32 s_vsize; /* virtual size */ uint32 s_vaddr; /* virtual address */ uint32 s_psize; /* physical size */ int32 s_scnptr; /* file ptr to raw data for section */ int32 s_relptr; /* file ptr to relocation */ int32 s_lnnoptr; /* file ptr to line numbers */ uint16 s_nreloc; /* number of relocation entries */ uint16 s_nlnno; /* number of line number entries */ int32 s_flags; /* flags */ #define PEST_REG 0x00000000 // obsolete: regular: allocated, relocated, loaded #define PEST_DUMMY 0x00000001 // obsolete: dummy: not allocated, relocated, not loaded #define PEST_NOLOAD 0x00000002 // obsolete: noload: allocated, relocated, not loaded #define PEST_GROUP 0x00000004 // obsolete: grouped: formed of input sections #define PEST_PAD 0x00000008 // obsolete: padding: not allocated, not relocated, loaded #define PEST_COPY 0x00000010 // obsolete: copy: for decision function used // by field update; not // allocated, not relocated, // loaded; reloc & lineno // entries processed normally */ #define PEST_TEXT 0x00000020L// section contains text only #define PEST_DATA 0x00000040L// section contains data only #define PEST_BSS 0x00000080L// section contains bss only #define PEST_EXCEPT 0x00000100L// obsolete: Exception section #define PEST_INFO 0x00000200L// Comment: not allocated, not relocated, not loaded #define PEST_OVER 0x00000400L// obsolete: Overlay: not allocated, relocated, not loaded #define PEST_LIB 0x00000800L// ".lib" section: treated like PEST_INFO #define PEST_LOADER 0x00001000L// Loader section: COMDAT #define PEST_DEBUG 0x00002000L// Debug section: #define PEST_TYPCHK 0x00004000L// Type check section: #define PEST_OVRFLO 0x00008000L// obsolete: RLD and line number overflow sec hdr #define PEST_F0000 0x000F0000L// Unknown #define PEST_ALIGN 0x00F00000L// Alignment 2^(x-1): uint32 get_sect_alignment(void) const { int align = ((s_flags >> 20) & 15); return align == 0 ? 0 : (1 << (align-1)); } asize_t get_vsize(const peheader_t &pe) const { return align_up(s_vsize ? s_vsize : s_psize, pe.objalign ? pe.objalign : 1); } asize_t get_psize(const peheader_t &pe) const { return qmin(s_psize, get_vsize(pe)); } #define PEST_1000000 0x01000000L// Unknown #define PEST_DISCARD 0x02000000L// Discardable #define PEST_NOCACHE 0x04000000L// Not cachable #define PEST_NOPAGE 0x08000000L// Not pageable #define PEST_SHARED 0x10000000L// Shareable #define PEST_EXEC 0x20000000L// Executable #define PEST_READ 0x40000000L// Readable #define PEST_WRITE 0x80000000L// Writable }; //------------------------------------------------------------------------- // // E X P O R T S // struct peexpdir_t { uint32 flags; // Currently set to zero. qtime32_t datetime; // Time/Date the export data was created. uint16 major; // A user settable major/minor version number. uint16 minor; uint32 dllname; // Relative Virtual Address of the Dll asciiz Name. // This is the address relative to the Image Base. uint32 ordbase; // First valid exported ordinal. This field specifies // the starting ordinal number for the export // address table for this image. Normally set to 1. uint32 naddrs; // Indicates number of entries in the Export Address // Table. uint32 nnames; // This indicates the number of entries in the Name // Ptr Table (and parallel Ordinal Table). uint32 adrtab; // Relative Virtual Address of the Export Address // Table. This address is relative to the Image Base. uint32 namtab; // Relative Virtual Address of the Export Name Table // Pointers. This address is relative to the // beginning of the Image Base. This table is an // array of RVA's with # NAMES entries. uint32 ordtab; // Relative Virtual Address of Export Ordinals // Table Entry. This address is relative to the // beginning of the Image Base. }; //------------------------------------------------------------------------- // // I M P O R T S // struct peimpdir_t { uint32 table1; // aka OriginalFirstThunk qtime32_t datetime; // Time/Date the import data was pre-snapped or // zero if not pre-snapped. uint32 fchain; // Forwarder chain uint32 dllname; // Relative Virtual Address of the Dll asciiz Name. // This is the address relative to the Image Base. uint32 looktab; // aka FirstThunk // This field contains the address of the start of // the import lookup table for this image. The address // is relative to the beginning of the Image Base. #define hibit(type) ((type(-1)>>1) ^ type(-1)) #define IMP_BY_ORD32 hibit(uint32) // Import by ordinal, otherwise by name #define IMP_BY_ORD64 hibit(uint64) // Import by ordinal, otherwise by name peimpdir_t(void) { memset(this, 0, sizeof(peimpdir_t)); } }; struct dimpdir_t // delayed load import table { uint32 attrs; // Attributes. #define DIMP_NOBASE 0x0001 // pe.imagebase was not added to addresses uint32 dllname; // Relative virtual address of the name of the DLL // to be loaded. The name resides in the read-only // data section of the image. uint32 handle; // Relative virtual address of the module handle // (in the data section of the image) of the DLL to // be delay-loaded. Used for storage by the routine // supplied to manage delay-loading. uint32 diat; // Relative virtual address of the delay-load import // address table. See below for further details. uint32 dint; // Relative virtual address of the delay-load name // table, which contains the names of the imports // that may need to be loaded. Matches the layout of // the Import Name Table, Section 6.4.3. Hint/Name Table. uint32 dbiat; // Bound Delay Import Table. Relative virtual address // of the bound delay-load address table, if it exists. uint32 duiat; // Unload Delay Import Table. Relative virtual address // of the unload delay-load address table, if it exists. // This is an exact copy of the Delay Import Address // Table. In the event that the caller unloads the DLL, // this table should be copied back over the Delay IAT // such that subsequent calls to the DLL continue to // use the thunking mechanism correctly. qtime32_t datetime; // Time stamp of DLL to which this image has been bound. }; // Bound Import Table format: struct BOUND_IMPORT_DESCRIPTOR { qtime32_t TimeDateStamp; uint16 OffsetModuleName; uint16 NumberOfModuleForwarderRefs; // Array of zero or more IMAGE_BOUND_FORWARDER_REF follows }; struct BOUND_FORWARDER_REF { qtime32_t TimeDateStamp; uint16 OffsetModuleName; uint16 Reserved; }; //------------------------------------------------------------------------- // // T H R E A D L O C A L D A T A // struct image_tls_directory64 { uint64 StartAddressOfRawData; uint64 EndAddressOfRawData; uint64 AddressOfIndex; // PDWORD uint64 AddressOfCallBacks; // PIMAGE_TLS_CALLBACK *; uint32 SizeOfZeroFill; uint32 Characteristics; }; struct image_tls_directory32 { uint32 StartAddressOfRawData; uint32 EndAddressOfRawData; uint32 AddressOfIndex; // PDWORD uint32 AddressOfCallBacks; // PIMAGE_TLS_CALLBACK * uint32 SizeOfZeroFill; uint32 Characteristics; }; //------------------------------------------------------------------------- // // Exception Tables (.pdata) // // ARM, PowerPC, SH3 and SH4 WindowsCE platforms struct function_entry_ce { uint32 FuncStart; // Virtual address of the corresponding function. uint32 PrologLen : 8; // Number of instructions in the function's prolog. uint32 FuncLen : 22; // Number of instructions in the function. uint32 ThirtyTwoBit : 1; // Set if the function is comprised of 32-bit instructions, cleared for a 16-bit function. uint32 ExceptionFlag : 1; // Set if an exception handler exists for the function. }; // ARMv7, ARM64 struct function_entry_arm_pdata { uint32 BeginAddress; // The RVA of the corresponding function uint32 UnwindInfo; // The RVA of the unwind information, including function length. // If the low 2 bits are non-zero, then this word represents a // compacted inline form of the unwind information, // including function length. }; // for MIPS and 32-bit Alpha struct function_entry_alpha { uint32 BeginAddress; // Virtual address of the corresponding function. uint32 EndAddress; // Virtual address of the end of the function. uint32 ExceptionHandler; // Pointer to the exception handler to be executed. uint32 HandlerData; // Pointer to additional information to be passed to the handler. uint32 PrologEndAddress; // Virtual address of the end of the function's prolog. }; // x64 typedef enum _UNWIND_OP_CODES { UWOP_PUSH_NONVOL = 0, // info == register number UWOP_ALLOC_LARGE =1, // alloc size/8 in next 1(info=0) or 2(info=1) slots UWOP_ALLOC_SMALL =2, // info == size of allocation / 8 - 1 UWOP_SET_FPREG = 3, // FP = RSP + UNWIND_INFO.FPRegOffset*16 UWOP_SAVE_NONVOL = 4, // info == register number, offset/8 in next slot UWOP_SAVE_NONVOL_FAR=5,// info == register number, offset/8 in next 2 slots UWOP_SAVE_XMM = 6, // Version 1: info == XMM reg number, offset/8 in next slot UWOP_EPILOG = 6, // Version 2; code offset is epilog size; UWOP_SAVE_XMM_FAR=7, // version 1:info == XMM reg number, offset/8 in next 2 slots UWOP_SPARE_CODE = 7, // unused ("previously 64-bit UWOP_SAVE_XMM_FAR"); skip 2 slots UWOP_SAVE_XMM128 = 8, // info == XMM reg number, offset/16 in next slot UWOP_SAVE_XMM128_FAR = 9,// info == XMM reg number, offset/16 in next 2 slots UWOP_PUSH_MACHFRAME = 10,// info == 0: no error-code, 1: with error code } UNWIND_CODE_OPS; enum // ARM64_UNWIND_OP_CODES; { // 1 byte long ARM64_UWOP_BAD = 0, ARM64_UWOP_UNNAMED, ARM64_UWOP_ALLOC_S, // allocate small stack with size < 512 (2^5 * 16). ARM64_UWOP_SAVE_R19R20_X, // save pair at [sp-#Z*8]!, pre-indexed offset >= -248 ARM64_UWOP_SAVE_FPLR, // save pair at [sp+#Z*8], offset <= 504 ARM64_UWOP_SAVE_FPLR_X, // save pair at [sp-(#Z+1)*8]!, pre-indexed offset >= -512 ARM64_UWOP_SET_FP, // set up x29: with: mov x29,sp ARM64_UWOP_ADD_FP, // set up x29 with: add x29,sp,#x*8 ARM64_UWOP_NOP, // no unwind operation is required ARM64_UWOP_END, // end of unwind code. Implies ret in epilog ARM64_UWOP_END_C, // end of unwind code in current chained scope ARM64_UWOP_SAVE_NEXT, // save next non-volatile Int or FP register pair // 2 bytes long ARM64_UWOP_ALLOC_M, // allocate large stack with size < 16k (2^11 * 16) ARM64_UWOP_SAVE_REGP, // save x(19+#X) pair at [sp+#Z*8], offset <= 504 ARM64_UWOP_SAVE_REGP_X, // save pair x(19+#X) at [sp-(#Z+1)*8]!, pre-indexed offset >= -512 ARM64_UWOP_SAVE_REG, // save reg x(19+#X) at [sp+#Z*8], offset <= 504 ARM64_UWOP_SAVE_REG_X, // save reg x(19+#X) at [sp-(#Z+1)*8]!, pre-indexed offset >= -256 ARM64_UWOP_SAVE_LRPAIR, // save pair at [sp+#Z*8], offset <= 504 ARM64_UWOP_SAVE_FREGP, // save pair d(8+#X) at [sp+#Z*8], offset <= 504 ARM64_UWOP_SAVE_FREGP_X, // save pair d(8+#X), at [sp-(#Z+1)*8]!, pre-indexed offset >= -512 ARM64_UWOP_SAVE_FREG, // save reg d(8+#X) at [sp+#Z*8], offset <= 504 ARM64_UWOP_SAVE_FREG_X, // save reg d(8+#X) at [sp-(#Z+1)*8]!, pre-indexed offset >= -256 // 4 bytes long ARM64_UWOP_ALLOC_L, // allocate large stack with size < 256M (2^24 *16) }; enum // ARM_UNWIND_OP_CODES; { // 1 byte long ARM_UWOP_ALLOC = 0, // add sp,sp, #X where X = (Code & 0x7F) * 4) ARM_UWOP_SAVE_SP, // mov sp,rX where X is Code & 0x0F ARM_UWOP_POP, // pop {r4-rX,lr} where X is (Code & 0x03) + 4 and LR is popped if Code & 0x04 ARM_UWOP_POP2, // pop {r4-rX,lr} where X is (Code & 0x03) + 8 and LR is popped if Code & 0x04 ARM_UWOP_VPOP, // vpop {d8-dX} where X is (Code & 0x07) + 8 ARM_UWOP_RESERVED, // Available (no opsize) ARM_UWOP_END, // end ARM_UWOP_END32, // end (+32bit nop in epilogue) ARM_UWOP_NOP32, // nop (32bit) ARM_UWOP_END16, // end (+16bit nop in epilogue) ARM_UWOP_NOP16, // nop (16bit) // 2 bytes long ARM_UWOP_POP3, // pop {r0-r12, lr} where LR is popped if Code & 0x2000 and r0-r12 are popped // if the corresponding bit is set in Code & 0x1FFF ARM_UWOP_ALLOC2, // addw sp,sp,#X where X is (Code & 0x03FF) * 4 ARM_UWOP_POP4, // pop {r0-r7,lr} where LR is popped if Code & 0x0100 and r0-r7 are popped // if the corresponding bit is set in Code & 0x00FF ARM_UWOP_MS_SPECIFIC, // Microsoft specific ARM_UWOP_RESERVED_W, // Available (16bit opsize) ARM_UWOP_LD_PC_UPD_SP, // ldr lr,[sp],#X where X is (Code & 0x000F) * 4 ARM_UWOP_RESERVED_DW, // Available (32bit opsize) ARM_UWOP_VPOP2, // vpop {dS-dE} where S is (Code & 0x00F0) >> 4 and E is Code & 0x000F ARM_UWOP_VPOP3, // vpop {dS-dE} where S is ((Code & 0x00F0) >> 4) + 16 and E is (Code & 0x000F) + 16 // 3 bytes long ARM_UWOP_ALLOC3, // add sp,sp,#X where X is (Code & 0x00FFFF) * 4 ARM_UWOP_ALLOC4, // add sp,sp,#X where X is (Code & 0x00FFFF) * 4 // 4 bytes long ARM_UWOP_ALLOC5, // add sp,sp,#X where X is (Code & 0x00FFFFFF) * 4 ARM_UWOP_ALLOC6, // add sp,sp,#X where X is (Code & 0x00FFFFFF) * 4 }; // Define unwind information flags. // #define UNW_FLAG_NHANDLER 0x0 #define UNW_FLAG_EHANDLER 0x1 #define UNW_FLAG_UHANDLER 0x2 #define UNW_FLAG_CHAININFO 0x4 //------------------------------------------------------------------------- // // F I X U P S // struct pefixup_t { uint32 page;// The image base plus the page rva is added to each offset // to create the virtual address of where the fixup needs to // be applied. uint32 size;// Number of bytes in the fixup block. This includes the // PAGE RVA and SIZE fields. }; #define PER_OFF 0x0FFF #define PER_TYPE 0xF000 #define PER_ABS 0x0000 // This is a NOP. The fixup is skipped. #define PER_HIGH 0x1000 // Add the high 16-bits of the delta to the // 16-bit field at Offset. The 16-bit field // represents the high value of a 32-bit word. #define PER_LOW 0x2000 // Add the low 16-bits of the delta to the // 16-bit field at Offset. The 16-bit field // represents the low half value of a // 32-bit word. This fixup will only be // emitted for a RISC machine when the image // Object Align isn't the default of 64K. #define PER_HIGHLOW 0x3000 // Apply the 32-bit delta to the 32-bit field // at Offset. #define PER_HIGHADJUST 0x4000 // This fixup requires a full 32-bit value. // The high 16-bits is located at Offset, and // the low 16-bits is located in the next // Offset array element (this array element // is included in the SIZE field). The two // need to be combined into a signed variable. // Add the 32-bit delta. Then add 0x8000 and // store the high 16-bits of the signed // variable to the 16-bit field at Offset. #define PER_REL5000 0x5000 // Machine-specific #define PER_SECTION 0x6000 // Reserved for future use #define PER_REL32 0x7000 // Relative intrasection #define PER_REL7000 0x7000 // Machine-specific #define PER_REL8000 0x8000 // Machine-specific #define PER_REL9000 0x9000 // Machine-specific #define PER_DIR64 0xA000 // This fixup applies the delta to the 64-bit // field at Offset #define PER_HIGH3ADJ 0xB000 // The fixup adds the high 16 bits of the delta // to the 16-bit field at Offset. The 16-bit // field represents the high value of a 48-bit // word. The low 32 bits of the 48-bit value are // stored in the 32-bit word that follows this // base relocation. This means that this base // relocation occupies three slots. // Platform-specific based relocation types. #define PER_IA64_IMM64 0x9000 #define PER_MIPS_JMPADDR 0x5000 // base relocation applies to a MIPS jump instruction. #define PER_MIPS_JMPADDR16 0x9000 // base relocation applies to a MIPS16 jump instruction. #define PER_ARM_MOV32A 0x5000 // base relocation applies the difference to the // 32-bit value encoded in the immediate fields of // a contiguous MOVW+MOVT pair in ARM mode at offset. #define PER_ARM_MOV32T 0x7000 // base relocation applies the difference to the // 32-bit value encoded in the immediate fields of // a contiguous MOVW+MOVT pair in Thumb mode at offset. //------------------------------------------------------------------------- // // DBG file debug entry format // struct debug_entry_t { uint32 flags; // usually zero qtime32_t datetime; uint16 major; uint16 minor; int32 type; #define DBG_COFF 1 #define DBG_CV 2 #define DBG_FPO 3 #define DBG_MISC 4 #define DBG_EXCEPTION 5 #define DBG_FIXUP 6 #define DBG_OMAP_TO_SRC 7 #define DBG_OMAP_FROM_SRC 8 #define DBG_BORLAND 9 #define DBG_RES10 10 #define DBG_CLSID 11 #define DBG_VCFEATURE 12 #define DBG_POGO 13 #define DBG_ILTCG 14 #define DBG_MPX 15 uint32 size; uint32 rva; // virtual address uint32 seek; // ptr to data in the file }; // now we can define has_debdir() because we have debug_entry_t defined template<> inline bool peheader_t::has_debdir() const { return debdir.size >= sizeof(debug_entry_t) && debdir.rva != 0; } //------------------------------------------------------------------------- // // DBG file COFF debug information header // struct coff_debug_t { uint32 NumberOfSymbols; uint32 LvaToFirstSymbol; uint32 NumberOfLinenumbers; uint32 LvaToFirstLinenumber; uint32 RvaToFirstByteOfCode; uint32 RvaToLastByteOfCode; uint32 RvaToFirstByteOfData; uint32 RvaToLastByteOfData; }; //------------------------------------------------------------------------- // // DBG file FPO debug information // struct fpo_t { uint32 address; uint32 size; uint32 locals; uint16 params; uchar prolog; uchar regs; #define FPO_REGS 0x07 // register number #define FPO_SEH 0x08 // #define FPO_BP 0x10 // has BP frame? #define FPO_TYPE 0xC0 #define FPO_T_FPO 0x00 #define FPO_T_TRAP 0x40 #define FPO_T_TSS 0x80 #define FPO_T_NONFPO 0xC0 }; // DBG file OMAP debug information struct omap_t { uint32 a1; uint32 a2; }; // misc entry format struct misc_debug_t { uint32 type; // type of misc data, see defines #define MISC_EXENAME 1 uint32 length; // total length of record, rounded to four // byte multiple. uchar unicode; // TRUE if data is unicode string uchar reserved[3]; // padding uchar data[1]; // Actual data }; //---------------------------------------------------------------------- // Resource information struct rsc_dir_t { uint32 Characteristics; uint32 TimeDateStamp; uint16 MajorVersion; uint16 MinorVersion; uint16 NumberOfNamedEntries; uint16 NumberOfIdEntries; }; struct rsc_dir_entry_t { union { struct { uint32 NameOffset:31; uint32 NameIsString:1; }; uint32 Name; uint16 Id; }; union { uint32 OffsetToData; struct { uint32 OffsetToDirectory:31; uint32 DataIsDirectory:1; }; }; }; struct rsc_data_entry_t { uint32 OffsetToData; uint32 Size; uint32 CodePage; uint32 Reserved; }; // Resource types #define PE_RT_CURSOR 1 #define PE_RT_BITMAP 2 #define PE_RT_ICON 3 #define PE_RT_MENU 4 #define PE_RT_DIALOG 5 #define PE_RT_STRING 6 #define PE_RT_FONTDIR 7 #define PE_RT_FONT 8 #define PE_RT_ACCELERATOR 9 #define PE_RT_RCDATA 10 #define PE_RT_MESSAGETABLE 11 #define PE_RT_GROUP_CURSOR 12 #define PE_RT_GROUP_ICON 14 #define PE_RT_VERSION 16 #define PE_RT_DLGINCLUDE 17 #define PE_RT_PLUGPLAY 19 #define PE_RT_VXD 20 #define PE_RT_ANICURSOR 21 #define PE_RT_ANIICON 22 #define PE_RT_HTML 23 #define PE_RT_MANIFEST 24 // Language codes #define PE_LANG_NEUTRAL 0x00 #define PE_LANG_INVARIANT 0x7f #define PE_LANG_AFRIKAANS 0x36 #define PE_LANG_ALBANIAN 0x1c #define PE_LANG_ARABIC 0x01 #define PE_LANG_ARMENIAN 0x2b #define PE_LANG_ASSAMESE 0x4d #define PE_LANG_AZERI 0x2c #define PE_LANG_BASQUE 0x2d #define PE_LANG_BELARUSIAN 0x23 #define PE_LANG_BENGALI 0x45 #define PE_LANG_BULGARIAN 0x02 #define PE_LANG_CATALAN 0x03 #define PE_LANG_CHINESE 0x04 #define PE_LANG_CROATIAN 0x1a #define PE_LANG_CZECH 0x05 #define PE_LANG_DANISH 0x06 #define PE_LANG_DIVEHI 0x65 #define PE_LANG_DUTCH 0x13 #define PE_LANG_ENGLISH 0x09 #define PE_LANG_ESTONIAN 0x25 #define PE_LANG_FAEROESE 0x38 #define PE_LANG_FARSI 0x29 #define PE_LANG_FINNISH 0x0b #define PE_LANG_FRENCH 0x0c #define PE_LANG_GALICIAN 0x56 #define PE_LANG_GEORGIAN 0x37 #define PE_LANG_GERMAN 0x07 #define PE_LANG_GREEK 0x08 #define PE_LANG_GUJARATI 0x47 #define PE_LANG_HEBREW 0x0d #define PE_LANG_HINDI 0x39 #define PE_LANG_HUNGARIAN 0x0e #define PE_LANG_ICELANDIC 0x0f #define PE_LANG_INDONESIAN 0x21 #define PE_LANG_ITALIAN 0x10 #define PE_LANG_JAPANESE 0x11 #define PE_LANG_KANNADA 0x4b #define PE_LANG_KASHMIRI 0x60 #define PE_LANG_KAZAK 0x3f #define PE_LANG_KONKANI 0x57 #define PE_LANG_KOREAN 0x12 #define PE_LANG_KYRGYZ 0x40 #define PE_LANG_LATVIAN 0x26 #define PE_LANG_LITHUANIAN 0x27 #define PE_LANG_MACEDONIAN 0x2f // the Former Yugoslav Republic of Macedonia #define PE_LANG_MALAY 0x3e #define PE_LANG_MALAYALAM 0x4c #define PE_LANG_MANIPURI 0x58 #define PE_LANG_MARATHI 0x4e #define PE_LANG_MONGOLIAN 0x50 #define PE_LANG_NEPALI 0x61 #define PE_LANG_NORWEGIAN 0x14 #define PE_LANG_ORIYA 0x48 #define PE_LANG_POLISH 0x15 #define PE_LANG_PORTUGUESE 0x16 #define PE_LANG_PUNJABI 0x46 #define PE_LANG_ROMANIAN 0x18 #define PE_LANG_RUSSIAN 0x19 #define PE_LANG_SANSKRIT 0x4f #define PE_LANG_SINDHI 0x59 #define PE_LANG_SLOVAK 0x1b #define PE_LANG_SLOVENIAN 0x24 #define PE_LANG_SPANISH 0x0a #define PE_LANG_SWAHILI 0x41 #define PE_LANG_SWEDISH 0x1d #define PE_LANG_SYRIAC 0x5a #define PE_LANG_TAMIL 0x49 #define PE_LANG_TATAR 0x44 #define PE_LANG_TELUGU 0x4a #define PE_LANG_THAI 0x1e #define PE_LANG_TURKISH 0x1f #define PE_LANG_UKRAINIAN 0x22 #define PE_LANG_URDU 0x20 #define PE_LANG_UZBEK 0x43 #define PE_LANG_VIETNAMESE 0x2a //---------------------------------------------------------------------- #define PE_NODE "$ PE header" // netnode name for PE header // value() -> peheader_t // altval(segnum) -> s->start_ea #define PE_ALT_DBG_FPOS nodeidx_t(-1) // altval() -> translated fpos of debuginfo #define PE_ALT_IMAGEBASE nodeidx_t(-2) // altval() -> loading address (usually pe.imagebase) #define PE_ALT_PEHDR_OFF nodeidx_t(-3) // altval() -> offset of PE header #define PE_ALT_NEFLAGS nodeidx_t(-4) // altval() -> neflags #define PE_ALT_TDS_LOADED nodeidx_t(-5) // altval() -> tds already loaded(1) or invalid(-1) #define PE_ALT_PSXDLL nodeidx_t(-6) // altval() -> if POSIX(x86) imports from PSXDLL netnode #define PE_ALT_OVRVA nodeidx_t(-7) // altval() -> overlay rva (if present) #define PE_ALT_OVRSZ nodeidx_t(-8) // altval() -> overlay size (if present) #define PE_SUPSTR_PDBNM nodeidx_t(-9) // supstr() -> pdb file name // supval(segnum) -> pesection_t // blob(0, PE_NODE_RELOC) -> relocation info // blob(0, RSDS_TAG) -> rsds_t structure // blob(0, NB10_TAG) -> cv_info_pdb20_t structure #define PE_ALT_NTAPI nodeidx_t(-10) // altval() -> uses Native API #define PE_EMBED_PDB_OFF nodeidx_t(-11) // altval() -> offset of embedded PDB file #define PE_NODE_RELOC 'r' #define RSDS_TAG 's' #define NB10_TAG 'n' #define UTDS_TAG 't' struct load_config_t { uint32 Size; uint32 TimeDateStamp; uint16 MajorVersion; uint16 MinorVersion; uint32 GlobalFlagsClear; uint32 GlobalFlagsSet; uint32 CriticalSectionDefaultTimeout; uint32 DeCommitFreeBlockThreshold; uint32 DeCommitTotalFreeThreshold; uint32 LockPrefixTable; // VA uint32 MaximumAllocationSize; uint32 VirtualMemoryThreshold; uint32 ProcessHeapFlags; uint32 ProcessAffinityMask; uint16 CSDVersion; uint16 Reserved1; uint32 EditList; // VA uint32 SecurityCookie; // VA // Version 2 uint32 SEHandlerTable; // VA uint32 SEHandlerCount; // Version 3 uint32 GuardCFCheckFunctionPointer; // VA uint32 GuardCFDispatchFunctionPointer; // VA uint32 GuardCFFunctionTable; // VA uint32 GuardCFFunctionCount; uint32 GuardFlags; }; struct load_config64_t { uint32 Size; uint32 TimeDateStamp; uint16 MajorVersion; uint16 MinorVersion; uint32 GlobalFlagsClear; uint32 GlobalFlagsSet; uint32 CriticalSectionDefaultTimeout; uint64 DeCommitFreeBlockThreshold; uint64 DeCommitTotalFreeThreshold; uint64 LockPrefixTable; // VA uint64 MaximumAllocationSize; uint64 VirtualMemoryThreshold; uint64 ProcessAffinityMask; uint32 ProcessHeapFlags; uint16 CSDVersion; uint16 Reserved1; uint64 EditList; // VA uint64 SecurityCookie; // VA // Version 2 uint64 SEHandlerTable; // VA uint64 SEHandlerCount; // Version 3 uint64 GuardCFCheckFunctionPointer; // VA uint64 GuardCFDispatchFunctionPointer; // VA uint64 GuardCFFunctionTable; // VA uint64 GuardCFFunctionCount; uint32 GuardFlags; }; #ifndef IMAGE_GUARD_CF_INSTRUMENTED #define IMAGE_GUARD_CF_INSTRUMENTED 0x000000100 // Module performs control flow integrity checks using system-supplied support #define IMAGE_GUARD_CFW_INSTRUMENTED 0x000000200 // Module performs control flow and write integrity checks #define IMAGE_GUARD_CF_FUNCTION_TABLE_PRESENT 0x000000400 // Module contains valid control flow target metadata #define IMAGE_GUARD_SECURITY_COOKIE_UNUSED 0x000000800 // Module does not make use of the /GS security cookie #define IMAGE_GUARD_PROTECT_DELAYLOAD_IAT 0x00001000 // Module supports read only delay load IAT #define IMAGE_GUARD_DELAYLOAD_IAT_IN_ITS_OWN_SECTION 0x00002000 // Delayload import table in its own .didat section (with nothing else in it) that can be freely reprotected #define IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK 0xF0000000 // Stride of Guard CF function table encoded in these bits (additional count of bytes per element) #define IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_SHIFT 28 // Shift to right-justify Guard CF function table stride #endif //---------------------------------------------------------------------- // MS Windows CLSID, GUID struct clsid_t { uint32 id1; uint16 id2; uint16 id3; uchar id4[8]; bool operator == (const struct clsid_t &r) const { return memcmp(this, &r, sizeof(r)) == 0; } }; //---------------------------------------------------------------------- // RSDS debug information struct rsds_t { uint32 magic; #define RSDS_MAGIC MC4('R','S','D','S') #define UTDS_MAGIC MC4('u','T','D','S') clsid_t guid; uint32 age; // char name[]; // followed by a zero-terminated UTF8 file name }; //---------------------------------------------------------------------- // NB10 debug information struct cv_info_pdb20_t { uint32 magic; // 'NB10' #define NB10_MAGIC MC4('N', 'B', '1', '0') uint32 offset; uint32 signature; uint32 age; // char pdb_file_name[]; }; //---------------------------------------------------------------------- // MTOC debug information. // denotes EFI binaries that were built on OSX as Mach-O, then converted to PE by the 'mtoc' utility. // see https://opensource.apple.com/source/cctools/cctools-921/efitools/mtoc.c.auto.html struct mtoc_info_t { uint32 magic; // 'MTOC' #define MTOC_MAGIC MC4('M', 'T', 'O', 'C') uchar uuid[16]; // UUID of original Mach-O file // char debug_filename[]; }; // TE (Terse Executable) struct teheader_t { uint16 signature; // 00 uint16 machine; // 02 same as in PE bool is_64bit_cpu(void) const { return machine == PECPU_AMD64 || machine == PECPU_IA64 || machine == PECPU_ARM64; } uint8 nobjs; // 04 number of sections uint8 subsys; // 05 target subsystem uint16 strippedsize; // 06 number of bytes removed from the base of the original image int32 first_section_pos(int32 peoff) const { return peoff + sizeof(teheader_t); } // value which should be added to the sections' file offsets and RVAs int32 te_adjust() const { return sizeof(teheader_t) - strippedsize; } uint32 entry; // 08 Entry point uint32 text_start; // 0C Base of code uint64 imagebase64; // 10 Virtual base of the image. uint64 imagebase() const { return imagebase64; } petab_t reltab; // 18 Relocation Table petab_t debdir; // 20 Debug Directory }; const char *get_pe_machine_name(uint16 machine); void print_pe_flags(uint16 flags); #pragma pack(pop) #endif