1 { $Id: fpdpeimage.pas 54031 2017-01-29 21:04:32Z joost $ } 2 { 3 --------------------------------------------------------------------------- 4 fpdpeimage.pas - FP standalone debugger - PE Image 5 --------------------------------------------------------------------------- 6 7 This unit contains routines to access or dump the PE header of a executable 8 loaded in memory. 9 10 --------------------------------------------------------------------------- 11 12 @created(Mon Apr 10th WET 2006) 13 @lastmod($Date: 2017-01-29 22:04:32 +0100 (So, 29 Jan 2017) $) 14 @author(Marc Weustink <marc@@dommelstein.nl>) 15 16 *************************************************************************** 17 * * 18 * This source is free software; you can redistribute it and/or modify * 19 * it under the terms of the GNU General Public License as published by * 20 * the Free Software Foundation; either version 2 of the License, or * 21 * (at your option) any later version. * 22 * * 23 * This code is distributed in the hope that it will be useful, but * 24 * WITHOUT ANY WARRANTY; without even the implied warranty of * 25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 26 * General Public License for more details. * 27 * * 28 * A copy of the GNU General Public License is available on the World * 29 * Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also * 30 * obtain it by writing to the Free Software Foundation, * 31 * Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA. * 32 * * 33 *************************************************************************** 34 } 35 unit FPDPEImage; 36 {$mode objfpc}{$H+} 37 interface 38 39 uses 40 Windows, SysUtils, FPDGLobal, FpDbgInfo, FpDbgClasses, FpDbgPETypes, DbgIntfBaseTypes, FpDbgUtil; 41 42 procedure DumpPEImage(const AProcessHandle: THandle; const AAddress: TDbgPtr); 43 44 implementation 45 46 const 47 DIR_NAMES: array[0..IMAGE_NUMBEROF_DIRECTORY_ENTRIES-1] of string = ( 48 'EXPORT', 49 'IMPORT', 50 'RESOURCE', 51 'EXCEPTION', 52 'SECURITY', 53 'BASERELOC', 54 'DEBUG', 55 'COPYRIGHT', 56 'GLOBALPTR', 57 'TLS', 58 'LOAD_CONFIG', 59 'BOUND_IMPORT', 60 'IAT', 61 'DELAY_IMPORT', 62 'COM_DECRIPTOR', 63 'Unknown(15)' 64 ); 65 66 67 procedure DumpPEImage(const AProcessHandle: THandle; const AAddress: TDbgPtr); 68 var 69 DosHeader: TImageDosHeader; 70 NtHeaders: TImageNtHeaders64; // read it as 64 bit, so there is enough room. The fields will be decoded manually 71 SectionHeader: TImageSectionHeader; 72 OH: PImageOptionalHeader64; 73 BytesRead: PtrUInt; 74 R: Boolean; 75 n: Integer; 76 Is64: Boolean; 77 SectionName: array[0..255] of Char; 78 begin 79 if not ReadProcessMemory(AProcessHandle, Pointer(PtrUInt(AAddress)), @DosHeader, SizeOf(DosHeader), BytesRead) 80 then begin 81 WriteLN('Unable to retrieve DOS header'); 82 Exit; 83 end; 84 85 if (DosHeader.e_magic <> IMAGE_DOS_SIGNATURE) 86 or (DosHeader.e_lfanew = 0) 87 then begin 88 WriteLN('Invalid DOS header'); 89 Exit; 90 end; 91 92 if not ReadProcessMemory(AProcessHandle, Pointer(PtrUInt(AAddress + DosHeader.e_lfanew)), @NTHeaders, SizeOf(NTHeaders), BytesRead) 93 then begin 94 WriteLN('Unable to retrieve NT headers'); 95 Exit; 96 end; 97 98 if NTHeaders.Signature <> IMAGE_NT_SIGNATURE 99 then begin 100 WriteLN('Invalid NT header: ', IntToHex(NTHeaders.Signature, 8)); 101 Exit; 102 end; 103 104 WriteLN('FileHeader: '); 105 106 with NTHeaders.FileHeader do 107 begin 108 Write(' Machine: ', IntToHex(Machine, 4)); 109 case Machine of 110 IMAGE_FILE_MACHINE_I386: WriteLN(' (Intel 386)'); 111 IMAGE_FILE_MACHINE_R3000: WriteLN(' (MIPS little-endian, 0x160 big-endian)'); 112 IMAGE_FILE_MACHINE_R4000: WriteLN(' (MIPS little-endian)'); 113 IMAGE_FILE_MACHINE_R10000: WriteLN(' (MIPS little-endian)'); 114 IMAGE_FILE_MACHINE_ALPHA: WriteLN(' (Alpha_AXP)'); 115 IMAGE_FILE_MACHINE_POWERPC: WriteLN(' (IBM PowerPC Little-Endian)'); 116 IMAGE_FILE_MACHINE_IA64: WriteLN(' (Intel IPF)'); 117 IMAGE_FILE_MACHINE_AMD64: WriteLN(' (x64)'); 118 else 119 WriteLN; 120 end; 121 WriteLN(' NumberOfSections: ', NumberOfSections); 122 WriteLN(' TimeDateStamp: ', TimeDateStamp); 123 WriteLN(' PointerToSymbolTable: ', PointerToSymbolTable); 124 WriteLN(' NumberOfSymbols: ', NumberOfSymbols); 125 WriteLN(' SizeOfOptionalHeader: ', SizeOfOptionalHeader); 126 Write(' Characteristics: ', IntToHex(Characteristics, 4), ' ['); 127 128 if Characteristics and IMAGE_FILE_RELOCS_STRIPPED <> 0 then Write('RELOCS_STRIPPED '); 129 if Characteristics and IMAGE_FILE_EXECUTABLE_IMAGE <> 0 then Write('EXECUTABLE_IMAGE '); 130 if Characteristics and IMAGE_FILE_LINE_NUMS_STRIPPED <> 0 then Write('LINE_NUMS_STRIPPED '); 131 if Characteristics and IMAGE_FILE_LOCAL_SYMS_STRIPPED <> 0 then Write('LOCAL_SYMS_STRIPPED '); 132 if Characteristics and IMAGE_FILE_AGGRESIVE_WS_TRIM <> 0 then Write('AGGRESIVE_WS_TRIM '); 133 if Characteristics and IMAGE_FILE_LARGE_ADDRESS_AWARE <> 0 then Write('LARGE_ADDRESS_AWARE '); 134 if Characteristics and IMAGE_FILE_BYTES_REVERSED_LO <> 0 then Write('BYTES_REVERSED_LO '); 135 if Characteristics and IMAGE_FILE_32BIT_MACHINE <> 0 then Write('32BIT_MACHINE '); 136 if Characteristics and IMAGE_FILE_DEBUG_STRIPPED <> 0 then Write('DEBUG_STRIPPED '); 137 if Characteristics and IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP <> 0 then Write('REMOVABLE_RUN_FROM_SWAP '); 138 if Characteristics and IMAGE_FILE_NET_RUN_FROM_SWAP <> 0 then Write('NET_RUN_FROM_SWAP '); 139 if Characteristics and IMAGE_FILE_SYSTEM <> 0 then Write('SYSTEM '); 140 if Characteristics and IMAGE_FILE_DLL <> 0 then Write('DLL '); 141 if Characteristics and IMAGE_FILE_UP_SYSTEM_ONLY <> 0 then Write('UP_SYSTEM_ONLY '); 142 if Characteristics and IMAGE_FILE_BYTES_REVERSED_HI <> 0 then Write('BYTES_REVERSED_HI '); 143 WriteLN(']'); 144 end; 145 146 WriteLN('OptionalHeader: '); 147 OH := @NTHeaders.OptionalHeader; 148 Is64 := OH^.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC; 149 Write(' Magic: ', IntToHex(OH^.Magic, 4)); 150 case OH^.Magic of 151 IMAGE_NT_OPTIONAL_HDR32_MAGIC : WriteLN(' (HDR32)'); 152 IMAGE_NT_OPTIONAL_HDR64_MAGIC : WriteLN(' (HDR64)'); 153 IMAGE_ROM_OPTIONAL_HDR_MAGIC : WriteLN(' (ROM)'); 154 else 155 WriteLN; 156 end; 157 WriteLN(' MajorLinkerVersion: ', OH^.MajorLinkerVersion); 158 WriteLN(' MinorLinkerVersion: ', OH^.MinorLinkerVersion); 159 WriteLN(' SizeOfCode: ', OH^.SizeOfCode); 160 WriteLN(' SizeOfInitializedData: ', OH^.SizeOfInitializedData); 161 WriteLN(' SizeOfUninitializedData: ', OH^.SizeOfUninitializedData); 162 WriteLN(' AddressOfEntryPoint: ', FormatAddress(OH^.AddressOfEntryPoint)); 163 WriteLN(' BaseOfCode: ', FormatAddress(OH^.BaseOfCode)); 164 if Is64 165 then begin 166 WriteLN(' ImageBase: $', IntToHex(OH^.ImageBase, 16)); 167 end 168 else begin 169 WriteLN(' BaseOfData: $', IntToHex(Integer(OH^.ImageBase), 8)); 170 WriteLN(' ImageBase: $', IntToHex(Integer(OH^.ImageBase shr 32), 8)); 171 end; 172 WriteLN(' SectionAlignment: ', OH^.SectionAlignment); 173 WriteLN(' FileAlignment: ', OH^.FileAlignment); 174 WriteLN(' MajorOperatingSystemVersion: ', OH^.MajorOperatingSystemVersion); 175 WriteLN(' MinorOperatingSystemVersion: ', OH^.MinorOperatingSystemVersion); 176 WriteLN(' MajorImageVersion: ', OH^.MajorImageVersion); 177 WriteLN(' MinorImageVersion: ', OH^.MinorImageVersion); 178 WriteLN(' MajorSubsystemVersion: ', OH^.MajorSubsystemVersion); 179 WriteLN(' MinorSubsystemVersion: ', OH^.MinorSubsystemVersion); 180 WriteLN(' Win32VersionValue: ', OH^.Win32VersionValue); 181 WriteLN(' SizeOfImage: ', OH^.SizeOfImage); 182 WriteLN(' SizeOfHeaders: ', OH^.SizeOfHeaders); 183 WriteLN(' CheckSum: ', OH^.CheckSum); 184 Write(' Subsystem: ', OH^.Subsystem); 185 case OH^.Subsystem of 186 IMAGE_SUBSYSTEM_UNKNOWN: WriteLN(' (Unknown)'); 187 IMAGE_SUBSYSTEM_NATIVE: WriteLN(' (Native)'); 188 IMAGE_SUBSYSTEM_WINDOWS_CUI: WriteLN(' (Windows CUI)'); 189 IMAGE_SUBSYSTEM_WINDOWS_GUI: WriteLN(' (Windows GUI)'); 190 IMAGE_SUBSYSTEM_OS2_CUI: WriteLN(' (OS2_CUI)'); 191 IMAGE_SUBSYSTEM_POSIX_CUI: WriteLN(' (POSIX CUI)'); 192 IMAGE_SUBSYSTEM_WINDOWS_CE_GUI: WriteLN(' (Windows CE GUI)'); 193 IMAGE_SUBSYSTEM_XBOX: WriteLN(' (XBOX)'); 194 else 195 WriteLN; 196 end; 197 Write(' DllCharacteristics: ', IntToHex(OH^.DllCharacteristics, 4), ' ['); 198 if OH^.DllCharacteristics and IMAGE_LIBRARY_PROCESS_INIT <> 0 then Write('PROCESS_INIT (reserved) '); 199 if OH^.DllCharacteristics and IMAGE_LIBRARY_PROCESS_TERM <> 0 then Write('PROCESS_TERM (reserved) '); 200 if OH^.DllCharacteristics and IMAGE_LIBRARY_THREAD_INIT <> 0 then Write('THREAD_INIT (reserved) '); 201 if OH^.DllCharacteristics and IMAGE_LIBRARY_THREAD_TERM <> 0 then Write('THREAD_TERM (reserved) '); 202 if OH^.DllCharacteristics and IMAGE_DLLCHARACTERISTICS_NO_ISOLATION <> 0 then Write('NO_ISOLATION '); 203 if OH^.DllCharacteristics and IMAGE_DLLCHARACTERISTICS_NO_SEH <> 0 then Write('NO_SEH '); 204 if OH^.DllCharacteristics and IMAGE_DLLCHARACTERISTICS_NO_BIND <> 0 then Write('NO_BIND '); 205 if OH^.DllCharacteristics and IMAGE_DLLCHARACTERISTICS_WDM_DRIVER <> 0 then Write('WDM_DRIVER '); 206 if OH^.DllCharacteristics and IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE <> 0 then Write('TERMINAL_SERVER_AWARE '); 207 WriteLN(']'); 208 209 Write(' SizeOfStackReserve: $'); 210 if Is64 211 then begin 212 WriteLN(IntToHex(OH^.SizeOfStackReserve, 16)); 213 end 214 else begin 215 WriteLN(IntToHex(Integer(OH^.SizeOfStackReserve), 8)); 216 Dec(PChar(OH), 4); // adjust with 4 bytes so the next record matches again 217 end; 218 Write(' SizeOfStackCommit: $'); 219 if Is64 220 then begin 221 WriteLN(IntToHex(OH^.SizeOfStackCommit, 16)); 222 end 223 else begin 224 WriteLN(IntToHex(Integer(OH^.SizeOfStackCommit), 8)); 225 Dec(PChar(OH), 4); // adjust with 4 bytes so the next record matches again 226 end; 227 Write(' SizeOfHeapReserve: $'); 228 if Is64 229 then begin 230 WriteLN(IntToHex(OH^.SizeOfHeapReserve, 16)); 231 end 232 else begin 233 WriteLN(IntToHex(Integer(OH^.SizeOfHeapReserve), 8)); 234 Dec(PChar(OH), 4); // adjust with 4 bytes so the next record matches again 235 end; 236 Write(' SizeOfHeapCommit: $'); 237 if Is64 238 then begin 239 WriteLN(IntToHex(OH^.SizeOfHeapCommit, 16)); 240 end 241 else begin 242 WriteLN(IntToHex(Integer(OH^.SizeOfHeapCommit), 8)); 243 Dec(PChar(OH), 4); // adjust with 4 bytes so the next record matches again 244 end; 245 WriteLN(' LoaderFlags: ', OH^.LoaderFlags); 246 WriteLN(' NumberOfRvaAndSizes: ', OH^.NumberOfRvaAndSizes); 247 WriteLN(' DataDirectory:'); 248 for n := 0 to IMAGE_NUMBEROF_DIRECTORY_ENTRIES-1 do 249 begin 250 WriteLN(' [', DIR_NAMES[n]+']':14, ' Address: $', IntToHex(OH^.DataDirectory[n].VirtualAddress, 8), ' Size: ', OH^.DataDirectory[n]. Size); 251 end; 252 253 WriteLN('Sections: '); 254 for n := 0 to NtHeaders.FileHeader.NumberOfSections - 1 do 255 begin 256 if not ReadProcessMemory(AProcessHandle, Pointer(PtrUInt(AAddress + DosHeader.e_lfanew + SizeOF(NTHeaders) - SizeOF(NTHeaders.OptionalHeader) + NTHeaders.FileHeader.SizeOfOptionalHeader + SizeOf(SectionHeader) * n)), @SectionHeader, SizeOf(SectionHeader), BytesRead) 257 then begin 258 WriteLN('Unable to retrieve section: ', n); 259 Continue; 260 end; 261 with SectionHeader do 262 begin 263 Write(' Name: '); 264 if (Name[0] = Ord('/')) and (Name[1] in [Ord('0')..Ord('9')]) 265 then begin 266 // long name 267 268 if ReadProcessMemory( 269 AProcessHandle, 270 Pointer(PtrUInt(AAddress + NTHeaders.FileHeader.PointerToSymbolTable + NTHeaders.FileHeader.NumberOfSymbols * IMAGE_SIZEOF_SYMBOL + StrToIntDef(PChar(@Name[1]), 0))), 271 @SectionName, 272 SizeOf(SectionName), 273 BytesRead 274 ) 275 then WriteLn(SectionName) 276 else WriteLn('Unable to retrieve sectionname @', PChar(@Name[1])); 277 end 278 else begin 279 // short name 280 Move(Name, SectionName, IMAGE_SIZEOF_SHORT_NAME); 281 SectionName[IMAGE_SIZEOF_SHORT_NAME] := #0; // make it #0 terminated 282 WriteLn(SectionName); 283 end; 284 285 WriteLN(' Misc.PhysicalAddress: ',FormatAddress(Misc.PhysicalAddress)); 286 WriteLN(' Misc.VirtualSize: ',Misc.VirtualSize); 287 WriteLN(' VirtualAddress: ',FormatAddress(VirtualAddress)); 288 WriteLN(' SizeOfRawData: ',SizeOfRawData); 289 WriteLN(' PointerToRawData: ',FormatAddress(PointerToRawData)); 290 WriteLN(' PointerToRelocations: ',FormatAddress(PointerToRelocations)); 291 WriteLN(' PointerToLinenumbers: ',FormatAddress(PointerToLinenumbers)); 292 WriteLN(' NumberOfRelocations: ',NumberOfRelocations); 293 WriteLN(' NumberOfLinenumbers: ',NumberOfLinenumbers); 294 Write(' Characteristics: ', IntToHex(Characteristics, 8), ' ['); 295 if Characteristics and IMAGE_SCN_TYPE_REG <> 0 then Write('IMAGE_SCN_TYPE_REG(r) '); 296 if Characteristics and IMAGE_SCN_TYPE_DSECT <> 0 then Write('IMAGE_SCN_TYPE_DSECT(r) '); 297 if Characteristics and IMAGE_SCN_TYPE_NOLOAD <> 0 then Write('IMAGE_SCN_TYPE_NOLOAD(r) '); 298 if Characteristics and IMAGE_SCN_TYPE_GROUP <> 0 then Write('IMAGE_SCN_TYPE_GROUP(r) '); 299 if Characteristics and IMAGE_SCN_TYPE_NO_PAD <> 0 then Write('IMAGE_SCN_TYPE_NO_PAD(r) '); 300 if Characteristics and IMAGE_SCN_TYPE_COPY <> 0 then Write('IMAGE_SCN_TYPE_COPY(r) '); 301 if Characteristics and IMAGE_SCN_CNT_CODE <> 0 then Write('IMAGE_SCN_CNT_CODE '); 302 if Characteristics and IMAGE_SCN_CNT_INITIALIZED_DATA <> 0 then Write('IMAGE_SCN_CNT_INITIALIZED_DATA '); 303 if Characteristics and IMAGE_SCN_CNT_UNINITIALIZED_DATA <> 0 then Write('IMAGE_SCN_CNT_UNINITIALIZED_DATA '); 304 if Characteristics and IMAGE_SCN_LNK_OTHER <> 0 then Write('IMAGE_SCN_LNK_OTHER(r) '); 305 if Characteristics and IMAGE_SCN_LNK_INFO <> 0 then Write('IMAGE_SCN_LNK_INFO(r) '); 306 if Characteristics and IMAGE_SCN_TYPE_OVER <> 0 then Write('IMAGE_SCN_TYPE_OVER(r) '); 307 if Characteristics and IMAGE_SCN_LNK_COMDAT <> 0 then Write('IMAGE_SCN_LNK_COMDAT '); 308 if Characteristics and IMAGE_SCN_MEM_PROTECTED <> 0 then Write('IMAGE_SCN_MEM_PROTECTED(o) '); 309 if Characteristics and IMAGE_SCN_MEM_FARDATA <> 0 then Write('IMAGE_SCN_MEM_FARDATA(r) '); 310 if Characteristics and IMAGE_SCN_MEM_SYSHEAP <> 0 then Write('IMAGE_SCN_MEM_SYSHEAP(o) '); 311 if Characteristics and IMAGE_SCN_MEM_PURGEABLE <> 0 then Write('IMAGE_SCN_MEM_PURGEABLE(r) '); 312 if Characteristics and IMAGE_SCN_MEM_16BIT <> 0 then Write('IMAGE_SCN_MEM_16BIT(r) '); 313 if Characteristics and IMAGE_SCN_MEM_LOCKED <> 0 then Write('IMAGE_SCN_MEM_LOCKED(r) '); 314 if Characteristics and IMAGE_SCN_MEM_PRELOAD <> 0 then Write('IMAGE_SCN_MEM_PRELOAD(r) '); 315 // Align 316 if Characteristics and $00F00000 <> 0 317 then Write('IMAGE_SCN_ALIGN_', 1 shl (((Characteristics and $00F00000) shr 20) - 1),'BYTES '); 318 if Characteristics and IMAGE_SCN_LNK_NRELOC_OVFL <> 0 then Write('IMAGE_SCN_LNK_NRELOC_OVFL '); 319 if Characteristics and IMAGE_SCN_MEM_DISCARDABLE <> 0 then Write('IMAGE_SCN_MEM_DISCARDABLE '); 320 if Characteristics and IMAGE_SCN_MEM_NOT_CACHED <> 0 then Write('IMAGE_SCN_MEM_NOT_CACHED '); 321 if Characteristics and IMAGE_SCN_MEM_NOT_PAGED <> 0 then Write('IMAGE_SCN_MEM_NOT_PAGED '); 322 if Characteristics and IMAGE_SCN_MEM_SHARED <> 0 then Write('IMAGE_SCN_MEM_SHARED '); 323 if Characteristics and IMAGE_SCN_MEM_EXECUTE <> 0 then Write('IMAGE_SCN_MEM_EXECUTE '); 324 if Characteristics and IMAGE_SCN_MEM_READ <> 0 then Write('IMAGE_SCN_MEM_READ '); 325 if Characteristics and IMAGE_SCN_MEM_WRITE <> 0 then Write('IMAGE_SCN_MEM_WRITE '); 326 WriteLN(']'); 327 end; 328 329 end; 330 end; 331 332 333 334 end. 335