Skip to content

Commit

Permalink
Add file
Browse files Browse the repository at this point in the history
resumes the execution of the process even if the dump fails
  • Loading branch information
r3yl4h authored Sep 5, 2024
1 parent 78c75b2 commit f0dfe07
Show file tree
Hide file tree
Showing 9 changed files with 734 additions and 0 deletions.
49 changes: 49 additions & 0 deletions src/dump/dump.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use std::ffi::CStr;
use std::fs::OpenOptions;
use winapi::shared::minwindef::LPVOID;

use winapi::um::tlhelp32::PROCESSENTRY32;
use winapi::um::winnt::HANDLE;
use crate::OPT;
use crate::process::get_base_addr;
use crate::utils::*;



pub fn dump_file(entry: PROCESSENTRY32, h_proc: HANDLE) {
unsafe {
let filename = CStr::from_ptr(entry.szExeFile.as_ptr()).to_string_lossy().to_string();
println!("\n\x1b[0;35mDump {filename}{RESET}");
let outpath = format!("{}\\{}", OPT.outpath.to_string_lossy(), filename.replace(".", &format!("_dump{}.", entry.th32ProcessID)));
let mut outfile = match OpenOptions::new().write(true).read(true).create(true).truncate(true).open(&outpath) {
Ok(file) => file,
Err(e) => {
eprintln!("{RED}Failed to create file {outpath} : {e}{RESET}");
return
}
};
let base_addr = match get_base_addr(entry.th32ProcessID){
Ok(base) => base,
Err(e) => {
eprintln!("{RED}{e}{RESET}");
return
}
};

let sectionv = match crate::dump::header::dump_header(h_proc, base_addr, &mut (0 as LPVOID), &mut outfile){
Ok(sectionv) => sectionv,
Err(e) => {
eprintln!("{RED}Failed to read header of process in output file : {e}{RESET}");
return
}
};

if let Err(e) = crate::dump::section::dump_section(&mut outfile, h_proc, &sectionv, base_addr){
eprintln!("{RED}Error to dump section : {e}{RESET}");
return
}
}
}



62 changes: 62 additions & 0 deletions src/dump/dump_child.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use std::{io, ptr};
use std::ffi::{c_char, CStr};
use winapi::um::handleapi::INVALID_HANDLE_VALUE;
use winapi::um::processthreadsapi::OpenProcess;
use winapi::um::tlhelp32::{CreateToolhelp32Snapshot, Process32First, Process32Next, PROCESSENTRY32, TH32CS_SNAPPROCESS};
use winapi::um::winnt::{PROCESS_QUERY_INFORMATION, PROCESS_SUSPEND_RESUME, PROCESS_VM_OPERATION, PROCESS_VM_READ};
use crate::dump;
use crate::utils::*;

pub fn dump_child(entry: PROCESSENTRY32) {
match find_child(entry.th32ProcessID) {
Ok(child_proc) => {
for child in child_proc {
let mut child = child;
let new_name = unsafe {CStr::from_ptr(child.szExeFile.as_ptr()).to_string_lossy()}.replace(".", "_child.");
let new_name = new_name.as_bytes();
if new_name.len() < 260 {
unsafe {
ptr::copy(new_name.as_ptr() as *const c_char, child.szExeFile.as_mut_ptr(), new_name.len());
}
child.szExeFile[new_name.len()] = 0;
}
unsafe {
let h_proc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_SUSPEND_RESUME, 0, child.th32ProcessID);
dump::dump::dump_file(child, h_proc);
}
}
}
Err(e) => eprintln!("{e}"),
}
}



