attach 0.1.0

💉 Simple LoadLibrary DLL injector.
use std::ffi::*;
use std::mem;
use std::os::windows::process::CommandExt;
use std::path::PathBuf;
use std::process::Command;
use std::thread;
use std::time::Duration;

use anyhow::Result;
use clap::Parser;
use windows::s;
use windows::Win32::Foundation::*;
use windows::Win32::System::Diagnostics::Debug::*;
use windows::Win32::System::LibraryLoader::*;
use windows::Win32::System::Memory::*;
use windows::Win32::System::Threading::*;

#[derive(Parser)]
struct Cli {
    #[arg(short, long)]
    executable: PathBuf,

    #[arg(short, long)]
    arguments: Option<String>,

    #[arg(short, long)]
    library: PathBuf,

    #[arg(short, long)]
    delay: Option<f32>,
}

fn main() -> Result<()> {
    let cli = Cli::parse();
    let executable = cli.executable;
    let arguments = cli.arguments;
    let library = cli.library;

    let mut process = Command::new(executable);

    if let Some(arguments) = arguments {
        process.raw_arg(arguments);
    }

    let process = process.spawn()?;

    if let Some(delay) = cli.delay {
        thread::sleep(Duration::from_secs_f32(delay));
    }

    unsafe {
        let process = OpenProcess(PROCESS_ALL_ACCESS, false, process.id())?;

        let kernel32 = GetModuleHandleA(s!("kernel32.dll"))?;
        let load_library = GetProcAddress(kernel32, s!("LoadLibraryA")).unwrap();

        let local_buffer = CString::new(library.canonicalize()?.to_str().unwrap())?;

        let remote_buffer = VirtualAllocEx(
            process,
            None,
            local_buffer.as_bytes().len(),
            MEM_COMMIT | MEM_RESERVE,
            PAGE_READWRITE,
        );

        WriteProcessMemory(
            process,
            remote_buffer,
            local_buffer.as_ptr() as _,
            local_buffer.as_bytes().len(),
            None,
        );

        CreateRemoteThread(
            process,
            None,
            0,
            Some(mem::transmute(load_library)),
            Some(remote_buffer),
            0,
            None,
        )?;

        thread::sleep(Duration::from_secs(1));
        VirtualFreeEx(process, remote_buffer, 0, MEM_RELEASE);
        CloseHandle(process);
    }

    Ok(())
}