feat: 完成后端状态的优化

This commit is contained in:
381848900@qq.com 2024-12-12 14:55:07 +08:00
parent 175189bbdf
commit bfe54cae1f
9 changed files with 164 additions and 233 deletions

View File

@ -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 {

View File

@ -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<String>,
/// 文件Mmap的只读内存映射
mmap: Option<Mmap>,
/// 文件是否是64位
pub is_64_bit: Option<bool>
}
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)
}
}

View File

@ -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<PeNodeTreeData>,
}
// 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<Vec<PeNodeTreeData>, 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<AppState>>,
) -> 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<AppState>>,
) -> Result<Vec<PeNodeTreeData>, 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<Vec<PeNodeTreeData>, 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<ResponseDOSHeaderData, AppError> {
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<AppState>>,
) -> Result<Value, AppError> {
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<ResponseNTHeaderData, AppError> {
let result = get_nt_headers_data()?;
Ok(result)
pub fn command_get_pe_data_nt_header(
app_state: State<'_, Mutex<AppState>>,
) -> Result<Value, AppError> {
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<ResponseFileHeaderData, AppError> {
let result = services::file::get_file_header_data()?;
Ok(result)
pub fn command_get_pe_data_file_header(app_state: State<'_, Mutex<AppState>>) -> Result<Value, AppError> {
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<ResponseOptionalHeaderData, AppError> {
let result = services::file::get_optional_header_data()?;
Ok(result)
pub fn command_get_pe_data_optional_header(app_state: State<'_, Mutex<AppState>>) -> Result<Value, AppError> {
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<ResponseSectionHeaderData, AppError> {
let result = services::file::get_section_header_data()?;
Ok(result)
pub fn command_get_pe_data_section_headers(app_state: State<'_, Mutex<AppState>>) -> Result<Value, AppError> {
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,
}))
}

View File

@ -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");
}

View File

@ -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)]

View File

@ -1,7 +1,7 @@
use super::{error::PEParseError, header::*};
use std::{ops::{Deref, DerefMut}, option};
use std::ops::Deref;
pub trait PE: Deref<Target = [u8]> + DerefMut<Target = [u8]> + Sized {
pub trait ReadOnlyPE: Deref<Target = [u8]> + Sized {
/// Get a reference to a type at a given offset.
fn get_ref<T>(&self, offset: usize) -> Result<&T, PEParseError> {
let len = std::mem::size_of::<T>();
@ -12,16 +12,6 @@ pub trait PE: Deref<Target = [u8]> + DerefMut<Target = [u8]> + Sized {
Ok(unsafe { &*ptr })
}
/// Get a mutable reference to a type at a given offset.
fn get_mut<T>(&mut self, offset: usize) -> Result<&mut T, PEParseError> {
let len = std::mem::size_of::<T>();
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<bool, PEParseError> {
// 先以32位加载可选头通过可选头的Magic字段判断
@ -30,36 +20,27 @@ pub trait PE: Deref<Target = [u8]> + DerefMut<Target = [u8]> + 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::<ImageDosHeader>(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::<ImageDosHeader>(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::<ImageNTHeaders32>(nt_offset)?;
let result = self.get_ref::<ImageNTHeader32>(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::<ImageNTHeaders64>(nt_offset)?;
let result = self.get_ref::<ImageNTHeader64>(nt_offset)?;
Ok(result)
}
fn get_nt_headers(&self) -> Result<ImageNTHeaders, PEParseError> {
fn get_nt_header(&self) -> Result<ImageNTHeader, PEParseError> {
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<Target = [u8]> + DerefMut<Target = [u8]> + 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::<ImageNTHeaders32>(nt_offset)?;
Ok(result)
}
// 获取文件头的偏移
fn get_file_header_offset(&self) -> Result<usize, PEParseError> {
// 1. 获取nt头偏移
@ -93,12 +67,6 @@ pub trait PE: Deref<Target = [u8]> + DerefMut<Target = [u8]> + Sized {
let result = self.get_ref::<ImageFileHeader>(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::<ImageFileHeader>(file_header_offset)?;
Ok(result)
}
// 获取节区数量
fn get_number_of_sections(&self) -> Result<usize, PEParseError> {
@ -147,7 +115,8 @@ pub trait PE: Deref<Target = [u8]> + DerefMut<Target = [u8]> + 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::<ImageFileHeader>() + optional_header_size;
let section_header_offset =
file_header_offset + std::mem::size_of::<ImageFileHeader>() + optional_header_size;
Ok(section_header_offset)
}
@ -159,7 +128,10 @@ pub trait PE: Deref<Target = [u8]> + DerefMut<Target = [u8]> + 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)
}

View File

@ -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<Mmap, std::io::Error> {
let file = std::fs::OpenOptions::new().read(true).open(file_path)?;
unsafe {
MmapOptions::new()
.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<ResponseNTHeaderData, AppError> {
// pub static GLOBAL_FILE_DATA: Mutex<Option<PeData>> = 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<ResponseFileHeaderData, AppError> {
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<ResponseOptionalHeaderData, AppError> {
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<ImageSectionHeader>,
pub base_offset: usize,
}
pub fn get_section_header_data() -> Result<ResponseSectionHeaderData, AppError> {
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)
}

View File

@ -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<String> = None;
// 文件是否是64位
pub static mut GLOBAL_IS_64_BIT: Option<bool> = None;
pub(crate) struct PeData(pub Vec<u8>);
// 实现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<Option<PeData>> = Mutex::new(None);
// 为文件映射实现PE结构
impl ReadOnlyPE for Mmap {}

View File

@ -15,7 +15,7 @@
"label": "main",
"title": "My CFF",
"width": 1000,
"height": 800,
"height": 600,
"visible": false
},
{