2 // PE32 headers (and other shit)
3 // collected from the various sources by Ketmar // Invisible Vector
12 IMAGE_DOS_SIGNATURE
= $5A4D; // MZ
13 IMAGE_DOS_MAGIC
= $5A4D; // MZ
14 IMAGE_NT_SIGNATURE
= $00004550; // PE00
16 IMAGE_SIZEOF_STD_OPTIONAL_HEADER
= 28;
17 IMAGE_SIZEOF_NT_OPTIONAL_HEADER
= 224;
18 IMAGE_NT_OPTIONAL_HDR_MAGIC
= $010B;
20 IMAGE_NUMBEROF_DIRECTORY_ENTRIES
= 16;
22 IMAGE_FILE_EXECUTABLE_IMAGE
= $0002; // file is executable (i.e. no unresolved externel references)
23 IMAGE_FILE_32BIT_MACHINE
= $0100; // 32 bit word machine
24 IMAGE_FILE_DLL
= $2000; // file is a DLL
26 IMAGE_FILE_MACHINE_I386
= $14C;
28 IMAGE_SUBSYSTEM_WINDOWS_GUI
= 2; // windoze GUI subsystem
29 IMAGE_SUBSYSTEM_WINDOWS_CUI
= 3; // windoze character subsystem (console mode)
31 IMAGE_DIRECTORY_ENTRY_EXPORT
= 0; // export Directory
32 IMAGE_DIRECTORY_ENTRY_IMPORT
= 1; // import Directory
33 IMAGE_DIRECTORY_ENTRY_RESOURCE
= 2; // resource Directory
34 IMAGE_DIRECTORY_ENTRY_EXCEPTION
= 3; // exception Directory
35 IMAGE_DIRECTORY_ENTRY_SECURITY
= 4; // security Directory
36 IMAGE_DIRECTORY_ENTRY_BASERELOC
= 5; // base Relocation Table
37 IMAGE_DIRECTORY_ENTRY_DEBUG
= 6; // debug Directory
38 IMAGE_DIRECTORY_ENTRY_COPYRIGHT
= 7; // description String
39 IMAGE_DIRECTORY_ENTRY_GLOBALPTR
= 8; // machine Value (MIPS GP)
40 IMAGE_DIRECTORY_ENTRY_TLS
= 9; // TLS Directory
41 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
= 10; // load Configuration Directory
42 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
= 11; // Bound Import Directory in headers
43 IMAGE_DIRECTORY_ENTRY_IAT
= 12; // Import Address Table
45 IMAGE_SIZEOF_SECTION_HEADER
= 40;
46 IMAGE_SIZEOF_SHORT_NAME
= 8; // section name
48 // section characteristics
49 IMAGE_SCN_CNT_CODE
= $00000020; // contains code
50 IMAGE_SCN_CNT_INITIALIZED_DATA
= $00000040; // contains initialized data
51 IMAGE_SCN_CNT_UNINITIALIZED_DATA
= $00000080; // contains uninitialized data
53 IMAGE_SCN_MEM_DISCARDABLE
= $02000000; // can be discarded
54 IMAGE_SCN_MEM_NOT_CACHED
= $04000000; // is not cachable
55 IMAGE_SCN_MEM_NOT_PAGED
= $08000000; // is not pageable
56 IMAGE_SCN_MEM_SHARED
= $10000000; // is shareable
57 IMAGE_SCN_MEM_EXECUTE
= $20000000; // is executable
58 IMAGE_SCN_MEM_READ
= $40000000; // is readable
59 IMAGE_SCN_MEM_WRITE
= LongWord($80000000); // is writeable
68 PE_DIR_DESCRIPTION
= 7;
71 PE_DIR_LOADCONFIG
= 10;
72 PE_DIR_BOUNDIMPORT
= 11;
73 PE_DIR_IMPORTADDR
= 12;
74 PE_DIR_DELAYIMPORT
= 13;
75 PE_DIR_COMPLUSHEADER
= 14;
86 RT_RCDATA
= 10; // ???
87 RT_MESSAGE_TABLE
= 11;
96 TImageDOSHeader
= packed record
97 e_magic
: Word; // magic number
98 e_cblp
: Word; // bytes on last page of file
99 e_cp
: Word; // pages in file
100 e_crlc
: Word; // relocations
101 e_cparhdr
: Word; // size of header in paragraphs
102 e_minalloc
: Word; // minimum extra paragraphs needed
103 e_maxalloc
: Word; // maximum extra paragraphs needed
104 e_ss
: Word; // initial (relative) SS value
105 e_sp
: Word; // initial SP value
106 e_csum
: Word; // checksum
107 e_ip
: Word; // initial IP value
108 e_cs
: Word; // initial (relative) CS value
109 e_lfarlc
: Word; // file address of relocation table
110 e_ovno
: Word; // overlay number
111 e_res
: packed array [0..3] of Word; // reserved words
112 e_oemid
: Word; // OEM identifier (for e_oeminfo)
113 e_oeminfo
: Word; // OEM information; e_oemid specific
114 e_res2
: packed array [0..9] of Word; // reserved words
115 _lfanew
: LongWord; // +$3C; file address of new exe header
118 PPEHeader
= ^TPEHeader
;
119 TPEHeader
= packed record
120 signature
: LongWord; //+$00; 'PE'#0#0
121 machine
: Word; //+$04; 0x14C-0x14F - x86-compatible
122 numberOfSections
: Word; //+$06; max - 96 (why? %-)
123 timeDateStamp
: LongWord; //+$08; shit. PE is full of shit...
124 pointerToSymbolTable
: LongWord; //+$0C; COFF symbol table. another shit.
125 numberOfSymbols
: LongWord; //+$10; and shit again.
126 ntHdrSize
: Word; //+$14; for COFF(obj) - 0, for pe - not 0. ;-)
128 // ok, let me tell you 'bout this stuff... %-)
129 // 0: =1 - relocations is stripped. for COFF %-) PE ignores this
130 // 1: =0 - image cannot be executed (really?)
131 //2,3: =1 - COFF line numbers and local symbols was stripped
132 // 4: =1 - aggresively trim working set (does nothing, afaik)
133 // 5: =1 - application can handle >2Gb addresses (newer saw one)
134 // 6: =0 - reserved, should be zero (the best flag of all! %-)
135 // 7: =1 - bytes swaped (x86-like) (windoze ignores this. at least XP)
136 // 8: =1 - 32-bit machine
137 // 9: =1 - debug info stripped (COFF again?)
138 // 10: =1 - copy to swap if executed from removable media (shit)
140 // 12: =1 - system file (and what it means?)
141 // 13: =1 - DLL, else -- application (which, in fact, can be loaded like
142 // any normal DLL. if it has the export section, we even can import
143 // something from EXE. but there will be no ititialization or
144 // shutdown for EXEs (alas...%-( )
145 // note: Win2K (may be NT/XP too?) doesn't apply fixups. asshole.
146 // chorus behind the scene: I LOVE MICRO$OFT!!!
147 // 14: =1 - "File should be run only on a UP machine". UP means "uniprocessor"
148 // 15: =1 - big endian machine (i.e. motorolas, etc.)
149 // let's drop a sight at bit 7. WHY IT IS HERE?!
150 // chorus: I *REALLY* LOVE MICRO$OFT!!!
151 // and "optional" header which is not optional at all %-)
152 magic
: Word; //+$18; $010B - PE32
153 linkerVersion
: Word; //+$1A; shit
154 sizeOfCode
: LongWord; //+$1C; 0
155 sizeOfData
: LongWord; //+$20; 0
156 sizeOfBSS
: LongWord; //+$24; 0
157 entryRVA
: LongWord; //+$28; rva. optional for DLLs (yep? ;-)
158 baseOfCode
: LongWord; //+$2C; rva again
159 baseOfData
: LongWord; //+$30; and one more rva, unused in PE
160 // NT additional fields
161 imageBase
: LongWord; //+$34; preferred loading address (not an RVA)
162 sectionAlignment
: LongWord;//+$38; default value is 0x1000 (page size)
163 fileAlignment
: LongWord; //+$3C; power of 2(512-64K), if sectionAlignment is less then page size then this must match SA
164 osMajor
: Word; //+$40; how's interesting...
165 osMinor
: Word; //+$42; ...
166 userMajor
: Word; //+$44; another meaningful fields...
167 userMinor
: Word; //+$46; ...
168 subsysMajor
: Word; //+$48; they driving me crazy... ;-)
169 subsysMinor
: Word; //+$4A; ...
170 w32VerValue
: LongWord; //+$4C; noting...
171 imageSize
: LongWord; //+$50; size, in bytes, of image, including all headers; must be a multiple of Section Alignment
172 headerSize
: LongWord; //+$54; combined size of MS-DOS stub, PE header, and section headers rounded up to a multiple of fileAlignment
173 fileChecksum
: LongWord; //+$58; significant for all drivers, any DLL loaded at boot time, and any DLL that ends up in the server. see IMAGHELP.DLL for algorithm
174 subsystem
: Word; //+$5C; 2 - GUI, 3 - CONSOLE, other is shit
175 dllFlags
: Word; //+$5E; bits 0..3 are reserved, bit 15 - terminal server aware, bit 13 - WDM driver, bit 11 - do not bind image
176 stackReserveSize
: LongWord; //+$60; max stack
177 stackCommitSize
: LongWord; //+$64; stack growing up by stackCommitSize bytes
178 heapReserveSize
: LongWord; //+$68; the same for heap
179 heapCommitSize
: LongWord; //+$6C; ...
180 loaderFlags
: LongWord; //+$70; nothing. obsolete field
181 numberOfRvaAndSizes
: LongWord; //+$74; # of valid objects in the following directory
183 //+$78; IMAGE_DATA_DIRECTORY - 16 entries
186 exportTableRVA
: LongWord; //+$78
187 totalExportDataSize
: LongWord; //+$7C
188 importTableRVA
: LongWord; //+$80
189 totalImportDataSize
: LongWord; //+$84
190 resourceTableRVA
: LongWord; //+$88
191 totalResourceDataSize
: LongWord; //+$8C
192 exceptionTableRVA
: LongWord; //+$90 not used on x86
193 totalExceptionDataSize
: LongWord; //+$94
194 securityTableRVA
: LongWord; //+$98 this will NOT be load into memory
195 totalSecurityDataSize
: LongWord; //+$9C
196 relocationTableRVA
: LongWord; //+$A0
197 totalRelocationDataSize
: LongWord; //+$A4
198 debugTableRVA
: LongWord; //+$A8
199 totalDebugDataSize
: LongWord; //+$AC
200 descriptionRVA
: LongWord; //+$B0
201 totalDescriptionDataSize
: LongWord;//+$B4
202 machineSpecificRVA
: LongWord; //+$B8
203 totalMachineSpecificDataSize
: LongWord;//+$BC
204 tlsTableRVA
: LongWord; //+$C0 statical data must NOT be used in DLLs that can be LoadLibrary'ed
205 totalTLSDataSize
: LongWord; //+$C4
206 loadConfigurationTableRVA
: LongWord;//+$C8
207 totalLoadConfigurationDataSize
: LongWord;//+$CC
208 boundImportTableRVA
: LongWord; //+$D0
209 totalBoundImportDataSize
: LongWord;//+$D4
210 iatTableRVA
: LongWord; //+$D8
211 totalIATDataSize
: LongWord; //+$DC
212 delayImportTableRVA
: LongWord; //+$E0
213 totalDelayImportDataSize
: LongWord;//+$E4
214 comPlusRuntimeHeaderRVA
: LongWord; //+$E8
215 comPlusRuntimeHeaderDataSize
: LongWord;//+$EC
216 resObjData
: packed array [0..1] of LongWord;//+$F0
218 1: (dirEntries
: packed array [0..15] of record rva
, size
: LongWord; end);
219 // if rva = 0 - field is unused
222 PPESectionInfo
= ^TPESectionInfo
;
223 TPESectionInfo
= packed record
224 name
: packed array [0..7] of Char;
225 virtualSize
: LongWord; //+$08; if this value is greater than PhysicalSize, the section is zero-padded
226 rva
: LongWord; //+$0C;
227 physSize
: LongWord; //+$10; on disk
228 physOffset
: LongWord; //+$14; in file, can be 0 if section contains only uninitialized data
229 fixupPointer
: LongWord; //+$18; file pointer, COFF only
230 lineNumberPointer
: LongWord; //+$1C; COFF only
231 fixupCount
: Word; //+$20; COFF only
232 lineCount
: Word; //+$22; COFF only
233 flags
: LongWord; //+$24
234 // bits 0-5 are reserved
235 // 6: =1 - contains executable code
236 // 7: =1 - contains initialized data
237 // 8: =1 - contains uninitialized data
239 // 25: =1 - can be discarded
240 // 26: =1 - cannot be cached
241 // 27: =1 - not pageable
242 // 28: =1 - can be shared in memory (can or should???)
243 // 29: =1 - can be executed
244 // 30: =1 - can be read
245 // 31: =1 - can be written to
248 PPEImportRec
= ^TPEImportRec
;
249 TPEImportRec
= packed record
250 origFirstThunkRVA
: LongWord; //+$00, can be 0, then take firstThunkRVA
251 timeDateStamp
: LongWord; //+$04
252 forwarderChainRVA
: LongWord; //+$08
253 nameRVA
: LongWord; //+$0C
254 firstThunkRVA
: LongWord; //+$10
257 PPEImportByName
= ^TPEImportByName
;
258 TPEImportByName
= packed record
260 name
: packed array [0..0] of Char;
263 PPEExportDir
= ^TPEExportDir
;
264 TPEExportDir
= packed record
265 characteristics
: LongWord;
266 timeDateStamp
: LongWord;
271 functionCount
: LongWord;
273 functionsRVA
: LongWord;
275 nameOrdinalsRVA
: LongWord;
278 PPETLSCallback
= procedure (dllHandle
: Pointer; reason
: LongWord; reserved
: Pointer); stdcall;
280 PPETLSDir
= ^TPETLSDir
;
281 TPETLSDir
= packed record
282 rawDataStart
: LongWord; // ~rva, add baseOfCode to obtain rva
283 rawDataEnd
: LongWord; // ~rva, add baseOfCode to obtain rva
284 indexRVA
: LongWord; // rva (PDWORD, as Jedi says). wtf???
285 callbacksRVA
: LongWord;
286 // rva; array of PPETLSCallback (ends with zero dword)
287 sizeOfZeroFill
: LongWord; // ???
288 characteristics
: LongWord; // zero (afais)
291 PPEResourceDirTable
= ^TPEResourceDirTable
;
292 TPEResourceDirTable
= packed record
293 characteristics
: LongWord; // unused?
294 timeDateStamp
: LongWord;
297 numberOfNamedEntries
: Word;
298 numberOfIdEntries
: Word;
301 // this immediately follows TPEResourceDirTable, named first
302 PPEResourceDirEntry
= ^TPEResourceDirEntry
;
303 TPEResourceDirEntry
= packed record
307 // =1: name, ofs from the beginning of the resource raw data,
308 // unicode string, first word is len, no trailing zero
309 // for ROOT dir (level 0): RT_xxx
310 // level 1: resource id or resource name
311 // level 2: language-id (must be a number)
313 // offset from the beginning of the resource raw data
315 // =0: to TPEResourceDataEntry
316 // =1: to the next dir (TPEResourceDirTable)
319 PPEResourceDataEntry
= ^TPEResourceDataEntry
;
320 TPEResourceDataEntry
= packed record
327 PPEResourceTableDirEntry
= ^TPEResourceTableDirEntry
;
328 TPEResourceTableDirEntry
= packed record
329 table
: TPEResourceDirTable
;
330 directory
: TPEResourceDirEntry
;
333 PPEIconDirEntry
= ^TPEIconDirEntry
;
334 TPEIconDirEntry
= packed record
341 bytesInRes
: LongWord;
345 PPEIconDir
= ^TPEIconDir
;
346 TPEIconDir
= packed record
350 //entries: packed array [0..31] of TPEIconDirEntry;
353 // peImg: buffer with PE image (loaded as-is)
354 // functions doesn't validate PE
356 // can return nil (out of image data)
357 // but this can be BSS!
358 function rva2ptr (peImg
: Pointer; rva
: LongWord): Pointer;
360 function getPEHeaderPtr (peImg
: Pointer): PPEHeader
;
361 function getPESectionsPtr (peImg
: Pointer): PPESectionInfo
;
363 // simple checks only!
364 function isValidPE (peImg
: Pointer): Boolean;
368 PResData
= ^TResData
;
371 data
: PChar; // читаем данные отсюда
373 rvaPatch
: PLongWord; // ставится не здесь
376 // ищем первый ресурс с типом rt
377 function peFindFirstRT (pe
: Pointer; rt
: LongWord; out rdo
: TResData
; cnt
: Integer=-1): Boolean;
383 function getPEHeaderPtr (peImg
: Pointer): PPEHeader
;
385 result
:= PPEHeader(PtrUInt(PtrUInt(peImg
)+PInteger(PtrUInt(peImg
)+$3C)^));
389 function getPESectionsPtr (peImg
: Pointer): PPESectionInfo
;
393 h
:= getPEHeaderPtr(peImg
);
394 result
:= PPESectionInfo(PtrUInt(PtrUInt(h
)+h
.ntHdrSize
+$18));
398 function rva2ptr (peImg
: Pointer; rva
: LongWord): Pointer;
404 h
:= getPEHeaderPtr(peImg
);
405 c
:= h
.numberOfSections
;
406 si
:= Pointer(PtrUInt(PtrUInt(h
)+h
.ntHdrSize
+$18));
409 if (si
.rva
<> 0) and (si
.physSize
<> 0) and
410 (rva
>= si
.rva
) and (rva
< si
.rva
+si
.physSize
) then
412 result
:= Pointer(PtrUInt(PtrUInt(peImg
)+si
.physOffset
+(rva
-si
.rva
)));
418 if (rva
< h
.headerSize
) then result
:= Pointer(PtrUInt(PtrUInt(peImg
)+rva
)) else result
:= nil;
422 function isValidPE (peImg
: Pointer): Boolean;
428 if (peImg
= nil) then exit
;
430 //if IsBadReadPtr(peImg, $40) then exit;
431 if (PWord(peImg
)^ <> IMAGE_DOS_MAGIC
) then exit
;
432 lfanew
:= PLongWord(PtrUInt(peImg
)+$3C)^;
433 if (lfanew
= 0) then exit
;
434 h
:= Pointer(PtrUInt(PtrUInt(peImg
)+lfanew
));
435 //if IsBadReadPtr(h, SizeOf(TPEHeader)) then exit;
436 if (h
.signature
<> IMAGE_NT_SIGNATURE
) or
437 (h
.magic
<> IMAGE_NT_OPTIONAL_HDR_MAGIC
) or
438 (h
.machine
< $14C) or (h
.machine
> $14F) then exit
;
446 function peFindFirstRT (pe
: Pointer; rt
: LongWord; out rdo
: TResData
; cnt
: Integer=-1): Boolean;
450 rtbl
: PPEResourceDirTable
;
451 re
, re1
: PPEResourceDirEntry
;
452 rd
: PPEResourceDataEntry
;
460 h
:= getPEHeaderPtr(pe
);
461 if (h
.resourceTableRVA
= 0) or (h
.totalResourceDataSize
= 0) then exit
;
462 rptr
:= PtrUInt(rva2ptr(pe
, h
.resourceTableRVA
));
463 if (rptr
= 0) then exit
;
464 rtbl
:= PPEResourceDirTable(rptr
);
465 nc
:= Integer(rtbl
.numberOfNamedEntries
);
466 f
:= Integer(rtbl
.numberOfIdEntries
);
468 if (f
= 0) then exit
;
469 re
:= Pointer(PtrUInt(rptr
+sizeof(TPEResourceDirTable
)));
480 // ищем собственно ресурс
482 while ((re1
.subdirOfs
and $80000000) <> 0) do
484 rtbl
:= PPEResourceDirTable(PtrUInt(rptr
+(re1
.subdirOfs
and $7FFFFFFF)));
485 //nc := Integer(rtbl.numberOfNamedEntries)+Integer(rtbl.numberOfIdEntries);
486 //if nc = 0 then Error('resource shit!');
487 re1
:= PPEResourceDirEntry(PtrUInt(PtrUInt(rtbl
)+sizeof(TPEResourceDirTable
)));
489 rd
:= PPEResourceDataEntry(PtrUInt(rptr
+re1
.subdirOfs
));
491 // а здесь -- RVA; заебись некроблядь суперпоследовательна
492 rdo
.data
:= rva2ptr(pe
, rd
.dataOfs
);
493 if (rdo
.data
= nil) then rdo
.size
:= 0 else begin rdo
.rtype
:= rt
; result
:= true; exit
; end;