DLL 注入

Rust
473
0
0
2023-02-01
  • 使用Rust实现一个DLL注入器
  • 依赖
[dependencies]
clap = "4.1"
anyhow = "1.0"

[dependencies.windows]
version="0.44"
features = [
    "Win32_Foundation",
    "Win32_System_Diagnostics_ToolHelp",
    "Win32_System_Memory",
    "Win32_System_Threading",
    "Win32_Security",
    "Win32_System_Diagnostics_Debug",
    "Win32_System_WindowsProgramming",
    "Win32_System_LibraryLoader",
]
  • main.rs
use std::{ffi::c_void, fs, os::windows::prelude::OsStrExt};

use clap::value_parser;
use windows::{
    core::{PCSTR, PCWSTR},
    Win32::{
        Foundation::{CloseHandle, HANDLE},
        System::{
            Diagnostics::{
                Debug::WriteProcessMemory,
                ToolHelp::{
                    CreateToolhelp32Snapshot, Process32FirstW, Process32NextW, PROCESSENTRY32W,
                    TH32CS_SNAPPROCESS,
                },
            },
            LibraryLoader::{GetModuleHandleA, GetProcAddress},
            Memory::{
                VirtualAllocEx, VirtualFreeEx, MEM_COMMIT, MEM_RELEASE, MEM_RESERVE, PAGE_READWRITE,
            },
            Threading::{CreateRemoteThread, OpenProcess, WaitForSingleObject, PROCESS_ALL_ACCESS},
            WindowsProgramming::INFINITE,
        },
    },
};

unsafe fn injection(process_id: u32, path: &Vec<u16>) {
    let process = OpenProcess(PROCESS_ALL_ACCESS, false, process_id).unwrap();
    println!("OpenProcess: {process:?}");
    let kernel32 = GetModuleHandleA(PCSTR::from_raw(b"kernel32.dll\0" as _)).unwrap();

    let load_library = GetProcAddress(kernel32, PCSTR::from_raw(b"LoadLibraryW\0" as _));
    println!("LoadLibraryW: {}", load_library.is_some());
    let load_library = *(&load_library as *const Option<unsafe extern "system" fn() -> isize>
        as *const Option<unsafe extern "system" fn(*mut c_void) -> u32>);

    let addr = VirtualAllocEx(
        process,
        None,
        path.len() * 2,
        MEM_COMMIT | MEM_RESERVE,
        PAGE_READWRITE,
    );
    let r = WriteProcessMemory(process, addr, path.as_ptr() as _, path.len() * 2, None);
    if !r.as_bool() {
        return;
    }
    let result = CreateRemoteThread(process, None, 0, load_library, Some(addr), 0, None).unwrap();
    WaitForSingleObject(result, INFINITE);

    VirtualFreeEx(process, addr, path.len() * 2, MEM_RELEASE);
    CloseHandle(result);
    CloseHandle(process);
    println!("完成");
}

fn main() {
    let cmd = clap::Command::new("Inject DLL")
        .group(clap::ArgGroup::new("process").required(true))
        .arg(clap::Arg::new("dll").required(true))
        .arg(
            clap::Arg::new("name")
                .short('n')
                .help("Process Name")
                .group("process"),
        )
        .arg(
            clap::Arg::new("pid")
                .short('p')
                .help("Process ID")
                .value_parser(value_parser!(u32))
                .group("process"),
        )
        .get_matches();
    let path = cmd.get_one::<String>("dll").unwrap();
    let path = fs::canonicalize(path).unwrap();
    if !path.is_file() {
        panic!("Path {path:?} is Not a File")
    }

    let mut path: Vec<_> = path.as_os_str().encode_wide().collect();
    path.push(0);

    if let Some(process_id) = cmd.get_one::<u32>("pid").copied() {
        unsafe { injection(process_id, &path) }
    } else {
        let name = cmd.get_one::<String>("name").expect("无法获取参数: name");
        unsafe { get_process_by_name(name).for_each(|process_id| injection(process_id, &path)) }
    }
}

struct ProcessIter {
    hobject: HANDLE,
    first: bool,
}

impl Drop for ProcessIter {
    fn drop(&mut self) {
        unsafe { CloseHandle(self.hobject) };
    }
}

impl Iterator for ProcessIter {
    type Item = PROCESSENTRY32W;

    #[allow(clippy::field_reassign_with_default)]
    fn next(&mut self) -> Option<Self::Item> {
        unsafe {
            let mut pe: PROCESSENTRY32W = Default::default();
            pe.dwSize = std::mem::size_of::<PROCESSENTRY32W>() as _;
            let r = if self.first {
                let r = Process32FirstW(self.hobject, &mut pe);
                self.first = false;
                r
            } else {
                Process32NextW(self.hobject, &mut pe)
            };
            if r.as_bool() {
                Some(pe)
            } else {
                None
            }
        }
    }
}

#[allow(clippy::field_reassign_with_default, clippy::needless_lifetimes)]
unsafe fn get_process_by_name<'a>(name: &'a str) -> impl Iterator<Item = u32> + 'a {
    let hobject = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0).unwrap();
    let iter = ProcessIter {
        hobject,
        first: true,
    };
    iter.into_iter().filter_map(move |pe| {
        let str = PCWSTR::from_raw(pe.szExeFile.as_ptr());
        match str.to_string() {
            Ok(s) => {
                println!("Process: {s}");
                if s.contains(name) {
                    Some(pe.th32ProcessID)
                } else {
                    None
                }
            }
            Err(s) => {
                println!("Process: {s}");
                None
            }
        }
    })
}