source: trunk/tools/common/kFilePE.cpp@ 4358

Last change on this file since 4358 was 4358, checked in by bird, 25 years ago

Added some limited dump capabilities for PE executables.

File size: 13.0 KB
Line 
1/*
2 * kFilePE - PE files.
3 *
4 * Copyright (c) 1999 knut st. osmundsen
5 *
6 */
7
8/*******************************************************************************
9* Defined Constants *
10*******************************************************************************/
11/* emx fixups */
12#ifdef __EMX__
13 #define __stdcall
14 #define max(a,b) (((a) > (b)) ? (a) : (b))
15 #define min(a,b) (((a) < (b)) ? (a) : (b))
16#endif
17
18/******************************************************************************
19* Header Files *
20******************************************************************************/
21#ifdef __EMX__
22#define INT INT_
23#define PCHAR PCHAR_
24#endif
25#include <os2.h>
26#ifdef __EMX__
27#undef PCHAR
28#undef INT
29#endif
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <malloc.h>
34#include <assert.h>
35#include <peexe.h>
36#include "kFile.h"
37#include "kFileFormatBase.h"
38#include "kFilePe.h"
39
40
41/**
42 * Constructs a kFilePE object for a file.
43 * @param phFile File to create object from.
44 * @remark throws errorcode (TODO: errorhandling.)
45 */
46kFilePE::kFilePE(FILE *phFile) throw(int) : pvBase(NULL),
47 pDosHdr(NULL), pFileHdr(NULL), pOptHdr(NULL), paDataDir(NULL), paSectionHdr(NULL),
48 pExportDir(NULL),
49 pImportDir(NULL),
50 pRsrcDir(NULL),
51 pBRelocDir(NULL),
52 pDebugDir(NULL),
53 pCopyright(NULL),
54 pulGlobalPtr(NULL),
55 pTLSDir(NULL),
56 pLoadConfigDir(NULL),
57 pBoundImportDir(NULL),
58 pIATDir(NULL),
59 pDelayImportDir(NULL)
60{
61 IMAGE_DOS_HEADER doshdr;
62
63 /* read dos-header - assumes there is one */
64 if (!fseek(phFile, 0, SEEK_SET)
65 && fread(&doshdr, sizeof(doshdr), 1, phFile) == 1
66 && doshdr.e_magic == IMAGE_DOS_SIGNATURE
67 && doshdr.e_lfanew > sizeof(doshdr)
68 )
69 {
70 IMAGE_NT_HEADERS pehdr;
71
72 /* read pe headers */
73 if (!fseek(phFile, doshdr.e_lfanew, SEEK_SET)
74 && fread(&pehdr, sizeof(pehdr), 1, phFile) == 1
75 && pehdr.Signature == IMAGE_NT_SIGNATURE
76 && pehdr.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER)
77 && pehdr.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC)
78 {
79 /* create mapping */
80 pvBase = malloc((size_t)pehdr.OptionalHeader.SizeOfImage);
81 if (pvBase != NULL)
82 {
83 memset(pvBase, 0, (size_t)pehdr.OptionalHeader.SizeOfImage);
84 /*
85 printf("%ld\n", pehdr.OptionalHeader.SizeOfHeaders);
86 printf("%ld\n", sizeof(IMAGE_NT_HEADERS) + sizeof(IMAGE_SECTION_HEADER) * pehdr.FileHeader.NumberOfSections);
87 assert(pehdr.OptionalHeader.SizeOfHeaders ==
88 sizeof(IMAGE_NT_HEADERS) + sizeof(IMAGE_SECTION_HEADER) * pehdr.FileHeader.NumberOfSections);
89 */
90 if (!fseek(phFile, 0, SEEK_SET)
91 && fread(pvBase, (size_t)pehdr.OptionalHeader.SizeOfHeaders, 1, phFile) == 1
92 )
93 {
94 /* read sections */
95 for (int i = 0; i < pehdr.FileHeader.NumberOfSections; i++)
96 {
97 ULONG cbSection;
98 PIMAGE_SECTION_HEADER pSectionHdr =
99 #if 0
100 IMAGE_FIRST_SECTION(((ULONG)pvBase + ((PIMAGE_DOS_HEADER)pvBase)->e_lfanew));
101 #else
102 (PIMAGE_SECTION_HEADER) ( (ULONG)pvBase + doshdr.e_lfanew + sizeof(IMAGE_NT_HEADERS) );
103 #endif
104 pSectionHdr += i;
105
106 cbSection = min(pSectionHdr->Misc.VirtualSize, pSectionHdr->SizeOfRawData);
107 if (cbSection
108 &&
109 (fseek(phFile, pSectionHdr->PointerToRawData, SEEK_SET)
110 ||
111 fread((void*)((ULONG)pvBase + pSectionHdr->VirtualAddress), (size_t)cbSection, 1, phFile) != 1
112 )
113 )
114 {
115 /* error */
116 free(pvBase);
117 pvBase = NULL;
118 throw(6);
119 }
120 }
121
122 /* set pointers */
123 if (*(unsigned short*)pvBase == IMAGE_DOS_SIGNATURE)
124 {
125 pDosHdr = (PIMAGE_DOS_HEADER)pvBase;
126 pFileHdr = (PIMAGE_FILE_HEADER)((DWORD)pvBase + pDosHdr->e_lfanew + 4);
127 }
128 else
129 pFileHdr = (PIMAGE_FILE_HEADER)((DWORD)pvBase + 4);
130
131 pOptHdr = (PIMAGE_OPTIONAL_HEADER)((int)pFileHdr + sizeof(*pFileHdr));
132 paDataDir = (PIMAGE_DATA_DIRECTORY)((int)pOptHdr + pFileHdr->SizeOfOptionalHeader
133 - pOptHdr->NumberOfRvaAndSizes*sizeof(*paDataDir));
134 paSectionHdr = (PIMAGE_SECTION_HEADER)((int)paDataDir +
135 pOptHdr->NumberOfRvaAndSizes*sizeof(*paDataDir));
136
137 //if (paDataDir[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)
138 // pExportDir = (PIMAGE_EXPORT_DIRECTORY)((int)pvBase + paDataDir[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
139 for (i = 0; i < pOptHdr->NumberOfRvaAndSizes && i < 16; i++)
140 {
141 if (paDataDir[i].VirtualAddress != 0)
142 {
143 if (paDataDir[i].VirtualAddress < pOptHdr->SizeOfImage)
144 ((PULONG)&this->pExportDir)[i] = (int)pvBase + paDataDir[i].VirtualAddress;
145 #ifdef DEBUG
146 else
147 fprintf(stderr, "bad directory pointer %d\n", i);
148 #endif
149 }
150 }
151 }
152 else
153 throw(4);
154 }
155 else
156 throw(3);
157 }
158 else
159 throw(2);
160 }
161 else
162 throw(1);
163}
164
165
166/**
167 * Destructor.
168 */
169kFilePE::~kFilePE()
170{
171 if (pvBase)
172 delete pvBase;
173}
174
175
176/**
177 * Query for the module name.
178 * @returns Success indicator. TRUE / FALSE.
179 * @param pszBuffer Pointer to buffer which to put the name into.
180 */
181BOOL kFilePE::queryModuleName(char *pszBuffer)
182{
183 if (pExportDir && pExportDir->Name)
184 strcpy(pszBuffer, (char*)((int)pExportDir->Name + (int)pvBase));
185 else
186 return FALSE;
187
188 return TRUE;
189}
190
191
192/**
193 * Finds the first exports.
194 * @returns Success indicator. TRUE / FALSE.
195 * @param pExport Pointer to export structure.
196 * @remark
197 */
198BOOL kFilePE::findFirstExport(PEXPORTENTRY pExport)
199{
200 if (pExportDir && pExportDir->NumberOfFunctions)
201 {
202 memset(pExport, 0, sizeof(EXPORTENTRY));
203 pExport->ulOrdinal = pExportDir->Base - 1;
204 return findNextExport(pExport);
205 }
206
207 return FALSE;
208}
209
210
211/**
212 * Finds the next export.
213 * @returns Success indicator. TRUE / FALSE.
214 * @param pExport Pointer to export structure.
215 * @remark
216 */
217BOOL kFilePE::findNextExport(PEXPORTENTRY pExport)
218{
219 if (pExportDir && pExportDir->NumberOfFunctions)
220 {
221 void **ppv = (void**)((int)pExportDir->AddressOfFunctions + (int)pvBase);
222
223 ++pExport->ulOrdinal -= pExportDir->Base;
224 while (ppv[pExport->ulOrdinal] == NULL && pExport->ulOrdinal < pExportDir->NumberOfFunctions)
225 pExport->ulOrdinal++;
226
227 if (pExport->ulOrdinal < pExportDir->NumberOfFunctions)
228 {
229 int iName = 0;
230 unsigned short *pawNameOrdinals = (unsigned short *)
231 ((int)pExportDir->AddressOfNameOrdinals + (int)pvBase);
232
233 /* look for name */
234 while (iName < (int)pExportDir->NumberOfNames &&
235 pawNameOrdinals[iName] != pExport->ulOrdinal)
236 iName++;
237 if (iName < (int)pExportDir->NumberOfNames)
238 strcpy(&pExport->achName[0],
239 (char*)((int)pvBase + ((int*)((int)pvBase + (int)pExportDir->AddressOfNames))[iName]));
240 else
241 pExport->achName[0] = '\0';
242 pExport->ulOrdinal += pExportDir->Base;
243 }
244 else
245 return FALSE;
246 }
247 else
248 return FALSE;
249
250 pExport->achIntName[0] = '\0';
251 pExport->pv = NULL;
252 return TRUE;
253}
254
255
256/**
257 * Mini dump function.
258 */
259BOOL kFilePE::dump(kFile *pOut)
260{
261 int i,j,k;
262 int c;
263
264 /*
265 * Dump sections.
266 */
267 pOut->printf("Sections\n"
268 "--------\n");
269 for (i = 0; i < pFileHdr->NumberOfSections; i++)
270 {
271 pOut->printf("%2d %-8.8s VirtSize: 0x%08x RVA: 0x%08x\n"
272 " RawSize: 0x%08x FileOffset: 0x%08x\n"
273 " #Relocs: 0x%08x FileOffset: 0x%08x\n"
274 " #LineNbr: 0x%08x FileOffset: 0x%08x\n"
275 " Characteristics: 0x%08x\n",
276 i,
277 paSectionHdr[i].Name,
278 paSectionHdr[i].Misc.VirtualSize,
279 paSectionHdr[i].VirtualAddress,
280 paSectionHdr[i].PointerToRawData,
281 paSectionHdr[i].PointerToRawData,
282 paSectionHdr[i].NumberOfRelocations,
283 paSectionHdr[i].PointerToRelocations,
284 paSectionHdr[i].NumberOfLinenumbers,
285 paSectionHdr[i].PointerToLinenumbers,
286 paSectionHdr[i].Characteristics
287 );
288
289 }
290
291
292 /*
293 * Dump the directories.
294 */
295 pOut->printf("Data Directory\n"
296 "--------------\n");
297 for (i = 0; i < pOptHdr->NumberOfRvaAndSizes; i++)
298 {
299 static const char * apszDirectoryNames[] =
300 {
301 "Export",
302 "Import",
303 "Resource",
304 "Exception",
305 "Security",
306 "Base Reloc",
307 "Debug",
308 "Copyright",
309 "Global Ptr",
310 "TLS",
311 "Load Config",
312 "Bound Import",
313 "IAT",
314 "Delay Import",
315 "COM Descriptor",
316 "unknown",
317 "unknown"
318 };
319
320 pOut->printf("%2d %-16s Size: 0x%08x RVA: 0x%08x\n",
321 i,
322 apszDirectoryNames[i],
323 pOptHdr->DataDirectory[i].Size,
324 pOptHdr->DataDirectory[i].VirtualAddress);
325 }
326 pOut->printf("\n");
327
328
329 /*
330 * Dump TLS directory if present
331 */
332 if (pTLSDir)
333 {
334 pOut->printf("TLS Directory\n"
335 "-------------\n");
336 if (pOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size % sizeof(IMAGE_TLS_DIRECTORY))
337 pOut->printf(" Warning! The size directory isn't a multiple of the directory struct!");
338
339 c = (int)(pOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size / sizeof(IMAGE_TLS_DIRECTORY));
340 for (i = 0; i < c; i++)
341 {
342
343 pOut->printf("%2d StartAddressOfRawData %p\n"
344 " EndAddressOfRawData %p\n"
345 " AddressOfIndex %p\n"
346 " AddressOfCallBacks %p\n"
347 " SizeOfZeroFill %p\n"
348 " Characteristics %p\n",
349 i,
350 pTLSDir[i].StartAddressOfRawData,
351 pTLSDir[i].EndAddressOfRawData,
352 pTLSDir[i].AddressOfIndex,
353 pTLSDir[i].AddressOfCallBacks,
354 pTLSDir[i].SizeOfZeroFill,
355 pTLSDir[i].Characteristics);
356
357 /* Print Callbacks */
358 if (pTLSDir[i].AddressOfCallBacks)
359 {
360 PULONG paulIndex;
361 PULONG paulCallback;
362 ULONG ulBorlandRVAFix = 0UL;
363
364 /* Check if the addresses in the TLSDir is RVAs or real addresses */
365 if (pTLSDir[i].StartAddressOfRawData > pOptHdr->ImageBase)
366 ulBorlandRVAFix = pOptHdr->ImageBase;
367
368 j = 0;
369 paulIndex = (PULONG)((ULONG)pTLSDir[i].AddressOfIndex - ulBorlandRVAFix + (ULONG)this->pvBase);
370 paulCallback = (PULONG)((ULONG)pTLSDir[i].AddressOfCallBacks - ulBorlandRVAFix + (ULONG)this->pvBase);
371 if (*paulCallback)
372 {
373 pOut->printf(" Callbacks:\n");
374 for (j = 0; paulCallback[j] != 0; j++)
375 {
376 pOut->printf(" %02d Address: 0x%08x Index: 0x%08x\n",
377 paulIndex[j],
378 paulCallback[j]);
379 }
380 }
381 else
382 pOut->printf(" (Empty callback array!)\n");
383 }
384
385 }
386
387 pOut->printf("\n");
388 }
389
390
391 return TRUE;
392}
393
Note: See TracBrowser for help on using the repository browser.