dll-syringe 0.2.0

A windows dll injection library written in rust.
Documentation
use std::{
    mem::{self, MaybeUninit},
    ptr,
};

use rust_win32error::Win32Error;
use widestring::U16CStr;
use winapi::um::{
    memoryapi::{VirtualAllocEx, VirtualFreeEx, WriteProcessMemory},
    winnt::{MEM_COMMIT, MEM_RELEASE, MEM_RESERVE, PAGE_READWRITE},
};

use crate::ProcessRef;

pub(crate) struct ForeignProcessWideString<'a> {
    process: ProcessRef<'a>,
    ptr: *mut winapi::ctypes::c_void,
    byte_count: usize,
}

impl<'a> ForeignProcessWideString<'a> {
    pub fn allocate_in_process(
        process: ProcessRef<'a>,
        str: impl AsRef<U16CStr>,
    ) -> Result<Self, Win32Error> {
        let str = str.as_ref();
        let str_byte_count = str.as_slice_with_nul().len() * mem::size_of::<u16>();

        let remote_string_ptr = unsafe {
            VirtualAllocEx(
                process.handle(),
                ptr::null_mut(),
                str_byte_count,
                MEM_COMMIT | MEM_RESERVE,
                PAGE_READWRITE,
            )
        };
        if remote_string_ptr.is_null() {
            return Err(Win32Error::new());
        }

        let mut bytes_written = MaybeUninit::uninit();
        let result = unsafe {
            WriteProcessMemory(
                process.handle(),
                remote_string_ptr,
                str.as_ptr().cast(),
                str_byte_count,
                bytes_written.as_mut_ptr(),
            )
        };
        if result == 0 {
            return Err(Win32Error::new());
        }

        assert_eq!(unsafe { bytes_written.assume_init() }, str_byte_count);

        Ok(Self {
            process,
            ptr: remote_string_ptr.cast(),
            byte_count: str_byte_count,
        })
    }

    #[allow(dead_code)]
    pub fn as_ptr(&mut self) -> *const winapi::ctypes::c_void {
        self.ptr
    }

    pub fn as_mut_ptr(&mut self) -> *mut winapi::ctypes::c_void {
        self.ptr
    }
}

impl<'a> Drop for ForeignProcessWideString<'a> {
    fn drop(&mut self) {
        unsafe {
            VirtualFreeEx(
                self.process.handle(),
                self.as_mut_ptr(),
                self.byte_count,
                MEM_RELEASE,
            );
        }
    }
}