Skip to main content

memexec/peloader/
winapi.rs

1use super::def::*;
2use super::error::{Error, Result};
3use std::ffi::CString;
4use std::mem;
5use std::os::raw::c_char;
6
7extern "system" {
8    fn LoadLibraryA(lpLibFileName: LPCSTR) -> HMODULE;
9    fn GetProcAddress(hModule: HMODULE, lpProcName: LPCSTR) -> PVOID;
10    fn GetCurrentProcess() -> HANDLE;
11}
12
13pub fn load_library(lib: &str) -> Result<HMODULE> {
14    if let Ok(lib) = CString::new(lib) {
15        let hmod = unsafe { LoadLibraryA(lib.as_ptr()) };
16        if hmod == 0 as HMODULE {
17            Err(Error::LoadLibararyFail)
18        } else {
19            Ok(hmod)
20        }
21    } else {
22        Err(Error::InvalidCString)
23    }
24}
25
26pub fn get_proc_address_by_name(hmod: HMODULE, proc_name: &str) -> Result<PVOID> {
27    if let Ok(proc_name) = CString::new(proc_name) {
28        let proc = unsafe { GetProcAddress(hmod, proc_name.as_ptr()) };
29        if proc == 0 as PVOID {
30            Err(Error::GetProcAddressFail)
31        } else {
32            Ok(proc)
33        }
34    } else {
35        Err(Error::InvalidCString)
36    }
37}
38
39pub fn get_proc_address_by_ordinal(hmod: HMODULE, proc_ordinal: isize) -> Result<PVOID> {
40    let proc = unsafe { GetProcAddress(hmod, proc_ordinal as *const c_char) };
41    if proc == 0 as PVOID {
42        Err(Error::GetProcAddressFail)
43    } else {
44        Ok(proc)
45    }
46}
47
48// raw pointer doesn't implement `Sync` trait
49static mut p_nt_alloc_vm: usize = 0_usize;
50static mut p_nt_protect_vm: usize = 0_usize;
51
52/*
53#[link(name = "ntdll")]
54extern "system" {
55    fn NtAllocateVirtualMemory(
56        ProcessHandle: HANDLE,
57        BaseAddress: *const PVOID,
58        ZeroBits: ULONG_PTR,
59        RegionSize: PSIZE_T,
60        AllocationType: ULONG,
61        Protect: ULONG,
62    ) -> NTSTATUS;
63}
64*/
65// bypass possible hooks
66pub unsafe fn nt_alloc_vm(
67    base_addr: *const PVOID,
68    size: PSIZE_T,
69    allocation_typ: ULONG,
70    protect: ULONG,
71) -> Result<()> {
72    if p_nt_alloc_vm == 0 as _ {
73        p_nt_alloc_vm =
74            get_proc_address_by_name(load_library("ntdll.dll")?, "NtAllocateVirtualMemory")? as _;
75    };
76
77    let ret = mem::transmute::<
78        usize,
79        unsafe extern "system" fn(
80            HANDLE,
81            *const PVOID,
82            ULONG_PTR,
83            PSIZE_T,
84            ULONG,
85            ULONG,
86        ) -> NTSTATUS,
87    >(p_nt_alloc_vm)(
88        GetCurrentProcess(),
89        base_addr,
90        0,
91        size,
92        allocation_typ,
93        protect,
94    );
95
96    if 0 == ret {
97        Ok(())
98    } else {
99        Err(Error::NtAllocVmErr(ret))
100    }
101}
102
103/*
104#[link(name = "ntdll")]
105extern "system" {
106    fn NtProtectVirtualMemory(
107        ProcessHandle: HANDLE,
108        BaseAddress: *const PVOID,
109        RegionSize: PSIZE_T,
110        NewProtect: ULONG,
111        OldProtect: PULONG,
112    ) -> NTSTATUS;
113}
114*/
115pub unsafe fn nt_protect_vm(
116    base_addr: *const PVOID,
117    size: PSIZE_T,
118    new_protect: ULONG,
119) -> Result<()> {
120    if p_nt_protect_vm == 0 as _ {
121        p_nt_protect_vm =
122            get_proc_address_by_name(load_library("ntdll.dll")?, "NtProtectVirtualMemory")? as _;
123    };
124
125    let old_protect: ULONG = 0;
126    let ret = mem::transmute::<
127        usize,
128        unsafe extern "system" fn(HANDLE, *const PVOID, PSIZE_T, ULONG, PULONG) -> NTSTATUS,
129    >(p_nt_protect_vm)(
130        GetCurrentProcess(),
131        base_addr,
132        size,
133        new_protect,
134        &old_protect as PULONG,
135    );
136
137    if 0 == ret {
138        Ok(())
139    } else {
140        Err(Error::NtProtectVmErr(ret))
141    }
142}