Subversion Repositories Kolibri OS

Rev

Rev 8600 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
8600 Boppan 1
// Dependencies:
2
//  or any another source of assert()
3
//  or any another source of uint64_t, uint32_t, uint16_t, uint8_t, size_t
4
 
5
#ifndef EPEP_ASSERT
6
#include 
7
#define EPEP_ASSERT(x) assert(x)
8
#endif
9
 
10
#ifndef EPEP_READER
11
#include 
12
#define EPEP_READER FILE *
13
#define EPEP_READER_GET(preader) getc(*preader)
14
#define EPEP_READER_SEEK(preader, offset) fseek(*preader, offset, SEEK_SET)
8948 Boppan 15
#define EPEP_READER_SEEK_END(preader, offset) fseek(*preader, offset, SEEK_END)
8600 Boppan 16
#define EPEP_READER_TELL(preader) ftell(*preader)
17
#define EPEP_READER_GET_BLOCK(preader, size, buf) fread(buf, 1, size, *preader);
18
#endif
19
 
20
//
21
// Constants
22
//
23
 
24
typedef enum {
25
	EPEP_INVALID,
26
	EPEP_IMAGE,
27
	EPEP_OBJECT,
28
} EpepKind;
29
 
30
typedef enum {
31
	EPEP_ERR_SUCCESS,
32
	EPEP_ERR_DATA_DIRECTORY_INDEX_IS_INVALID,
33
	EPEP_ERR_SECTION_HEADER_INDEX_IS_INVALID,
34
	EPEP_ERR_SYMBOL_INDEX_IS_INVALID,
35
	EPEP_ERR_NOT_AN_OBJECT,
36
	EPEP_ERR_ADDRESS_IS_OUT_OF_SECTION_RAW_DATA,
37
	EPEP_ERR_OUTPUT_CAPACITY_IS_ZERO,
38
	EPEP_ERR_OUTPUT_IS_NULL,
39
	EPEP_ERR_ADDRESS_IS_OUT_OF_ANY_SECTION,
40
	EPEP_ERR_EXPORT_ADDRESS_TABLE_ENTRY_NAME_NOT_FOUND,
41
	EPEP_ERR_NO_BASE_RELOCATION_TABLE,
42
	EPEP_ERR_BASE_RELOCATION_IS_ALREADY_END,
8948 Boppan 43
	EPEP_ERR_INVALID_DATA_DIRECTORY_OFFSET,
44
	EPEP_ERR_INVALID_SECTION_HEADER_OFFSET,
45
	EPEP_ERR_INVALID_SECTION_DATA_OFFSET,
46
	EPEP_ERR_INVALID_STRING_TABLE_SIZE_OFFSET,
47
	EPEP_ERR_INVALID_SYMBOL_OFFSET,
48
	EPEP_ERR_INVALID_IMPORT_DIRECTORY_OFFSET,
49
	EPEP_ERR_INVALID_IMPORT_DIRECTORY_NAME_OFFSET,
50
	EPEP_ERR_INVALID_LOOKUP_OFFSET,
51
	EPEP_ERR_INVALID_LOOKUP_NAME_OFFSET,
52
	EPEP_ERR_INVALID_EXPORT_TABLE_OFFSET,
53
	EPEP_ERR_INVALID_DLL_NAME_OFFSET,
54
	EPEP_ERR_INVALID_EXPORT_NAME_POINTER_OFFSET,
55
	EPEP_ERR_INVALID_ORDINAL_TABLE_OFFSET,
56
	EPEP_ERR_INVALID_EXPORT_NAME_OFFSET,
57
	EPEP_ERR_INVALID_EXPORT_ADDRESS_OFFSET,
58
	EPEP_ERR_INVALID_FORWARDER_OFFSET,
59
	EPEP_ERR_INVALID_BASE_RELOCATION_BLOCK_OFFSET,
60
	EPEP_ERR_INVALID_NEXT_BASE_RELOCATION_BLOCK_OFFSET,
61
	EPEP_ERR_INVALID_BASE_RELOCATION_BLOCK_BASE_RELOCATION_OFFSET,
62
	EPEP_ERR_INVALID_SECTION_RELOCATION_OFFSET,
63
	EPEP_ERR_INVALID_LINENUMBER_OFFSET,
8600 Boppan 64
} EpepError;
65
 
66
//
67
// Generic
68
//
69
 
70
typedef struct {
71
	EPEP_READER reader;
72
	EpepKind kind;
73
	EpepError error_code;
8948 Boppan 74
	size_t file_size;
8600 Boppan 75
	size_t signature_offset_offset;
76
	size_t signature_offset;
77
	size_t first_data_directory_offset;
78
	size_t first_section_header_offset;
79
	size_t export_table_offset;
80
	size_t import_table_offset;
81
	size_t base_relocation_table_offset;
82
	size_t base_relocation_table_end_offset;
83
	struct {
84
		uint16_t Machine;
85
		uint16_t NumberOfSections;
86
		uint32_t TimeDateStamp;
87
		uint32_t PointerToSymbolTable;
88
		uint32_t NumberOfSymbols;
89
		uint16_t SizeOfOptionalHeader;
90
		uint16_t Characteristics;
91
	} coffFileHeader;
92
	struct {
93
		// Standard fields
94
		uint16_t Magic;
95
		uint8_t MajorLinkerVersion;
96
		uint8_t MinorLinkerVersion;
97
		uint32_t SizeOfCode;
98
		uint32_t SizeOfInitializedData;
99
		uint32_t SizeOfUninitializedData;
100
		uint32_t AddressOfEntryPoint;
101
		uint32_t BaseOfCode;
102
		uint32_t BaseOfData; // PE32-only
103
		// Windows-specific fields
104
		uint64_t ImageBase;
105
		uint32_t SectionAlignment;
106
		uint32_t FileAlignment;
107
		uint16_t MajorOperatingSystemVersion;
108
		uint16_t MinorOperatingSystemVersion;
109
		uint16_t MajorImageVersion;
110
		uint16_t MinorImageVersion;
111
		uint16_t MajorSubsystemVersion;
112
		uint16_t MinorSubsystemVersion;
113
		uint32_t Win32VersionValue;
114
		uint32_t SizeOfImage;
115
		uint32_t SizeOfHeaders;
116
		uint32_t CheckSum;
117
		uint16_t Subsystem;
118
		uint16_t DllCharacteristics;
119
		uint64_t SizeOfStackReserve;
120
		uint64_t SizeOfStackCommit;
121
		uint64_t SizeOfHeapReserve;
122
		uint64_t SizeOfHeapCommit;
123
		uint32_t LoaderFlags;
124
		uint32_t NumberOfRvaAndSizes;
125
	} optionalHeader;
126
	struct {
127
		uint32_t ExportFlags;
128
		uint32_t TimeDateStamp;
129
		uint16_t MajorVersion;
130
		uint16_t MinorVersion;
131
		uint32_t NameRva;
132
		uint32_t OrdinalBase;
133
		uint32_t AddressTableEntries;
134
		uint32_t NumberOfNamePointers;
135
		uint32_t ExportAddressTableRva;
136
		uint32_t NamePointerRva;
137
		uint32_t OrdinalTableRva;
138
	} export_directory;
139
} Epep;
140
 
