diff options
Diffstat (limited to 'rust/examples/minidump/src')
| -rw-r--r-- | rust/examples/minidump/src/command.rs | 41 | ||||
| -rw-r--r-- | rust/examples/minidump/src/lib.rs | 38 | ||||
| -rw-r--r-- | rust/examples/minidump/src/view.rs | 402 |
3 files changed, 0 insertions, 481 deletions
diff --git a/rust/examples/minidump/src/command.rs b/rust/examples/minidump/src/command.rs deleted file mode 100644 index d33a8d0b..00000000 --- a/rust/examples/minidump/src/command.rs +++ /dev/null @@ -1,41 +0,0 @@ -use std::str; - -use log::{debug, error, info}; -use minidump::{Minidump, MinidumpMemoryInfoList}; - -use binaryninja::binaryview::{BinaryView, BinaryViewBase, BinaryViewExt}; - -pub fn print_memory_information(bv: &BinaryView) { - debug!("Printing memory information"); - if let Ok(minidump_bv) = bv.parent_view() { - if let Ok(read_buffer) = minidump_bv.read_buffer(0, minidump_bv.len()) { - if let Ok(minidump_obj) = Minidump::read(read_buffer.get_data()) { - if let Ok(memory_info_list) = minidump_obj.get_stream::<MinidumpMemoryInfoList>() { - let mut memory_info_list_writer = Vec::new(); - match memory_info_list.print(&mut memory_info_list_writer) { - Ok(_) => { - if let Ok(memory_info_str) = str::from_utf8(&memory_info_list_writer) { - info!("{memory_info_str}"); - } else { - error!("Could not convert the memory information description from minidump into a valid string"); - } - } - Err(_) => { - error!("Could not get memory information from minidump"); - } - } - } else { - error!( - "Could not parse a valid MinidumpMemoryInfoList stream from the minidump" - ); - } - } else { - error!("Could not parse a valid minidump file from the parent binary view's data buffer"); - } - } else { - error!("Could not read data from parent binary view"); - } - } else { - error!("Could not get the parent binary view"); - } -} diff --git a/rust/examples/minidump/src/lib.rs b/rust/examples/minidump/src/lib.rs deleted file mode 100644 index 62898301..00000000 --- a/rust/examples/minidump/src/lib.rs +++ /dev/null @@ -1,38 +0,0 @@ -use binaryninja::binaryview::BinaryView; -use binaryninja::command::{register, Command}; -use binaryninja::custombinaryview::register_view_type; -use log::{debug, LevelFilter}; -use binaryninja::logger::Logger; - -mod command; -mod view; - -struct PrintMemoryInformationCommand; - -impl Command for PrintMemoryInformationCommand { - fn action(&self, binary_view: &BinaryView) { - command::print_memory_information(binary_view); - } - - fn valid(&self, _binary_view: &BinaryView) -> bool { - true // TODO: Of course, the command will not always be valid! - } -} - -#[no_mangle] -#[allow(non_snake_case)] -pub extern "C" fn CorePluginInit() -> bool { - Logger::new("Minidump").with_level(LevelFilter::Trace).init(); - - debug!("Registering minidump binary view type"); - register_view_type("Minidump", "Minidump", view::MinidumpBinaryViewType::new); - - debug!("Registering minidump plugin commands"); - register( - "Minidump\\[DEBUG] Print Minidump Memory Information", - "Print a human-readable description of the contents of the MinidumpMemoryInfoList stream in the loaded minidump", - PrintMemoryInformationCommand {}, - ); - - true -} diff --git a/rust/examples/minidump/src/view.rs b/rust/examples/minidump/src/view.rs deleted file mode 100644 index ddb18c77..00000000 --- a/rust/examples/minidump/src/view.rs +++ /dev/null @@ -1,402 +0,0 @@ -use std::collections::HashMap; -use std::ops::Range; - -use binaryninja::section::Section; -use binaryninja::segment::Segment; -use log::{debug, error, info, warn}; -use minidump::format::MemoryProtection; -use minidump::{ - Minidump, MinidumpMemory64List, MinidumpMemoryInfoList, MinidumpMemoryList, MinidumpModuleList, - MinidumpStream, MinidumpSystemInfo, Module, -}; - -use binaryninja::binaryview::{BinaryView, BinaryViewBase, BinaryViewExt}; -use binaryninja::custombinaryview::{ - BinaryViewType, BinaryViewTypeBase, CustomBinaryView, CustomBinaryViewType, CustomView, - CustomViewBuilder, -}; -use binaryninja::platform::Platform; -use binaryninja::Endianness; - -type BinaryViewResult<R> = binaryninja::binaryview::Result<R>; - -/// The _Minidump_ binary view type, which the Rust plugin registers with the Binary Ninja core -/// (via `binaryninja::custombinaryview::register_view_type`) as a possible binary view -/// that can be applied to opened binaries. -/// -/// If this view type is valid for an opened binary (determined by `is_valid_for`), -/// the Binary Ninja core then uses this view type to create an actual instance of the _Minidump_ -/// binary view (via `create_custom_view`). -pub struct MinidumpBinaryViewType { - view_type: BinaryViewType, -} - -impl MinidumpBinaryViewType { - pub fn new(view_type: BinaryViewType) -> Self { - MinidumpBinaryViewType { view_type } - } -} - -impl AsRef<BinaryViewType> for MinidumpBinaryViewType { - fn as_ref(&self) -> &BinaryViewType { - &self.view_type - } -} - -impl BinaryViewTypeBase for MinidumpBinaryViewType { - fn is_deprecated(&self) -> bool { - false - } - - fn is_force_loadable(&self) -> bool { - false - } - - fn is_valid_for(&self, data: &BinaryView) -> bool { - let mut magic_number = Vec::<u8>::new(); - data.read_into_vec(&mut magic_number, 0, 4); - - magic_number == b"MDMP" - } -} - -impl CustomBinaryViewType for MinidumpBinaryViewType { - fn create_custom_view<'builder>( - &self, - data: &BinaryView, - builder: CustomViewBuilder<'builder, Self>, - ) -> BinaryViewResult<CustomView<'builder>> { - debug!("Creating MinidumpBinaryView from registered MinidumpBinaryViewType"); - - let binary_view = builder.create::<MinidumpBinaryView>(data, ()); - binary_view - } -} - -#[derive(Debug)] -struct SegmentData { - rva_range: Range<u64>, - mapped_addr_range: Range<u64>, -} - -impl SegmentData { - fn from_addresses_and_size(rva: u64, mapped_addr: u64, size: u64) -> Self { - SegmentData { - rva_range: Range { - start: rva, - end: rva + size, - }, - mapped_addr_range: Range { - start: mapped_addr, - end: mapped_addr + size, - }, - } - } -} - -#[derive(Debug)] -struct SegmentMemoryProtection { - readable: bool, - writable: bool, - executable: bool, -} - -/// An instance of the actual _Minidump_ custom binary view. -/// This contains the main logic to load the memory segments inside a minidump file into the binary view. -pub struct MinidumpBinaryView { - /// The handle to the "real" BinaryView object, in the Binary Ninja core. - inner: binaryninja::rc::Ref<BinaryView>, -} - -impl MinidumpBinaryView { - fn new(view: &BinaryView) -> Self { - MinidumpBinaryView { - inner: view.to_owned(), - } - } - - fn init(&self) -> BinaryViewResult<()> { - let parent_view = self.parent_view()?; - let read_buffer = parent_view.read_buffer(0, parent_view.len())?; - - if let Ok(minidump_obj) = Minidump::read(read_buffer.get_data()) { - // Architecture, platform information - if let Ok(minidump_system_info) = minidump_obj.get_stream::<MinidumpSystemInfo>() { - if let Some(platform) = MinidumpBinaryView::translate_minidump_platform( - minidump_system_info.cpu, - minidump_obj.endian, - minidump_system_info.os, - ) { - self.set_default_platform(&platform); - } else { - error!( - "Could not parse valid system information from minidump: could not map system information in MinidumpSystemInfo stream (arch {:?}, endian {:?}, os {:?}) to a known architecture", - minidump_system_info.cpu, - minidump_obj.endian, - minidump_system_info.os, - ); - return Err(()); - } - } else { - error!("Could not parse system information from minidump: could not find a valid MinidumpSystemInfo stream"); - return Err(()); - } - - // Memory segments - let mut segment_data = Vec::<SegmentData>::new(); - - // Memory segments in a full memory dump (MinidumpMemory64List) - // Grab the shared base RVA for all entries in the MinidumpMemory64List, - // since the minidump crate doesn't expose this to us - if let Ok(raw_stream) = minidump_obj.get_raw_stream(MinidumpMemory64List::STREAM_TYPE) { - if let Ok(base_rva_array) = raw_stream[8..16].try_into() { - let base_rva = u64::from_le_bytes(base_rva_array); - debug!("Found BaseRVA value {:#x}", base_rva); - - if let Ok(minidump_memory_list) = - minidump_obj.get_stream::<MinidumpMemory64List>() - { - let mut current_rva = base_rva; - for memory_segment in minidump_memory_list.iter() { - debug!( - "Found memory segment at RVA {:#x} with virtual address {:#x} and size {:#x}", - current_rva, - memory_segment.base_address, - memory_segment.size, - ); - segment_data.push(SegmentData::from_addresses_and_size( - current_rva, - memory_segment.base_address, - memory_segment.size, - )); - current_rva += memory_segment.size; - } - } - } else { - error!("Could not parse BaseRVA value shared by all entries in the MinidumpMemory64List stream") - } - } else { - warn!("Could not read memory from minidump: could not find a valid MinidumpMemory64List stream. This minidump may not be a full memory dump. Trying to find partial dump memory from a MinidumpMemoryList now..."); - // Memory segments in a regular memory dump (MinidumpMemoryList), - // i.e. one that does not include the full process memory data. - if let Ok(minidump_memory_list) = minidump_obj.get_stream::<MinidumpMemoryList>() { - for memory_segment in minidump_memory_list.by_addr() { - debug!( - "Found memory segment at RVA {:#x} with virtual address {:#x} and size {:#x}", - memory_segment.desc.memory.rva, - memory_segment.base_address, - memory_segment.size - ); - segment_data.push(SegmentData::from_addresses_and_size( - memory_segment.desc.memory.rva as u64, - memory_segment.base_address, - memory_segment.size, - )); - } - } else { - error!("Could not read any memory from minidump: could not find a valid MinidumpMemory64List stream or a valid MinidumpMemoryList stream."); - } - } - - // Memory protection information - let mut segment_protection_data = HashMap::new(); - - if let Ok(minidump_memory_info_list) = - minidump_obj.get_stream::<MinidumpMemoryInfoList>() - { - for memory_info in minidump_memory_info_list.iter() { - if let Some(memory_range) = memory_info.memory_range() { - debug!( - "Found memory protection info for memory segment ranging from virtual address {:#x} to {:#x}: {:#?}", - memory_range.start, - memory_range.end, - memory_info.protection - ); - segment_protection_data.insert( - // The range returned to us by MinidumpMemoryInfoList is an - // end-inclusive range_map::Range; we need to add 1 to - // the end index to make it into an end-exclusive std::ops::Range. - Range { - start: memory_range.start, - end: memory_range.end + 1, - }, - memory_info.protection, - ); - } - } - } - - for segment in segment_data.iter() { - if let Some(segment_protection) = - segment_protection_data.get(&segment.mapped_addr_range) - { - let segment_memory_protection = - MinidumpBinaryView::translate_memory_protection(*segment_protection); - - info!( - "Adding memory segment at virtual address {:#x} to {:#x}, from data range {:#x} to {:#x}, with protections readable {}, writable {}, executable {}", - segment.mapped_addr_range.start, - segment.mapped_addr_range.end, - segment.rva_range.start, - segment.rva_range.end, - segment_memory_protection.readable, - segment_memory_protection.writable, - segment_memory_protection.executable, - ); - - self.add_segment( - Segment::builder(segment.mapped_addr_range.clone()) - .parent_backing(segment.rva_range.clone()) - .is_auto(true) - .readable(segment_memory_protection.readable) - .writable(segment_memory_protection.writable) - .executable(segment_memory_protection.executable), - ); - } else { - error!( - "Could not find memory protection information for memory segment from {:#x} to {:#x}", segment.mapped_addr_range.start, - segment.mapped_addr_range.end, - ); - } - } - - // Module information - // This stretches the concept a bit, but we can add each module as a - // separate "section" of the binary. - // Sections can be named, and can span multiple segments. - if let Ok(minidump_module_list) = minidump_obj.get_stream::<MinidumpModuleList>() { - for module_info in minidump_module_list.by_addr() { - info!( - "Found module with name {} at virtual address {:#x} with size {:#x}", - module_info.name, - module_info.base_address(), - module_info.size(), - ); - let module_address_range = Range { - start: module_info.base_address(), - end: module_info.base_address() + module_info.size(), - }; - self.add_section( - Section::builder(module_info.name.clone(), module_address_range) - .is_auto(true), - ); - } - } else { - warn!("Could not find valid module information in minidump: could not find a valid MinidumpModuleList stream"); - } - } else { - error!("Could not parse data as minidump"); - return Err(()); - } - Ok(()) - } - - fn translate_minidump_platform( - minidump_cpu_arch: minidump::system_info::Cpu, - minidump_endian: minidump::Endian, - minidump_os: minidump::system_info::Os, - ) -> Option<binaryninja::rc::Ref<Platform>> { - match minidump_os { - minidump::system_info::Os::Windows => match minidump_cpu_arch { - minidump::system_info::Cpu::Arm64 => Platform::by_name("windows-aarch64"), - minidump::system_info::Cpu::Arm => Platform::by_name("windows-armv7"), - minidump::system_info::Cpu::X86 => Platform::by_name("windows-x86"), - minidump::system_info::Cpu::X86_64 => Platform::by_name("windows-x86_64"), - _ => None, - }, - minidump::system_info::Os::MacOs => match minidump_cpu_arch { - minidump::system_info::Cpu::Arm64 => Platform::by_name("mac-aarch64"), - minidump::system_info::Cpu::Arm => Platform::by_name("mac-armv7"), - minidump::system_info::Cpu::X86 => Platform::by_name("mac-x86"), - minidump::system_info::Cpu::X86_64 => Platform::by_name("mac-x86_64"), - _ => None, - }, - minidump::system_info::Os::Linux => match minidump_cpu_arch { - minidump::system_info::Cpu::Arm64 => Platform::by_name("linux-aarch64"), - minidump::system_info::Cpu::Arm => Platform::by_name("linux-armv7"), - minidump::system_info::Cpu::X86 => Platform::by_name("linux-x86"), - minidump::system_info::Cpu::X86_64 => Platform::by_name("linux-x86_64"), - minidump::system_info::Cpu::Ppc => match minidump_endian { - minidump::Endian::Little => Platform::by_name("linux-ppc32_le"), - minidump::Endian::Big => Platform::by_name("linux-ppc32"), - }, - minidump::system_info::Cpu::Ppc64 => match minidump_endian { - minidump::Endian::Little => Platform::by_name("linux-ppc64_le"), - minidump::Endian::Big => Platform::by_name("linux-ppc64"), - }, - _ => None, - }, - minidump::system_info::Os::NaCl => None, - minidump::system_info::Os::Android => None, - minidump::system_info::Os::Ios => None, - minidump::system_info::Os::Ps3 => None, - minidump::system_info::Os::Solaris => None, - _ => None, - } - } - - fn translate_memory_protection( - minidump_memory_protection: MemoryProtection, - ) -> SegmentMemoryProtection { - let (readable, writable, executable) = match minidump_memory_protection { - MemoryProtection::PAGE_NOACCESS => (false, false, false), - MemoryProtection::PAGE_READONLY => (true, false, false), - MemoryProtection::PAGE_READWRITE => (true, true, false), - MemoryProtection::PAGE_WRITECOPY => (true, true, false), - MemoryProtection::PAGE_EXECUTE => (false, false, true), - MemoryProtection::PAGE_EXECUTE_READ => (true, false, true), - MemoryProtection::PAGE_EXECUTE_READWRITE => (true, true, true), - MemoryProtection::PAGE_EXECUTE_WRITECOPY => (true, true, true), - MemoryProtection::ACCESS_MASK => (false, false, false), - MemoryProtection::PAGE_GUARD => (false, false, false), - MemoryProtection::PAGE_NOCACHE => (false, false, false), - MemoryProtection::PAGE_WRITECOMBINE => (false, false, false), - _ => (false, false, false), - }; - SegmentMemoryProtection { - readable, - writable, - executable, - } - } -} - -impl AsRef<BinaryView> for MinidumpBinaryView { - fn as_ref(&self) -> &BinaryView { - &self.inner - } -} - -impl BinaryViewBase for MinidumpBinaryView { - // TODO: This should be filled out with the actual address size - // from the platform information in the minidump. - fn address_size(&self) -> usize { - 0 - } - - fn default_endianness(&self) -> Endianness { - // TODO: This should be filled out with the actual endianness - // from the platform information in the minidump. - Endianness::LittleEndian - } - - fn entry_point(&self) -> u64 { - // TODO: We should fill this out with a real entry point. - // This can be done by getting the main module of the minidump - // with MinidumpModuleList::main_module, - // then parsing the PE metadata of the main module to find its entry point(s). - 0 - } -} - -unsafe impl CustomBinaryView for MinidumpBinaryView { - type Args = (); - - fn new(handle: &BinaryView, _args: &Self::Args) -> BinaryViewResult<Self> { - Ok(MinidumpBinaryView::new(handle)) - } - - fn init(&mut self, _args: Self::Args) -> BinaryViewResult<()> { - MinidumpBinaryView::init(self) - } -} |
