Files
youssefnoob003-SindriKit/docs/parsers/api_reference.md
T
2026-06-22 12:38:04 +01:00

233 lines
9.7 KiB
Markdown

# PE Parser: API Reference
This page documents the full public API surface of the parsers subsystem. Headers live under `include/sindri/parsers/pe/`.
---
## Core Parser (`sindri/parsers/pe/pe_parser.h`)
### `snd_pe_parse`
Validates and parses a raw or mapped PE buffer into a `snd_pe_parser_t` context. Checks the DOS signature (`MZ`), the NT signature (`PE\0\0`), and the Optional Header magic (`0x10B` for PE32, `0x20B` for PE32+). Populates all fields of the output structure on success.
| Parameter | Type | Description |
|---|---|---|
| `buf` | `const snd_buffer_t*` | Buffer descriptor containing the PE data (pointer + size) |
| `is_mapped` | `BOOL` | `FALSE` for a raw file, `TRUE` for a memory-mapped image |
| `parser` | `snd_pe_parser_t*` | Output context to populate |
**Returns:** `snd_status_t``SND_OK` on success, or a parse error (`SND_STATUS_INVALID_DOS_SIGNATURE`, `SND_STATUS_INVALID_NT_SIGNATURE`, `SND_STATUS_UNSUPPORTED_OPTIONAL_HEADER_MAGIC`, etc.).
---
### `SND_PE_GET_NT_FIELD(parser, field)`
Macro for reading a field from the NT Optional Header without branching on `is_64bit` at every call site. Selects `nt.nt64->field` or `nt.nt32->field` based on `parser->is_64bit`.
```c
DWORD size_of_image = SND_PE_GET_NT_FIELD(&ctx.pe, OptionalHeader.SizeOfImage);
```
---
### `SND_SYS_DLL_SIZE_DEFAULT`
**Value:** `0x1000` (4096 bytes)
Bootstrap bound used when parsing the headers of an in-memory system DLL before `SizeOfImage` is known. After `snd_pe_parse` succeeds, the caller must update `parser->source.size` to `SizeOfImage` before calling any directory resolution function.
---
### `snd_pe_parser_t`
| Field | Type | Description |
|---|---|---|
| `source` | `snd_buffer_t` | Buffer descriptor (base pointer + tracked size) |
| `dos` | `PIMAGE_DOS_HEADER` | Pointer to the DOS header |
| `nt.nt32` | `PIMAGE_NT_HEADERS32` | NT headers pointer for 32-bit images (valid when `is_64bit == FALSE`) |
| `nt.nt64` | `PIMAGE_NT_HEADERS64` | NT headers pointer for 64-bit images (valid when `is_64bit == TRUE`) |
| `section_head` | `PIMAGE_SECTION_HEADER` | Pointer to the first section header entry |
| `string_table` | `BYTE*` | COFF string table pointer (used for long section names) |
| `is_64bit` | `BOOL` | `TRUE` for PE32+ (64-bit image) |
| `is_dll` | `BOOL` | `TRUE` if `IMAGE_FILE_DLL` is set in FileHeader.Characteristics |
| `is_mapped` | `BOOL` | `TRUE` if the source buffer is a loaded image, `FALSE` if raw file |
| `sections_count` | `DWORD` | Number of section header entries |
| `imports_rva` | `DWORD` | Cached RVA of the import data directory |
| `import_size` | `DWORD` | Cached size of the import data directory |
### `SND_PE_MIN_FILE_ALIGNMENT`
**Value:** `512`
The minimum valid file alignment factor allowed for a PE image. Used to sanity-check PE structures against malformed headers.
---
## Utilities (`sindri/parsers/pe/pe_utils.h`)
### `snd_pe_compatibility_check`
Validates that a payload's bitness matches the host process architecture. This validation should occur before allocating memory or mapping sections.
| Parameter | Type | Description |
|---|---|---|
| `is_64bit` | `BOOL` | `TRUE` if the payload is 64-bit |
**Returns:** `BOOL``TRUE` if compatible, `FALSE` on mismatch.
---
### `snd_pe_get_entry_point`
Computes the absolute entry point address from `OptionalHeader.AddressOfEntryPoint` relative to the parser's source base.
| Parameter | Type | Description |
|---|---|---|
| `parser` | `const snd_pe_parser_t*` | Parsed PE context |
**Returns:** `void*` — absolute entry point address, or `NULL` if the RVA is zero or invalid.
---
### `snd_pe_get_tls_callbacks`
Retrieves the TLS callback array pointer from the TLS data directory. Returns `NULL` if no TLS directory is present.
| Parameter | Type | Description |
|---|---|---|
| `base_address` | `PVOID` | Base address of the mapped image |
| `parser` | `const snd_pe_parser_t*` | Parsed PE context |
**Returns:** `PVOID` — pointer to the null-terminated `PIMAGE_TLS_CALLBACK` array, or `NULL`.
---
### `snd_pe_execute_tls_callbacks`
Iterates the TLS callback array and calls each entry with the specified reason.
| Parameter | Type | Description |
|---|---|---|
| `virtual_base` | `PVOID` | Base address of the mapped image |
| `parser` | `const snd_pe_parser_t*` | Parsed PE context |
| `reason` | `DWORD` | Callback reason (e.g., `DLL_PROCESS_ATTACH`, `DLL_PROCESS_DETACH`) |
**Returns:** `snd_status_t``SND_OK` on success (including when no TLS directory exists).
---
### `snd_pe_rva_to_ptr`
Translates an RVA to an absolute pointer within the parser's tracked buffer. Performs a bounds check on `(rva, size)` before returning. For raw files (`is_mapped = FALSE`), performs section-table-based translation. For mapped images (`is_mapped = TRUE`), returns `source.base + rva` directly.
| Parameter | Type | Description |
|---|---|---|
| `parser` | `const snd_pe_parser_t*` | Parsed PE context |
| `rva` | `DWORD` | Relative Virtual Address to translate |
| `size` | `SIZE_T` | Expected data size at the target address (used for bounds checking) |
**Returns:** `PVOID` — pointer to the data, or `NULL` if out-of-bounds or the RVA is invalid.
---
### `snd_pe_get_directory`
Safely retrieves a data directory entry by index from the Optional Header's `DataDirectory` array.
| Parameter | Type | Description |
|---|---|---|
| `parser` | `const snd_pe_parser_t*` | Parsed PE context |
| `index` | `DWORD` | Directory index (e.g., `IMAGE_DIRECTORY_ENTRY_IMPORT`, `IMAGE_DIRECTORY_ENTRY_EXPORT`) |
| `dir_out` | `IMAGE_DATA_DIRECTORY*` | Output structure populated with `VirtualAddress` and `Size` |
**Returns:** `snd_status_t``SND_OK` on success, `SND_STATUS_DIRECTORY_NOT_FOUND` if the directory index is out of range or the directory's `VirtualAddress` is zero.
---
## Export Resolution (`sindri/parsers/pe/pe_exports.h`)
### `snd_pe_get_export_address`
Resolves an exported symbol by name from a mapped PE image. Handles export forwarders recursively via the `resolver` callback.
| Parameter | Type | Description |
|---|---|---|
| `base_address` | `PVOID` | Base address of the mapped PE image |
| `size` | `SIZE_T` | Size of the mapped PE image (for bounds checking) |
| `func_name` | `const char*` | Null-terminated export name to resolve |
| `func_addr_out` | `FARPROC*` | Receives the resolved function address |
| `resolver` | `snd_module_resolver_cb` | Callback to resolve external module bases for forwarders; pass `NULL` to fail on forwarders |
**Returns:** `snd_status_t``SND_OK` on success, `SND_STATUS_EXPORT_NOT_FOUND` if the name is not in the export table, `SND_STATUS_EXPORT_FORWARDER_UNSUPPORTED` if a forwarder is encountered and `resolver` is `NULL`.
---
### `snd_pe_get_export_address_by_hash`
Hash-based variant of export resolution. Eliminates plaintext function name strings from the binary entirely.
| Parameter | Type | Description |
|---|---|---|
| `base_address` | `PVOID` | Base address of the mapped PE image |
| `size` | `SIZE_T` | Size of the mapped PE image |
| `func_hash` | `DWORD` | Pre-computed hash of the target export name |
| `func_addr_out` | `FARPROC*` | Receives the resolved function address |
| `resolver` | `snd_module_resolver_hash_cb` | Hash-based resolver callback for forwarder modules |
**Returns:** `snd_status_t``SND_OK` on success, or an export resolution error.
---
### `SND_FWD_MAX_DEPTH`
**Value:** `4`
Maximum recursion depth for export forwarder resolution. Prevents infinite loops from cyclically forwarded exports.
---
## Import Resolution (`sindri/parsers/pe/pe_imports.h`)
### `snd_pe_resolve_imports`
Walks the Import Descriptor table of a mapped PE and patches the IAT. For each descriptor: loads the dependency module via `mod_api->load_library`, then iterates the thunk array resolving by ordinal or name via `mod_api->get_proc_address`.
| Parameter | Type | Description |
|---|---|---|
| `base_address` | `PVOID` | Base address of the mapped PE image |
| `mod_api` | `const snd_module_api_t*` | Module API used for all loading and symbol resolution |
| `parser` | `const snd_pe_parser_t*` | Parsed PE context |
**Returns:** `snd_status_t``SND_OK` on success, or an import resolution error (`SND_STATUS_IMPORT_DLL_LOAD_FAILED`, `SND_STATUS_IMPORT_SYMBOL_RESOLVE_FAILED`, etc.).
---
### Ordinal Detection Macros
| Macro | Description |
|---|---|
| `SND_PE_SNAP_BY_ORDINAL32(ordinal)` | `TRUE` if the high bit of a 32-bit thunk value is set (ordinal-based import) |
| `SND_PE_SNAP_BY_ORDINAL64(ordinal)` | `TRUE` if the high bit of a 64-bit thunk value is set |
| `SND_PE_ORDINAL(ordinal)` | Extracts the 16-bit ordinal value from a thunk entry |
---
## Base Relocations (`sindri/parsers/pe/pe_relocations.h`)
### `snd_pe_apply_relocations`
Iterates the Base Relocation Table (`.reloc` section) and patches all hardcoded absolute addresses to align with the actual runtime base address. Each entry is bounds-checked before the write is applied.
The function computes `delta = actual_base - preferred_base`. If `delta` is zero (the image landed at its preferred `ImageBase`), the function returns immediately with `SND_OK`.
> [!NOTE]
> The memory at `base_address` must have at least `PAGE_READWRITE` permissions before calling this function, as it physically overwrites pointer-sized values inside `.text` and `.data` sections.
| Parameter | Type | Description |
|---|---|---|
| `base_address` | `PVOID` | Actual runtime base address where the PE image is mapped |
| `delta_offset` | `LONG_PTR` | Difference between actual base and preferred `ImageBase`; zero triggers early exit |
| `parser` | `const snd_pe_parser_t*` | Validated PE parser context |
**Returns:** `snd_status_t``SND_OK` on success, or `SND_STATUS_RELOCS_STRIPPED` if `IMAGE_FILE_RELOCS_STRIPPED` is set in the PE characteristics.