141
/// Constructor of the general information container
142
int epep_init(Epep *epep, EPEP_READER reader);
143
 
144
/// Gives file offset corresponding to RVA is any, returns 0 othervice
145
int epep_get_file_offset_by_rva(Epep *epep, size_t *offset, size_t addr);
146
 
147
//
148
// Data Directories
149
//
150
 
151
typedef struct {
152
	uint32_t VirtualAddress;
153
	uint32_t Size;
154
} EpepImageDataDirectory;
155
 
156
/// Gives Data Directiry by its index
157
int epep_get_data_directory_by_index(Epep *epep, EpepImageDataDirectory *idd, size_t index);
158
 
159
//
160
// Sections
161
//
162
 
163
typedef struct {
164
	char Name[8];
165
	uint32_t VirtualSize;
166
	uint32_t VirtualAddress;
167
	uint32_t SizeOfRawData;
168
	uint32_t PointerToRawData;
169
	uint32_t PointerToRelocations;
170
	uint32_t PointerToLinenumbers;
171
	uint16_t NumberOfRelocations;
172
	uint16_t NumberOfLinenumbers;
173
	uint32_t Characteristics;
174
} EpepSectionHeader;
175
 
176
/// Gives Section Header by its index
177
int epep_get_section_header_by_index(Epep *epep, EpepSectionHeader *sh, size_t index);
178
 
179
/// Gives section header by RVA
180
int epep_get_section_header_by_rva(Epep *epep, EpepSectionHeader *sh, size_t addr);
181
 
182
/// Gives section contents by Section Header
183
int epep_get_section_contents(Epep *epep, EpepSectionHeader *sh, void *buf);
184
 
185
//
186
// COFF Symbols (object file symbols)
187
//
188
 
189
typedef union {
190
	struct {
191
		union {
192
			char ShortName[8];
193
			struct {
194
				uint32_t Zeroes;
195
				uint32_t Offset;
196
			};
197
		};
198
		uint32_t Value;
199
		uint16_t SectionNumber;
200
		uint16_t Type;
201
		uint8_t StorageClass;
202
		uint8_t NumberOfAuxSymbols;
203
	} symbol;
204
	struct {
205
		uint32_t TagIndex;
206
		uint32_t TotalSize;
207
		uint32_t PointerToLinenumber;
208
		uint32_t PointerToNextFunction;
209
		uint16_t Unused;
210
	} auxFunctionDefinition;
211
	struct {
212
		uint8_t Unused0[4];
213
		uint16_t Linenumber;
214
		uint8_t Unused1[6];
215
		uint32_t PointerToNextFunction;
216
		uint8_t Unused2[2];
217
	} auxBfOrEfSymbol;
218
	struct {
219
		uint32_t TagIndex;
220
		uint32_t Characteristics;
221
		uint8_t Unused[10];
222
	} auxWeakExternal;
223
	struct {
224
		char FileName[18];
225
	} auxFile;
226
	struct {
227
		uint32_t Length;
228
		uint16_t NumberOfRelocations;
229
		uint16_t NumberOfLinenumbers;
230
		uint32_t CheckSum;
231
		uint16_t Number;
232
		uint8_t  Selection;
233
		uint8_t Unused[3];
234
	} auxSectionDefinition;
235
} EpepCoffSymbol;
236
 
237
/// Gives COFF string table size
238
int epep_get_string_table_size(Epep *epep, size_t *size);
239
 
240
/// Gives COFF string table
241
int epep_get_string_table(Epep *epep, char *string_table);
242
 
243
/// Gives COFF Symbol by its index
244
int epep_get_symbol_by_index(Epep *epep, EpepCoffSymbol *sym, size_t index);
245
 
246
//
247
// Imports
248
//
249
 
250
typedef struct {
251
	uint32_t ImportLookupTableRva;
252
	uint32_t TimeDateStamp;
253
	uint32_t ForwarderChain;
254
	uint32_t NameRva;
255
	uint32_t ImportAddressTableRva;
256
} EpepImportDirectory;
257
 
258
/// Returns non-zero if import table exists in the file
259
int epep_has_import_table(Epep *epep);
260
 
261
/// Places offset of import table into epep structure
262
int epep_read_import_table_offset(Epep *epep);
263
 
264
/// Gives Import Directory by index
265
int epep_get_import_directory_by_index(Epep *epep, EpepImportDirectory *import_directory, size_t index);
266
 
267
/// Gives name of Import Directory (library)
268
int epep_get_import_directory_name_s(Epep *epep, EpepImportDirectory *import_directory, char *name, size_t name_max);
269
 
270
/// Gives Import Lookup (imported symbol) by import directory and index
271
int epep_get_import_directory_lookup_by_index(Epep *epep, EpepImportDirectory *import_directory, size_t *lookup, size_t index);
272
 
