feat: 添加dump进程功能

This commit is contained in:
381848900@qq.com 2024-12-17 20:14:38 +08:00
parent 8835ca5f26
commit 253cfcd399
7 changed files with 400 additions and 49 deletions

151
src-tauri/Cargo.lock generated
View File

@ -520,6 +520,25 @@ dependencies = [
"crossbeam-utils", "crossbeam-utils",
] ]
[[package]]
name = "crossbeam-deque"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
dependencies = [
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
dependencies = [
"crossbeam-utils",
]
[[package]] [[package]]
name = "crossbeam-utils" name = "crossbeam-utils"
version = "0.8.20" version = "0.8.20"
@ -753,6 +772,12 @@ version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125"
[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]] [[package]]
name = "embed-resource" name = "embed-resource"
version = "2.5.1" version = "2.5.1"
@ -864,11 +889,13 @@ dependencies = [
"memmap2", "memmap2",
"serde", "serde",
"serde_json", "serde_json",
"sysinfo",
"tauri", "tauri",
"tauri-build", "tauri-build",
"tauri-plugin-dialog", "tauri-plugin-dialog",
"tauri-plugin-shell", "tauri-plugin-shell",
"thiserror 2.0.4", "thiserror 2.0.4",
"windows 0.58.0",
] ]
[[package]] [[package]]
@ -2047,6 +2074,15 @@ version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
[[package]]
name = "ntapi"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "num-conv" name = "num-conv"
version = "0.1.0" version = "0.1.0"
@ -2809,6 +2845,26 @@ version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539"
[[package]]
name = "rayon"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
dependencies = [
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
dependencies = [
"crossbeam-deque",
"crossbeam-utils",
]
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.5.7" version = "0.5.7"
@ -3395,6 +3451,20 @@ dependencies = [
"syn 2.0.90", "syn 2.0.90",
] ]
[[package]]
name = "sysinfo"
version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "948512566b1895f93b1592c7574baeb2de842f224f2aab158799ecadb8ebbb46"
dependencies = [
"core-foundation-sys",
"libc",
"memchr",
"ntapi",
"rayon",
"windows 0.57.0",
]
[[package]] [[package]]
name = "system-deps" name = "system-deps"
version = "6.2.2" version = "6.2.2"
@ -3441,7 +3511,7 @@ dependencies = [
"tao-macros", "tao-macros",
"unicode-segmentation", "unicode-segmentation",
"url", "url",
"windows", "windows 0.58.0",
"windows-core 0.58.0", "windows-core 0.58.0",
"windows-version", "windows-version",
"x11-dl", "x11-dl",
@ -3511,7 +3581,7 @@ dependencies = [
"webkit2gtk", "webkit2gtk",
"webview2-com", "webview2-com",
"window-vibrancy", "window-vibrancy",
"windows", "windows 0.58.0",
] ]
[[package]] [[package]]
@ -3672,7 +3742,7 @@ dependencies = [
"tauri-utils", "tauri-utils",
"thiserror 2.0.4", "thiserror 2.0.4",
"url", "url",
"windows", "windows 0.58.0",
] ]
[[package]] [[package]]
@ -3697,7 +3767,7 @@ dependencies = [
"url", "url",
"webkit2gtk", "webkit2gtk",
"webview2-com", "webview2-com",
"windows", "windows 0.58.0",
"wry", "wry",
] ]
@ -4416,10 +4486,10 @@ checksum = "6f61ff3d9d0ee4efcb461b14eb3acfda2702d10dc329f339303fc3e57215ae2c"
dependencies = [ dependencies = [
"webview2-com-macros", "webview2-com-macros",
"webview2-com-sys", "webview2-com-sys",
"windows", "windows 0.58.0",
"windows-core 0.58.0", "windows-core 0.58.0",
"windows-implement", "windows-implement 0.58.0",
"windows-interface", "windows-interface 0.58.0",
] ]
[[package]] [[package]]
@ -4440,7 +4510,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3a3e2eeb58f82361c93f9777014668eb3d07e7d174ee4c819575a9208011886" checksum = "a3a3e2eeb58f82361c93f9777014668eb3d07e7d174ee4c819575a9208011886"
dependencies = [ dependencies = [
"thiserror 1.0.69", "thiserror 1.0.69",
"windows", "windows 0.58.0",
"windows-core 0.58.0", "windows-core 0.58.0",
] ]
@ -4489,6 +4559,16 @@ dependencies = [
"windows-version", "windows-version",
] ]
[[package]]
name = "windows"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143"
dependencies = [
"windows-core 0.57.0",
"windows-targets 0.52.6",
]
[[package]] [[package]]
name = "windows" name = "windows"
version = "0.58.0" version = "0.58.0"
@ -4508,19 +4588,42 @@ dependencies = [
"windows-targets 0.52.6", "windows-targets 0.52.6",
] ]
[[package]]
name = "windows-core"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d"
dependencies = [
"windows-implement 0.57.0",
"windows-interface 0.57.0",
"windows-result 0.1.2",
"windows-targets 0.52.6",
]
[[package]] [[package]]
name = "windows-core" name = "windows-core"
version = "0.58.0" version = "0.58.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
dependencies = [ dependencies = [
"windows-implement", "windows-implement 0.58.0",
"windows-interface", "windows-interface 0.58.0",
"windows-result", "windows-result 0.2.0",
"windows-strings", "windows-strings",
"windows-targets 0.52.6", "windows-targets 0.52.6",
] ]
[[package]]
name = "windows-implement"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.90",
]
[[package]] [[package]]
name = "windows-implement" name = "windows-implement"
version = "0.58.0" version = "0.58.0"
@ -4532,6 +4635,17 @@ dependencies = [
"syn 2.0.90", "syn 2.0.90",
] ]
[[package]]
name = "windows-interface"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.90",
]
[[package]] [[package]]
name = "windows-interface" name = "windows-interface"
version = "0.58.0" version = "0.58.0"
@ -4549,11 +4663,20 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0"
dependencies = [ dependencies = [
"windows-result", "windows-result 0.2.0",
"windows-strings", "windows-strings",
"windows-targets 0.52.6", "windows-targets 0.52.6",
] ]
[[package]]
name = "windows-result"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
dependencies = [
"windows-targets 0.52.6",
]
[[package]] [[package]]
name = "windows-result" name = "windows-result"
version = "0.2.0" version = "0.2.0"
@ -4569,7 +4692,7 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
dependencies = [ dependencies = [
"windows-result", "windows-result 0.2.0",
"windows-targets 0.52.6", "windows-targets 0.52.6",
] ]
@ -4873,7 +4996,7 @@ dependencies = [
"webkit2gtk", "webkit2gtk",
"webkit2gtk-sys", "webkit2gtk-sys",
"webview2-com", "webview2-com",
"windows", "windows 0.58.0",
"windows-core 0.58.0", "windows-core 0.58.0",
"windows-version", "windows-version",
"x11-dl", "x11-dl",

View File

@ -18,11 +18,23 @@ name = "test_tauri_lib"
tauri-build = {version = "2", features = [] } tauri-build = {version = "2", features = [] }
[dependencies] [dependencies]
bitflags = {version= "2.6.0", features = ["serde"] } bitflags = {version = "2.6.0", features = ["serde"] }
memmap2 = "0.9.5" memmap2 = "0.9.5"
serde = {version = "1", features = ["derive"] } serde = {version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"
sysinfo = "0.33.0"
tauri = {version = "2", features = [] } tauri = {version = "2", features = [] }
tauri-plugin-dialog = "2" tauri-plugin-dialog = "2"
tauri-plugin-shell = "2" tauri-plugin-shell = "2"
thiserror = "2.0.4" thiserror = "2.0.4"
[dependencies.windows]
version = "0.58.0"
features = [
"Data_Xml_Dom",
"Win32_Foundation",
"Win32_Security",
"Win32_System_Threading",
"Win32_UI_WindowsAndMessaging",
"Win32_System_ProcessStatus"
]

View File

@ -38,6 +38,11 @@ pub enum AppError {
/// 节名过长 /// 节名过长
#[error("节名过长!")] #[error("节名过长!")]
SectionNameTooLong, SectionNameTooLong,
#[error("打开进程失败!: {0}")]
OpenProcessError(String),
#[error("查询进程路径失败!: {0}")]
QueryFullProcessImageNameWError(String),
} }
impl serde::Serialize for AppError { impl serde::Serialize for AppError {

View File

@ -128,7 +128,6 @@ impl AppState {
Ok(()) Ok(())
} }
pub fn get_import_tables(&self) -> Result<Vec<ImportModuleTable>, AppError> { pub fn get_import_tables(&self) -> Result<Vec<ImportModuleTable>, AppError> {
let mmap = self.get_mmap_ref()?; let mmap = self.get_mmap_ref()?;
let is_64_bit = self.is_64_bit.unwrap(); let is_64_bit = self.is_64_bit.unwrap();
@ -204,31 +203,29 @@ impl AppState {
} }
}; };
let mut import_function_table = ImportFunctionTable::default(); let mut import_function_table = ImportFunctionTable::default();
let hint_name_table_rva = import_lookup_table as u32 & 0x7FFFFFFF;
let hint_name_table_foa = mmap.rva_to_foa(hint_name_table_rva)?; if is_named == true {
// 1. 读hint 两个字节 // TODO: 仅当序号/名称标志位字段为 0按名称导入才使用此字段。
let funtion_hint: u16 = unsafe { let hint_name_table_rva = import_lookup_table as u32 & 0x7FFFFFFF;
let ptr = mmap[hint_name_table_foa as usize..].as_ptr() as *const u16; let hint_name_table_foa = mmap.rva_to_foa(hint_name_table_rva)?;
ptr.read() // 1. 读hint 两个字节
}; let funtion_hint: u16 = unsafe {
import_function_table.function_hint = funtion_hint; let ptr = mmap[hint_name_table_foa as usize..].as_ptr() as *const u16;
import_function_table.function_address = hint_name_table_rva; ptr.read()
match is_named { };
true => { import_function_table.function_hint = funtion_hint;
// 命名函数 import_function_table.function_address = hint_name_table_rva;
let function_name = unsafe { let function_name = unsafe {
let ptr = let ptr = mmap[hint_name_table_foa as usize + 2..].as_ptr() as *const i8;
mmap[hint_name_table_foa as usize + 2..].as_ptr() as *const i8; CStr::from_ptr(ptr).to_str()?.to_string()
CStr::from_ptr(ptr).to_str()?.to_string() };
}; import_function_table.function_name = function_name;
import_function_table.function_name = function_name; } else {
functions.push(import_function_table); let function_ordianl = import_lookup_table as u32 & ImportLookupTable32::IMPORT_BY_ORDINAL_MASK.bits();
} import_function_table.function_hint = function_ordianl as u16;
false => { import_function_table.function_type = ImportFunctionTableItem::Ordinal;
import_function_table.function_type = ImportFunctionTableItem::Ordinal;
functions.push(import_function_table);
}
} }
functions.push(import_function_table);
// 下一个 // 下一个
base_offset += if is_64_bit { 8 } else { 4 }; base_offset += if is_64_bit { 8 } else { 4 };
} }
@ -242,13 +239,13 @@ impl AppState {
// 定义一个获取导入表后需要返回的结构 // 定义一个获取导入表后需要返回的结构
#[derive(Debug, Default, Clone, Serialize)] #[derive(Debug, Default, Clone, Serialize)]
pub struct ImportModuleTable { pub struct ImportModuleTable {
pub module_name: String, // 模块名称 pub module_name: String, // 模块名称
pub functions: Vec<ImportFunctionTable>, // 这里要另一个结构体来描述 pub functions: Vec<ImportFunctionTable>, // 这里要另一个结构体来描述
pub timestamp: u32, // 时间戳 pub timestamp: u32, // 时间戳
pub forwarder_chain: u32, // 转发链 pub forwarder_chain: u32, // 转发链
pub module_name_rva: u32, // dll名称的RVA pub module_name_rva: u32, // dll名称的RVA
pub iat_rva: u32, // IAT的RVA pub iat_rva: u32, // IAT的RVA
pub int_rva: u32, // INT的RVA pub int_rva: u32, // INT的RVA
} }
// 因为导入查找表可能是函数名、也可能是序号 所以用枚举包一下最好 // 因为导入查找表可能是函数名、也可能是序号 所以用枚举包一下最好
@ -266,5 +263,5 @@ pub struct ImportFunctionTable {
pub function_name: String, // 函数名称 pub function_name: String, // 函数名称
pub function_address: u32, // 函数地址 IAT pub function_address: u32, // 函数地址 IAT
pub function_hint: u16, // 函数提示 pub function_hint: u16, // 函数提示
pub function_type: ImportFunctionTableItem pub function_type: ImportFunctionTableItem,
} }

