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

Last change on this file since 8706 was 8003, checked in by bird, 24 years ago

New kFile* classes; now in sync with os2tools.

File size: 14.1 KB
Line 
1/* $Id: kFilePE.cpp,v 1.5 2002-02-24 02:47:26 bird Exp $
2 *
3 * kFilePE - PE files.
4 *
5 * Copyright (c) 1999 knut st. osmundsen
6 *
7 */
8
9/******************************************************************************
10* Header Files *
11******************************************************************************/
12#include <string.h>
13
14#include "MZexe.h"
15#include "PEexe.h"
16
17#include "kTypes.h"
18#include "kError.h"
19#include "kFile.h"
20#include "kFileFormatBase.h"
21#include "kFileInterfaces.h"
22#include "kFilePE.h"
23
24
25/*******************************************************************************
26* Global Variables *
27*******************************************************************************/
28#if 0
29kFilePE kFilePE((kFile*)NULL);
30#endif
31
32
33/**
34 * Constructs a kFilePE object for a file.
35 * @param pFile File to create object from.
36 * @remark throws errorcode
37 */
38kFilePE::kFilePE(kFile *pFile) :
39 kFileFormatBase(pFile),
40 pvBase(NULL),
41 pDosHdr(NULL), pFileHdr(NULL), pOptHdr(NULL), paDataDir(NULL), paSectionHdr(NULL),
42 pExportDir(NULL),
43 pImportDir(NULL),
44 pRsrcDir(NULL),
45 pBRelocDir(NULL),
46 pDebugDir(NULL),
47 pCopyright(NULL),
48 pulGlobalPtr(NULL),
49 pTLSDir(NULL),
50 pLoadConfigDir(NULL),
51 pBoundImportDir(NULL),
52 pIATDir(NULL),
53 pDelayImportDir(NULL)
54{
55 IMAGE_DOS_HEADER doshdr;
56 long offPEHdr = 0;
57 IMAGE_NT_HEADERS pehdr;
58
59 /* read dos-header (If tehre is one) */
60 pFile->setThrowOnErrors();
61 pFile->readAt(&doshdr, sizeof(doshdr), 0);
62 if (doshdr.e_magic == IMAGE_DOS_SIGNATURE)
63 {
64 if (doshdr.e_lfanew <= sizeof(doshdr))
65 throw(kError(kError::INVALID_EXE_SIGNATURE));
66 offPEHdr = doshdr.e_lfanew;
67 }
68
69 /* read pe headers and do minor verifications */
70 pFile->readAt(&pehdr, sizeof(pehdr), offPEHdr);
71 if (pehdr.Signature != IMAGE_NT_SIGNATURE)
72 throw(kError(kError::INVALID_EXE_SIGNATURE));
73 if ( pehdr.FileHeader.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER)
74 || pehdr.OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
75 throw(kError(kError::BAD_EXE_FORMAT));
76
77 /* create mapping */
78 pvBase = new char [pehdr.OptionalHeader.SizeOfImage];
79 if (pvBase == NULL)
80 throw(kError(kError::NOT_ENOUGH_MEMORY));
81 memset(pvBase, 0, pehdr.OptionalHeader.SizeOfImage);
82
83 /*
84 printf("%ld\n", pehdr.OptionalHeader.SizeOfHeaders);
85 printf("%ld\n", sizeof(IMAGE_NT_HEADERS) + sizeof(IMAGE_SECTION_HEADER) * pehdr.FileHeader.NumberOfSections);
86 kASSERT(pehdr.OptionalHeader.SizeOfHeaders ==
87 sizeof(IMAGE_NT_HEADERS) + sizeof(IMAGE_SECTION_HEADER) * pehdr.FileHeader.NumberOfSections);
88 */
89 try
90 {
91 /* read optional header */
92 pFile->readAt(pvBase, pehdr.OptionalHeader.SizeOfHeaders, 0);
93
94 /* read sections */
95 for (int i = 0; i < pehdr.FileHeader.NumberOfSections; i++)
96 {
97 unsigned long cbSection;
98 PIMAGE_SECTION_HEADER pSectionHdr =
99 #if 0
100 IMAGE_FIRST_SECTION(((unsigned long)pvBase + ((PIMAGE_DOS_HEADER)pvBase)->e_lfanew));
101 #else
102 (PIMAGE_SECTION_HEADER) ( (unsigned long)pvBase + doshdr.e_lfanew + sizeof(IMAGE_NT_HEADERS) );
103 #endif
104 pSectionHdr += i;
105
106 cbSection = KMIN(pSectionHdr->Misc.VirtualSize, pSectionHdr->SizeOfRawData);
107 if (cbSection)
108 pFile->readAt((char*)pvBase + pSectionHdr->VirtualAddress,
109 cbSection, pSectionHdr->PointerToRawData);
110 }
111
112 /* set pointers */
113 if (*(unsigned short*)pvBase == IMAGE_DOS_SIGNATURE)
114 {
115 pDosHdr = (PIMAGE_DOS_HEADER)pvBase;
116 pFileHdr = (PIMAGE_FILE_HEADER)((char*)pvBase + pDosHdr->e_lfanew + 4);
117 }
118 else
119 pFileHdr = (PIMAGE_FILE_HEADER)((char*)pvBase + 4);
120
121 pOptHdr = (PIMAGE_OPTIONAL_HEADER)((int)pFileHdr + sizeof(*pFileHdr));
122 paDataDir = (PIMAGE_DATA_DIRECTORY)((int)pOptHdr + pFileHdr->SizeOfOptionalHeader
123 - pOptHdr->NumberOfRvaAndSizes*sizeof(*paDataDir));
124 paSectionHdr = (PIMAGE_SECTION_HEADER)((int)paDataDir +
125 pOptHdr->NumberOfRvaAndSizes*sizeof(*paDataDir));
126
127 //if (paDataDir[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)
128 // pExportDir = (PIMAGE_EXPORT_DIRECTORY)((int)pvBase + paDataDir[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
129 for (i = 0; i < pOptHdr->NumberOfRvaAndSizes && i < 16; i++)
130 {
131 if (paDataDir[i].VirtualAddress != 0)
132 {
133 if (paDataDir[i].VirtualAddress < pOptHdr->SizeOfImage)
134 ((unsigned long*)&this->pExportDir)[i] = (int)pvBase + paDataDir[i].VirtualAddress;
135 }
136 }
137 }
138 catch (kError err)
139 {
140 delete(pvBase);
141 pvBase = NULL;
142 throw(err);
143 }
144}
145
146
147/**
148 * Destructor.
149 */
150kFilePE::~kFilePE()
151{
152 if (pvBase)
153 delete(pvBase);
154}
155
156
157/**
158 * Query for the module name.
159 * @returns Success indicator. TRUE / FALSE.
160 * @param pszBuffer Pointer to buffer which to put the name into.
161 * @param cchBuffer Size of the buffer (defaults to 260 chars).
162 */
163KBOOL kFilePE::moduleGetName(char *pszBuffer, int cchSize/* = 260*/)
164{
165 if (pExportDir && pExportDir->Name)
166 {
167 char *psz = (char*)((int)pExportDir->Name + (int)pvBase);
168 int cch = strlen(psz) + 1;
169 if (cch > cchSize)
170 return FALSE;
171 memcpy(pszBuffer, psz, cch);
172 }
173 else
174 return FALSE;
175
176 return TRUE;
177}
178
179
180/**
181 * Finds the first exports.
182 * @returns Success indicator. TRUE / FALSE.
183 * @param pExport Pointer to export structure.
184 * @remark
185 */
186KBOOL kFilePE::exportFindFirst(kExportEntry *pExport)
187{
188 if (pExportDir && pExportDir->NumberOfFunctions)
189 {
190 memset(pExport, 0, sizeof(kExportEntry));
191 pExport->ulOrdinal = pExportDir->Base - 1;
192 return exportFindNext(pExport);
193 }
194
195 return FALSE;
196}
197
198
199/**
200 * Finds the next export.
201 * @returns Success indicator. TRUE / FALSE.
202 * @param pExport Pointer to export structure.
203 * @remark
204 */
205KBOOL kFilePE::exportFindNext(kExportEntry *pExport)
206{
207 if (pExportDir && pExportDir->NumberOfFunctions)
208 {
209 void **ppv = (void**)((int)pExportDir->AddressOfFunctions + (int)pvBase);
210
211 ++pExport->ulOrdinal -= pExportDir->Base;
212 while (ppv[pExport->ulOrdinal] == NULL && pExport->ulOrdinal < pExportDir->NumberOfFunctions)
213 pExport->ulOrdinal++;
214
215 if (pExport->ulOrdinal < pExportDir->NumberOfFunctions)
216 {
217 int iName = 0;
218 unsigned short *pawNameOrdinals = (unsigned short *)
219 ((int)pExportDir->AddressOfNameOrdinals + (int)pvBase);
220
221 /* look for name */
222 while (iName < (int)pExportDir->NumberOfNames &&
223 pawNameOrdinals[iName] != pExport->ulOrdinal)
224 iName++;
225 if (iName < (int)pExportDir->NumberOfNames)
226 strcpy(&pExport->achName[0],
227 (char*)((int)pvBase + ((int*)((int)pvBase + (int)pExportDir->AddressOfNames))[iName]));
228 else
229 pExport->achName[0] = '\0';
230 pExport->ulOrdinal += pExportDir->Base;
231 }
232 else
233 return FALSE;
234 }
235 else
236 return FALSE;
237
238 pExport->ulAddress = pExport->iObject = pExport->ulOffset = ~0UL; /* FIXME/TODO */
239 pExport->achIntName[0] = '\0';
240 pExport->pv = NULL;
241 return TRUE;
242}
243
244
245/**
246 * Frees resources associated with the communicatin area.
247 * It's not necessary to call this when exportFindNext has return FALSE.
248 * (We don't allocate anything so it's not a problem ;-)
249 * @param pExport Communication area which has been successfully
250 * processed by findFirstExport.
251 */
252void kFilePE::exportFindClose(kExportEntry *pExport)
253{
254 pExport = pExport;
255 return;
256}
257
258
259/**
260 * Lookup information on a spesific export given by ordinal number.
261 * @returns Success indicator.
262 * @param pExport Communication area containing export information
263 * on successful return.
264 * @remark stub
265 */
266KBOOL kFilePE::exportLookup(unsigned long ulOrdinal, kExportEntry *pExport)
267{
268 kASSERT(!"not implemented.");
269 ulOrdinal = ulOrdinal;
270 pExport = pExport;
271 return FALSE;
272}
273
274/**
275 * Lookup information on a spesific export given by name.
276 * @returns Success indicator.
277 * @param pExport Communication area containing export information
278 * on successful return.
279 * @remark stub
280 */
281KBOOL kFilePE::exportLookup(const char * pszName, kExportEntry *pExport)
282{
283 kASSERT(!"not implemented.");
284 pszName = pszName;
285 pExport = pExport;
286 return FALSE;
287}
288
289
290/**
291 * Mini dump function.
292 */
293KBOOL kFilePE::dump(kFile *pOut)
294{
295 int i,j,k;
296 int c;
297
298 /*
299 * Dump sections.
300 */
301 pOut->printf("Sections\n"
302 "--------\n");
303 for (i = 0; i < pFileHdr->NumberOfSections; i++)
304 {
305 pOut->printf("%2d %-8.8s VirtSize: 0x%08x RVA: 0x%08x\n"
306 " RawSize: 0x%08x FileOffset: 0x%08x\n"
307 " #Relocs: 0x%08x FileOffset: 0x%08x\n"
308 " #LineNbr: 0x%08x FileOffset: 0x%08x\n"
309 " Characteristics: 0x%08x\n",
310 i,
311 paSectionHdr[i].Name,
312 paSectionHdr[i].Misc.VirtualSize,
313 paSectionHdr[i].VirtualAddress,
314 paSectionHdr[i].PointerToRawData,
315 paSectionHdr[i].PointerToRawData,
316 paSectionHdr[i].NumberOfRelocations,
317 paSectionHdr[i].PointerToRelocations,
318 paSectionHdr[i].NumberOfLinenumbers,
319 paSectionHdr[i].PointerToLinenumbers,
320 paSectionHdr[i].Characteristics
321 );
322 }
323 pOut->printf("\n");
324
325
326 /*
327 * Dump the directories.
328 */
329 pOut->printf("Data Directory\n"
330 "--------------\n");
331 for (i = 0; i < pOptHdr->NumberOfRvaAndSizes; i++)
332 {
333 static const char * apszDirectoryNames[] =
334 {
335 "Export",
336 "Import",
337 "Resource",
338 "Exception",
339 "Security",
340 "Base Reloc",
341 "Debug",
342 "Copyright",
343 "Global Ptr",
344 "TLS",
345 "Load Config",
346 "Bound Import",
347 "IAT",
348 "Delay Import",
349 "COM Descriptor",
350 "unknown",
351 "unknown"
352 };
353
354 pOut->printf("%2d %-16s Size: 0x%08x RVA: 0x%08x\n",
355 i,
356 apszDirectoryNames[i],
357 pOptHdr->DataDirectory[i].Size,
358 pOptHdr->DataDirectory[i].VirtualAddress);
359 }
360 pOut->printf("\n");
361
362
363 /*
364 * Dump Import Directory if present.
365 */
366 if (pImportDir)
367 {
368 pOut->printf("Import Directory\n"
369 "----------------\n");
370
371 PIMAGE_IMPORT_DESCRIPTOR pCur = pImportDir;
372 while (pCur->u.Characteristics != 0)
373 {
374 pOut->printf("%s\n", (char*)pvBase + pCur->Name);
375 pCur++;
376 }
377 }
378
379
380 /*
381 * Dump TLS directory if present
382 */
383 if (pTLSDir)
384 {
385 pOut->printf("TLS Directory\n"
386 "-------------\n");
387 if (pOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size % sizeof(IMAGE_TLS_DIRECTORY))
388 pOut->printf(" Warning! The size directory isn't a multiple of the directory struct!");
389
390 c = (int)(pOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size / sizeof(IMAGE_TLS_DIRECTORY));
391 for (i = 0; i < c; i++)
392 {
393
394 pOut->printf("%2d StartAddressOfRawData %p\n"
395 " EndAddressOfRawData %p\n"
396 " AddressOfIndex %p\n"
397 " AddressOfCallBacks %p\n"
398 " SizeOfZeroFill %p\n"
399 " Characteristics %p\n",
400 i,
401 pTLSDir[i].StartAddressOfRawData,
402 pTLSDir[i].EndAddressOfRawData,
403 pTLSDir[i].AddressOfIndex,
404 pTLSDir[i].AddressOfCallBacks,
405 pTLSDir[i].SizeOfZeroFill,
406 pTLSDir[i].Characteristics);
407
408 /* Print Callbacks */
409 if (pTLSDir[i].AddressOfCallBacks)
410 {
411 unsigned long * paulIndex;
412 unsigned long * paulCallback;
413 unsigned long ulBorlandRVAFix = 0UL;
414
415 /* Check if the addresses in the TLSDir is RVAs or real addresses */
416 if (pTLSDir[i].StartAddressOfRawData > pOptHdr->ImageBase)
417 ulBorlandRVAFix = pOptHdr->ImageBase;
418
419 j = 0;
420 paulIndex = (unsigned long *)((unsigned long)pTLSDir[i].AddressOfIndex - ulBorlandRVAFix + (unsigned long)this->pvBase);
421 paulCallback = (unsigned long *)((unsigned long)pTLSDir[i].AddressOfCallBacks - ulBorlandRVAFix + (unsigned long)this->pvBase);
422 if (*paulCallback)
423 {
424 pOut->printf(" Callbacks:\n");
425 for (j = 0; paulCallback[j] != 0; j++)
426 {
427 pOut->printf(" %02d Address: 0x%08x Index: 0x%08x\n",
428 paulIndex[j],
429 paulCallback[j]);
430 }
431 }
432 else
433 pOut->printf(" (Empty callback array!)\n");
434 }
435
436 }
437
438 pOut->printf("\n");
439 }
440
441
442 return TRUE;
443}
444
Note: See TracBrowser for help on using the repository browser.