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