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 180 : #[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 180 : #[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 180 : fn from(value: u32) -> Self {
49 180 : match value {
50 0 : 0x00000001 => Type::COFF,
51 50 : 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 10 : 0x0000000a => Type::RESERVED10,
60 0 : 0x0000000b => Type::CLSID,
61 30 : 0x0000000c => Type::VC_FEATURE,
62 50 : 0x0000000d => Type::POGO,
63 10 : 0x0000000e => Type::ILTCG,
64 0 : 0x0000000f => Type::MPX,
65 20 : 0x00000010 => Type::REPRO,
66 10 : 0x00000014 => Type::EX_DLLCHARACTERISTICS,
67 0 : _ => Type::UNKNOWN(value),
68 : }
69 180 : }
70 : }
71 :
72 : pub trait DebugEntry {
73 : #[doc(hidden)]
74 : fn get_base(&self) -> &ffi::PE_Debug;
75 :
76 : /// Reserved should be 0
77 180 : fn characteristics(&self) -> u32 {
78 180 : self.get_base().characteristics()
79 180 : }
80 :
81 : /// The time and date when the debug data was created.
82 180 : fn timestamp(&self) -> u32 {
83 180 : self.get_base().timestamp()
84 180 : }
85 :
86 : /// The major version number of the debug data format.
87 180 : fn major_version(&self) -> u16 {
88 180 : self.get_base().major_version()
89 180 : }
90 :
91 : /// The minor version number of the debug data format.
92 180 : fn minor_version(&self) -> u16 {
93 180 : self.get_base().minor_version()
94 180 : }
95 :
96 : /// The format of the debugging information
97 180 : fn get_type(&self) -> Type {
98 180 : Type::from(self.get_base().get_type())
99 180 : }
100 :
101 : /// Size of the debug data
102 180 : fn sizeof_data(&self) -> u32 {
103 180 : self.get_base().sizeof_data()
104 180 : }
105 :
106 : /// Address of the debug data relative to the image base
107 180 : fn addressof_rawdata(&self) -> u32 {
108 180 : self.get_base().addressof_rawdata()
109 180 : }
110 :
111 : /// File offset of the debug data
112 180 : fn pointerto_rawdata(&self) -> u32 {
113 180 : self.get_base().pointerto_rawdata()
114 180 : }
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 180 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145 180 : f.debug_struct("DebugEntry")
146 180 : .field("characteristics", &self.characteristics())
147 180 : .field("timestamp", &self.timestamp())
148 180 : .field("major_version", &self.major_version())
149 180 : .field("minor_version", &self.minor_version())
150 180 : .field("type", &self.get_type())
151 180 : .field("sizeof_data", &self.sizeof_data())
152 180 : .field("addressof_rawdata", &self.addressof_rawdata())
153 180 : .field("pointerto_rawdata", &self.pointerto_rawdata())
154 180 : .finish()
155 180 : }
156 : }
157 :
158 : impl<'a> FromFFI<ffi::PE_Debug> for Entries<'a> {
159 180 : fn from_ffi(ffi_entry: cxx::UniquePtr<ffi::PE_Debug>) -> Self {
160 180 : unsafe {
161 180 : let debug_ref = ffi_entry.as_ref().unwrap();
162 180 : if ffi::PE_Pogo::classof(debug_ref) {
163 50 : let raw = {
164 50 : type From = cxx::UniquePtr<ffi::PE_Debug>;
165 50 : type To = cxx::UniquePtr<ffi::PE_Pogo>;
166 50 : std::mem::transmute::<From, To>(ffi_entry)
167 50 : };
168 50 : Entries::Pogo(Pogo::from_ffi(raw))
169 130 : } else if ffi::PE_CodeViewPDB::classof(debug_ref) {
170 50 : let raw = {
171 50 : type From = cxx::UniquePtr<ffi::PE_Debug>;
172 50 : type To = cxx::UniquePtr<ffi::PE_CodeViewPDB>;
173 50 : std::mem::transmute::<From, To>(ffi_entry)
174 50 : };
175 50 : Entries::CodeViewPDB(CodeViewPDB::from_ffi(raw))
176 80 : } else if ffi::PE_Repro::classof(debug_ref) {
177 20 : let raw = {
178 20 : type From = cxx::UniquePtr<ffi::PE_Debug>;
179 20 : type To = cxx::UniquePtr<ffi::PE_Repro>;
180 20 : std::mem::transmute::<From, To>(ffi_entry)
181 20 : };
182 20 : Entries::Repro(Repro::from_ffi(raw))
183 60 : } 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 60 : Entries::Generic(Generic::from_ffi(ffi_entry))
192 : }
193 : }
194 180 : }
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 60 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_Debug>) -> Self {
204 60 : Self {
205 60 : ptr,
206 60 : _owner: PhantomData,
207 60 : }
208 60 : }
209 : }
210 :
211 : impl DebugEntry for Generic<'_> {
212 480 : fn get_base(&self) -> &ffi::PE_Debug {
213 480 : self.ptr.as_ref().unwrap()
214 480 : }
215 : }
216 :
217 : impl std::fmt::Debug for Generic<'_> {
218 60 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
219 60 : let base = self as &dyn DebugEntry;
220 60 : f.debug_struct("Generic").field("base", &base).finish()
221 60 : }
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 50 : pub fn entries(&self) -> PogoEntries {
235 50 : PogoEntries::new(self.ptr.entries())
236 50 : }
237 : }
238 :
239 : impl<'a> FromFFI<ffi::PE_Pogo> for Pogo<'a> {
240 50 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_Pogo>) -> Self {
241 50 : Self {
242 50 : ptr,
243 50 : _owner: PhantomData,
244 50 : }
245 50 : }
246 : }
247 :
248 : impl DebugEntry for Pogo<'_> {
249 400 : fn get_base(&self) -> &ffi::PE_Debug {
250 400 : self.ptr.as_ref().unwrap().as_ref()
251 400 : }
252 : }
253 :
254 : impl std::fmt::Debug for Pogo<'_> {
255 50 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
256 50 : let base = self as &dyn DebugEntry;
257 50 : f.debug_struct("Pogo").field("base", &base).finish()
258 50 : }
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 2170 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_PogoEntry>) -> Self {
269 2170 : Self {
270 2170 : ptr,
271 2170 : _owner: PhantomData,
272 2170 : }
273 2170 : }
274 : }
275 :
276 : impl PogoEntry<'_> {
277 2170 : pub fn start_rva(&self) -> u32 {
278 2170 : self.ptr.start_rva()
279 2170 : }
280 2170 : pub fn size(&self) -> u32 {
281 2170 : self.ptr.size()
282 2170 : }
283 2170 : pub fn name(&self) -> String {
284 2170 : self.ptr.name().to_string()
285 2170 : }
286 : }
287 :
288 : impl std::fmt::Debug for PogoEntry<'_> {
289 2170 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
290 2170 : f.debug_struct("PogoEntry")
291 2170 : .field("name", &self.name())
292 2170 : .field("size", &self.size())
293 2170 : .field("start_rva", &self.start_rva())
294 2170 : .finish()
295 2170 : }
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 50 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_CodeViewPDB>) -> Self {
333 50 : Self {
334 50 : ptr,
335 50 : _owner: PhantomData,
336 50 : }
337 50 : }
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 50 : pub fn age(&self) -> u32 {
346 50 : self.ptr.age()
347 50 : }
348 :
349 : /// The path to the `.pdb` file
350 50 : pub fn filename(&self) -> String {
351 50 : self.ptr.filename().to_string()
352 50 : }
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 400 : fn get_base(&self) -> &ffi::PE_Debug {
370 400 : self.ptr.as_ref().unwrap().as_ref().as_ref()
371 400 : }
372 : }
373 :
374 : impl std::fmt::Debug for CodeViewPDB<'_> {
375 50 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
376 50 : let base = self as &dyn DebugEntry;
377 50 : f.debug_struct("CodeViewPDB")
378 50 : .field("base", &base)
379 50 : .field("age", &self.age())
380 50 : .field("filename", &self.filename())
381 50 : .finish()
382 50 : }
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 20 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_Repro>) -> Self {
397 20 : Self {
398 20 : ptr,
399 20 : _owner: PhantomData,
400 20 : }
401 20 : }
402 : }
403 :
404 : impl Repro<'_> {
405 : /// The hash associated with the reproducible build
406 20 : pub fn hash(&self) -> &[u8] {
407 20 : to_slice!(self.ptr.hash());
408 20 : }
409 : }
410 :
411 : impl DebugEntry for Repro<'_> {
412 160 : fn get_base(&self) -> &ffi::PE_Debug {
413 160 : self.ptr.as_ref().unwrap().as_ref()
414 160 : }
415 : }
416 :
417 : impl std::fmt::Debug for Repro<'_> {
418 20 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
419 20 : let base = self as &dyn DebugEntry;
420 20 : f.debug_struct("Repro").field("base", &base).finish()
421 20 : }
422 : }
423 :
424 2170 : declare_iterator!(
425 2170 : PogoEntries,
426 2170 : PogoEntry<'a>,
427 2170 : ffi::PE_PogoEntry,
428 2170 : ffi::PE_Pogo,
429 2170 : ffi::PE_Pogo_it_entries
430 2170 : );
|