Line data Source code
1 : use super::load_configuration::AsCHPEMetadata;
2 : use crate::common::FromFFI;
3 : use crate::declare_iterator;
4 : use lief_ffi as ffi;
5 : use std::marker::PhantomData;
6 :
7 : /// This class represents ARM64-specific metadata used in CHPE
8 : /// (Compatible Hybrid PE) binaries, particularly for hybrid architectures like
9 : /// ARM64EC and ARM64X.
10 : ///
11 : /// It provides access to metadata describing code ranges, redirections, entry points, and other
12 : /// hybrid-specific information relevant for binary analysis
13 : pub struct CHPEMetadata<'a> {
14 : ptr: cxx::UniquePtr<ffi::PE_CHPEMetadataARM64>,
15 : _owner: PhantomData<&'a ffi::PE_LoadConfiguration>,
16 : }
17 :
18 : impl<'a> FromFFI<ffi::PE_CHPEMetadataARM64> for CHPEMetadata<'a> {
19 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_CHPEMetadataARM64>) -> Self {
20 0 : Self {
21 0 : ptr,
22 0 : _owner: PhantomData,
23 0 : }
24 0 : }
25 : }
26 :
27 : impl CHPEMetadata<'_> {
28 : /// RVA to the array that describes architecture-specific ranges
29 0 : pub fn code_map(&self) -> u32 {
30 0 : self.ptr.code_map()
31 0 : }
32 :
33 : /// Number of entries in the code map
34 0 : pub fn code_map_count(&self) -> u32 {
35 0 : self.ptr.code_map_count()
36 0 : }
37 :
38 0 : pub fn redirection_metadata(&self) -> u32 {
39 0 : self.ptr.redirection_metadata()
40 0 : }
41 :
42 0 : pub fn os_arm64x_dispatch_call_no_redirect(&self) -> u32 {
43 0 : self.ptr.os_arm64x_dispatch_call_no_redirect()
44 0 : }
45 :
46 0 : pub fn os_arm64x_dispatch_ret(&self) -> u32 {
47 0 : self.ptr.os_arm64x_dispatch_ret()
48 0 : }
49 :
50 0 : pub fn os_arm64x_dispatch_call(&self) -> u32 {
51 0 : self.ptr.os_arm64x_dispatch_call()
52 0 : }
53 :
54 0 : pub fn os_arm64x_dispatch_icall(&self) -> u32 {
55 0 : self.ptr.os_arm64x_dispatch_icall()
56 0 : }
57 :
58 0 : pub fn os_arm64x_dispatch_icall_cfg(&self) -> u32 {
59 0 : self.ptr.os_arm64x_dispatch_icall_cfg()
60 0 : }
61 :
62 0 : pub fn alternate_entry_point(&self) -> u32 {
63 0 : self.ptr.alternate_entry_point()
64 0 : }
65 :
66 0 : pub fn auxiliary_iat(&self) -> u32 {
67 0 : self.ptr.auxiliary_iat()
68 0 : }
69 :
70 0 : pub fn code_ranges_to_entry_points_count(&self) -> u32 {
71 0 : self.ptr.code_ranges_to_entry_points_count()
72 0 : }
73 :
74 0 : pub fn redirection_metadata_count(&self) -> u32 {
75 0 : self.ptr.redirection_metadata_count()
76 0 : }
77 :
78 0 : pub fn get_x64_information_function_pointer(&self) -> u32 {
79 0 : self.ptr.get_x64_information_function_pointer()
80 0 : }
81 :
82 0 : pub fn set_x64_information_function_pointer(&self) -> u32 {
83 0 : self.ptr.set_x64_information_function_pointer()
84 0 : }
85 :
86 : /// RVA to this architecture-specific exception table
87 0 : pub fn extra_rfe_table(&self) -> u32 {
88 0 : self.ptr.extra_rfe_table()
89 0 : }
90 :
91 : /// Architecture-specific exception table size
92 0 : pub fn extra_rfe_table_size(&self) -> u32 {
93 0 : self.ptr.extra_rfe_table_size()
94 0 : }
95 :
96 0 : pub fn auxiliary_iat_copy(&self) -> u32 {
97 0 : self.ptr.auxiliary_iat_copy()
98 0 : }
99 :
100 0 : pub fn auxiliary_delay_import(&self) -> u32 {
101 0 : self.ptr.auxiliary_delay_import()
102 0 : }
103 :
104 0 : pub fn auxiliary_delay_import_copy(&self) -> u32 {
105 0 : self.ptr.auxiliary_delay_import_copy()
106 0 : }
107 :
108 0 : pub fn bitfield_info(&self) -> u32 {
109 0 : self.ptr.bitfield_info()
110 0 : }
111 :
112 0 : pub fn code_ranges(&self) -> CodeRanges {
113 0 : CodeRanges::new(self.ptr.code_ranges())
114 0 : }
115 :
116 0 : pub fn redirections(&self) -> Redirections {
117 0 : Redirections::new(self.ptr.redirections())
118 0 : }
119 :
120 0 : pub fn code_range_entry_point(&self) -> CodeRangeEntrypoints {
121 0 : CodeRangeEntrypoints::new(self.ptr.code_range_entry_point())
122 0 : }
123 : }
124 :
125 : impl AsCHPEMetadata for CHPEMetadata<'_> {
126 0 : fn as_generic(&self) -> &ffi::PE_CHPEMetadata {
127 0 : self.ptr.as_ref().unwrap().as_ref()
128 0 : }
129 : }
130 :
131 : impl std::fmt::Debug for CHPEMetadata<'_> {
132 0 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
133 0 : f.debug_struct("CHPEMetadataARM64")
134 0 : .field("code_map", &self.code_map())
135 0 : .field("code_map_count", &self.code_map_count())
136 0 : .field("redirection_metadata", &self.redirection_metadata())
137 0 : .field(
138 0 : "os_arm64x_dispatch_call_no_redirect",
139 0 : &self.os_arm64x_dispatch_call_no_redirect(),
140 0 : )
141 0 : .field("os_arm64x_dispatch_ret", &self.os_arm64x_dispatch_ret())
142 0 : .field("os_arm64x_dispatch_call", &self.os_arm64x_dispatch_call())
143 0 : .field("os_arm64x_dispatch_icall", &self.os_arm64x_dispatch_icall())
144 0 : .field(
145 0 : "os_arm64x_dispatch_icall_cfg",
146 0 : &self.os_arm64x_dispatch_icall_cfg(),
147 0 : )
148 0 : .field("alternate_entry_point", &self.alternate_entry_point())
149 0 : .field("auxiliary_iat", &self.auxiliary_iat())
150 0 : .field(
151 0 : "code_ranges_to_entry_points_count",
152 0 : &self.code_ranges_to_entry_points_count(),
153 0 : )
154 0 : .field(
155 0 : "redirection_metadata_count",
156 0 : &self.redirection_metadata_count(),
157 0 : )
158 0 : .field(
159 0 : "get_x64_information_function_pointer",
160 0 : &self.get_x64_information_function_pointer(),
161 0 : )
162 0 : .field(
163 0 : "set_x64_information_function_pointer",
164 0 : &self.set_x64_information_function_pointer(),
165 0 : )
166 0 : .field("extra_rfe_table", &self.extra_rfe_table())
167 0 : .field("extra_rfe_table_size", &self.extra_rfe_table_size())
168 0 : .field("auxiliary_iat_copy", &self.auxiliary_iat_copy())
169 0 : .field("auxiliary_delay_import", &self.auxiliary_delay_import())
170 0 : .field(
171 0 : "auxiliary_delay_import_copy",
172 0 : &self.auxiliary_delay_import_copy(),
173 0 : )
174 0 : .field("bitfield_info", &self.bitfield_info())
175 0 : .finish()
176 0 : }
177 : }
178 :
179 : /// Structure that describes architecture-specific ranges
180 : pub struct RangeEntry<'a> {
181 : ptr: cxx::UniquePtr<ffi::PE_CHPEMetadataARM64_range_entry_t>,
182 : _owner: PhantomData<&'a ffi::PE_LoadConfiguration>,
183 : }
184 :
185 : impl<'a> FromFFI<ffi::PE_CHPEMetadataARM64_range_entry_t> for RangeEntry<'a> {
186 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_CHPEMetadataARM64_range_entry_t>) -> Self {
187 0 : Self {
188 0 : ptr,
189 0 : _owner: PhantomData,
190 0 : }
191 0 : }
192 : }
193 :
194 : #[allow(non_camel_case_types)]
195 0 : #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
196 : pub enum RangeType {
197 : /// Pure ARM64 code
198 : ARM64,
199 :
200 : /// ARM64EC hybrid code (compatible with x64)
201 : ARM64EC,
202 :
203 : /// x64 code
204 : AMD64,
205 : UNKNOWN(u32),
206 : }
207 :
208 : impl From<u32> for RangeType {
209 0 : fn from(value: u32) -> Self {
210 0 : match value {
211 0 : 0x000000000 => RangeType::ARM64,
212 0 : 0x000000001 => RangeType::ARM64EC,
213 0 : 0x000000002 => RangeType::AMD64,
214 0 : _ => RangeType::UNKNOWN(value),
215 : }
216 0 : }
217 : }
218 :
219 : impl RangeEntry<'_> {
220 : /// Raw data (include start RVA and type)
221 0 : pub fn start_offset(&self) -> u32 {
222 0 : self.ptr.start_offset()
223 0 : }
224 :
225 : /// Range's length
226 0 : pub fn length(&self) -> u32 {
227 0 : self.ptr.length()
228 0 : }
229 :
230 : /// Start of the range (RVA)
231 0 : pub fn start(&self) -> u32 {
232 0 : self.ptr.start()
233 0 : }
234 :
235 : /// End of the range (RVA)
236 0 : pub fn end(&self) -> u32 {
237 0 : self.ptr.end()
238 0 : }
239 :
240 : /// Architecture for this range
241 0 : pub fn range_type(&self) -> RangeType {
242 0 : RangeType::from(self.ptr.get_type())
243 0 : }
244 : }
245 :
246 : impl std::fmt::Debug for RangeEntry<'_> {
247 0 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
248 0 : f.debug_struct("RangeEntry")
249 0 : .field("start_offset", &self.start_offset())
250 0 : .field("length", &self.length())
251 0 : .field("start", &self.start())
252 0 : .field("end", &self.end())
253 0 : .field("range_type", &self.range_type())
254 0 : .finish()
255 0 : }
256 : }
257 :
258 : /// Structure that describes a redirection
259 : pub struct RedirectionEntry<'a> {
260 : ptr: cxx::UniquePtr<ffi::PE_CHPEMetadataARM64_redirection_entry_t>,
261 : _owner: PhantomData<&'a ffi::PE_LoadConfiguration>,
262 : }
263 :
264 : impl<'a> FromFFI<ffi::PE_CHPEMetadataARM64_redirection_entry_t> for RedirectionEntry<'a> {
265 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_CHPEMetadataARM64_redirection_entry_t>) -> Self {
266 0 : Self {
267 0 : ptr,
268 0 : _owner: PhantomData,
269 0 : }
270 0 : }
271 : }
272 :
273 : impl RedirectionEntry<'_> {
274 0 : pub fn src(&self) -> u32 {
275 0 : self.ptr.src()
276 0 : }
277 :
278 0 : pub fn dst(&self) -> u32 {
279 0 : self.ptr.dst()
280 0 : }
281 : }
282 :
283 : impl std::fmt::Debug for RedirectionEntry<'_> {
284 0 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
285 0 : f.debug_struct("RedirectionEntry")
286 0 : .field("src", &self.src())
287 0 : .field("dst", &self.dst())
288 0 : .finish()
289 0 : }
290 : }
291 :
292 : /// Mirror of `IMAGE_ARM64EC_CODE_RANGE_ENTRY_POINT`:
293 : /// Represents a mapping between code range and its entry point.
294 : pub struct CodeRangeEntrypoint<'a> {
295 : ptr: cxx::UniquePtr<ffi::PE_CHPEMetadataARM64_code_range_entry_point_t>,
296 : _owner: PhantomData<&'a ffi::PE_LoadConfiguration>,
297 : }
298 :
299 : impl<'a> FromFFI<ffi::PE_CHPEMetadataARM64_code_range_entry_point_t> for CodeRangeEntrypoint<'a> {
300 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_CHPEMetadataARM64_code_range_entry_point_t>) -> Self {
301 0 : Self {
302 0 : ptr,
303 0 : _owner: PhantomData,
304 0 : }
305 0 : }
306 : }
307 :
308 : impl CodeRangeEntrypoint<'_> {
309 : /// Start of the code range.
310 0 : pub fn start_rva(&self) -> u32 {
311 0 : self.ptr.start_rva()
312 0 : }
313 :
314 : /// End of the code range (RVA).
315 0 : pub fn end_rva(&self) -> u32 {
316 0 : self.ptr.end_rva()
317 0 : }
318 :
319 : /// RVA of the entry point for this range.
320 0 : pub fn entrypoint(&self) -> u32 {
321 0 : self.ptr.entrypoint()
322 0 : }
323 : }
324 :
325 : impl std::fmt::Debug for CodeRangeEntrypoint<'_> {
326 0 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
327 0 : f.debug_struct("CodeRangeEntrypoint")
328 0 : .field("start_rva", &self.start_rva())
329 0 : .field("end_rva", &self.end_rva())
330 0 : .field("entrypoint", &self.entrypoint())
331 0 : .finish()
332 0 : }
333 : }
334 :
335 :
336 0 : declare_iterator!(
337 0 : CodeRanges,
338 0 : RangeEntry<'a>,
339 0 : ffi::PE_CHPEMetadataARM64_range_entry_t,
340 0 : ffi::PE_CHPEMetadataARM64,
341 0 : ffi::PE_CHPEMetadataARM64_it_const_range_entries
342 0 : );
343 :
344 0 : declare_iterator!(
345 0 : Redirections,
346 0 : RedirectionEntry<'a>,
347 0 : ffi::PE_CHPEMetadataARM64_redirection_entry_t,
348 0 : ffi::PE_CHPEMetadataARM64,
349 0 : ffi::PE_CHPEMetadataARM64_it_const_redirection_entries
350 0 : );
351 :
352 0 : declare_iterator!(
353 0 : CodeRangeEntrypoints,
354 0 : CodeRangeEntrypoint<'a>,
355 0 : ffi::PE_CHPEMetadataARM64_code_range_entry_point_t,
356 0 : ffi::PE_CHPEMetadataARM64,
357 0 : ffi::PE_CHPEMetadataARM64_it_const_code_range_entry_point
358 0 : );
|