273
/// Gives name of Import Directory Lookup (imported symbol) or nothing if imported by ordinal
274
int epep_get_lookup_name_s(Epep *epep, size_t lookup, char *name, size_t name_max);
275
 
276
//
277
// Exports
278
//
279
 
280
typedef union {
281
	uint32_t ExportRva;
282
	uint32_t ForwarderRva;
283
} EpepExportAddress;
284
 
285
/// Returns non-zero if export table exists in the file
286
int epep_has_export_table(Epep *epep);
287
 
288
/// Palces offset of export table into epep structrue
289
int epep_read_export_table_offset(Epep *epep);
290
 
291
/// Palces export table into epep structrue
292
//! Needs to be called before next export functions
293
int epep_read_export_directory(Epep *epep);
294
 
295
/// Gives name of the DLL
296
//! epep_read_export_directory needs to be called before
297
int epep_get_dll_name_s(Epep *epep, char *name, size_t name_max);
298
 
299
/// Gives entry from Export Name Pointer Table by its index
300
//! epep_read_export_directory needs to be called before
301
int epep_get_export_name_pointer_by_index(Epep *epep, size_t *name_rva, size_t index);
302
 
303
/// Gives export name by its index in Export Address Table (receives name buffer length)
304
//! epep_read_export_directory needs to be called before
305
int epep_get_export_name_s_by_index(Epep *epep, char *name, size_t name_max, size_t index);
306
 
307
/// Gives export address by its index in Export Address Table
308
//! epep_read_export_directory needs to be called before
309
int epep_get_export_address_by_index(Epep *epep, EpepExportAddress *export_address, size_t index);
310
 
311
/// Gives forwarder string of Export Address
312
//! epep_read_export_directory needs to be called before
313
int epep_get_export_address_forwarder_s(Epep *epep, EpepExportAddress *export_address, char *forwarder, size_t forwarder_max);
314
 
315
/// Returns non-zero if the export address specifies forwarder string
316
//! epep_read_export_directory needs to be called before
317
int epep_export_address_is_forwarder(Epep *epep, EpepExportAddress *export_address);
318
 
319
//
320
// DLL Base Relocations
321
//
322
 
323
typedef struct {
324
	size_t offset;
325
	uint32_t PageRva;
326
	uint32_t BlockSize;
327
	uint16_t BaseRelocation[0];
328
} EpepBaseRelocationBlock;
329
 
330
typedef union {
331
	struct {
332
		uint16_t Offset: 12,
333
			Type: 4;
334
	};
335
	uint16_t u16;
336
} EpepBaseRelocation;
337
 
338
/// Returns non-zero if the file contains Base Relocations
339
int epep_has_base_relocation_table(Epep *epep);
340
 
341
/// Places offset to Base Relocation Table into epep structure
342
int epep_read_base_relocation_table_offset(Epep *epep);
343
 
344
/// Gives first Base Relocation Block
345
int epep_get_first_base_relocation_block(Epep *epep, EpepBaseRelocationBlock *brb);
346
 
347
/// Gives next Base Relocation Block (replaces contents of the given block)
348
int epep_get_next_base_relocation_block(Epep *epep, EpepBaseRelocationBlock *it);
349
 
350
/// Gives Base Relocation by its index in Base Relocation Block
351
int epep_get_base_relocation_block_base_relocation_by_index(Epep *epep, EpepBaseRelocationBlock *brb, EpepBaseRelocation *br, size_t index);
352
 
353
//
354
// COFF Relocations
355
//
356
 
357
typedef struct {
358
	uint32_t VirtualAddress;
359
	uint32_t SymbolTableIndex;
360
	uint16_t Type;
361
} EpepCoffRelocation;
362
 
363
int epep_get_section_relocation_by_index(Epep *epep, EpepSectionHeader *sh, EpepCoffRelocation *rel, size_t index);
364
 
365
//
366
// COFF Line Numbers
367
//
368
 
369
typedef struct {
370
	union {
371
		uint32_t SymbolTableIndex;
372
		uint32_t VirtualAddress;
373
	} Type;
374
	uint16_t Linenumber;
375
} EpepCoffLinenumber;
376
 
377
int epep_get_section_line_number_by_index(Epep *epep, EpepSectionHeader *sh, EpepCoffLinenumber *ln, size_t index);
378
 
379
#ifdef EPEP_INST
380
 
381
//
382
// Private functions
383
//
384
 
385
static int epep_seek(Epep *epep, size_t offset) {
386
	EPEP_READER_SEEK(&epep->reader, offset);
387
	return 1;
388
}
389
 
8948 Boppan 390
static int epep_seek_end(Epep *epep, size_t offset) {
391
	EPEP_READER_SEEK_END(&epep->reader, offset);
392
	return 1;
393
}
394
 
8600 Boppan 395
static int epep_read_block(Epep *epep, size_t size, void *block) {
396
	EPEP_READER_GET_BLOCK(&epep->reader, size, block);
397
	return 1;
398
}
399
 
400
static int is_pe32(Epep *epep) {
401
	return epep->optionalHeader.Magic == 0x10b;
402
}
403
 
404
static int is_pe32p(Epep *epep) {
405
	return epep->optionalHeader.Magic == 0x20b;
406
}
407
 
408
static uint8_t epep_read_u8(Epep *epep) {
409
	return EPEP_READER_GET(&epep->reader);
410
}
411
 
412
static uint16_t epep_read_u16(Epep *epep) {
413
	unsigned l = epep_read_u8(epep);
414
	unsigned h = epep_read_u8(epep);
415
	return l | (h << 8);
416
}
417
 
418
static uint32_t epep_read_u32(Epep *epep) {
419
	unsigned b0 = epep_read_u8(epep);
420
	unsigned b1 = epep_read_u8(epep);
421
	unsigned b2 = epep_read_u8(epep);
422
	unsigned b3 = epep_read_u8(epep);
423
	return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24);
