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 | // |
||
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, |
||
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>>>>>>=>><>>><>><>><>><> |