feat: 添加前后端交互的示例代码
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
use thiserror;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum AppError {
|
||||
#[error(transparent)]
|
||||
Io(#[from] std::io::Error),
|
||||
|
||||
// 未打开文件映射
|
||||
#[error("文件未打开!")]
|
||||
NoFileOpened,
|
||||
}
|
||||
|
||||
impl serde::Serialize for AppError {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::ser::Serializer,
|
||||
{
|
||||
serializer.serialize_str(self.to_string().as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,74 @@
|
||||
use thiserror;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
enum AppError {
|
||||
#[error(transparent)]
|
||||
Io(#[from] std::io::Error),
|
||||
use crate::{app_error::AppError, services};
|
||||
use serde::Serialize;
|
||||
#[tauri::command]
|
||||
pub fn greet(name: &str) -> String {
|
||||
format!("Hello, {}! You've been greeted from Rust!", name)
|
||||
}
|
||||
#[derive(Serialize)]
|
||||
pub struct PeNodeTreeData {
|
||||
title: String,
|
||||
key: String,
|
||||
children: Vec<PeNodeTreeData>,
|
||||
}
|
||||
|
||||
impl serde::Serialize for AppError {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::ser::Serializer,
|
||||
{
|
||||
serializer.serialize_str(self.to_string().as_ref())
|
||||
// TODO: 获取PE节点树的JSON数据
|
||||
#[tauri::command]
|
||||
pub fn command_get_file_pe_node_tree_data() -> Result<Vec<PeNodeTreeData>, AppError> {
|
||||
// 1. 如果全局内存映射句柄为空,则返回错误
|
||||
if unsafe { services::GLOBAL_MEMMAP_HANDLE.is_none() } {
|
||||
return Err(AppError::NoFileOpened);
|
||||
}
|
||||
// 从文件路径中获取文件名
|
||||
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 result = PeNodeTreeData {
|
||||
title: format!("文件: {}", file_name),
|
||||
key: "fileName".to_string(),
|
||||
children: vec![
|
||||
PeNodeTreeData {
|
||||
title: "DOS 头部".to_string(),
|
||||
key: "DOS Header".to_string(),
|
||||
children: vec![], // 空数组表示没有子节点
|
||||
},
|
||||
PeNodeTreeData {
|
||||
title: "NT 头部".to_string(),
|
||||
key: "NT Headers".to_string(),
|
||||
children: vec![
|
||||
PeNodeTreeData {
|
||||
title: "文件头部".to_string(),
|
||||
key: "File Header".to_string(),
|
||||
children: vec![],
|
||||
},
|
||||
PeNodeTreeData {
|
||||
title: "可选头部".to_string(),
|
||||
key: "Optional Header".to_string(),
|
||||
children: vec![PeNodeTreeData {
|
||||
title: "数据目录".to_string(),
|
||||
key: "Data Directories".to_string(),
|
||||
children: vec![],
|
||||
}],
|
||||
},
|
||||
],
|
||||
},
|
||||
PeNodeTreeData {
|
||||
title: "节区头部".to_string(),
|
||||
key: "Section Headers".to_string(),
|
||||
children: vec![],
|
||||
},
|
||||
],
|
||||
};
|
||||
Ok(vec![result])
|
||||
}
|
||||
|
||||
// 命令,打开文件
|
||||
#[tauri::command]
|
||||
pub fn command_open_file(file_path: &str) -> Result<(), AppError> {
|
||||
unsafe {
|
||||
services::GLOBAL_MEMMAP_HANDLE = Some(services::file::mmap_mut_file(file_path)?);
|
||||
services::GLOBAL_FILE_PATH = Some(file_path.to_string());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
|
||||
#[tauri::command]
|
||||
fn greet(name: &str) -> String {
|
||||
format!("Hello, {}! You've been greeted from Rust!", name)
|
||||
}
|
||||
pub mod app_error;
|
||||
pub mod commands;
|
||||
pub mod pe_parse;
|
||||
pub mod services;
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
tauri::Builder::default()
|
||||
.plugin(tauri_plugin_shell::init())
|
||||
.invoke_handler(tauri::generate_handler![greet])
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
commands::command_open_file,
|
||||
commands::command_get_file_pe_node_tree_data
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
mod commands;
|
||||
mod app_error;
|
||||
|
||||
fn main() {
|
||||
test_tauri_lib::run()
|
||||
|
||||
15
src-tauri/src/pe_parse/error.rs
Normal file
15
src-tauri/src/pe_parse/error.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum PEParseError {
|
||||
#[error("无效的DOSMagic值")]
|
||||
InvalidDOSMagic,
|
||||
#[error("Invalid NT header signature")]
|
||||
InvalidNTSignature,
|
||||
#[error("Invalid optional header magic number")]
|
||||
InvalidOptionalMagic,
|
||||
#[error("Invalid optional header size")]
|
||||
InvalidOptionalSize,
|
||||
#[error("解析超出了文件范围")]
|
||||
OutOfBounds
|
||||
}
|
||||
113
src-tauri/src/pe_parse/header.rs
Normal file
113
src-tauri/src/pe_parse/header.rs
Normal file
@@ -0,0 +1,113 @@
|
||||
use super::types::*;
|
||||
use bitflags::bitflags;
|
||||
#[repr(C)]
|
||||
pub struct ImageDosHeader {
|
||||
pub e_magic: u16, // Magic number 固定值 0x5A4D
|
||||
pub e_cblp: u16,
|
||||
pub e_cp: u16,
|
||||
pub e_crlc: u16,
|
||||
pub e_cparhdr: u16,
|
||||
pub e_minalloc: u16,
|
||||
pub e_maxalloc: u16,
|
||||
pub e_ss: u16,
|
||||
pub e_sp: u16,
|
||||
pub e_csum: u16,
|
||||
pub e_ip: u16,
|
||||
pub e_cs: u16,
|
||||
pub e_lfarlc: u16,
|
||||
pub e_ovno: u16,
|
||||
pub e_res: [u16; 4],
|
||||
pub e_oemid: u16,
|
||||
pub e_oeminfo: u16,
|
||||
pub e_res2: [u16; 10],
|
||||
pub e_lfanew: Offset, // File address of new exe header nt头的偏移
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ImageNTHeaders32 {
|
||||
pub signature: u32,
|
||||
pub file_header: ImageFileHeader,
|
||||
pub optional_header: ImageOptionalHeader32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ImageFileHeader {
|
||||
pub machine: u16,
|
||||
pub number_of_sections: u16,
|
||||
pub time_date_stamp: u32,
|
||||
pub pointer_to_symbol_table: Offset,
|
||||
pub number_of_symbols: u32,
|
||||
pub size_of_optional_header: u16,
|
||||
pub characteristics: FileCharacteristics,
|
||||
}
|
||||
bitflags! {
|
||||
#[repr(C)]
|
||||
pub struct FileCharacteristics: u16 {
|
||||
const RELOCS_STRIPPED = 0x0001;
|
||||
const EXECUTABLE_IMAGE = 0x0002;
|
||||
const LINE_NUMS_STRIPPED = 0x0004;
|
||||
const LOCAL_SYMS_STRIPPED = 0x0008;
|
||||
const AGGRESSIVE_WS_TRIM = 0x0010;
|
||||
const LARGE_ADDRESS_AWARE = 0x0020;
|
||||
const BYTES_REVERSED_LO = 0x0080;
|
||||
const MACHINE_32BIT = 0x0100;
|
||||
const DEBUG_STRIPPED = 0x0200;
|
||||
const REMOVABLE_RUN_FROM_SWAP = 0x0400;
|
||||
const NET_RUN_FROM_SWAP = 0x0800;
|
||||
const SYSTEM = 0x1000;
|
||||
const DLL = 0x2000;
|
||||
const UP_SYSTEM_ONLY = 0x4000;
|
||||
const BYTES_REVERSED_HI = 0x8000;
|
||||
}
|
||||
#[repr(C)]
|
||||
pub struct DLLCharacteristics: u16 {
|
||||
const RESERVED1 = 0x0001;
|
||||
const RESERVED2 = 0x0002;
|
||||
const RESERVED4 = 0x0004;
|
||||
const RESERVED8 = 0x0008;
|
||||
const HIGH_ENTROPY_VA = 0x0020;
|
||||
const DYNAMIC_BASE = 0x0040;
|
||||
const FORCE_INTEGRITY = 0x0080;
|
||||
const NX_COMPAT = 0x0100;
|
||||
const NO_ISOLATION = 0x0200;
|
||||
const NO_SEH = 0x0400;
|
||||
const NO_BIND = 0x0800;
|
||||
const APPCONTAINER = 0x1000;
|
||||
const WDM_DRIVER = 0x2000;
|
||||
const GUARD_CF = 0x4000;
|
||||
const TERMINAL_SERVER_AWARE = 0x8000;
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
pub struct ImageOptionalHeader32 {
|
||||
pub magic: u16,
|
||||
pub major_linker_version: u8,
|
||||
pub minor_linker_version: u8,
|
||||
pub size_of_code: u32,
|
||||
pub size_of_initialized_data: u32,
|
||||
pub size_of_uninitialized_data: u32,
|
||||
pub address_of_entry_point: RVA,
|
||||
pub base_of_code: RVA,
|
||||
pub base_of_data: RVA,
|
||||
pub image_base: u32,
|
||||
pub section_alignment: u32,
|
||||
pub file_alignment: u32,
|
||||
pub major_operating_system_version: u16,
|
||||
pub minor_operating_system_version: u16,
|
||||
pub major_image_version: u16,
|
||||
pub minor_image_version: u16,
|
||||
pub major_subsystem_version: u16,
|
||||
pub minor_subsystem_version: u16,
|
||||
pub win32_version_value: u32,
|
||||
pub size_of_image: u32,
|
||||
pub size_of_headers: u32,
|
||||
pub checksum: u32,
|
||||
pub subsystem: u16,
|
||||
pub dll_characteristics: DLLCharacteristics,
|
||||
pub size_of_stack_reserve: u32,
|
||||
pub size_of_stack_commit: u32,
|
||||
pub size_of_heap_reserve: u32,
|
||||
pub size_of_heap_commit: u32,
|
||||
pub loader_flags: u32,
|
||||
pub number_of_rva_and_sizes: u32,
|
||||
}
|
||||
4
src-tauri/src/pe_parse/mod.rs
Normal file
4
src-tauri/src/pe_parse/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
pub mod header;
|
||||
pub mod types;
|
||||
pub mod pe;
|
||||
pub mod error;
|
||||
35
src-tauri/src/pe_parse/pe.rs
Normal file
35
src-tauri/src/pe_parse/pe.rs
Normal file
@@ -0,0 +1,35 @@
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use super::{error::PEParseError, header::*};
|
||||
|
||||
pub trait PE: Deref<Target = [u8]> + DerefMut<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>();
|
||||
if offset + len > self.len() {
|
||||
return Err(PEParseError::OutOfBounds);
|
||||
}
|
||||
let ptr = self.as_ptr().wrapping_offset(offset as isize) as *const T;
|
||||
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 })
|
||||
}
|
||||
|
||||
/// 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)
|
||||
}
|
||||
}
|
||||
4
src-tauri/src/pe_parse/types.rs
Normal file
4
src-tauri/src/pe_parse/types.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
#[repr(C)]
|
||||
pub struct Offset(pub u32);
|
||||
|
||||
pub struct RVA(pub u32);
|
||||
15
src-tauri/src/services/file.rs
Normal file
15
src-tauri/src/services/file.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
use memmap::*;
|
||||
|
||||
// TODO: 打开文件,并将文件映射到内存
|
||||
pub fn mmap_mut_file(file_path: &str) -> Result<MmapMut, std::io::Error> {
|
||||
let file = std::fs::OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.open(file_path)?;
|
||||
|
||||
unsafe {
|
||||
MmapOptions::new()
|
||||
.map_mut(&file)
|
||||
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))
|
||||
}
|
||||
}
|
||||
9
src-tauri/src/services/mod.rs
Normal file
9
src-tauri/src/services/mod.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
use memmap::MmapMut;
|
||||
|
||||
pub mod file;
|
||||
|
||||
// 映射到内存的文件句柄
|
||||
pub static mut GLOBAL_MEMMAP_HANDLE: Option<MmapMut> = None;
|
||||
|
||||
// 全局文件路径
|
||||
pub static mut GLOBAL_FILE_PATH: Option<String> = None;
|
||||
Reference in New Issue
Block a user