424
}
425
 
426
static uint64_t epep_read_u64(Epep *epep) {
427
	uint64_t res = 0;
428
	for (unsigned i = 0; i < 64; i += 8) {
429
		res |= epep_read_u8(epep) << i;
430
	}
431
	return res;
432
}
433
 
434
static uint64_t epep_read_ptr(Epep *epep) {
435
	return is_pe32(epep) ? epep_read_u32(epep) : epep_read_u64(epep);
436
}
437
 
8948 Boppan 438
static int epep_valid_offset(Epep *epep, size_t offset, size_t size) {
439
	return (offset + size) <= epep->file_size;
440
}
441
 
8600 Boppan 442
//
443
// Generic
444
//
445
 
446
int epep_init(Epep *epep, EPEP_READER reader) {
447
	*epep = (Epep){ 0 };
448
	epep->kind = EPEP_IMAGE;
449
	epep->reader = reader;
8948 Boppan 450
	epep_seek_end(epep, 0);
451
	epep->file_size = EPEP_READER_TELL(&epep->reader);
452
	epep_seek(epep, 0);
8600 Boppan 453
	epep->error_code = EPEP_ERR_SUCCESS;
454
	epep->signature_offset_offset = 0x3c;
455
	epep_seek(epep, epep->signature_offset_offset);
8948 Boppan 456
	epep->signature_offset = epep_read_u32(epep);
8600 Boppan 457
	epep_seek(epep, epep->signature_offset);
458
	char signature_buf[4];
459
	signature_buf[0] = epep_read_u8(epep);
460
	signature_buf[1] = epep_read_u8(epep);
461
	signature_buf[2] = epep_read_u8(epep);
462
	signature_buf[3] = epep_read_u8(epep);
463
	if (signature_buf[0] != 'P' || signature_buf[1] != 'E' ||
464
		signature_buf[2] != '\0' || signature_buf[3] != '\0') {
465
		epep->kind = EPEP_OBJECT;
466
		epep_seek(epep, 0);
467
	}
468
	epep->coffFileHeader.Machine = epep_read_u16(epep);
469
	epep->coffFileHeader.NumberOfSections = epep_read_u16(epep);
470
	epep->coffFileHeader.TimeDateStamp = epep_read_u32(epep);
471
	epep->coffFileHeader.PointerToSymbolTable = epep_read_u32(epep);
472
	epep->coffFileHeader.NumberOfSymbols = epep_read_u32(epep);
473
	epep->coffFileHeader.SizeOfOptionalHeader = epep_read_u16(epep);
474
	epep->coffFileHeader.Characteristics = epep_read_u16(epep);
475
	if (epep->coffFileHeader.SizeOfOptionalHeader != 0) {
476
		// Standard fields
477
		epep->optionalHeader.Magic = epep_read_u16(epep);
478
		epep->optionalHeader.MajorLinkerVersion = epep_read_u8(epep);
479
		epep->optionalHeader.MinorLinkerVersion = epep_read_u8(epep);
480
		epep->optionalHeader.SizeOfCode = epep_read_u32(epep);
481
		epep->optionalHeader.SizeOfInitializedData = epep_read_u32(epep);
482
		epep->optionalHeader.SizeOfUninitializedData = epep_read_u32(epep);
483
		epep->optionalHeader.AddressOfEntryPoint = epep_read_u32(epep);
484
		epep->optionalHeader.BaseOfCode = epep_read_u32(epep);
485
		if (is_pe32(epep)) {
486
			epep->optionalHeader.BaseOfData = epep_read_u32(epep);
487
		}
488
		// Windows-specific fields
489
		epep->optionalHeader.ImageBase = epep_read_ptr(epep);
490
		epep->optionalHeader.SectionAlignment = epep_read_u32(epep);
491
		epep->optionalHeader.FileAlignment = epep_read_u32(epep);
492
		epep->optionalHeader.MajorOperatingSystemVersion = epep_read_u16(epep);
493
		epep->optionalHeader.MinorOperatingSystemVersion = epep_read_u16(epep);
494
		epep->optionalHeader.MajorImageVersion = epep_read_u16(epep);
495
		epep->optionalHeader.MinorImageVersion = epep_read_u16(epep);
496
		epep->optionalHeader.MajorSubsystemVersion = epep_read_u16(epep);
497
		epep->optionalHeader.Win32VersionValue = epep_read_u32(epep);
498
		epep->optionalHeader.MinorSubsystemVersion = epep_read_u16(epep);
499
		epep->optionalHeader.SizeOfImage = epep_read_u32(epep);
500
		epep->optionalHeader.SizeOfHeaders = epep_read_u32(epep);
501
		epep->optionalHeader.CheckSum = epep_read_u32(epep);
502
		epep->optionalHeader.Subsystem = epep_read_u16(epep);
503
		epep->optionalHeader.DllCharacteristics = epep_read_u16(epep);
504
		epep->optionalHeader.SizeOfStackReserve = epep_read_ptr(epep);
505
		epep->optionalHeader.SizeOfStackCommit = epep_read_ptr(epep);
506
		epep->optionalHeader.SizeOfHeapReserve = epep_read_ptr(epep);
507
		epep->optionalHeader.SizeOfHeapCommit = epep_read_ptr(epep);
508
		epep->optionalHeader.LoaderFlags = epep_read_u32(epep);
509
		epep->optionalHeader.NumberOfRvaAndSizes = epep_read_u32(epep);
510
		epep->first_data_directory_offset = EPEP_READER_TELL(&epep->reader);
511
	}
512
	epep->first_section_header_offset = EPEP_READER_TELL(&epep->reader);
513
	if (epep->coffFileHeader.SizeOfOptionalHeader != 0) {
514
		epep->first_section_header_offset += epep->optionalHeader.NumberOfRvaAndSizes * sizeof(EpepImageDataDirectory);
515
	}
516
	return 1;
517
}
518
 
