Subversion Repositories Kolibri OS

Rev

Rev 8948 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. // Dependencies:
  2. // <assert.h> or any another source of assert()
  3. // <stdint.h> or any another source of uint64_t, uint32_t, uint16_t, uint8_t, size_t
  4.  
  5. #ifndef EPEP_ASSERT
  6. #include <assert.h>
  7. #define EPEP_ASSERT(x) assert(x)
  8. #endif
  9.  
  10. #ifndef EPEP_READER
  11. #include <stdio.h>
  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)
  15. #define EPEP_READER_SEEK_END(preader, offset) fseek(*preader, offset, SEEK_END)
  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,
  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,
  64.         EPEP_ERR_INVALID_NUMBER_OF_RELOCATIONS_FOR_EXTENDED,
  65.         EPEP_ERR_END
  66. } EpepError;
  67.  
  68. //
  69. // Generic
  70. //
  71.  
  72. typedef struct {
  73.         EPEP_READER reader;
  74.         EpepKind kind;
  75.         EpepError error_code;
  76.         size_t file_size;
  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.  
  290. /// Palces offset of export table into epep structure
  291. int epep_read_export_table_offset(Epep *epep);
  292.  
  293. /// Palces export table into epep structure
  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.  
  365. /// Gives a COFF Relocation by its index
  366. int epep_get_section_relocation_by_index(Epep *epep, EpepSectionHeader *sh, EpepCoffRelocation *rel, size_t index);
  367.  
  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.  
  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.  
  407. static int epep_seek_end(Epep *epep, size_t offset) {
  408.         EPEP_READER_SEEK_END(&epep->reader, offset);
  409.         return 1;
  410. }
  411.  
  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.  
  455. static int epep_valid_offset(Epep *epep, size_t offset, size_t size) {
  456.         return (offset + size) <= epep->file_size;
  457. }
  458.  
  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;
  467.         epep_seek_end(epep, 0);
  468.         epep->file_size = EPEP_READER_TELL(&epep->reader);
  469.         epep_seek(epep, 0);
  470.         epep->error_code = EPEP_ERR_SUCCESS;
  471.         epep->signature_offset_offset = 0x3c;
  472.         epep_seek(epep, epep->signature_offset_offset);
  473.         epep->signature_offset = epep_read_u32(epep);
  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.         }
  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);
  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.         }
  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);
  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) {
  614.         size_t offset = sh->PointerToRawData;
  615.         size_t size_of_raw_data = sh->SizeOfRawData;
  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);
  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) {
  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);
  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.         }
  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);
  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.         }
  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);
  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.         }
  723.         if (!epep_valid_offset(epep, name_offset, 0)) {
  724.                 epep->error_code = EPEP_ERR_INVALID_IMPORT_DIRECTORY_NAME_OFFSET;
  725.                 return 0;
  726.         }
  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;
  739.         if (!epep_valid_offset(epep, lookup_offset, size_of_lookup)) {
  740.                 epep->error_code = EPEP_ERR_INVALID_LOOKUP_OFFSET;
  741.                 return 0;
  742.         }
  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;
  769.         if (!epep_valid_offset(epep, name_offset, 0)) {
  770.                 epep->error_code = EPEP_ERR_INVALID_LOOKUP_NAME_OFFSET;
  771.                 return 0;
  772.         }
  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.         }
  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.         }
  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.         }
  824.         if (!epep_valid_offset(epep, offset, 0)) {
  825.                 epep->error_code = EPEP_ERR_INVALID_DLL_NAME_OFFSET;
  826.                 return 0;
  827.         }
  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.         }
  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);
  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.         }
  854.         if (!epep_valid_offset(epep, ordinal_table_offset, 0)) {
  855.                 epep->error_code = EPEP_ERR_INVALID_ORDINAL_TABLE_OFFSET;
  856.                 return 0;
  857.         }
  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.                         }
  870.                         if (!epep_valid_offset(epep, name_offset, 0)) {
  871.                                 epep->error_code = EPEP_ERR_INVALID_EXPORT_NAME_OFFSET;
  872.                                 return 0;
  873.                         }
  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));
  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);
  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.         }
  904.         if (!epep_valid_offset(epep, forwarder_offset, 0)) {
  905.                 epep->error_code = EPEP_ERR_INVALID_FORWARDER_OFFSET;
  906.                 return 0;
  907.         }
  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.         }
  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.         }
  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.         }
  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.         }
  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) {
  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;
  1000.                 return 0;
  1001.         }
  1002.         if (!epep_seek(epep, offset)) {
  1003.                 return 0;
  1004.         }
  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) {
  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);
  1020.         epep_read_block(epep, 10, rel);
  1021.         return 1;
  1022. }
  1023.  
  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.  
  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) {
  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);
  1078.         epep_read_block(epep, 6, ln);
  1079.         return 1;
  1080. }
  1081.  
  1082. #endif // EPEP_INST
  1083.