Line data Source code
1 : //! Module that wraps the different debug information structure we can find in a PE binary.
2 :
3 : use std::marker::PhantomData;
4 :
5 : use crate::declare_iterator;
6 : use crate::{common::FromFFI, to_slice};
7 : use lief_ffi as ffi;
8 :
9 144 : #[derive(Debug)]
10 : /// This enum exposes the different debug entries that can be
11 : /// found in the debug DataDirectory.
12 : pub enum Entries<'a> {
13 : CodeView(CodeView<'a>),
14 : /// Entry associated with the `IMAGE_DEBUG_TYPE_CODEVIEW`
15 : CodeViewPDB(CodeViewPDB<'a>),
16 : /// Entry associated with `IMAGE_DEBUG_TYPE_REPRO`
17 : Repro(Repro<'a>),
18 : /// Entry associated with `IMAGE_DEBUG_TYPE_POGO`
19 : Pogo(Pogo<'a>),
20 : /// Generic entry for all the other ``IMAGE_DEBUG_xxx`
21 : Generic(Generic<'a>),
22 : }
23 :
24 : #[allow(non_camel_case_types)]
25 144 : #[derive(Debug, Copy, Clone)]
26 : pub enum Type {
27 : COFF,
28 : CODEVIEW,
29 : FPO,
30 : MISC,
31 : EXCEPTION,
32 : FIXUP,
33 : OMAP_TO_SRC,
34 : OMAP_FROM_SRC,
35 : BORLAND,
36 : RESERVED10,
37 : CLSID,
38 : VC_FEATURE,
39 : POGO,
40 : ILTCG,
41 : MPX,
42 : REPRO,
43 : EX_DLLCHARACTERISTICS,
44 : UNKNOWN(u32),
45 : }
46 :
47 : impl From<u32> for Type {
48 144 : fn from(value: u32) -> Self {
49 144 : match value {
50 0 : 0x00000001 => Type::COFF,
51 40 : 0x00000002 => Type::CODEVIEW,
52 0 : 0x00000003 => Type::FPO,
53 0 : 0x00000004 => Type::MISC,
54 0 : 0x00000005 => Type::EXCEPTION,
55 0 : 0x00000006 => Type::FIXUP,
56 0 : 0x00000007 => Type::OMAP_TO_SRC,
57 0 : 0x00000008 => Type::OMAP_FROM_SRC,
58 0 : 0x00000009 => Type::BORLAND,
59 8 : 0x0000000a => Type::RESERVED10,
60 0 : 0x0000000b => Type::CLSID,
61 24 : 0x0000000c => Type::VC_FEATURE,
62 40 : 0x0000000d => Type::POGO,
63 8 : 0x0000000e => Type::ILTCG,
64 0 : 0x0000000f => Type::MPX,
65 16 : 0x00000010 => Type::REPRO,
66 8 : 0x00000014 => Type::EX_DLLCHARACTERISTICS,
67 0 : _ => Type::UNKNOWN(value),
68 : }
69 144 : }
70 : }
71 :
72 : pub trait DebugEntry {
73 : #[doc(hidden)]
74 : fn get_base(&self) -> &ffi::PE_Debug;
75 :
76 : /// Reserved should be 0
77 144 : fn characteristics(&self) -> u32 {
78 144 : self.get_base().characteristics()
79 144 : }
80 :
81 : /// The time and date when the debug data was created.
82 144 : fn timestamp(&self) -> u32 {
83 144 : self.get_base().timestamp()
84 144 : }
85 :
86 : /// The major version number of the debug data format.
87 144 : fn major_version(&self) -> u16 {
88 144 : self.get_base().major_version()
89 144 : }
90 :
91 : /// The minor version number of the debug data format.
92 144 : fn minor_version(&self) -> u16 {
93 144 : self.get_base().minor_version()
94 144 : }
95 :
96 : /// The format of the debugging information
97 144 : fn get_type(&self) -> Type {
98 144 : Type::from(self.get_base().get_type())
99 144 : }
100 :
101 : /// Size of the debug data
102 144 : fn sizeof_data(&self) -> u32 {
103 144 : self.get_base().sizeof_data()
104 144 : }
105 :
106 : /// Address of the debug data relative to the image base
107 144 : fn addressof_rawdata(&self) -> u32 {
108 144 : self.get_base().addressof_rawdata()
109 144 : }
110 :
111 : /// File offset of the debug data
112 144 : fn pointerto_rawdata(&self) -> u32 {
113 144 : self.get_base().pointerto_rawdata()
114 144 : }
115 : }
116 :
117 : impl DebugEntry for Entries<'_> {
118 0 : fn get_base(&self) -> &ffi::PE_Debug {
119 0 : match &self {
120 0 : Entries::CodeView(entry) => {
121 0 : entry.get_base()
122 : }
123 :
124 0 : Entries::CodeViewPDB(entry) => {
125 0 : entry.get_base()
126 : }
127 :
128 0 : Entries::Repro(entry) => {
129 0 : entry.get_base()
130 : }
131 :
132 0 : Entries::Pogo(entry) => {
133 0 : entry.get_base()
134 : }
135 :
136 0 : Entries::Generic(entry) => {
137 0 : entry.get_base()
138 : }
139 : }
140 0 : }
141 : }
142 :
143 : impl std::fmt::Debug for &dyn DebugEntry {
144 144 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145 144 : f.debug_struct("DebugEntry")
146 144 : .field("characteristics", &self.characteristics())
147 144 : .field("timestamp", &self.timestamp())
148 144 : .field("major_version", &self.major_version())
149 144 : .field("minor_version", &self.minor_version())
150 144 : .field("type", &self.get_type())
151 144 : .field("sizeof_data", &self.sizeof_data())
152 144 : .field("addressof_rawdata", &self.addressof_rawdata())
153 144 : .field("pointerto_rawdata", &self.pointerto_rawdata())
154 144 : .finish()
155 144 : }
156 : }
157 :
158 : impl<'a> FromFFI<ffi::PE_Debug> for Entries<'a> {
159 144 : fn from_ffi(ffi_entry: cxx::UniquePtr<ffi::PE_Debug>) -> Self {
160 144 : unsafe {
161 144 : let debug_ref = ffi_entry.as_ref().unwrap();
162 144 : if ffi::PE_Pogo::classof(debug_ref) {
163 40 : let raw = {
164 40 : type From = cxx::UniquePtr<ffi::PE_Debug>;
165 40 : type To = cxx::UniquePtr<ffi::PE_Pogo>;
166 40 : std::mem::transmute::<From, To>(ffi_entry)
167 40 : };
168 40 : Entries::Pogo(Pogo::from_ffi(raw))
169 104 : } else if ffi::PE_CodeViewPDB::classof(debug_ref) {
170 40 : let raw = {
171 40 : type From = cxx::UniquePtr<ffi::PE_Debug>;
172 40 : type To = cxx::UniquePtr<ffi::PE_CodeViewPDB>;
173 40 : std::mem::transmute::<From, To>(ffi_entry)
174 40 : };
175 40 : Entries::CodeViewPDB(CodeViewPDB::from_ffi(raw))
176 64 : } else if ffi::PE_Repro::classof(debug_ref) {
177 16 : let raw = {
178 16 : type From = cxx::UniquePtr<ffi::PE_Debug>;
179 16 : type To = cxx::UniquePtr<ffi::PE_Repro>;
180 16 : std::mem::transmute::<From, To>(ffi_entry)
181 16 : };
182 16 : Entries::Repro(Repro::from_ffi(raw))
183 48 : } else if ffi::PE_CodeView::classof(debug_ref) {
184 0 : let raw = {
185 0 : type From = cxx::UniquePtr<ffi::PE_Debug>;
186 0 : type To = cxx::UniquePtr<ffi::PE_CodeView>;
187 0 : std::mem::transmute::<From, To>(ffi_entry)
188 0 : };
189 0 : Entries::CodeView(CodeView::from_ffi(raw))
190 : } else {
191 48 : Entries::Generic(Generic::from_ffi(ffi_entry))
192 : }
193 : }
194 144 : }
195 : }
196 :
197 : pub struct Generic<'a> {
198 : ptr: cxx::UniquePtr<ffi::PE_Debug>,
199 : _owner: PhantomData<&'a ffi::PE_Binary>,
200 : }
201 :
202 : impl<'a> FromFFI<ffi::PE_Debug> for Generic<'a> {
203 48 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_Debug>) -> Self {
204 48 : Self {
205 48 : ptr,
206 48 : _owner: PhantomData,
207 48 : }
208 48 : }
209 : }
210 :
211 : impl DebugEntry for Generic<'_> {
212 384 : fn get_base(&self) -> &ffi::PE_Debug {
213 384 : self.ptr.as_ref().unwrap()
214 384 : }
215 : }
216 :
217 : impl std::fmt::Debug for Generic<'_> {
218 48 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
219 48 : let base = self as &dyn DebugEntry;
220 48 : f.debug_struct("Generic").field("base", &base).finish()
221 48 : }
222 : }
223 :
224 : /// This structure represents a *Profile Guided Optimization* entry from the
225 : /// debug directory (`IMAGE_DEBUG_TYPE_POGO`).
226 : pub struct Pogo<'a> {
227 : ptr: cxx::UniquePtr<ffi::PE_Pogo>,
228 : _owner: PhantomData<&'a ffi::PE_Binary>,
229 : }
230 :
231 : impl Pogo<'_> {
232 :
233 : /// An iterator over the different POGO elements: [`PogoEntry`]
234 40 : pub fn entries(&self) -> PogoEntries {
235 40 : PogoEntries::new(self.ptr.entries())
236 40 : }
237 : }
238 :
239 : impl<'a> FromFFI<ffi::PE_Pogo> for Pogo<'a> {
240 40 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_Pogo>) -> Self {
241 40 : Self {
242 40 : ptr,
243 40 : _owner: PhantomData,
244 40 : }
245 40 : }
246 : }
247 :
248 : impl DebugEntry for Pogo<'_> {
249 320 : fn get_base(&self) -> &ffi::PE_Debug {
250 320 : self.ptr.as_ref().unwrap().as_ref()
251 320 : }
252 : }
253 :
254 : impl std::fmt::Debug for Pogo<'_> {
255 40 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
256 40 : let base = self as &dyn DebugEntry;
257 40 : f.debug_struct("Pogo").field("base", &base).finish()
258 40 : }
259 : }
260 :
261 : /// Structure which reprents an entry in the [`Pogo`] debug structure
262 : pub struct PogoEntry<'a> {
263 : ptr: cxx::UniquePtr<ffi::PE_PogoEntry>,
264 : _owner: PhantomData<&'a ffi::PE_Pogo>,
265 : }
266 :
267 : impl<'a> FromFFI<ffi::PE_PogoEntry> for PogoEntry<'a> {
268 1736 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_PogoEntry>) -> Self {
269 1736 : Self {
270 1736 : ptr,
271 1736 : _owner: PhantomData,
272 1736 : }
273 1736 : }
274 : }
275 :
276 : impl PogoEntry<'_> {
277 1736 : pub fn start_rva(&self) -> u32 {
278 1736 : self.ptr.start_rva()
279 1736 : }
280 1736 : pub fn size(&self) -> u32 {
281 1736 : self.ptr.size()
282 1736 : }
283 1736 : pub fn name(&self) -> String {
284 1736 : self.ptr.name().to_string()
285 1736 : }
286 : }
287 :
288 : impl std::fmt::Debug for PogoEntry<'_> {
289 1736 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
290 1736 : f.debug_struct("PogoEntry")
291 1736 : .field("name", &self.name())
292 1736 : .field("size", &self.size())
293 1736 : .field("start_rva", &self.start_rva())
294 1736 : .finish()
295 1736 : }
296 : }
297 :
298 : /// Structure that represents the (generic) Debug CodeView (`IMAGE_DEBUG_TYPE_CODEVIEW`).
299 : pub struct CodeView<'a> {
300 : ptr: cxx::UniquePtr<ffi::PE_CodeView>,
301 : _owner: PhantomData<&'a ffi::PE_Binary>,
302 : }
303 :
304 : impl<'a> FromFFI<ffi::PE_CodeView> for CodeView<'a> {
305 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_CodeView>) -> Self {
306 0 : Self {
307 0 : ptr,
308 0 : _owner: PhantomData,
309 0 : }
310 0 : }
311 : }
312 :
313 : impl DebugEntry for CodeView<'_> {
314 0 : fn get_base(&self) -> &ffi::PE_Debug {
315 0 : self.ptr.as_ref().unwrap().as_ref()
316 0 : }
317 : }
318 :
319 : impl std::fmt::Debug for CodeView<'_> {
320 0 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
321 0 : f.debug_struct("CodeView").finish()
322 0 : }
323 : }
324 :
325 : /// CodeView PDB specialization
326 : pub struct CodeViewPDB<'a> {
327 : ptr: cxx::UniquePtr<ffi::PE_CodeViewPDB>,
328 : _owner: PhantomData<&'a ffi::PE_Binary>,
329 : }
330 :
331 : impl<'a> FromFFI<ffi::PE_CodeViewPDB> for CodeViewPDB<'a> {
332 40 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_CodeViewPDB>) -> Self {
333 40 : Self {
334 40 : ptr,
335 40 : _owner: PhantomData,
336 40 : }
337 40 : }
338 : }
339 :
340 : /// CodeView PDB specialization
341 : impl CodeViewPDB<'_> {
342 : /// Age value to verify. The age does not necessarily correspond to any known
343 : /// time value, it is used to determine if a .pdb file is out of sync with a corresponding
344 : /// `.exe` file.
345 40 : pub fn age(&self) -> u32 {
346 40 : self.ptr.age()
347 40 : }
348 :
349 : /// The path to the `.pdb` file
350 40 : pub fn filename(&self) -> String {
351 40 : self.ptr.filename().to_string()
352 40 : }
353 :
354 : /// The GUID signature to verify against the .pdb file signature.
355 : /// This attribute might be used to lookup remote PDB file on a symbol server.
356 0 : pub fn guid(&self) -> String {
357 0 : self.ptr.guid().to_string()
358 0 : }
359 :
360 : /// The 32-bit signature to verify against the .pdb file signature.
361 0 : pub fn signature(&self) -> [u8; 16] {
362 0 : let vector: Vec<u8> = self.ptr.signature().iter().map(|&e| e as u8).collect();
363 0 : vector.try_into().expect("Wrong size")
364 0 : }
365 :
366 : }
367 :
368 : impl DebugEntry for CodeViewPDB<'_> {
369 320 : fn get_base(&self) -> &ffi::PE_Debug {
370 320 : self.ptr.as_ref().unwrap().as_ref().as_ref()
371 320 : }
372 : }
373 :
374 : impl std::fmt::Debug for CodeViewPDB<'_> {
375 40 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
376 40 : let base = self as &dyn DebugEntry;
377 40 : f.debug_struct("CodeViewPDB")
378 40 : .field("base", &base)
379 40 : .field("age", &self.age())
380 40 : .field("filename", &self.filename())
381 40 : .finish()
382 40 : }
383 : }
384 :
385 : /// This structure represents a reproducible build entry from the debug directory
386 : /// (`IMAGE_DEBUG_TYPE_REPRO`)
387 : ///
388 : /// This entry is usually generated with the undocumented `/Brepro` linker flag.
389 : /// See: <https://nikhilism.com/post/2020/windows-deterministic-builds/>
390 : pub struct Repro<'a> {
391 : ptr: cxx::UniquePtr<ffi::PE_Repro>,
392 : _owner: PhantomData<&'a ffi::PE_Binary>,
393 : }
394 :
395 : impl<'a> FromFFI<ffi::PE_Repro> for Repro<'a> {
396 16 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_Repro>) -> Self {
397 16 : Self {
398 16 : ptr,
399 16 : _owner: PhantomData,
400 16 : }
401 16 : }
402 : }
403 :
404 : impl Repro<'_> {
405 : /// The hash associated with the reproducible build
406 16 : pub fn hash(&self) -> &[u8] {
407 16 : to_slice!(self.ptr.hash());
408 16 : }
409 : }
410 :
411 : impl DebugEntry for Repro<'_> {
412 128 : fn get_base(&self) -> &ffi::PE_Debug {
413 128 : self.ptr.as_ref().unwrap().as_ref()
414 128 : }
415 : }
416 :
417 : impl std::fmt::Debug for Repro<'_> {
418 16 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
419 16 : let base = self as &dyn DebugEntry;
420 16 : f.debug_struct("Repro").field("base", &base).finish()
421 16 : }
422 : }
423 :
424 1736 : declare_iterator!(
425 1736 : PogoEntries,
426 1736 : PogoEntry<'a>,
427 1736 : ffi::PE_PogoEntry,
428 1736 : ffi::PE_Pogo,
429 1736 : ffi::PE_Pogo_it_entries
430 1736 : );
|