519
int epep_get_file_offset_by_rva(Epep *epep, size_t *offset, size_t addr) {
520
	EpepSectionHeader sh = { 0 };
521
	if (!epep_get_section_header_by_rva(epep, &sh, addr)) {
522
		return 0;
523
	}
524
	size_t diff = addr - sh.VirtualAddress;
525
	if (diff >= sh.SizeOfRawData) {
526
		epep->error_code = EPEP_ERR_ADDRESS_IS_OUT_OF_SECTION_RAW_DATA;
527
		return 0;
528
	}
529
	*offset = sh.PointerToRawData + diff;
530
	return 1;
531
}
532
 
533
//
534
// Data Directories
535
//
536
 
537
int epep_get_data_directory_by_index(Epep *epep, EpepImageDataDirectory *idd, size_t index) {
538
	if (index >= epep->optionalHeader.NumberOfRvaAndSizes) {
539
		epep->error_code = EPEP_ERR_DATA_DIRECTORY_INDEX_IS_INVALID;
540
		return 0;
541
	}
8948 Boppan 542
	size_t offset = epep->first_data_directory_offset + sizeof(EpepImageDataDirectory) * index;
543
	if (!epep_valid_offset(epep, offset, sizeof(EpepImageDataDirectory))) {
544
		epep->error_code = EPEP_ERR_INVALID_DATA_DIRECTORY_OFFSET;
545
		return 0;
546
	}
547
	epep_seek(epep, offset);
8600 Boppan 548
	idd->VirtualAddress = epep_read_u32(epep);
549
	idd->Size = epep_read_u32(epep);
550
	return 1;
551
}
552
 
553
//
554
// Sections
555
//
556
 
557
int epep_get_section_header_by_index(Epep *epep, EpepSectionHeader *sh, size_t index) {
558
	if (index >= epep->coffFileHeader.NumberOfSections) {
559
		epep->error_code = EPEP_ERR_SECTION_HEADER_INDEX_IS_INVALID;
560
		return 0;
561
	}
8948 Boppan 562
	size_t offset = epep->first_section_header_offset + sizeof(EpepSectionHeader) * index;
563
	if (!epep_valid_offset(epep, offset, sizeof(EpepSectionHeader))) {
564
		epep->error_code = EPEP_ERR_INVALID_SECTION_HEADER_OFFSET;
565
		return 0;
566
	}
567
	epep_seek(epep, offset);
8600 Boppan 568
	for (int i = 0; i < 8; i++) {
569
		sh->Name[i] = epep_read_u8(epep);
570
	}
571
	sh->VirtualSize = epep_read_u32(epep);
572
	sh->VirtualAddress = epep_read_u32(epep);
573
	sh->SizeOfRawData = epep_read_u32(epep);
574
	sh->PointerToRawData = epep_read_u32(epep);
575
	sh->PointerToRelocations = epep_read_u32(epep);
576
	sh->PointerToLinenumbers = epep_read_u32(epep);
577
	sh->NumberOfRelocations = epep_read_u16(epep);
578
	sh->NumberOfLinenumbers = epep_read_u16(epep);
579
	sh->Characteristics = epep_read_u32(epep);
580
	return 1;
581
}
582
 
583
int epep_get_section_header_by_rva(Epep *epep, EpepSectionHeader *sh, size_t addr) {
584
	EpepSectionHeader sh0 = { 0 };
585
	for (size_t i = 0; i < epep->coffFileHeader.NumberOfSections; i++) {
586
		epep_get_section_header_by_index(epep, &sh0, i);
587
		if (addr >= sh0.VirtualAddress && addr < (sh0.VirtualAddress + sh0.VirtualSize)) {
588
			*sh = sh0;
589
			return 1;
590
		}
591
	}
592
	epep->error_code = EPEP_ERR_ADDRESS_IS_OUT_OF_ANY_SECTION;
593
	return 0;
594
}
595
 
596
int epep_get_section_contents(Epep *epep, EpepSectionHeader *sh, void *buf) {
8948 Boppan 597
	size_t offset = sh->PointerToRawData;
8600 Boppan 598
	size_t size_of_raw_data = sh->SizeOfRawData;
8948 Boppan 599
	if (!epep_valid_offset(epep, offset, size_of_raw_data)) {
600
		epep->error_code = EPEP_ERR_INVALID_SECTION_DATA_OFFSET;
601
		return 0;
602
	}
603
	epep_seek(epep, offset);
8600 Boppan 604
	epep_read_block(epep, size_of_raw_data, buf);
605
	return 1;
606
}
607
 
608
//
609
// COFF Symbols
610
//
611
 
612
int epep_get_string_table_size(Epep *epep, size_t *size) {
8948 Boppan 613
	size_t offset = epep->coffFileHeader.PointerToSymbolTable + 18 * epep->coffFileHeader.NumberOfSymbols;
614
	if (!epep_valid_offset(epep, offset, sizeof(uint32_t))) {
615
		epep->error_code = EPEP_ERR_INVALID_STRING_TABLE_SIZE_OFFSET;
616
		return 0;
617
	}
618
	epep_seek(epep, offset);
8600 Boppan 619
	*size = epep_read_u32(epep);
620
	return 1;
621
}
622
 
623
int epep_get_string_table(Epep *epep, char *string_table) {
624
	size_t size = 0;
625
	if (!epep_get_string_table_size(epep, &size)) {
626
		return 0;
627
	}
628
	// A COFF strings table starts with its size
629
	*string_table++ = (size & 0x000000ff) >> 0;
630
	*string_table++ = (size & 0x0000ff00) >> 8;
631
	*string_table++ = (size & 0x00ff0000) >> 16;
632
	*string_table++ = (size & 0xff000000) >> 24;
633
	epep_read_block(epep, size - 4, string_table);
634
	return 1;
635
}
636
 
