1 use scroll::{Pread, Pwrite, SizeWith}; 2 use crate::error; 3 4 use crate::pe::section_table; 5 use crate::pe::utils; 6 use crate::pe::data_directories; 7 8 #[derive(Debug, PartialEq, Copy, Clone, Default)] 9 pub struct DebugData<'a> { 10 pub image_debug_directory: ImageDebugDirectory, 11 pub codeview_pdb70_debug_info: Option<CodeviewPDB70DebugInfo<'a>>, 12 } 13 14 impl<'a> DebugData<'a> { parse(bytes: &'a [u8], dd: data_directories::DataDirectory, sections: &[section_table::SectionTable], file_alignment: u32) -> error::Result<Self>15 pub fn parse(bytes: &'a [u8], dd: data_directories::DataDirectory, sections: &[section_table::SectionTable], file_alignment: u32) -> error::Result<Self> { 16 let image_debug_directory = ImageDebugDirectory::parse(bytes, dd, sections, file_alignment)?; 17 let codeview_pdb70_debug_info = CodeviewPDB70DebugInfo::parse(bytes, &image_debug_directory)?; 18 19 Ok(DebugData{ 20 image_debug_directory, 21 codeview_pdb70_debug_info 22 }) 23 } 24 25 /// Return this executable's debugging GUID, suitable for matching against a PDB file. guid(&self) -> Option<[u8; 16]>26 pub fn guid(&self) -> Option<[u8; 16]> { 27 self.codeview_pdb70_debug_info 28 .map(|pdb70| pdb70.signature) 29 } 30 } 31 32 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680307(v=vs.85).aspx 33 #[repr(C)] 34 #[derive(Debug, PartialEq, Copy, Clone, Default)] 35 #[derive(Pread, Pwrite, SizeWith)] 36 pub struct ImageDebugDirectory { 37 pub characteristics: u32, 38 pub time_date_stamp: u32, 39 pub major_version: u16, 40 pub minor_version: u16, 41 pub data_type: u32, 42 pub size_of_data: u32, 43 pub address_of_raw_data: u32, 44 pub pointer_to_raw_data: u32, 45 } 46 47 pub const IMAGE_DEBUG_TYPE_UNKNOWN: u32 = 0; 48 pub const IMAGE_DEBUG_TYPE_COFF: u32 = 1; 49 pub const IMAGE_DEBUG_TYPE_CODEVIEW: u32 = 2; 50 pub const IMAGE_DEBUG_TYPE_FPO: u32 = 3; 51 pub const IMAGE_DEBUG_TYPE_MISC: u32 = 4; 52 pub const IMAGE_DEBUG_TYPE_EXCEPTION: u32 = 5; 53 pub const IMAGE_DEBUG_TYPE_FIXUP: u32 = 6; 54 pub const IMAGE_DEBUG_TYPE_BORLAND: u32 = 9; 55 56 impl ImageDebugDirectory { parse(bytes: &[u8], dd: data_directories::DataDirectory, sections: &[section_table::SectionTable], file_alignment: u32) -> error::Result<Self>57 fn parse(bytes: &[u8], dd: data_directories::DataDirectory, sections: &[section_table::SectionTable], file_alignment: u32) -> error::Result<Self> { 58 let rva = dd.virtual_address as usize; 59 let offset = utils::find_offset(rva, sections, file_alignment).ok_or_else(|| error::Error::Malformed(format!("Cannot map ImageDebugDirectory rva {:#x} into offset", rva)))?;; 60 let idd: Self = bytes.pread_with(offset, scroll::LE)?; 61 Ok (idd) 62 } 63 } 64 65 pub const CODEVIEW_PDB70_MAGIC: u32 = 0x5344_5352; 66 pub const CODEVIEW_PDB20_MAGIC: u32 = 0x3031_424e; 67 pub const CODEVIEW_CV50_MAGIC: u32 = 0x3131_424e; 68 pub const CODEVIEW_CV41_MAGIC: u32 = 0x3930_424e; 69 70 // http://llvm.org/doxygen/CVDebugRecord_8h_source.html 71 #[repr(C)] 72 #[derive(Debug, PartialEq, Copy, Clone, Default)] 73 pub struct CodeviewPDB70DebugInfo<'a> { 74 pub codeview_signature: u32, 75 pub signature: [u8; 16], 76 pub age: u32, 77 pub filename: &'a [u8], 78 } 79 80 impl<'a> CodeviewPDB70DebugInfo<'a> { parse(bytes: &'a [u8], idd: &ImageDebugDirectory) -> error::Result<Option<Self>>81 pub fn parse(bytes: &'a [u8], idd: &ImageDebugDirectory) -> error::Result<Option<Self>> { 82 if idd.data_type != IMAGE_DEBUG_TYPE_CODEVIEW { 83 // not a codeview debug directory 84 // that's not an error, but it's not a CodeviewPDB70DebugInfo either 85 return Ok(None); 86 } 87 88 // ImageDebugDirectory.pointer_to_raw_data stores a raw offset -- not a virtual offset -- which we can use directly 89 let mut offset: usize = idd.pointer_to_raw_data as usize; 90 91 // calculate how long the eventual filename will be, which doubles as a check of the record size 92 let filename_length = idd.size_of_data as isize - 24; 93 if filename_length < 0 || filename_length > 1024 { 94 // the record is too short or too long to be plausible 95 return Err(error::Error::Malformed(format!("ImageDebugDirectory size of data seems wrong: {:?}", idd.size_of_data))); 96 } 97 let filename_length = filename_length as usize; 98 99 // check the codeview signature 100 let codeview_signature: u32 = bytes.gread_with(&mut offset, scroll::LE)?; 101 if codeview_signature != CODEVIEW_PDB70_MAGIC { 102 return Ok(None); 103 } 104 105 // read the rest 106 let mut signature: [u8; 16] = [0; 16]; 107 signature.copy_from_slice(bytes.gread_with(&mut offset, 16)?); 108 let age: u32 = bytes.gread_with(&mut offset, scroll::LE)?; 109 let filename = &bytes[offset..offset + filename_length]; 110 111 Ok(Some(CodeviewPDB70DebugInfo{ 112 codeview_signature, 113 signature, 114 age, 115 filename, 116 })) 117 } 118 } 119