From 8da5388b94de7a6ebadd9f0cd6c293ecf709e78a Mon Sep 17 00:00:00 2001 From: Romain Thomas Date: Fri, 20 Mar 2026 18:00:41 +0100 Subject: [PATCH] pe: add address range checks for LoadConfiguration fields Add VA range validation for all address fields in LoadConfiguration that were previously unchecked. It validates that each address falls within [imagebase, imagebase + virtual_size). --- api/python/lief/PE/__init__.pyi | 6 +- src/PE/layout_check.cpp | 128 +++++++++++++++++++++++++++++++- 2 files changed, 126 insertions(+), 8 deletions(-) diff --git a/api/python/lief/PE/__init__.pyi b/api/python/lief/PE/__init__.pyi index d4db7d34..61b0876b 100644 --- a/api/python/lief/PE/__init__.pyi +++ b/api/python/lief/PE/__init__.pyi @@ -1014,11 +1014,9 @@ class ImportEntry(lief.Symbol): @property def hint(self) -> int: ... - @property - def iat_value(self) -> int: ... + iat_value: int - @property - def ilt_value(self) -> int: ... + ilt_value: int @property def iat_address(self) -> int: ... diff --git a/src/PE/layout_check.cpp b/src/PE/layout_check.cpp index 78f2ef9e..5c83b980 100644 --- a/src/PE/layout_check.cpp +++ b/src/PE/layout_check.cpp @@ -44,7 +44,9 @@ class LayoutChecker { filesz(bin.original_size()), section_alignment(bin.optional_header().section_alignment()), file_alignment(bin.optional_header().file_alignment()), - sizeof_headers(bin.optional_header().sizeof_headers()) + sizeof_headers(bin.optional_header().sizeof_headers()), + va_start(bin.imagebase()), + va_end(bin.imagebase() + bin.virtual_size()) {} bool check_dos_header(); @@ -134,15 +136,28 @@ class LayoutChecker { return pe.optional_header().magic() == PE_TYPE::PE32; } + bool contains(uint64_t va) const { + return va_start <= va && va < va_end; + } + + bool contains(optional va) const { + if (va.value_or(0) == 0) { + return true; + } + return contains(*va); + } + private: std::string error_msg; const Binary& pe; Header::MACHINE_TYPES arch; uint32_t e_lfanew = 0; uint64_t filesz = 0; - uint32_t section_alignment; - uint32_t file_alignment; - uint64_t sizeof_headers; + uint32_t section_alignment = 0; + uint32_t file_alignment = 0; + uint64_t sizeof_headers = 0; + uint64_t va_start = 0; + uint64_t va_end = 0; }; @@ -466,6 +481,111 @@ bool LayoutChecker::check_load_config() { } } + if (!contains(config->security_cookie())) { + return error("Security cookie out of range: {:#010x} ([{:#010x}, {:#010x}])", + config->security_cookie(), va_start, va_end); + } + + if (!contains(config->lock_prefix_table())) { + return error("Lock prefix table out of range: {:#010x} ([{:#010x}, {:#010x}])", + config->lock_prefix_table(), va_start, va_end); + } + + if (!contains(config->se_handler_table())) { + return error("SE handler table out of range: {:#010x} ([{:#010x}, {:#010x}])", + config->se_handler_table().value_or(0), va_start, va_end); + } + + if (!contains(config->guard_cf_check_function_pointer())) { + return error("Guard CF check function pointer out of range: {:#010x} ([{:#010x}, {:#010x}])", + config->guard_cf_check_function_pointer().value_or(0), va_start, va_end); + } + + if (!contains(config->guard_cf_dispatch_function_pointer())) { + return error("Guard CF dispatch function pointer out of range: {:#010x} ([{:#010x}, {:#010x}])", + config->guard_cf_dispatch_function_pointer().value_or(0), va_start, va_end); + } + + if (!contains(config->guard_address_taken_iat_entry_table())) { + return error("Guard address taken IAT entry table out of range: {:#010x} ([{:#010x}, {:#010x}])", + config->guard_address_taken_iat_entry_table().value_or(0), va_start, va_end); + } + + if (!contains(config->guard_long_jump_target_table())) { + return error("Guard long jump target table out of range: {:#010x} ([{:#010x}, {:#010x}])", + config->guard_long_jump_target_table().value_or(0), va_start, va_end); + } + + if (!contains(config->dynamic_value_reloc_table())) { + return error("Dynamic value reloc table out of range: {:#010x} ([{:#010x}, {:#010x}])", + config->dynamic_value_reloc_table().value_or(0), va_start, va_end); + } + + if (!contains(config->hybrid_metadata_pointer())) { + return error("Hybrid metadata pointer out of range: {:#010x} ([{:#010x}, {:#010x}])", + config->hybrid_metadata_pointer().value_or(0), va_start, va_end); + } + + if (!contains(config->guard_rf_failure_routine())) { + return error("Guard RF failure routine out of range: {:#010x} ([{:#010x}, {:#010x}])", + config->guard_rf_failure_routine().value_or(0), va_start, va_end); + } + + if (!contains(config->guard_rf_failure_routine_function_pointer())) { + return error("Guard RF failure routine function pointer out of range: {:#010x} ([{:#010x}, {:#010x}])", + config->guard_rf_failure_routine_function_pointer().value_or(0), va_start, va_end); + } + + if (!contains(config->guard_rf_verify_stackpointer_function_pointer())) { + return error("Guard RF verify stack pointer function pointer out of range: {:#010x} ([{:#010x}, {:#010x}])", + config->guard_rf_verify_stackpointer_function_pointer().value_or(0), va_start, va_end); + } + + if (!contains(config->enclave_configuration_ptr())) { + return error("Enclave configuration pointer out of range: {:#010x} ([{:#010x}, {:#010x}])", + config->enclave_configuration_ptr().value_or(0), va_start, va_end); + } + + if (!contains(config->volatile_metadata_pointer())) { + return error("Volatile metadata pointer out of range: {:#010x} ([{:#010x}, {:#010x}])", + config->volatile_metadata_pointer().value_or(0), va_start, va_end); + } + + if (!contains(config->guard_eh_continuation_table())) { + return error("Guard EH continuation table out of range: {:#010x} ([{:#010x}, {:#010x}])", + config->guard_eh_continuation_table().value_or(0), va_start, va_end); + } + + if (!contains(config->guard_xfg_check_function_pointer())) { + return error("Guard XFG check function pointer out of range: {:#010x} ([{:#010x}, {:#010x}])", + config->guard_xfg_check_function_pointer().value_or(0), va_start, va_end); + } + + if (!contains(config->guard_xfg_dispatch_function_pointer())) { + return error("Guard XFG dispatch function pointer out of range: {:#010x} ([{:#010x}, {:#010x}])", + config->guard_xfg_dispatch_function_pointer().value_or(0), va_start, va_end); + } + + if (!contains(config->guard_xfg_table_dispatch_function_pointer())) { + return error("Guard XFG table dispatch function pointer out of range: {:#010x} ([{:#010x}, {:#010x}])", + config->guard_xfg_table_dispatch_function_pointer().value_or(0), va_start, va_end); + } + + if (!contains(config->cast_guard_os_determined_failure_mode())) { + return error("Cast guard OS determined failure mode out of range: {:#010x} ([{:#010x}, {:#010x}])", + config->cast_guard_os_determined_failure_mode().value_or(0), va_start, va_end); + } + + if (!contains(config->guard_memcpy_function_pointer())) { + return error("Guard memcpy function pointer out of range: {:#010x} ([{:#010x}, {:#010x}])", + config->guard_memcpy_function_pointer().value_or(0), va_start, va_end); + } + + if (!contains(config->uma_function_pointers())) { + return error("UMA function pointers out of range: {:#010x} ([{:#010x}, {:#010x}])", + config->uma_function_pointers().value_or(0), va_start, va_end); + } + return true; }