View File

@ -4,6 +4,7 @@ use crate::pe_parse::pe::{
MutablePE MutablePE
}; };
pub mod file; pub mod file;
pub mod win_proc;
// 为文件映射实现PE结构 // 为文件映射实现PE结构
impl ReadOnlyPE for Mmap {} impl ReadOnlyPE for Mmap {}

View File

@ -0,0 +1,213 @@
use std::{alloc::{alloc, Layout}, io::{Seek, Write}};
use crate::{
app_error::AppError,
pe_parse::{header::ImageDosHeader, pe::ReadOnlyPE},
};
use memmap2::Mmap;
use sysinfo::{self, System};
use windows::{
core::PWSTR,
Win32::{
Foundation::{CloseHandle, HMODULE},
System::{
Diagnostics::Debug::ReadProcessMemory,
ProcessStatus::EnumProcessModules,
Threading::{
OpenProcess, QueryFullProcessImageNameW, PROCESS_ACCESS_RIGHTS, PROCESS_ALL_ACCESS,
PROCESS_NAME_WIN32,
},
},
},
};
/// 遍历进程并返回进程名\PID
pub fn get_process_list() -> Vec<(String, u32)> {
let mut sys = System::new_all();
sys.refresh_all();
let mut process_list = Vec::new();
for (pid, process) in sys.processes() {
let pid = pid.as_u32();
process_list.push((process.name().to_str().unwrap().to_string(), pid));
}
process_list
}
pub fn dump_process(pid: u32, save_file_path: &str) -> Result<(), AppError> {
#[warn(unused_assignments)]
let mut file_path = String::new();
// 1. 打开进程
let mut image_base = 0; // 模块基址
let h_process = unsafe {
OpenProcess(PROCESS_ACCESS_RIGHTS(PROCESS_ALL_ACCESS.0), false, pid)
.map_err(|e| AppError::OpenProcessError(e.to_string()))?
};
// 2. 获取进程对应的文件路径
let mut buffer = [0u16; 1024];
let pwstr = PWSTR(buffer.as_mut_ptr());
let mut size = buffer.len() as u32;
unsafe {
let result = QueryFullProcessImageNameW(h_process, PROCESS_NAME_WIN32, pwstr, &mut size);
if result.is_err() {
return Err(AppError::QueryFullProcessImageNameWError(
result.unwrap_err().to_string(),
));
}
}
unsafe {
file_path = pwstr.to_string().unwrap();
println!("进程路径: {:?}", file_path);
}
// 创建新文件
let mut save_file = std::fs::OpenOptions::new()
.write(true)
.create(true)
.open(save_file_path)
.map_err(|e| AppError::Io(e))?;
// 3. 读取进程的文件读取它的PE头
// 3.1 映射文件
let file = std::fs::OpenOptions::new()
.read(true)
.open(file_path)
.map_err(|e| AppError::Io(e))?;
let mmap = unsafe { Mmap::map(&file).map_err(|e| AppError::Io(e)) }?;
// 3.2 读取PE头
{
// 3.2.1 读取DOS头
let dos_header = mmap.get_dos_header()?;
let write_size = std::mem::size_of::<ImageDosHeader>() as u64;
save_file.write_all(&mmap[..write_size as usize])?;
// 3.2.2 读取PE头
let nt_header = mmap.get_nt_header()?;
let nt_header_size = match nt_header {
crate::pe_parse::header::ImageNTHeader::NTHeader32(_) => {
std::mem::size_of::<crate::pe_parse::header::ImageNTHeader32>() as u64
}
crate::pe_parse::header::ImageNTHeader::NTHeader64(_) => {
std::mem::size_of::<crate::pe_parse::header::ImageNTHeader64>() as u64
}
};
let nt_header_offset = dos_header.e_lfanew;
// 移动文件指针
save_file.seek(std::io::SeekFrom::Start(nt_header_offset.0 as u64))?;
// 写入PE头
save_file.write_all(
&mmap[nt_header_offset.0 as usize
..(nt_header_offset.0 as usize + nt_header_size as usize) as usize],
)?;
// 写入nt_header_offset.0 - sizeof(dos_header)的数据
// 移动文件指针到dos_header之后
save_file.seek(std::io::SeekFrom::Start(write_size))?;
save_file.write_all(&mmap[write_size as usize..nt_header_offset.0 as usize])?;
// 移动文件指针到最后
save_file.seek(std::io::SeekFrom::Start(
nt_header_offset.0 as u64 + nt_header_size,
))?;
// 数据目录
let data_directory_offset = nt_header_offset.0 as usize + nt_header_size as usize;
save_file.write_all(&mmap[data_directory_offset..data_directory_offset + 16 * 17])?;
// 节区头
let sections_num = mmap.get_section_headers()?.len();
let section_header_offset = mmap.get_section_headers_offset()?;
let section_header_size = std::mem::size_of::<crate::pe_parse::header::ImageSectionHeader>()
as u64
* sections_num as u64;
save_file.seek(std::io::SeekFrom::Start(section_header_offset as u64))?;
save_file.write_all(
&mmap[section_header_offset as usize
..(section_header_offset as usize + section_header_size as usize) as usize],
)?;
save_file.flush()?;
}
// 获取模块基址
{
let mut h_module = HMODULE::default();
let mut cb_needed = 0;
unsafe {
EnumProcessModules(
h_process,
&mut h_module,
std::mem::size_of::<HMODULE>() as u32,
&mut cb_needed,
)
.unwrap();
// 获取模块基址
image_base = h_module.0 as u64;
}
}
// 5. 遍历节表头,从进程中读取节的内容,写入文件
{
let sections = mmap.get_section_headers()?;
for section in sections.iter() {
let section_va = section.virtual_address as u64;
let section_size = section.size_of_raw_data as u64;
let section_size_align = mmap.align_size_with_section_alignment(section_size as u32)?;
let section_offset = image_base + section_va;
let section_foa = section.pointer_to_raw_data as u64;
let data_buf = unsafe {
let layout = Layout::array::<u8>(section_size_align as usize).unwrap();
alloc(layout)
};
let mut read_size = 0;
unsafe {
ReadProcessMemory(
h_process,
section_offset as *const _,
data_buf as *mut _,
section_size_align as usize,
Some(&mut read_size),
)
.unwrap();
}
println!(
"读取节: VA: {:#x}, Size: {:#x}, FOA: {:#x}",
section_va, section_size, section_foa
);
println!(
"读取节: Size: {:#x}, ReadSize: {:#x}",
section_size_align, read_size
);
IMAGE_SECTION_HEADER;
// 如果文件长度不够,则先扩容
let file_size = save_file.metadata().unwrap().len();
if file_size < section_foa + section_size_align as u64 {
// 文件指针要移动到末尾
save_file.seek(std::io::SeekFrom::End(0))?;
save_file.set_len(section_foa + section_size_align as u64)?;
}
save_file.seek(std::io::SeekFrom::Start(section_foa))?;
save_file.write_all(unsafe {
std::slice::from_raw_parts(data_buf as *const u8, section_size_align as usize)
})?;
}
}
// 6. 关闭进程
unsafe {
CloseHandle(h_process).unwrap();
};
// 7. 返回
Ok(())
}
// 来个测试
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_process_list() {
let process_list = get_process_list();
for (name, pid) in process_list {
println!("进程名: {}, PID: {}", name, pid);
}
}
#[test]
fn test_dump_process() {
dump_process(11696, "D:\\download\\a.exe").unwrap();
}
}

View File

@ -16,8 +16,8 @@
"noImplicitAny": false, "noImplicitAny": false,
/* Linting */ /* Linting */
"strict": false, "strict": false,
"noUnusedLocals": true, "noUnusedLocals": false,
"noUnusedParameters": true, "noUnusedParameters": false,
"noFallthroughCasesInSwitch": true "noFallthroughCasesInSwitch": true
}, },
"include": ["src"], "include": ["src"],