637
int epep_get_symbol_by_index(Epep *epep, EpepCoffSymbol *sym, size_t index) {
638
	if (epep->kind != EPEP_OBJECT) {
639
		epep->error_code = EPEP_ERR_NOT_AN_OBJECT;
640
		return 0;
641
	}
642
	if (index >= epep->coffFileHeader.NumberOfSymbols) {
643
		epep->error_code = EPEP_ERR_SYMBOL_INDEX_IS_INVALID;
644
		return 0;
645
	}
8948 Boppan 646
	size_t offset = epep->coffFileHeader.PointerToSymbolTable + 18 * index;
647
	if (!epep_valid_offset(epep, offset, 18)) {
648
		epep->error_code = EPEP_ERR_INVALID_SYMBOL_OFFSET;
649
		return 0;
650
	}
651
	epep_seek(epep, offset);
8600 Boppan 652
	for (size_t i = 0; i < 18; i++) {
653
		sym->auxFile.FileName[i] = epep_read_u8(epep);
654
	}
655
	return 1;
656
}
657
 
658
//
659
// Imports
660
//
661
 
662
int epep_has_import_table(Epep *epep) {
663
	if (epep->kind != EPEP_IMAGE) {
664
		return 0;
665
	}
666
	EpepImageDataDirectory idd = { 0 };
667
	if (!epep_get_data_directory_by_index(epep, &idd, 1)) {
668
		return 0;
669
	}
670
	return idd.VirtualAddress;
671
}
672
 
673
int epep_read_import_table_offset(Epep *epep) {
674
	EpepImageDataDirectory import_table_dd = { 0 };
675
	if (!epep_get_data_directory_by_index(epep, &import_table_dd, 1)) {
676
		return 0;
677
	}
678
	if (!epep_get_file_offset_by_rva(epep, &epep->import_table_offset, import_table_dd.VirtualAddress)) {
679
		return 0;
680
	}
681
	return 1;
682
}
683
 
684
int epep_get_import_directory_by_index(Epep *epep, EpepImportDirectory *import_directory, size_t index) {
685
	if (epep->import_table_offset == 0) {
686
		if (!epep_read_import_table_offset(epep)) {
687
			return 0;
688
		}
689
	}
8948 Boppan 690
	size_t offset = epep->import_table_offset + index * sizeof(*import_directory);
691
	if (!epep_valid_offset(epep, offset, sizeof(*import_directory))) {
692
		epep->error_code = EPEP_ERR_INVALID_IMPORT_DIRECTORY_OFFSET;
693
		return 0;
694
	}
695
	epep_seek(epep, offset);
8600 Boppan 696
	epep_read_block(epep, sizeof(*import_directory), import_directory);
697
	return 1;
698
}
699
 
700
int epep_get_import_directory_name_s(Epep *epep, EpepImportDirectory *import_directory, char *name, size_t name_max) {
701
	size_t name_rva = import_directory->NameRva;
702
	size_t name_offset = 0;
703
	if (!epep_get_file_offset_by_rva(epep, &name_offset, name_rva)) {
704
		return 0;
705
	}
8948 Boppan 706
	if (!epep_valid_offset(epep, name_offset, 0)) {
707
		epep->error_code = EPEP_ERR_INVALID_IMPORT_DIRECTORY_NAME_OFFSET;
708
		return 0;
709
	}
8600 Boppan 710
	epep_seek(epep, name_offset);
711
	epep_read_block(epep, name_max, name);
712
	return 1;
713
}
714
 
715
int epep_get_import_directory_lookup_by_index(Epep *epep, EpepImportDirectory *import_directory, size_t *lookup, size_t index) {
716
	size_t first_lookup_offset = 0;
717
	if (!epep_get_file_offset_by_rva(epep, &first_lookup_offset, import_directory->ImportLookupTableRva)) {
718
		return 0;
719
	}
720
	size_t size_of_lookup = is_pe32(epep) ? 4 : 8;
721
	size_t lookup_offset = first_lookup_offset + size_of_lookup * index;
8948 Boppan 722
	if (!epep_valid_offset(epep, lookup_offset, size_of_lookup)) {
723
		epep->error_code = EPEP_ERR_INVALID_LOOKUP_OFFSET;
724
		return 0;
725
	}
8600 Boppan 726
	epep_seek(epep, lookup_offset);
727
	epep_read_block(epep, size_of_lookup, lookup);
728
	return 1;
729
}
730
 
731
int epep_get_lookup_name_s(Epep *epep, size_t lookup, char *name, size_t name_max) {
732
	if (name_max == 0) {
733
		epep->error_code = EPEP_ERR_OUTPUT_CAPACITY_IS_ZERO;
734
		return 0;
735
	}
736
	if (name == NULL) {
737
		epep->error_code = EPEP_ERR_OUTPUT_IS_NULL;
738
		return 0;
739
	}
740
	uint64_t mask = is_pe32(epep) ? 0x80000000 : 0x8000000000000000;
741
	if (lookup & mask) {
742
		name[0] = '\0';
743
		return 1;
744
	}
745
	size_t name_rva = lookup;
746
	size_t name_offset = 0;
747
	if (!epep_get_file_offset_by_rva(epep, &name_offset, name_rva)) {
748
		return 0;
749
	}
750
	// skip 2 bytes (Name Table :: Hint)
751
	name_offset += 2;
8948 Boppan 752
	if (!epep_valid_offset(epep, name_offset, 0)) {
753
		epep->error_code = EPEP_ERR_INVALID_LOOKUP_NAME_OFFSET;
754
		return 0;
755
	}
8600 Boppan 756
	epep_seek(epep, name_offset);
757
	epep_read_block(epep, name_max, name);
758
	return 1;
759
}
760
 
761
//
762
// Exports
763
//
764
 
765
int epep_has_export_table(Epep *epep) {
766
	if (epep->kind != EPEP_IMAGE) {
767
		return 0;
768
	}
769
	EpepImageDataDirectory idd = { 0 };
770
	if (!epep_get_data_directory_by_index(epep, &idd, 0)) {
771
		return 0;
772
	}
773
	return idd.VirtualAddress;
774
}
775
 
