Last active
May 22, 2022 10:28
-
-
Save janoglezcampos/ac0136af89a6aa3765f00e6e0bf5e375 to your computer and use it in GitHub Desktop.
Simple function to find the address of a call to a function, in a specified function inside a loaded module.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#[cfg(windows)] | |
extern crate winapi; | |
use std::{ptr, mem::size_of,ffi::CString,}; | |
use libc; | |
use winapi::{ | |
um::{ | |
psapi::{ | |
GetModuleFileNameExW, | |
EnumProcessModules | |
}, | |
winnt::{ | |
HANDLE, | |
LPWSTR | |
}, | |
processthreadsapi::GetCurrentProcess, | |
libloaderapi::GetProcAddress | |
}, | |
shared::{ | |
minwindef::{ | |
BOOL, | |
FALSE, | |
FARPROC, | |
HMODULE, | |
DWORD, | |
LPVOID, | |
MAX_PATH | |
} | |
} | |
}; | |
use win32_error::Win32Error; | |
use thiserror::Error; | |
const CALL_OPCODE: u8 = 0xe8; | |
const MAX_AMOUNT_OF_MODULES: usize = 1024; | |
#[derive(Error, Debug, Clone)] | |
pub enum Error { | |
#[error("Cannot find module on the specified executable!")] | |
InvalidModuleName, | |
#[error("Cannot find call to specified function!")] | |
CallNotFound | |
} | |
#[cfg(windows)] | |
fn get_function_base(remote_handle: HANDLE, module_name: &str, function_name: CString) -> Result<FARPROC, anyhow::Error> { | |
let mut res: BOOL; | |
let mut cb_needed: DWORD = 0; | |
let mut current_module_name: String; | |
let mut module_list: [HMODULE; MAX_AMOUNT_OF_MODULES] = [ptr::null_mut(); MAX_AMOUNT_OF_MODULES]; | |
unsafe { | |
let module_list_size = (size_of::<HMODULE>() * MAX_AMOUNT_OF_MODULES).try_into().unwrap(); | |
res = EnumProcessModules(remote_handle, &mut module_list[0], module_list_size, &mut cb_needed); | |
if res == FALSE { | |
// Retry one more time. | |
res = EnumProcessModules(remote_handle, &mut module_list[0], module_list_size, &mut cb_needed); | |
if res == FALSE { | |
let err = Win32Error::new(); | |
return Err(err.into()); | |
} | |
} | |
for module in module_list { | |
let ptr_current_module_name: LPWSTR; | |
ptr_current_module_name = libc::malloc(MAX_PATH) as LPWSTR; | |
libc::memset(ptr_current_module_name as *mut libc::c_void, 0, MAX_PATH); | |
// Getting the module name. | |
if GetModuleFileNameExW(remote_handle, module, ptr_current_module_name, (MAX_PATH - size_of::<LPWSTR>()).try_into().unwrap()) == 0 { | |
let err = Win32Error::new(); | |
println!("[-] Failed to get modules name: {}", err.to_string()); | |
continue; | |
} | |
// Converting to String so it will be compareable. | |
let len = (0..).take_while(|&i| *ptr_current_module_name.offset(i) != 0).count(); | |
let slice = std::slice::from_raw_parts(ptr_current_module_name, len); | |
match String::from_utf16(slice) { | |
Ok(val) => current_module_name = val, | |
Err(e) => return Err(e.into()) | |
} | |
if current_module_name.contains(module_name) { | |
let function_address = GetProcAddress(module, function_name.as_ptr()); | |
return Ok(function_address); | |
} | |
} | |
} | |
return Err(Error::InvalidModuleName.into()) | |
} | |
#[cfg(windows)] | |
fn find_call_addr(module_name: &str, in_function_name: &str, call_function_name: &str, max_search_offset: u32) -> Result<LPVOID, anyhow::Error>{ | |
let proc_handle: HANDLE = unsafe{GetCurrentProcess()}; | |
let base_function_address: FARPROC; | |
let target_function_addr: FARPROC; | |
let function_base_result: Result<FARPROC, anyhow::Error>; | |
let target_function_addr_result: Result<FARPROC, anyhow::Error>; | |
function_base_result = get_function_base(proc_handle, module_name, CString::new(in_function_name).unwrap()); | |
match function_base_result { | |
Ok(val) => base_function_address = val, | |
Err(e) => return Err(e.into()) | |
} | |
target_function_addr_result = get_function_base(proc_handle, module_name, CString::new(call_function_name).unwrap()); | |
match target_function_addr_result { | |
Ok(val) => target_function_addr = val, | |
Err(e) => return Err(e.into()) | |
} | |
let mut op_code: u8; | |
let mut next_op_addr: u64; | |
let mut call_value: i32; | |
for offset in 0..max_search_offset as u64 { | |
op_code = unsafe { *((base_function_address as u64 + offset) as *mut _) }; | |
if op_code == CALL_OPCODE { | |
next_op_addr = base_function_address as u64 + offset + 5; | |
call_value = unsafe { *((base_function_address as u64 + offset + 1) as *mut _) }; | |
if target_function_addr == (next_op_addr as i64 + call_value as i64) as FARPROC { | |
println!("[-] Call value: {:#?}", call_value); | |
return Ok((base_function_address as u64 + offset) as LPVOID); | |
} | |
} | |
} | |
return Err(Error::CallNotFound.into()); | |
} | |
#[cfg(windows)] | |
fn main() { | |
println!("[-] Found call at: {:#?}", find_call_addr("ntdll.dll", "RtlExitUserThread", "NtTerminateThread", 1000).unwrap()); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment