Skip to content

Instantly share code, notes, and snippets.

@janoglezcampos
Last active May 22, 2022 10:28
Show Gist options
  • Save janoglezcampos/ac0136af89a6aa3765f00e6e0bf5e375 to your computer and use it in GitHub Desktop.
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.
#[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