776
int epep_read_export_table_offset(Epep *epep) {
777
	EpepImageDataDirectory export_table_dd = { 0 };
778
	if (!epep_get_data_directory_by_index(epep, &export_table_dd, 0)) {
779
		return 0;
780
	}
781
	if (!epep_get_file_offset_by_rva(epep, &epep->export_table_offset, export_table_dd.VirtualAddress)) {
782
		return 0;
783
	}
784
	return 1;
785
}
786
 
787
int epep_read_export_directory(Epep *epep) {
788
	if (epep->export_table_offset == 0) {
789
		if (!epep_read_export_table_offset(epep)) {
790
			return 0;
791
		}
792
	}
8948 Boppan 793
	if (!epep_valid_offset(epep, epep->export_table_offset, sizeof(epep->export_directory))) {
794
		epep->error_code = EPEP_ERR_INVALID_EXPORT_TABLE_OFFSET;
795
		return 0;
796
	}
8600 Boppan 797
	epep_seek(epep, epep->export_table_offset);
798
	epep_read_block(epep, sizeof(epep->export_directory), &epep->export_directory);
799
	return 1;
800
}
801
 
802
int epep_get_dll_name_s(Epep *epep, char *name, size_t name_max) {
803
	size_t offset = 0;
804
	if (!epep_get_file_offset_by_rva(epep, &offset, epep->export_directory.NameRva)) {
805
		return 0;
806
	}
8948 Boppan 807
	if (!epep_valid_offset(epep, offset, 0)) {
808
		epep->error_code = EPEP_ERR_INVALID_DLL_NAME_OFFSET;
809
		return 0;
810
	}
8600 Boppan 811
	epep_seek(epep, offset);
812
	epep_read_block(epep, name_max, name);
813
	return 1;
814
}
815
 
816
int epep_get_export_name_pointer_by_index(Epep *epep, size_t *name_rva, size_t index) {
817
	size_t name_pointer_table_rva = epep->export_directory.NamePointerRva;
818
	size_t name_pointer_table_offset = 0;
819
	if (!epep_get_file_offset_by_rva(epep, &name_pointer_table_offset, name_pointer_table_rva)) {
820
		return 0;
821
	}
8948 Boppan 822
	size_t offset = name_pointer_table_offset + sizeof(uint32_t) * index;
823
	if (!epep_valid_offset(epep, offset, sizeof(uint32_t))) {
824
		epep->error_code = EPEP_ERR_INVALID_EXPORT_NAME_POINTER_OFFSET;
825
		return 0;
826
	}
827
	epep_seek(epep, offset);
8600 Boppan 828
	*name_rva = epep_read_u32(epep);
829
	return 1;
830
}
831
 
832
int epep_get_export_name_s_by_index(Epep *epep, char *name, size_t name_max, size_t index) {
833
	size_t ordinal_table_offset = 0;
834
	if (!epep_get_file_offset_by_rva(epep, &ordinal_table_offset, epep->export_directory.OrdinalTableRva)) {
835
		return 0;
836
	}
8948 Boppan 837
	if (!epep_valid_offset(epep, ordinal_table_offset, 0)) {
838
		epep->error_code = EPEP_ERR_INVALID_ORDINAL_TABLE_OFFSET;
839
		return 0;
840
	}
8600 Boppan 841
	epep_seek(epep, ordinal_table_offset);
842
	for (size_t i = 0; i < epep->export_directory.NumberOfNamePointers; i++) {
843
		uint16_t ordinal = epep_read_u16(epep);
844
		if (ordinal == index) { // SPEC_VIOL: Why should not epep->export_directory.OrdinalBase be substracted?
845
			size_t name_rva = 0;
846
			if (!epep_get_export_name_pointer_by_index(epep, &name_rva, i)) {
847
				return 0;
848
			}
849
			size_t name_offset = 0;
850
			if (!epep_get_file_offset_by_rva(epep, &name_offset, name_rva)) {
851
				return 0;
852
			}
8948 Boppan 853
			if (!epep_valid_offset(epep, name_offset, 0)) {
854
				epep->error_code = EPEP_ERR_INVALID_EXPORT_NAME_OFFSET;
855
				return 0;
856
			}
8600 Boppan 857
			epep_seek(epep, name_offset);
858
			epep_read_block(epep, name_max, name);
859
			return 1;
860
		}
861
	}
862
	epep->error_code = EPEP_ERR_EXPORT_ADDRESS_TABLE_ENTRY_NAME_NOT_FOUND;
863
	return 0;
864
}
865
 
866
int epep_get_export_address_by_index(Epep *epep, EpepExportAddress *export_address, size_t index) {
867
	size_t export_address_table_offset = 0;
868
	if (!epep_get_file_offset_by_rva(epep, &export_address_table_offset, epep->export_directory.ExportAddressTableRva)) {
869
		return 0;
870
	}
871
	EPEP_ASSERT(sizeof(EpepExportAddress) == sizeof(uint32_t));
8948 Boppan 872
	size_t offset = export_address_table_offset + sizeof(EpepExportAddress) * index;
873
	if (!epep_valid_offset(epep, offset, sizeof(*export_address))) {
874
		epep->error_code = EPEP_ERR_INVALID_EXPORT_ADDRESS_OFFSET;
875
		return 0;
876
	}
877
	epep_seek(epep, offset);
8600 Boppan 878
	epep_read_block(epep, sizeof(*export_address), export_address);
879
	return 1;
880
}
881
 
882
int epep_get_export_address_forwarder_s(Epep *epep, EpepExportAddress *export_address, char *forwarder, size_t forwarder_max) {
883
	size_t forwarder_offset = 0;
884
	if (!epep_get_file_offset_by_rva(epep, &forwarder_offset, export_address->ForwarderRva)) {
885
		return 0;
886
	}
8948 Boppan 887
	if (!epep_valid_offset(epep, forwarder_offset, 0)) {
888
		epep->error_code = EPEP_ERR_INVALID_FORWARDER_OFFSET;
889
		return 0;
890
	}
8600 Boppan 891
	epep_seek(epep, forwarder_offset);
892
	epep_read_block(epep, forwarder_max, forwarder);
893
	return 1;
894
}
895
 