pub fn find_child(parent_pid: u32) -> Result<Vec<PROCESSENTRY32>, String> {
let mut child_proc = Vec::new();
unsafe {
let snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if snapshot == INVALID_HANDLE_VALUE {
return Err(format!("{RED}failed to create snapshot for dump child process: {}{RESET}", io::Error::last_os_error()))
}
let mut entry: PROCESSENTRY32 = std::mem::zeroed();
entry.dwSize = std::mem::size_of::<PROCESSENTRY32>() as u32;
if Process32First(snapshot, &mut entry) != 0 {
loop {
if entry.th32ParentProcessID == parent_pid {
child_proc.push(entry)
}
if Process32Next(snapshot, &mut entry) == 0 {
break;
}
}
}else {
return Err(format!("{RED}failed to get info of first process : {}{RESET}", io::Error::last_os_error()));
}
}
if child_proc.len() != 0 {
Ok(child_proc)
}else {
Err(String::from("the process does not contain children"))
}
}
257 changes: 257 additions & 0 deletions src/dump/header.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
use std::fs::File;
use std::{io, mem, ptr};
use std::io::{ErrorKind, Seek, SeekFrom, Write};
use winapi::shared::minwindef::LPVOID;
use winapi::um::handleapi::CloseHandle;
use winapi::um::memoryapi::ReadProcessMemory;
use crate::dump::{Bitness, HeaderNt};
use winapi::um::winnt::*;
use crate::utils::*;


pub trait OptHeader {
fn set_file_alignment(&mut self);
fn set_size_of_code(&mut self, new_size: u32);
fn set_size_of_init(&mut self, new_size: u32);
fn set_size_of_uninit(&mut self, new_size: u32);
fn set_size_of_image(&mut self, new_size: u32);
fn get_size_of_struct_opt(&self) -> usize;
}



impl OptHeader for IMAGE_OPTIONAL_HEADER32 {
fn set_file_alignment(&mut self) {
if self.FileAlignment < self.SectionAlignment {
self.FileAlignment = self.SectionAlignment;
println!("\x1b[0;36m new section align : {:#x}", self.SectionAlignment);
}
}
fn set_size_of_code(&mut self, new_size: u32) {
if new_size > self.SizeOfCode {
self.SizeOfCode = new_size;
println!("\x1b[0;36m new size of code : {:#x}", self.SizeOfCode);
}
}
fn set_size_of_init(&mut self, new_size: u32) {
if self.SizeOfInitializedData < new_size {
self.SizeOfInitializedData = new_size;
println!("\x1b[0;36m new size of init : {:#x}", new_size);
}
}
fn set_size_of_uninit(&mut self, new_size: u32) {
if self.SizeOfUninitializedData < new_size {
self.SizeOfUninitializedData = new_size;
println!("\x1b[0;36m new size of uinit : {:#x}", new_size);
}
}
fn set_size_of_image(&mut self, new_size: u32) {
if self.SizeOfImage < new_size {
self.SizeOfImage = new_size;
println!("\x1b[0;36m new size of image : {:#x}", new_size);
}
}
fn get_size_of_struct_opt(&self) -> usize { mem::size_of::<IMAGE_NT_HEADERS32>() }
}


impl OptHeader for IMAGE_OPTIONAL_HEADER64 {
fn set_file_alignment(&mut self) {
if self.FileAlignment < self.SectionAlignment {
self.FileAlignment = self.SectionAlignment;
println!("\x1b[0;36m new section align : {:#x}", self.SectionAlignment);
}
}

fn set_size_of_code(&mut self, new_size: u32) {
if new_size > self.SizeOfCode {
self.SizeOfCode = new_size;
println!("\x1b[0;36m new size of code : {:#x}", self.SizeOfCode);
}
}

fn set_size_of_init(&mut self, new_size: u32) {
if self.SizeOfInitializedData < new_size {
self.SizeOfInitializedData = new_size;
println!("\x1b[0;36m new size of init : {:#x}", new_size);
}
}

fn set_size_of_uninit(&mut self, new_size: u32) {
if self.SizeOfUninitializedData < new_size {
self.SizeOfUninitializedData = new_size;
println!("\x1b[0;36m new size of uinit : {:#x}", new_size);
}
}

fn set_size_of_image(&mut self, new_size: u32) {
if self.SizeOfImage < new_size {
self.SizeOfImage = new_size;
println!("\x1b[0;36m new size of image : {:#x}", new_size);
}
}

fn get_size_of_struct_opt(&self) -> usize { mem::size_of::<IMAGE_NT_HEADERS64>() }
}



