Skip to main content

xll_utils/
types.rs

1use std::fmt;
2
3/// CPU architecture for PE files.
4///
5/// # Examples
6///
7/// ```
8/// use xll_utils::Architecture;
9///
10/// let arch = Architecture::from_machine_type(0x8664);
11/// assert_eq!(arch, Architecture::X64);
12/// assert!(arch.is_x64());
13/// assert_eq!(arch.to_string(), "x64");
14/// ```
15#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
16#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17pub enum Architecture {
18    X86,
19    X64,
20    Arm,
21    Arm64,
22    Unknown(u16),
23}
24
25impl Architecture {
26    /// Create an `Architecture` from a PE machine type constant.
27    ///
28    /// ```
29    /// use xll_utils::Architecture;
30    ///
31    /// assert_eq!(Architecture::from_machine_type(0x014c), Architecture::X86);
32    /// assert_eq!(Architecture::from_machine_type(0x8664), Architecture::X64);
33    /// assert_eq!(Architecture::from_machine_type(0xaa64), Architecture::Arm64);
34    /// assert_eq!(Architecture::from_machine_type(0x9999), Architecture::Unknown(0x9999));
35    /// ```
36    pub const fn from_machine_type(machine: u16) -> Self {
37        match machine {
38            0x014c => Self::X86,   // IMAGE_FILE_MACHINE_I386
39            0x8664 => Self::X64,   // IMAGE_FILE_MACHINE_AMD64
40            0x01c0 => Self::Arm,   // IMAGE_FILE_MACHINE_ARM
41            0xaa64 => Self::Arm64, // IMAGE_FILE_MACHINE_ARM64
42            other => Self::Unknown(other),
43        }
44    }
45
46    /// Return the PE machine type constant, if known.
47    ///
48    /// ```
49    /// use xll_utils::Architecture;
50    ///
51    /// assert_eq!(Architecture::X64.as_image_file_machine(), Some(0x8664));
52    /// assert_eq!(Architecture::Unknown(0x1234).as_image_file_machine(), None);
53    /// ```
54    pub const fn as_image_file_machine(self) -> Option<u16> {
55        match self {
56            Self::X86 => Some(0x014c),
57            Self::X64 => Some(0x8664),
58            Self::Arm => Some(0x01c0),
59            Self::Arm64 => Some(0xaa64),
60            Self::Unknown(_) => None,
61        }
62    }
63
64    pub const fn is_x86(self) -> bool {
65        matches!(self, Self::X86)
66    }
67    pub const fn is_x64(self) -> bool {
68        matches!(self, Self::X64)
69    }
70    pub const fn is_arm(self) -> bool {
71        matches!(self, Self::Arm | Self::Arm64)
72    }
73}
74
75impl fmt::Display for Architecture {
76    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77        match self {
78            Self::X86 => write!(f, "x86"),
79            Self::X64 => write!(f, "x64"),
80            Self::Arm => write!(f, "ARM"),
81            Self::Arm64 => write!(f, "ARM64"),
82            Self::Unknown(v) => write!(f, "Unknown(0x{v:04x})"),
83        }
84    }
85}
86
87/// Information about a single exported symbol.
88#[derive(Clone, Debug, PartialEq, Eq)]
89#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
90pub struct ExportInfo {
91    /// Export name (if any; may be `None` for ordinal-only exports).
92    pub name: Option<String>,
93    /// Ordinal value (ordinal base + index into the export table).
94    pub ordinal: u32,
95    /// Whether the export is forwarded to another DLL.
96    pub is_forwarded: bool,
97    /// Forward string (e.g., "NTDLL.RtlAllocateHeap") if forwarded.
98    pub forward_to: Option<String>,
99    /// Exported address relative to image base (if available).
100    pub relative_address: Option<u32>,
101}
102
103/// Export directory information from a PE file.
104///
105/// Corresponds to the `IMAGE_EXPORT_DIRECTORY` structure in PE format.
106#[derive(Clone, Debug)]
107#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
108pub struct ExportDirectory {
109    pub characteristics: u32,
110    pub timestamp: u32,
111    pub major_version: u16,
112    pub minor_version: u16,
113    pub name_rva: u32,
114    pub ordinal_base: u32,
115    pub address_table_entries: u32,
116    pub number_of_name_pointers: u32,
117    pub address_table_rva: u32,
118    pub name_pointer_rva: u32,
119    pub ordinal_table_rva: u32,
120}
121
122/// Result of export verification.
123#[derive(Clone, Debug)]
124#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
125pub struct VerificationReport {
126    /// Path to the DLL that was verified.
127    pub dll_path: std::path::PathBuf,
128    /// Total exports found.
129    pub total_exports: usize,
130    /// Required exports that were found.
131    pub found: Vec<String>,
132    /// Required exports that are missing.
133    pub missing: Vec<String>,
134    /// Whether all required exports are present.
135    pub complete: bool,
136    /// Unexpected exports (found but not in expected list).
137    pub unexpected: Vec<String>,
138    /// Exports with name mismatches.
139    pub mismatches: Vec<NameMismatch>,
140    /// Architecture of the DLL.
141    pub architecture: Architecture,
142}
143
144/// Record of an export name mismatch.
145#[derive(Clone, Debug, PartialEq, Eq)]
146#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
147pub struct NameMismatch {
148    /// The expected export name.
149    pub expected: String,
150    /// The actual export name found.
151    pub actual: String,
152    /// Ordinal of the mismatched export.
153    pub ordinal: u32,
154}
155
156/// Summary differences between two export lists.
157#[derive(Clone, Debug, Default)]
158#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
159pub struct ExportDiff {
160    /// Exports present in expected but not in actual.
161    pub missing: Vec<String>,
162    /// Exports present in actual but not in expected.
163    pub extra: Vec<String>,
164    /// Common exports.
165    pub common: Vec<String>,
166}
167
168/// Parsed PE file information.
169#[derive(Clone, Debug)]
170#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
171pub struct PeFile {
172    /// File path.
173    pub path: std::path::PathBuf,
174    /// CPU architecture.
175    pub architecture: Architecture,
176    /// Whether this is a DLL (vs EXE).
177    pub is_dll: bool,
178    /// Image base address.
179    pub image_base: u64,
180    /// Entry point RVA.
181    pub entry_point_rva: u32,
182    /// Export directory (if present).
183    pub export_directory: Option<ExportDirectory>,
184    /// All exports.
185    pub exports: Vec<ExportInfo>,
186}