896
int epep_export_address_is_forwarder(Epep *epep, EpepExportAddress *export_address) {
897
	EpepImageDataDirectory edd = { 0 };
898
	if (!epep_get_data_directory_by_index(epep, &edd, 0)) {
899
		return 0;
900
	}
901
	if (export_address->ForwarderRva >= edd.VirtualAddress && export_address->ForwarderRva < edd.VirtualAddress + edd.Size) {
902
		return 1;
903
	}
904
	return 0;
905
}
906
 
907
//
908
// DLL Base Relocaions
909
//
910
 
911
int epep_has_base_relocation_table(Epep *epep) {
912
	EpepImageDataDirectory brtdd = { 0 };
913
	if (!epep_get_data_directory_by_index(epep, &brtdd, 5)) {
914
		return 0;
915
	}
916
	if (brtdd.VirtualAddress == 0) {
917
		return 0;
918
	}
919
	return 1;
920
}
921
 
922
int epep_read_base_relocation_table_offset(Epep *epep) {
923
	EpepImageDataDirectory brtdd = { 0 };
924
	if (!epep_get_data_directory_by_index(epep, &brtdd, 5)) {
925
		return 0;
926
	}
927
	if (!epep_get_file_offset_by_rva(epep, &epep->base_relocation_table_offset, brtdd.VirtualAddress)) {
928
		return 0;
929
	}
930
	epep->base_relocation_table_end_offset = epep->base_relocation_table_offset + brtdd.Size;
931
	return 1;
932
}
933
 
934
int epep_get_first_base_relocation_block(Epep *epep, EpepBaseRelocationBlock *brb) {
935
	if (epep->base_relocation_table_offset == 0) {
936
		if (!epep_read_base_relocation_table_offset(epep)) {
937
			return 0;
938
		}
939
	}
940
	if (epep->base_relocation_table_offset == 0) {
941
		epep->error_code = EPEP_ERR_NO_BASE_RELOCATION_TABLE;
942
		return 0;
943
	}
8948 Boppan 944
	if (!epep_valid_offset(epep, epep->base_relocation_table_offset, 0)) {
945
		epep->error_code = EPEP_ERR_INVALID_BASE_RELOCATION_BLOCK_OFFSET;
946
		return 0;
947
	}
8600 Boppan 948
	if (!epep_seek(epep, epep->base_relocation_table_offset)) {
949
		return 0;
950
	}
951
	brb->offset = epep->base_relocation_table_offset;
952
	brb->PageRva = epep_read_u32(epep);
953
	brb->BlockSize = epep_read_u32(epep);
954
	return 1;
955
}
956
 
957
int epep_get_next_base_relocation_block(Epep *epep, EpepBaseRelocationBlock *it) {
958
	if (it->offset == 0) {
959
		epep->error_code = EPEP_ERR_BASE_RELOCATION_IS_ALREADY_END;
960
		return 0;
961
	}
962
	it->offset = it->offset + it->BlockSize;
963
	if (it->offset >= epep->base_relocation_table_end_offset) {
964
		*it = (EpepBaseRelocationBlock){ 0 };
965
		return 1;
966
	}
8948 Boppan 967
	if (!epep_valid_offset(epep, it->offset, 0)) {
968
		epep->error_code = EPEP_ERR_INVALID_NEXT_BASE_RELOCATION_BLOCK_OFFSET;
969
		return 0;
970
	}
8600 Boppan 971
	if (!epep_seek(epep, it->offset)) {
972
		return 0;
973
	}
974
	it->PageRva = epep_read_u32(epep);
975
	it->BlockSize = epep_read_u32(epep);
976
	return 1;
977
}
978
 
979
int epep_get_base_relocation_block_base_relocation_by_index(Epep *epep, EpepBaseRelocationBlock *brb, EpepBaseRelocation *br, size_t index) {
8948 Boppan 980
	size_t offset = brb->offset + 8 + sizeof(EpepBaseRelocation) * index;
981
	if (!epep_valid_offset(epep, offset, sizeof(EpepBaseRelocation))) {
982
		epep->error_code = EPEP_ERR_INVALID_BASE_RELOCATION_BLOCK_BASE_RELOCATION_OFFSET;
8600 Boppan 983
		return 0;
984
	}
8948 Boppan 985
	if (!epep_seek(epep, offset)) {
986
		return 0;
987
	}
8600 Boppan 988
	br->u16 = epep_read_u16(epep);
989
	return 1;
990
}
991
 
992
//
993
// COFF Relocations
994
//
995
 
996
int epep_get_section_relocation_by_index(Epep *epep, EpepSectionHeader *sh, EpepCoffRelocation *rel, size_t index) {
8948 Boppan 997
	size_t offset = sh->PointerToRelocations + 10 * index;
998
	if (!epep_valid_offset(epep, offset, 10)) {
999
		epep->error_code = EPEP_ERR_INVALID_SECTION_RELOCATION_OFFSET;
1000
		return 0;
1001
	}
1002
	epep_seek(epep, offset);
8600 Boppan 1003
	epep_read_block(epep, 10, rel);
1004
	return 1;
1005
}
1006
 
1007
//
1008
// COFF Line Numbers
1009
//
1010
 
1011
int epep_get_section_line_number_by_index(Epep *epep, EpepSectionHeader *sh, EpepCoffLinenumber *ln, size_t index) {
8948 Boppan 1012
	size_t offset = sh->PointerToLinenumbers + 6 * index;
1013
	if (!epep_valid_offset(epep, offset, 6)) {
1014
		epep->error_code = EPEP_ERR_INVALID_LINENUMBER_OFFSET;
1015
		return 0;
1016
	}
1017
	epep_seek(epep, offset);
8600 Boppan 1018
	epep_read_block(epep, 6, ln);
1019
	return 1;
1020
}
1021
 
1022
#endif // EPEP_INST