pub unsafe fn fix_nt_head(outfile: &mut File, e_lafnew: i32, header_nt: &HeaderNt, sectionv: &[IMAGE_SECTION_HEADER]) -> Result<(), io::Error> {
let (mut size_code, mut size_uninit, mut size_init) = (0, 0, 0);
let size_image = sectionv.last().unwrap().VirtualAddress + sectionv.last().unwrap().Misc.VirtualSize();

for sec in sectionv {
if sec.Characteristics & IMAGE_SCN_CNT_CODE != 0 {
size_code += *sec.Misc.VirtualSize();
}
if sec.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA != 0 {
size_init += *sec.Misc.VirtualSize();
}
if sec.Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA != 0 {
size_uninit += *sec.Misc.VirtualSize();
}
}

let opt_pos = e_lafnew + 0x18;
let last_pos = outfile.metadata()?.len();

match header_nt.bitness {
Bitness::X32 => {
let mut nt32 = *(header_nt.nt_header.0 as *const IMAGE_NT_HEADERS32);
update_optional_header(&mut nt32.OptionalHeader, size_code, size_init, size_uninit, size_image);
outfile.write_header(opt_pos, last_pos, nt32.OptionalHeader)?;
},
Bitness::X64 => {
let mut nt64 = *(header_nt.nt_header.0 as *const IMAGE_NT_HEADERS64);
update_optional_header(&mut nt64.OptionalHeader, size_code, size_init, size_uninit, size_image);
outfile.write_header(opt_pos, last_pos, nt64.OptionalHeader)?;
},
}

if let Some(offs) = recl_symptr_table(header_nt.nt_header.0 as *const IMAGE_NT_HEADERS32, sectionv) {
let ptr_sym = e_lafnew + 0xc;
outfile.seek_write(ptr_sym as u64, last_pos, &offs.to_le_bytes())?;
println!("new symbol ptr : {:#x}", offs);
}
Ok(())
}



unsafe fn update_optional_header<T: OptHeader>(opt_header: &mut T, size_code: u32, size_init: u32, size_uninit: u32, size_image: u32, ) {
opt_header.set_file_alignment();
opt_header.set_size_of_code(size_code);
opt_header.set_size_of_init(size_init);
opt_header.set_size_of_uninit(size_uninit);
opt_header.set_size_of_image(size_image);
}


trait WriteHeader {
fn write_header<T: OptHeader>(&mut self, opt_pos: i32, last_pos: u64, opt_header: T) -> io::Result<()>;
fn seek_write(&mut self, pos: u64, last_pos: u64, data: &[u8]) -> io::Result<()>;
}


impl WriteHeader for File {
fn write_header<T: OptHeader>(&mut self, opt_pos: i32, last_pos: u64, opt_header: T) -> io::Result<()> {
let data = unsafe { std::slice::from_raw_parts(ptr::addr_of!(opt_header) as *const u8, opt_header.get_size_of_struct_opt()) };
self.seek_write(opt_pos as u64, last_pos, data)
}

fn seek_write(&mut self, pos: u64, last_pos: u64, data: &[u8]) -> io::Result<()> {
self.seek(SeekFrom::Start(pos))?;
self.write_all(data)?;
self.seek(SeekFrom::Start(last_pos))?;
Ok(())
}
}


pub unsafe fn recl_symptr_table(nt_h: *const IMAGE_NT_HEADERS32, sectionv: &[IMAGE_SECTION_HEADER]) -> Option<u32> {
let sym_ptr = (*nt_h).FileHeader.PointerToSymbolTable;
if sym_ptr != 0 {
sectionv.iter().find_map(|sec| {
if sec.PointerToRawData <= sym_ptr && sec.PointerToRawData + sec.SizeOfRawData >= sym_ptr {
Some(sym_ptr - sec.PointerToRawData + sec.VirtualAddress)
} else {
None
}
})
}else {
None
}
}











