use bitflags::bitflags;
use std::marker::PhantomData;
use crate::common::FromFFI;
use lief_ffi as ffi;
pub struct DosHeader<'a> {
ptr: cxx::UniquePtr<ffi::PE_DosHeader>,
_owner: PhantomData<&'a ffi::PE_Binary>,
}
impl FromFFI<ffi::PE_DosHeader> for DosHeader<'_> {
fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_DosHeader>) -> Self {
Self {
ptr,
_owner: PhantomData,
}
}
}
impl<'a> DosHeader<'a> {
pub fn magic(&self) -> u16 {
self.ptr.magic()
}
pub fn used_bytes_in_last_page(&self) -> u16 {
self.ptr.used_bytes_in_last_page()
}
pub fn file_size_in_pages(&self) -> u16 {
self.ptr.file_size_in_pages()
}
pub fn numberof_relocation(&self) -> u16 {
self.ptr.numberof_relocation()
}
pub fn header_size_in_paragraphs(&self) -> u16 {
self.ptr.header_size_in_paragraphs()
}
pub fn minimum_extra_paragraphs(&self) -> u16 {
self.ptr.minimum_extra_paragraphs()
}
pub fn maximum_extra_paragraphs(&self) -> u16 {
self.ptr.maximum_extra_paragraphs()
}
pub fn initial_relative_ss(&self) -> u16 {
self.ptr.initial_relative_ss()
}
pub fn initial_sp(&self) -> u16 {
self.ptr.initial_sp()
}
pub fn checksum(&self) -> u16 {
self.ptr.checksum()
}
pub fn initial_ip(&self) -> u16 {
self.ptr.initial_ip()
}
pub fn initial_relative_cs(&self) -> u16 {
self.ptr.initial_relative_cs()
}
pub fn addressof_relocation_table(&self) -> u16 {
self.ptr.addressof_relocation_table()
}
pub fn overlay_number(&self) -> u16 {
self.ptr.overlay_number()
}
pub fn reserved(&self) -> Vec<u16> {
Vec::from_iter(self.ptr.reserved().iter().map(|x| *x as u16))
}
pub fn oem_id(&self) -> u16 {
self.ptr.oem_id()
}
pub fn oem_info(&self) -> u16 {
self.ptr.oem_info()
}
pub fn reserved2(&self) -> Vec<u16> {
Vec::from_iter(self.ptr.reserved2().iter().map(|x| *x as u16))
}
pub fn addressof_new_exeheader(&self) -> u32 {
self.ptr.addressof_new_exeheader()
}
}
impl std::fmt::Debug for DosHeader<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("DosHeader")
.field("magic", &self.magic())
.field("used_bytes_in_last_page", &self.used_bytes_in_last_page())
.field("file_size_in_pages", &self.file_size_in_pages())
.field("numberof_relocation", &self.numberof_relocation())
.field(
"header_size_in_paragraphs",
&self.header_size_in_paragraphs(),
)
.field("minimum_extra_paragraphs", &self.minimum_extra_paragraphs())
.field("maximum_extra_paragraphs", &self.maximum_extra_paragraphs())
.field("initial_relative_ss", &self.initial_relative_ss())
.field("initial_sp", &self.initial_sp())
.field("checksum", &self.checksum())
.field("initial_ip", &self.initial_ip())
.field("initial_relative_cs", &self.initial_relative_cs())
.field(
"addressof_relocation_table",
&self.addressof_relocation_table(),
)
.field("overlay_number", &self.overlay_number())
.field("reserved", &self.reserved())
.field("oem_info", &self.oem_info())
.field("oem_id", &self.oem_id())
.field("reserved2", &self.reserved2())
.field("addressof_new_exeheader", &self.addressof_new_exeheader())
.finish()
}
}
pub struct Header<'a> {
ptr: cxx::UniquePtr<ffi::PE_Header>,
_owner: PhantomData<&'a ffi::PE_Binary>,
}
impl FromFFI<ffi::PE_Header> for Header<'_> {
fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_Header>) -> Self {
Self {
ptr,
_owner: PhantomData,
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum MachineType {
ALPHA,
ALPHA64,
AM33,
AMD64,
ARM,
ARMNT,
ARM64,
EBC,
I386,
IA64,
LOONGARCH32,
LOONGARCH64,
M32R,
MIPS16,
MIPSFPU,
MIPSFPU16,
POWERPC,
POWERPCFP,
POWERPCBE,
R4000,
RISCV32,
RISCV64,
RISCV128,
SH3,
SH3DSP,
SH4,
SH5,
THUMB,
WCEMIPSV2,
ARM64EC,
ARM64X,
CHPE_X86,
UNKNOWN(u32),
}
impl From<u32> for MachineType {
fn from(value: u32) -> Self {
match value {
0x00000184 => MachineType::ALPHA,
0x00000284 => MachineType::ALPHA64,
0x000001d3 => MachineType::AM33,
0x00008664 => MachineType::AMD64,
0x000001c0 => MachineType::ARM,
0x000001c4 => MachineType::ARMNT,
0x0000aa64 => MachineType::ARM64,
0x00000ebc => MachineType::EBC,
0x0000014c => MachineType::I386,
0x00000200 => MachineType::IA64,
0x00006232 => MachineType::LOONGARCH32,
0x00006264 => MachineType::LOONGARCH64,
0x00009041 => MachineType::M32R,
0x00000266 => MachineType::MIPS16,
0x00000366 => MachineType::MIPSFPU,
0x00000466 => MachineType::MIPSFPU16,
0x000001f0 => MachineType::POWERPC,
0x000001f1 => MachineType::POWERPCFP,
0x000001f2 => MachineType::POWERPCBE,
0x00000166 => MachineType::R4000,
0x00005032 => MachineType::RISCV32,
0x00005064 => MachineType::RISCV64,
0x00005128 => MachineType::RISCV128,
0x000001a2 => MachineType::SH3,
0x000001a3 => MachineType::SH3DSP,
0x000001a6 => MachineType::SH4,
0x000001a8 => MachineType::SH5,
0x000001c2 => MachineType::THUMB,
0x00000169 => MachineType::WCEMIPSV2,
0x0000a641 => MachineType::ARM64EC,
0x0000a64e => MachineType::ARM64X,
0x00003a64 => MachineType::CHPE_X86,
_ => MachineType::UNKNOWN(value),
}
}
}
impl From<MachineType> for u32 {
fn from(value: MachineType) -> u32 {
match value {
MachineType::ALPHA => 0x184,
MachineType::ALPHA64 => 0x284,
MachineType::AM33 => 0x000001d3,
MachineType::AMD64 => 0x00008664,
MachineType::ARM => 0x000001c0,
MachineType::ARMNT => 0x000001c4,
MachineType::ARM64 => 0x0000aa64,
MachineType::EBC => 0x00000ebc,
MachineType::I386 => 0x0000014c,
MachineType::IA64 => 0x00000200,
MachineType::LOONGARCH32 => 0x6232,
MachineType::LOONGARCH64 => 0x6264,
MachineType::M32R => 0x00009041,
MachineType::MIPS16 => 0x00000266,
MachineType::MIPSFPU => 0x00000366,
MachineType::MIPSFPU16 => 0x00000466,
MachineType::POWERPC => 0x000001f0,
MachineType::POWERPCFP => 0x000001f1,
MachineType::POWERPCBE => 0x000001f2,
MachineType::R4000 => 0x00000166,
MachineType::RISCV32 => 0x00005032,
MachineType::RISCV64 => 0x00005064,
MachineType::RISCV128 => 0x00005128,
MachineType::SH3 => 0x000001a2,
MachineType::SH3DSP => 0x000001a3,
MachineType::SH4 => 0x000001a6,
MachineType::SH5 => 0x000001a8,
MachineType::THUMB => 0x000001c2,
MachineType::WCEMIPSV2 => 0x00000169,
MachineType::ARM64EC => 0x0000a641,
MachineType::ARM64X => 0x0000a64e,
MachineType::CHPE_X86 => 0x00003a64,
MachineType::UNKNOWN(_) => 0,
}
}
}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Characteristics: u32 {
const NONE = 0x0;
const RELOCS_STRIPPED = 0x1;
const EXECUTABLE_IMAGE = 0x2;
const LINE_NUMS_STRIPPED = 0x4;
const LOCAL_SYMS_STRIPPED = 0x8;
const AGGRESSIVE_WS_TRIM = 0x10;
const LARGE_ADDRESS_AWARE = 0x20;
const BYTES_REVERSED_LO = 0x80;
const NEED_32BIT_MACHINE = 0x100;
const DEBUG_STRIPPED = 0x200;
const REMOVABLE_RUN_FROM_SWAP = 0x400;
const NET_RUN_FROM_SWAP = 0x800;
const SYSTEM = 0x1000;
const DLL = 0x2000;
const UP_SYSTEM_ONLY = 0x4000;
const BYTES_REVERSED_HI = 0x8000;
}
}
impl std::fmt::Display for Characteristics {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
bitflags::parser::to_writer(self, f)
}
}
impl From<u32> for Characteristics {
fn from(value: u32) -> Self {
Characteristics::from_bits_truncate(value)
}
}
impl From<Characteristics> for u32 {
fn from(value: Characteristics) -> Self {
value.bits()
}
}
impl Header<'_> {
pub fn signature(&self) -> Vec<u8> {
Vec::from(self.ptr.signature().as_slice())
.iter()
.map(|&v: &u64| v as u8)
.collect()
}
pub fn machine(&self) -> MachineType {
MachineType::from(self.ptr.machine())
}
pub fn nb_sections(&self) -> u16 {
self.ptr.numberof_sections()
}
pub fn time_date_stamp(&self) -> u32 {
self.ptr.time_date_stamp()
}
pub fn pointerto_symbol_table(&self) -> u32 {
self.ptr.pointerto_symbol_table()
}
pub fn numberof_symbols(&self) -> u32 {
self.ptr.numberof_symbols()
}
pub fn sizeof_optional_header(&self) -> u16 {
self.ptr.sizeof_optional_header()
}
pub fn characteristics(&self) -> Characteristics {
Characteristics::from(self.ptr.characteristics())
}
pub fn set_machine(&mut self, machine: MachineType) {
self.ptr.pin_mut().set_machine(u32::from(machine));
}
pub fn set_numberof_sections(&mut self, value: u16) {
self.ptr.pin_mut().set_numberof_sections(value);
}
pub fn set_time_date_stamp(&mut self, value: u32) {
self.ptr.pin_mut().set_time_date_stamp(value);
}
pub fn set_pointerto_symbol_table(&mut self, value: u32) {
self.ptr.pin_mut().set_pointerto_symbol_table(value);
}
pub fn set_numberof_symbols(&mut self, value: u32) {
self.ptr.pin_mut().set_numberof_symbols(value);
}
pub fn set_sizeof_optional_header(&mut self, value: u16) {
self.ptr.pin_mut().set_sizeof_optional_header(value);
}
pub fn set_characteristics(&mut self, characteristics: Characteristics) {
self.ptr
.pin_mut()
.set_characteristics(characteristics.bits());
}
pub fn add_characteristic(&mut self, characteristics: Characteristics) {
self.ptr
.pin_mut()
.add_characteristic(characteristics.bits());
}
pub fn remove_characteristic(&mut self, characteristics: Characteristics) {
self.ptr
.pin_mut()
.remove_characteristic(characteristics.bits());
}
}
impl std::fmt::Debug for Header<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Header")
.field("machine", &self.machine())
.field("nb_sections", &self.nb_sections())
.field("time_date_stamp", &self.time_date_stamp())
.field("pointerto_symbol_table", &self.pointerto_symbol_table())
.field("numberof_symbols", &self.numberof_symbols())
.field("sizeof_optional_header", &self.sizeof_optional_header())
.field("characteristics", &self.characteristics())
.finish()
}
}
pub struct OptionalHeader<'a> {
ptr: cxx::UniquePtr<ffi::PE_OptionalHeader>,
_owner: PhantomData<&'a ffi::PE_Binary>,
}
impl FromFFI<ffi::PE_OptionalHeader> for OptionalHeader<'_> {
fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_OptionalHeader>) -> Self {
Self {
ptr,
_owner: PhantomData,
}
}
}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DllCharacteristics: u32 {
const HIGH_ENTROPY_VA = 0x20;
const DYNAMIC_BASE = 0x40;
const FORCE_INTEGRITY = 0x80;
const NX_COMPAT = 0x100;
const NO_ISOLATION = 0x200;
const NO_SEH = 0x400;
const NO_BIND = 0x800;
const APPCONTAINER = 0x1000;
const WDM_DRIVER = 0x2000;
const GUARD_CF = 0x4000;
const TERMINAL_SERVER_AWARE = 0x8000;
}
}
impl From<u32> for DllCharacteristics {
fn from(value: u32) -> Self {
DllCharacteristics::from_bits_truncate(value)
}
}
impl From<DllCharacteristics> for u32 {
fn from(value: DllCharacteristics) -> Self {
value.bits()
}
}
impl std::fmt::Display for DllCharacteristics {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
bitflags::parser::to_writer(self, f)
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Subsystem {
NATIVE,
WINDOWS_GUI,
WINDOWS_CUI,
OS2_CUI,
POSIX_CUI,
NATIVE_WINDOWS,
WINDOWS_CE_GUI,
EFI_APPLICATION,
EFI_BOOT_SERVICE_DRIVER,
EFI_RUNTIME_DRIVER,
EFI_ROM,
XBOX,
WINDOWS_BOOT_APPLICATION,
XBOX_CODE_CATALOG,
UNKNOWN(u64),
}
impl From<u64> for Subsystem {
fn from(value: u64) -> Self {
match value {
0x00000001 => Subsystem::NATIVE,
0x00000002 => Subsystem::WINDOWS_GUI,
0x00000003 => Subsystem::WINDOWS_CUI,
0x00000005 => Subsystem::OS2_CUI,
0x00000007 => Subsystem::POSIX_CUI,
0x00000008 => Subsystem::NATIVE_WINDOWS,
0x00000009 => Subsystem::WINDOWS_CE_GUI,
0x0000000a => Subsystem::EFI_APPLICATION,
0x0000000b => Subsystem::EFI_BOOT_SERVICE_DRIVER,
0x0000000c => Subsystem::EFI_RUNTIME_DRIVER,
0x0000000d => Subsystem::EFI_ROM,
0x0000000e => Subsystem::XBOX,
0x00000010 => Subsystem::WINDOWS_BOOT_APPLICATION,
0x00000011 => Subsystem::XBOX_CODE_CATALOG,
_ => Subsystem::UNKNOWN(value),
}
}
}
impl From<Subsystem> for u64 {
fn from(value: Subsystem) -> u64 {
match value {
Subsystem::NATIVE => 0x00000001,
Subsystem::WINDOWS_GUI => 0x00000002,
Subsystem::WINDOWS_CUI => 0x00000003,
Subsystem::OS2_CUI => 0x00000005,
Subsystem::POSIX_CUI => 0x00000007,
Subsystem::NATIVE_WINDOWS => 0x00000008,
Subsystem::WINDOWS_CE_GUI => 0x00000009,
Subsystem::EFI_APPLICATION => 0x0000000a,
Subsystem::EFI_BOOT_SERVICE_DRIVER => 0x0000000b,
Subsystem::EFI_RUNTIME_DRIVER => 0x0000000c,
Subsystem::EFI_ROM => 0x0000000d,
Subsystem::XBOX => 0x0000000e,
Subsystem::WINDOWS_BOOT_APPLICATION => 0x00000010,
Subsystem::XBOX_CODE_CATALOG => 0x00000011,
Subsystem::UNKNOWN(_) => 0,
}
}
}
impl OptionalHeader<'_> {
pub fn magic(&self) -> u32 {
self.ptr.magic() as u32
}
pub fn major_linker_version(&self) -> u8 {
self.ptr.major_linker_version()
}
pub fn minor_linker_version(&self) -> u8 {
self.ptr.minor_linker_version()
}
pub fn sizeof_code(&self) -> u32 {
self.ptr.sizeof_code()
}
pub fn sizeof_initialized_data(&self) -> u32 {
self.ptr.sizeof_initialized_data()
}
pub fn sizeof_uninitialized_data(&self) -> u32 {
self.ptr.sizeof_uninitialized_data()
}
pub fn addressof_entrypoint(&self) -> u32 {
self.ptr.addressof_entrypoint()
}
pub fn baseof_code(&self) -> u32 {
self.ptr.baseof_code()
}
pub fn baseof_data(&self) -> u32 {
self.ptr.baseof_data()
}
pub fn imagebase(&self) -> u64 {
self.ptr.imagebase()
}
pub fn section_alignment(&self) -> u32 {
self.ptr.section_alignment()
}
pub fn file_alignment(&self) -> u32 {
self.ptr.file_alignment()
}
pub fn major_operating_system_version(&self) -> u16 {
self.ptr.major_operating_system_version()
}
pub fn minor_operating_system_version(&self) -> u16 {
self.ptr.minor_operating_system_version()
}
pub fn major_image_version(&self) -> u16 {
self.ptr.major_image_version()
}
pub fn minor_image_version(&self) -> u16 {
self.ptr.minor_image_version()
}
pub fn major_subsystem_version(&self) -> u16 {
self.ptr.major_subsystem_version()
}
pub fn minor_subsystem_version(&self) -> u16 {
self.ptr.minor_subsystem_version()
}
pub fn win32_version_value(&self) -> u32 {
self.ptr.win32_version_value()
}
pub fn sizeof_image(&self) -> u32 {
self.ptr.sizeof_image()
}
pub fn sizeof_headers(&self) -> u32 {
self.ptr.sizeof_headers()
}
pub fn checksum(&self) -> u32 {
self.ptr.checksum()
}
pub fn subsystem(&self) -> Subsystem {
Subsystem::from(self.ptr.subsystem())
}
pub fn dll_characteristics(&self) -> DllCharacteristics {
DllCharacteristics::from(self.ptr.dll_characteristics())
}
pub fn sizeof_stack_reserve(&self) -> u64 {
self.ptr.sizeof_stack_reserve()
}
pub fn sizeof_stack_commit(&self) -> u64 {
self.ptr.sizeof_stack_commit()
}
pub fn sizeof_heap_reserve(&self) -> u64 {
self.ptr.sizeof_heap_reserve()
}
pub fn sizeof_heap_commit(&self) -> u64 {
self.ptr.sizeof_heap_commit()
}
pub fn loader_flags(&self) -> u32 {
self.ptr.loader_flags()
}
pub fn numberof_rva_and_size(&self) -> u32 {
self.ptr.numberof_rva_and_size()
}
pub fn set_addressof_entrypoint(&mut self, value: u32) {
self.ptr.pin_mut().set_addressof_entrypoint(value)
}
pub fn set_imagebase(&mut self, value: u64) {
self.ptr.pin_mut().set_imagebase(value)
}
pub fn add_dll_characteristic(&mut self, c: DllCharacteristics) {
self.ptr.pin_mut().add_dll_characteristic(c.bits());
}
pub fn remove_dll_characteristic(&mut self, c: DllCharacteristics) {
self.ptr.pin_mut().remove_dll_characteristic(c.bits());
}
}
impl std::fmt::Debug for OptionalHeader<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("OptionalHeader")
.field("major_linker_version", &self.major_linker_version())
.field("minor_linker_version", &self.minor_linker_version())
.field("sizeof_code", &self.sizeof_code())
.field("sizeof_initialized_data", &self.sizeof_initialized_data())
.field(
"sizeof_uninitialized_data",
&self.sizeof_uninitialized_data(),
)
.field("addressof_entrypoint", &self.addressof_entrypoint())
.field("baseof_code", &self.baseof_code())
.field("baseof_data", &self.baseof_data())
.field("imagebase", &self.imagebase())
.field("section_alignment", &self.section_alignment())
.field("file_alignment", &self.file_alignment())
.field(
"major_operating_system_version",
&self.major_operating_system_version(),
)
.field(
"minor_operating_system_version",
&self.minor_operating_system_version(),
)
.field("major_image_version", &self.major_image_version())
.field("minor_image_version", &self.minor_image_version())
.field("major_subsystem_version", &self.major_subsystem_version())
.field("minor_subsystem_version", &self.minor_subsystem_version())
.field("win32_version_value", &self.win32_version_value())
.field("sizeof_image", &self.sizeof_image())
.field("sizeof_headers", &self.sizeof_headers())
.field("checksum", &self.checksum())
.field("subsystem", &self.subsystem())
.field("dll_characteristics", &self.dll_characteristics())
.field("sizeof_stack_reserve", &self.sizeof_stack_reserve())
.field("sizeof_stack_commit", &self.sizeof_stack_commit())
.field("sizeof_heap_reserve", &self.sizeof_heap_reserve())
.field("sizeof_heap_commit", &self.sizeof_heap_commit())
.field("loader_flags", &self.loader_flags())
.field("numberof_rva_and_size", &self.numberof_rva_and_size())
.finish()
}
}