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