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

68 lines
4.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# PE Mutation Engine (`tests/loader/pe_mutator.py`)
**Location:** `tests/loader/pe_mutator.py`
The PE mutation engine applies targeted structural modifications to valid PE files to produce variants that stress-test the reflective loader's parser and loading pipeline. Every mutation is designed to exercise a specific safety boundary or parsing assumption.
## Mutation Categories
Mutations are divided into two strict categories:
### Benign Edge-Cases
These produce PE files that are unusual or hyper-optimized but structurally valid — Windows can still load and run them. The reflective loader **must** adapt and succeed.
| Mutation | Description | What It Tests |
|---|---|---|
| `unaligned_sections` | Forces `SectionAlignment` and `FileAlignment` to `0x200` | Loaders that hardcode `0x1000` page alignment assumptions |
| `strip_relocs_from_exe` | Strips the `.reloc` directory and sets `IMAGE_FILE_RELOCS_STRIPPED` | Loaders that aggressively demand relocations for EXEs |
| `garbage_dos_stub` | Overwrites the DOS stub (bytes 2`e_lfanew`) with deterministic garbage | Parsers that read linearly through the DOS stub instead of seeking via `e_lfanew` |
| `append_overlay` | Appends 4 KB of junk data after the last section | Loaders that map beyond declared section boundaries |
| `null_section_names` | Zeroes out every section name string | Loaders that match section names unsafely or log via unchecked `printf` |
### Breaking Stressors
These produce structurally corrupted PE files. The parser **must** detect the violation and reject the input gracefully — **never crash**.
| Mutation | Description | What It Tests |
|---|---|---|
| `corrupt_reloc_block_size` | Sets first reloc block's `SizeOfBlock` to `0xFFFFFFFF` | Unbounded `while` loops in relocation parsing |
| `massive_size_of_headers` | Sets `SizeOfHeaders` to `0xFFFFFFFF` | Unchecked `memcpy` using header-sourced sizes |
| `section_truncated_raw_data` | Inflates a section's `SizeOfRawData` beyond the physical file | Blind section mapping without file bounds checks |
| `section_integer_overflow` | Sets `VirtualSize` and `SizeOfRawData` to `0xFFFFFFFF` | Integer overflow in allocation arithmetic (`VA + ALIGN(VirtualSize)`) |
| `section_overlap_corruption` | Collapses all section file offsets to zero | File alignment normalization bugs |
| `corrupt_pe_signature` | Replaces `PE\0\0` with `0xDEADBEEF` | NT signature validation |
| `invalid_e_lfanew` | Points `e_lfanew` 1 MB past EOF | Offset bounds checking before NT headers access |
| `zero_size_of_image` | Sets `SizeOfImage` to 0 | Allocation size validation |
| `corrupt_import_rva` | Points import directory to `0xDEAD0000` | RVA bounds checking before import traversal |
| `corrupt_export_rva` | Points export directory to `0xDEAD0000` | RVA bounds checking before export parsing |
| `huge_sections_count` | Sets `NumberOfSections` to `0xFFFF` | Section table overflow protection |
| `unterminated_imports` | Overwrites the null-terminating import descriptor with `0xFF` | Import loop termination without boundary checks |
| `massive_export_count` | Sets `NumberOfFunctions` and `NumberOfNames` to `0xFFFFFFFF` | Export iteration bounds checking |
| `oob_entry_point` | Points `AddressOfEntryPoint` past `SizeOfImage` | Entry point RVA validation before execution transfer |
## API
### `Mutation` Dataclass
| Field | Type | Description |
|---|---|---|
| `name` | `str` | Short string identifier (used in output filenames) |
| `description` | `str` | Human-readable label |
| `apply` | `Callable` | The mutation function (`(src, dst) -> None`) |
| `expect_loadable` | `bool` | `True` = loader must succeed; `False` = loader must reject gracefully |
| `applies_to` | `str` | `"both"`, `"exe"`, or `"dll"` |
### `mutate_pe(src_path, mutation, output_dir) -> str`
Applies the specified mutation to the source PE file and writes the mutated output to `output_dir`. Returns the path to the generated file. Raises `MutationError` on failure.
## Dependency
Requires the `pefile` Python package for structured PE modifications:
```
pip install pefile
```
Raw byte-level mutations (`garbage_dos_stub`, `corrupt_pe_signature`, `invalid_e_lfanew`, `huge_sections_count`) operate directly on the byte buffer without `pefile`.