pub unsafe fn dump_header(h_proc: HANDLE, base_addr: u64, addr: &mut LPVOID, outfile: &mut File) -> Result<Vec<IMAGE_SECTION_HEADER>, io::Error> {
let mut h_nt: HeaderNt = HeaderNt::default();
let mut dos_header: IMAGE_DOS_HEADER = mem::zeroed();
if ReadProcessMemory(h_proc, base_addr as LPVOID, ptr::addr_of_mut!(dos_header) as LPVOID, mem::size_of::<IMAGE_DOS_HEADER>(), &mut 0) == 0 {
return Err(io::Error::new(ErrorKind::Other, format!("{RED}Failed to read IMAGE_DOS_HEADER : {}{RESET}", io::Error::last_os_error())))
}
*addr = (base_addr + dos_header.e_lfanew as u64 + 4) as LPVOID;
let mut machine = 0u16;
if ReadProcessMemory(h_proc, *addr as LPVOID, ptr::addr_of_mut!(machine) as LPVOID, 2, &mut 0) == 0 {
return Err(io::Error::new(ErrorKind::Other, format!("{RED}Failed to read IMAGE_NT_HEADER : {}{RESET}", io::Error::last_os_error())));
}

*addr = (*addr as u64 - 4) as LPVOID;

match machine {
IMAGE_FILE_MACHINE_I386 => {
let mut nt32: IMAGE_NT_HEADERS32 = mem::zeroed();
if ReadProcessMemory(h_proc, *addr, ptr::addr_of_mut!(nt32) as LPVOID, mem::size_of::<IMAGE_NT_HEADERS32>(), &mut 0) == 0 {
return Err(io::Error::new(ErrorKind::Other,format!("{RED}Failed to read IMAGE_NT_HEADER32 : {}{RESET}", io::Error::last_os_error())));
}
h_nt.nt_header.0 = ptr::addr_of_mut!(nt32) as LPVOID;
h_nt.bitness = Bitness::X32;
*addr = (*addr as usize + mem::size_of::<IMAGE_NT_HEADERS32>()) as LPVOID;
},

IMAGE_FILE_MACHINE_AMD64 => {
let mut nt64: IMAGE_NT_HEADERS64 = mem::zeroed();
if ReadProcessMemory(h_proc, *addr, ptr::addr_of_mut!(nt64) as LPVOID, mem::size_of::<IMAGE_NT_HEADERS64>(), &mut 0) == 0 {
return Err(io::Error::new(ErrorKind::Other, format!("{RED}Failed to read IMAGE_NT_HEADER64 : {}{RESET}", io::Error::last_os_error())))
}
h_nt.nt_header.0 = ptr::addr_of_mut!(nt64) as LPVOID;
h_nt.bitness = Bitness::X64;
*addr = (*addr as usize + mem::size_of::<IMAGE_NT_HEADERS64>()) as LPVOID;
},
_ => {
return Err(io::Error::new(ErrorKind::Other, format!("{RED}the target machine of this file is not supported{RESET}")))
}
}
let size_all = (*addr as u64 - base_addr) as usize;
let mut header_byte = vec![0u8; size_all];
if ReadProcessMemory(h_proc, base_addr as LPVOID, header_byte.as_mut_ptr() as LPVOID, size_all, &mut 0) == 0 {
eprintln!("{RED}Failed to read all header of file : {}{RESET}", io::Error::last_os_error());
CloseHandle(h_proc);
std::process::exit(1)
}
outfile.write_all(&header_byte)?;
let num_sec = *((h_nt.nt_header.0 as u64 + 0x6) as *const u16);
let mut sectionv = vec![mem::zeroed::<IMAGE_SECTION_HEADER>(); num_sec as usize];
let size_secb = mem::size_of::<IMAGE_SECTION_HEADER>() * num_sec as usize;
if ReadProcessMemory(h_proc, *addr, sectionv.as_mut_ptr() as LPVOID, size_secb, &mut 0) == 0 {
eprintln!("{RED}Failed to read section header of process : {}{RESET}", io::Error::last_os_error());
CloseHandle(h_proc);
std::process::exit(1)
}
fix_nt_head(outfile, dos_header.e_lfanew, &h_nt, &sectionv)?;
sectionv.iter_mut().for_each(|sec| {
sec.PointerToRawData = sec.VirtualAddress;
sec.SizeOfRawData = *sec.Misc.VirtualSize();
});
outfile.write_all(std::slice::from_raw_parts(sectionv.as_ptr() as *const u8, size_secb))?;
Ok(sectionv)
}
Loading

0 comments on commit f0dfe07

Please sign in to comment.