diff --git a/src-tauri/src/app_error.rs b/src-tauri/src/app_error.rs index 9519dfe..bad370e 100644 --- a/src-tauri/src/app_error.rs +++ b/src-tauri/src/app_error.rs @@ -1,6 +1,6 @@ use thiserror; -use crate::pe_parse::error::{self, PEParseError}; +use crate::pe_parse::error::PEParseError; #[derive(Debug, thiserror::Error)] pub enum AppError { @@ -11,8 +11,16 @@ pub enum AppError { #[error("文件未打开!")] NoFileOpened, + // 文件没有初始化打开 + #[error("文件未初始化打开!")] + NotInitOpenFile, + #[error(transparent)] PeParseError(#[from] PEParseError), + + /// 初始化打开文件失败 + #[error("初始化打开文件失败!: {0}")] + InitOpenFileFailed(String), } impl serde::Serialize for AppError { diff --git a/src-tauri/src/app_state.rs b/src-tauri/src/app_state.rs new file mode 100644 index 0000000..a3f3d90 --- /dev/null +++ b/src-tauri/src/app_state.rs @@ -0,0 +1,30 @@ +use memmap2::Mmap; +use crate::app_error::AppError; +use crate::{pe_parse::pe::ReadOnlyPE, services::file}; + +/// 应用的状态结构体 +#[derive(Default)] +pub struct AppState { + /// 文件路径 + pub file_path: Option, + /// 文件Mmap的只读内存映射 + mmap: Option, + /// 文件是否是64位 + pub is_64_bit: Option +} + +impl AppState { + /// 初始化打开文件 + pub fn init_open_file(&mut self, file_path: &str) -> Result<(), AppError> { + self.file_path = Some(file_path.to_string()); + self.mmap = Some(file::mmap_mut_file(file_path)?); + // 读取PE格式来判断是否是64位 + let mmap: &Mmap = self.mmap.as_ref().unwrap(); + self.is_64_bit = Some(mmap.is_64_bit()?); + Ok(()) + } + /// 获取文件内存映射 + pub fn get_mmap_ref(&self) -> Result<&Mmap, AppError> { + self.mmap.as_ref().ok_or(AppError::NoFileOpened) + } +} \ No newline at end of file diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index d29dc5e..c60f772 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -1,10 +1,13 @@ +use std::sync::Mutex; + use crate::{ app_error::AppError, - pe_parse::pe::PE, - services::{self, file::*, GLOBAL_FILE_DATA}, + app_state::AppState, + pe_parse::pe::ReadOnlyPE, }; use serde::Serialize; -use tauri::{AppHandle, Manager}; +use serde_json::{json, Value}; +use tauri::{AppHandle, Manager, State}; #[derive(Serialize)] pub struct PeNodeTreeData { @@ -12,7 +15,7 @@ pub struct PeNodeTreeData { key: String, children: Vec, } -// set_complete +/// 设置闪屏的切换 #[tauri::command] pub fn set_complete(app: AppHandle) -> Result<(), AppError> { let splash_window = app.get_webview_window("splashscreen"); @@ -26,18 +29,37 @@ pub fn set_complete(app: AppHandle) -> Result<(), AppError> { Ok(()) } +// 命令,打开文件 #[tauri::command] -pub fn command_get_file_pe_node_tree_data() -> Result, AppError> { - // 1. 如果没有打开文件,则返回错误 - if GLOBAL_FILE_DATA.lock().unwrap().is_none() { - return Err(AppError::NoFileOpened); +pub fn command_open_file( + file_path: &str, + app_state: State<'_, Mutex>, +) -> Result<(), AppError> { + app_state + .lock() + .unwrap() + .init_open_file(file_path) + .map_err(|e| AppError::InitOpenFileFailed(e.to_string()))?; + Ok(()) +} + +#[tauri::command] +pub fn command_get_file_pe_node_tree_data( + app_state: State<'_, Mutex>, +) -> Result, AppError> { + let app_state = app_state.lock().unwrap(); + + // 如果没有打开文件,则返回错误 + if app_state.file_path.is_none() { + return Err(AppError::NotInitOpenFile); } - // 从文件路径中获取文件名 - let file_name: &str = unsafe { - let file_path = services::GLOBAL_FILE_PATH.as_ref().unwrap(); - let file_name = std::path::Path::new(file_path).file_name().unwrap(); - file_name.to_str().unwrap() - }; + let file_path = app_state.file_path.as_ref().unwrap(); + let file_name = std::path::Path::new(file_path) + .file_name() + .unwrap() + .to_str() + .unwrap(); + let result = PeNodeTreeData { title: format!("文件: {}", file_name), key: "file_name".to_string(), @@ -77,65 +99,73 @@ pub fn command_get_file_pe_node_tree_data() -> Result, AppEr Ok(vec![result]) } -// 命令,打开文件 -#[tauri::command] -pub fn command_open_file(file_path: &str) -> Result<(), AppError> { - let mmap = Some(services::file::mmap_mut_file(file_path)?); - // 将内存clone到Vec中 - let mmap = mmap.as_ref().unwrap(); - let mmap = mmap.to_vec(); - *services::GLOBAL_FILE_DATA.lock().unwrap() = Some(services::PeData(mmap)); - unsafe { - services::GLOBAL_FILE_PATH = Some(file_path.to_string()); - } - - // 判断文件是否是64位 - let binding = GLOBAL_FILE_DATA.lock().unwrap(); - let file_data = binding.as_ref().unwrap(); - let is64bit = file_data.is_64_bit()?; - unsafe { - services::GLOBAL_IS_64_BIT = Some(is64bit); - } - Ok(()) -} - // 命令,获取DOS头数据 #[tauri::command] -pub fn command_get_pe_data_dos_header() -> Result { - let binding = GLOBAL_FILE_DATA.lock().unwrap(); - let file_data = binding.as_ref().unwrap(); - let dos_header = file_data.get_dos_header()?; - let result = ResponseDOSHeaderData { - fields: dos_header.clone(), - base_offset: 0, - }; - Ok(result) +pub fn command_get_pe_data_dos_header( + app_state: State<'_, Mutex>, +) -> Result { + let app_state = app_state.lock().unwrap(); + let mmap = app_state.get_mmap_ref()?; + let dos_header = mmap.get_dos_header()?; + Ok(json!({ + "fields": dos_header.clone(), + "base_offset": 0, + })) } // 命令,获取NT头数据 #[tauri::command] -pub fn command_get_pe_data_nt_header() -> Result { - let result = get_nt_headers_data()?; - Ok(result) +pub fn command_get_pe_data_nt_header( + app_state: State<'_, Mutex>, +) -> Result { + let app_state = app_state.lock().unwrap(); + let mmap = app_state.get_mmap_ref()?; + let nt_header: crate::pe_parse::header::ImageNTHeader = mmap.get_nt_header()?; + let nt_offset = mmap.get_nt_headers_offset()?; + Ok(json! ({ + "fields": nt_header, + "base_offset": nt_offset, + })) } // 命令,获取文件头数据 #[tauri::command] -pub fn command_get_pe_data_file_header() -> Result { - let result = services::file::get_file_header_data()?; - Ok(result) +pub fn command_get_pe_data_file_header(app_state: State<'_, Mutex>) -> Result { + let app_state = app_state.lock().unwrap(); + let mmap = app_state.get_mmap_ref()?; + let file_header = mmap.get_file_header()?; + let file_header_offset = mmap.get_file_header_offset()?; + Ok(json!({ + "fields": file_header.clone(), + "base_offset": file_header_offset, + })) } // 命令,获取可选头数据 #[tauri::command] -pub fn command_get_pe_data_optional_header() -> Result { - let result = services::file::get_optional_header_data()?; - Ok(result) +pub fn command_get_pe_data_optional_header(app_state: State<'_, Mutex>) -> Result { + let app_state = app_state.lock().unwrap(); + let mmap = app_state.get_mmap_ref()?; + let optional_header = mmap.get_optional_header()?; + let optional_header_offset = mmap.get_optional_header_offset()?; + let is_64_bit = mmap.is_64_bit()?; + Ok(json!({ + "fields": optional_header.clone(), + "base_offset": optional_header_offset, + "is_64_bit": is_64_bit, + })) } // 命令,获取节区头数据 #[tauri::command] -pub fn command_get_pe_data_section_headers() -> Result { - let result = services::file::get_section_header_data()?; - Ok(result) -} \ No newline at end of file +pub fn command_get_pe_data_section_headers(app_state: State<'_, Mutex>) -> Result { + let app_state = app_state.lock().unwrap(); + let mmap = app_state.get_mmap_ref()?; + let section_headers = mmap.get_section_headers()?; + let section_headers_offset = mmap.get_section_headers_offset()?; + let vec_section_headers = section_headers.to_vec(); + Ok(json!({ + "fields": vec_section_headers, + "base_offset": section_headers_offset, + })) +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index d83f2af..b4879de 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,8 +1,13 @@ +use std::sync::Mutex; + +use tauri::Manager; + // Learn more about Tauri commands at https://tauri.app/develop/calling-rust/ pub mod app_error; pub mod commands; pub mod pe_parse; pub mod services; +pub mod app_state; #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { @@ -19,6 +24,10 @@ pub fn run() { commands::command_get_pe_data_section_headers, commands::set_complete, ]) + .setup(|app| { + app.manage(Mutex::new(app_state::AppState::default())); + Ok(()) + }) .run(tauri::generate_context!()) .expect("error while running tauri application"); } diff --git a/src-tauri/src/pe_parse/header.rs b/src-tauri/src/pe_parse/header.rs index c81d117..a4a9522 100644 --- a/src-tauri/src/pe_parse/header.rs +++ b/src-tauri/src/pe_parse/header.rs @@ -28,7 +28,7 @@ pub struct ImageDosHeader { #[repr(C)] #[derive(Debug, Clone, Copy, Serialize)] -pub struct ImageNTHeaders32 { +pub struct ImageNTHeader32 { pub signature: u32, pub file_header: ImageFileHeader, pub optional_header: ImageOptionalHeader32, @@ -36,7 +36,7 @@ pub struct ImageNTHeaders32 { #[repr(C)] #[derive(Debug, Clone, Copy, Serialize)] -pub struct ImageNTHeaders64 { +pub struct ImageNTHeader64 { pub signature: u32, pub file_header: ImageFileHeader, pub optional_header: ImageOptionalHeader64, @@ -44,9 +44,9 @@ pub struct ImageNTHeaders64 { #[derive(Serialize, Clone, Copy)] #[serde(untagged)] -pub enum ImageNTHeaders{ - NTHeaders32(ImageNTHeaders32), - NTHeaders64(ImageNTHeaders64), +pub enum ImageNTHeader{ + NTHeader32(ImageNTHeader32), + NTHeader64(ImageNTHeader64), } #[repr(C)] diff --git a/src-tauri/src/pe_parse/pe.rs b/src-tauri/src/pe_parse/pe.rs index a88ef3d..d361dcf 100644 --- a/src-tauri/src/pe_parse/pe.rs +++ b/src-tauri/src/pe_parse/pe.rs @@ -1,7 +1,7 @@ use super::{error::PEParseError, header::*}; -use std::{ops::{Deref, DerefMut}, option}; +use std::ops::Deref; -pub trait PE: Deref + DerefMut + Sized { +pub trait ReadOnlyPE: Deref + Sized { /// Get a reference to a type at a given offset. fn get_ref(&self, offset: usize) -> Result<&T, PEParseError> { let len = std::mem::size_of::(); @@ -12,16 +12,6 @@ pub trait PE: Deref + DerefMut + Sized { Ok(unsafe { &*ptr }) } - /// Get a mutable reference to a type at a given offset. - fn get_mut(&mut self, offset: usize) -> Result<&mut T, PEParseError> { - let len = std::mem::size_of::(); - if offset + len > self.len() { - return Err(PEParseError::OutOfBounds); - } - let ptr = self.as_mut_ptr().wrapping_offset(offset as isize) as *mut T; - Ok(unsafe { &mut *ptr }) - } - // 判断是64位还是32位 fn is_64_bit(&self) -> Result { // 先以32位加载可选头,通过可选头的Magic字段判断 @@ -30,36 +20,27 @@ pub trait PE: Deref + DerefMut + Sized { Ok(is_64_bit) } - - /// Get the DOS header without verifying its contents. fn get_dos_header(&self) -> Result<&ImageDosHeader, PEParseError> { let result = self.get_ref::(0)?; Ok(result) } - /// Get the DOS header without mutating its contents. - fn get_dos_header_mut(&mut self) -> Result<&mut ImageDosHeader, PEParseError> { - let result = self.get_mut::(0)?; - Ok(result) - } - - - fn get_nt_headers32(&self) -> Result<&ImageNTHeaders32, PEParseError> { + fn get_nt_header32(&self) -> Result<&ImageNTHeader32, PEParseError> { let nt_offset = self.get_nt_headers_offset()?; - let result = self.get_ref::(nt_offset)?; + let result = self.get_ref::(nt_offset)?; Ok(result) } - fn get_nt_headers64(&self) -> Result<&ImageNTHeaders64, PEParseError> { + fn get_nt_header64(&self) -> Result<&ImageNTHeader64, PEParseError> { let nt_offset = self.get_nt_headers_offset()?; - let result = self.get_ref::(nt_offset)?; + let result = self.get_ref::(nt_offset)?; Ok(result) } - fn get_nt_headers(&self) -> Result { + fn get_nt_header(&self) -> Result { let is_64_bit = self.is_64_bit()?; let result = match is_64_bit { - true => ImageNTHeaders::NTHeaders64(*self.get_nt_headers64()?), - false => ImageNTHeaders::NTHeaders32(*self.get_nt_headers32()?), + true => ImageNTHeader::NTHeader64(*self.get_nt_header64()?), + false => ImageNTHeader::NTHeader32(*self.get_nt_header32()?), }; Ok(result) } @@ -71,13 +52,6 @@ pub trait PE: Deref + DerefMut + Sized { Ok(nt_offset) } - /// Get the NT headers without mutating its contents. - fn get_nt_headers_mut(&mut self) -> Result<&mut ImageNTHeaders32, PEParseError> { - let nt_offset = self.get_nt_headers_offset()?; - let result = self.get_mut::(nt_offset)?; - Ok(result) - } - // 获取文件头的偏移 fn get_file_header_offset(&self) -> Result { // 1. 获取nt头偏移 @@ -93,12 +67,6 @@ pub trait PE: Deref + DerefMut + Sized { let result = self.get_ref::(file_header_offset)?; Ok(result) } - // 获取文件头数据 - fn get_file_header_mut(&mut self) -> Result<&mut ImageFileHeader, PEParseError> { - let file_header_offset = self.get_file_header_offset()?; - let result = self.get_mut::(file_header_offset)?; - Ok(result) - } // 获取节区数量 fn get_number_of_sections(&self) -> Result { @@ -126,7 +94,7 @@ pub trait PE: Deref + DerefMut + Sized { let result = self.get_ref::(optional_header_offset)?; Ok(result) } - + fn get_optional_header(&self) -> Result { let is_64_bit = self.is_64_bit()?; let result = match is_64_bit { @@ -147,7 +115,8 @@ pub trait PE: Deref + DerefMut + Sized { // 节区头偏移在可选头之后,可选头大小是可变的,所以需要计算 let optional_header_size = self.get_size_of_optional_header()?; let file_header_offset = self.get_file_header_offset()?; - let section_header_offset = file_header_offset + std::mem::size_of::() + optional_header_size; + let section_header_offset = + file_header_offset + std::mem::size_of::() + optional_header_size; Ok(section_header_offset) } @@ -159,7 +128,10 @@ pub trait PE: Deref + DerefMut + Sized { let section_header_offset = self.get_section_headers_offset()?; // 3. 获取节区头数据 unsafe { - let ptr = self.as_ptr().wrapping_offset(section_header_offset as isize) as *const ImageSectionHeader; + let ptr = self + .as_ptr() + .wrapping_offset(section_header_offset as isize) + as *const ImageSectionHeader; let result = std::slice::from_raw_parts(ptr, number_of_sections); Ok(result) } diff --git a/src-tauri/src/services/file.rs b/src-tauri/src/services/file.rs index a1d741f..d5c2a5b 100644 --- a/src-tauri/src/services/file.rs +++ b/src-tauri/src/services/file.rs @@ -1,103 +1,11 @@ use memmap2::*; -use serde::Serialize; - -use crate::{app_error::AppError, pe_parse::{header::{ImageDosHeader, ImageFileHeader, ImageNTHeaders, ImageNTHeaders32, ImageOptionalHeader, ImageSectionHeader}, pe::PE}}; - -use super::{GLOBAL_FILE_DATA, GLOBAL_IS_64_BIT}; +/// 以只读的方式创建文件映射 pub fn mmap_mut_file(file_path: &str) -> Result { let file = std::fs::OpenOptions::new().read(true).open(file_path)?; - unsafe { MmapOptions::new() - .map(&file) + .map(&file) .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string())) } } - - -#[derive(Serialize)] -pub struct ResponseDOSHeaderData { - pub fields: ImageDosHeader, - pub base_offset: usize, -} - -#[derive(Serialize)] -pub struct ResponseNTHeaderData { - fields: ImageNTHeaders, - base_offset: usize, -} - -pub fn get_nt_headers_data<'a>() -> Result { - // pub static GLOBAL_FILE_DATA: Mutex> = Mutex::new(None); - let binding = GLOBAL_FILE_DATA.lock().unwrap(); - // `binding` does not live long enough borrowed value does not live long enough - let file_data = binding.as_ref().unwrap(); - let nt_header_enmu= file_data.get_nt_headers()?; - let nt_offset = file_data.get_nt_headers_offset()?; - let result = ResponseNTHeaderData { - fields: nt_header_enmu, - base_offset: nt_offset, - }; - Ok(result) -} - -// 获取文件头数据 -#[derive(Serialize)] -pub struct ResponseFileHeaderData { - pub fields: ImageFileHeader, - pub base_offset: usize, -} - -pub fn get_file_header_data() -> Result { - let binding = GLOBAL_FILE_DATA.lock().unwrap(); - let file_data = binding.as_ref().unwrap(); - let file_header = file_data.get_file_header()?; - let file_header_offset = file_data.get_file_header_offset()?; - let result = ResponseFileHeaderData { - fields: file_header.clone(), - base_offset: file_header_offset, - }; - Ok(result) -} -// 获取可选头数据 -#[derive(Serialize)] -pub struct ResponseOptionalHeaderData { - pub fields: ImageOptionalHeader, - pub base_offset: usize, - pub is_64_bit: bool, -} - -pub fn get_optional_header_data() -> Result { - let binding = GLOBAL_FILE_DATA.lock().unwrap(); - let file_data = binding.as_ref().unwrap(); - let optional_header = file_data.get_optional_header()?; - let optional_header_offset = file_data.get_optional_header_offset()?; - let is_64_bit = file_data.is_64_bit()?; - let result = ResponseOptionalHeaderData { - fields: optional_header.clone(), - base_offset: optional_header_offset, - is_64_bit, - }; - Ok(result) -} - -// 获取节区头数据 -#[derive(Serialize)] -pub struct ResponseSectionHeaderData { - pub fields: Vec, - pub base_offset: usize, -} - -pub fn get_section_header_data() -> Result { - let binding = GLOBAL_FILE_DATA.lock().unwrap(); - let file_data = binding.as_ref().unwrap(); - let section_headers = file_data.get_section_headers()?; - let section_headers_offset = file_data.get_section_headers_offset()?; - let vec_section_headers = section_headers.to_vec(); - let result = ResponseSectionHeaderData { - fields: vec_section_headers, - base_offset: section_headers_offset, - }; - Ok(result) -} \ No newline at end of file diff --git a/src-tauri/src/services/mod.rs b/src-tauri/src/services/mod.rs index 0fb8b78..735c4a2 100644 --- a/src-tauri/src/services/mod.rs +++ b/src-tauri/src/services/mod.rs @@ -1,32 +1,6 @@ -use memmap2::{Mmap, MmapMut}; -use std::{ - ops::{Deref, DerefMut}, - sync::Mutex, -}; - -use crate::pe_parse::pe::PE; +use memmap2::Mmap; +use crate::pe_parse::pe::ReadOnlyPE; pub mod file; -// 全局文件路径 -pub static mut GLOBAL_FILE_PATH: Option = None; -// 文件是否是64位 -pub static mut GLOBAL_IS_64_BIT: Option = None; - -pub(crate) struct PeData(pub Vec); -// 实现Deref -impl Deref for PeData { - type Target = [u8]; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -// 实现DerefMut -impl DerefMut for PeData { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} -impl PE for PeData {} -// 文件的内存映射clone -pub static GLOBAL_FILE_DATA: Mutex> = Mutex::new(None); +// 为文件映射实现PE结构 +impl ReadOnlyPE for Mmap {} diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 9652d86..dac76fa 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -15,7 +15,7 @@ "label": "main", "title": "My CFF", "width": 1000, - "height": 800, + "height": 600, "visible": false }, {