Functions exported only by ordinal are now correctly handled

This includes, for example, ntdll's ordinal 8, which is not exported by name.
This commit is contained in:
Kudaes
2024-11-02 15:33:52 +01:00
parent a4cd7035dc
commit f525607c97
3 changed files with 71 additions and 24 deletions
+38 -8
View File
@@ -116,8 +116,14 @@ fn print_usage(program: &str, opts: Options) {
print!("{}", opts.usage(&brief));
}
fn demangle_name(mangled_name: &String) -> String
fn demangle_name(mangled_name: &String, ordinal: u32) -> String
{
if mangled_name.is_empty() {
let placeholder = format!("{}{}", "OrdinalPlaceholder", ordinal);
return placeholder;
}
let demangled: String = mangled_name
.replace("?", "1")
.replace("!", "2")
@@ -149,15 +155,21 @@ fn generate_tracer_dll(original_dll_path: String, log_path: String, link_runtime
for (i,name) in names_info.iter().enumerate()
{
let demangled_name = demangle_name(&name.0);
let demangled_name = demangle_name(&name.0, name.1);
let template1 = TEMPLATE1.replace("{FUNC_NAME}", &demangled_name).replace("{INDEX}", &i.to_string());
first_string.push_str(&template1);
let template2 = TEMPLATE2.replace("{NUM}", &i.to_string()).replace("{NAME}", &demangled_name);
second_string.push_str("\n\t\t");
second_string.push_str(&template2);
let export_string = format!("{}={} @{}\n",&name.0, demangled_name, name.1);
def_file_string.push_str(&export_string);
if name.0.is_empty() {
let export_string = format!("{}={} @{}\n",demangled_name, demangled_name, name.1);
def_file_string.push_str(&export_string);
} else {
let export_string = format!("{}={} @{}\n",&name.0, demangled_name, name.1);
def_file_string.push_str(&export_string);
}
}
let ending = "\n\t\t_ => {String::new()}\n\t}\n} ";
@@ -225,14 +237,14 @@ fn generate_proxy_dll(original_dll_path: String, hijacked_exports: Vec<&str>, na
let mut index = 0u32;
for (_, name) in names_info.iter().enumerate()
{
let demangled_name = demangle_name(&name.0);
if !mangled_names_detected && (demangled_name != name.0)
let demangled_name = demangle_name(&name.0, name.1);
if !mangled_names_detected && (demangled_name != name.0) && !demangled_name.contains("OrdinalPlaceholder")
{
mangled_names_detected = true;
println!("[!] Exported functions with mangled names detected in the source DLL. Proxying will be disabled for those symbols.");
}
if hijacked_exports.contains(&name.0.as_str())
if !&name.0.is_empty() && hijacked_exports.contains(&name.0.as_str())
{
println!("[+] Exported function {} found.", &name.0);
let template4 = TEMPLATE4.replace("{FUNC_NAME}", &demangled_name).replace("{INDEX}", &index.to_string());
@@ -262,7 +274,11 @@ fn generate_proxy_dll(original_dll_path: String, hijacked_exports: Vec<&str>, na
let export_string;
if demangled_name != name.0 {
export_string = format!("{}={} @{}\n",&name.0, demangled_name, name.1);
if demangled_name.contains("OrdinalPlaceholder") {
export_string = format!("{}={}.#{} @{}\n", demangled_name, module_name, name.1, name.1);
} else {
export_string = format!("{}={} @{}\n",&name.0, demangled_name, name.1);
}
} else {
export_string = format!("{}={}.{} @{}\n", &name.0, module_name, &name.0, name.1);
}
@@ -333,6 +349,7 @@ pub fn get_function_info(module_base_address: usize) -> Vec<(String,u32)> {
let export_rva = *(p_export as *mut i32);
let ordinal_base = *((module_base_address + export_rva as usize + 0x10) as *mut u32);
let number_of_exports = *((module_base_address + export_rva as usize + 0x14) as *mut u32);
let number_of_names = *((module_base_address + export_rva as usize + 0x18) as *mut u32);
let names_rva = *((module_base_address + export_rva as usize + 0x20) as *mut u32);
let ordinals_rva = *((module_base_address + export_rva as usize + 0x24) as *mut u32);
@@ -355,6 +372,19 @@ pub fn get_function_info(module_base_address: usize) -> Vec<(String,u32)> {
}
let ordinals_list: Vec<u32> = functions_info.iter().map(|(_, num)| *num).collect();
if number_of_exports > number_of_names
{
for i in 0..number_of_exports
{
let current_ordinal = ordinal_base + i as u32;
if !ordinals_list.contains(&current_ordinal) {
functions_info.push((String::new(),current_ordinal)); // This takes care of those functions exported exclusively by ordinal, like ntdll's ordinal 8
}
}
}
functions_info
}
+30 -10
View File
@@ -7,10 +7,7 @@ const LOG_NAME: &str = r"{LOG_PATH}";
static mut ADDRESSES: [usize;{NUM_FUNCTIONS}] = [0;{NUM_FUNCTIONS}];
fn terminate_process()
{
let mut file = fs::OpenOptions::new().create(true).append(true).open(LOG_NAME).unwrap();
file.write_all(b"\nError ocurred!").unwrap();
fn terminate_process() {
process::exit(-1);
}
@@ -18,15 +15,19 @@ fn gateway(index: i32) -> usize
{
let func_name = get_function_name(index);
if func_name.is_empty() {
let mut file = fs::OpenOptions::new().create(true).append(true).open(LOG_NAME).unwrap();
if func_name.is_empty()
{
file.write_all(b"[x] Error ocurred, empty function name detected.").unwrap();
return (terminate_process as *const()) as usize;
}
unsafe
{
if ADDRESSES[index as usize] != 0
{
let mut file = fs::OpenOptions::new().create(true).append(true).open(LOG_NAME).unwrap();
file.write_all(func_name.as_bytes()).unwrap();
file.write_all(b"\n").unwrap();
return ADDRESSES[index as usize];
@@ -37,17 +38,36 @@ fn gateway(index: i32) -> usize
file.write_all(func_name.as_bytes()).unwrap();
file.write_all(b"\n").unwrap();
let dll_address = dinvoke_rs::dinvoke::load_library_a(DLL_NAME);
if dll_address == 0 {
if dll_address == 0
{
let error_message = format!("[x] Error trying to load the dll {}.", DLL_NAME);
file.write_all(error_message.as_bytes()).unwrap();
return (terminate_process as *const()) as usize;
}
let mut func_address = dinvoke_rs::dinvoke::get_function_address(dll_address, &func_name);
if func_address == 0 && func_name.contains("OrdinalPlaceholder")
{
let ordinal = func_name.replace("OrdinalPlaceholder", "");
let ordinal: u32 = ordinal.parse().unwrap();
func_address = dinvoke_rs::dinvoke::get_function_address_by_ordinal(dll_address, ordinal);
}
if func_address == 0
{
let error_message = format!("[x] Error trying to locate the function {}.", func_name);
file.write_all(error_message.as_bytes()).unwrap();
return (terminate_process as *const()) as usize;
}
let func_address = dinvoke_rs::dinvoke::get_function_address(dll_address, &func_name);
unsafe {
ADDRESSES[index as usize] = func_address;
}
file.write_all(func_name.as_bytes()).unwrap();
file.write_all(b"\n").unwrap();
func_address
}
+3 -6
View File
@@ -70,20 +70,17 @@ fn gateway(arg1:u64, arg2:u64, arg3:u64, arg4:u64, arg5:u64, arg6:u64, arg7:u64,
_ => "".to_string(),
};
if func_name.is_empty()
{
if func_name.is_empty() {
return 0;
}
let dll_address = dinvoke_rs::dinvoke::load_library_a(DLL_NAME);
if dll_address == 0
{
if dll_address == 0 {
return 0;
}
let func_address = dinvoke_rs::dinvoke::get_function_address(dll_address, &func_name);
if func_address == 0
{
if func_address == 0 {
return 0;
}