Skip to content

Commit

Permalink
Add cleanup for duplicate loads of Deucalion
Browse files Browse the repository at this point in the history
Essentially just call FreeLibrary for each extra LoadLibrary call.
Uses GlblcntUsage from  MODULEENTRY32, which seems to work fine for
injected DLLs. This is a best-effort attempt, so it won't do anything
if there are any issues with this approach.
  • Loading branch information
ff14wed committed Jul 7, 2024
1 parent 17b0d51 commit f7362be
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 1 deletion.
1 change: 1 addition & 0 deletions deucalion/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ winapi = { version = "0.3", features = [
"libloaderapi",
"consoleapi",
"wincon",
"tlhelp32",
] }

[dev-dependencies]
Expand Down
9 changes: 8 additions & 1 deletion deucalion/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::path::PathBuf;
use std::time::SystemTime;

use simplelog::{LevelFilter, WriteLogger};
use w32module::drop_ref_count_to_one;
#[cfg(windows)]
use winapi::shared::minwindef::*;
use winapi::um::libloaderapi;
Expand All @@ -24,6 +25,7 @@ use tokio::select;
use tokio::sync::oneshot;

mod hook;
mod w32module;

pub mod namedpipe;
pub mod procloader;
Expand Down Expand Up @@ -152,10 +154,12 @@ async fn main_with_result() -> Result<()> {
Ok(())
}

const DLL_PROCESS_ATTACH: u32 = 1;

#[allow(non_snake_case)]
#[no_mangle]
unsafe extern "system" fn DllMain(hModule: HINSTANCE, reason: u32, _: u32) -> BOOL {
if reason == 1 {
if reason == DLL_PROCESS_ATTACH {
processthreadsapi::CreateThread(
0 as LPSECURITY_ATTRIBUTES,
0,
Expand Down Expand Up @@ -220,6 +224,9 @@ unsafe extern "system" fn main(dll_base_addr: LPVOID) -> u32 {
error!("Panic happened: {cause:?}");
pause();
}
if let Err(e) = drop_ref_count_to_one(dll_base_addr as HMODULE) {
error!("Could not drop ref count to one: {e}")
}
info!("Shut down!");
#[cfg(debug_assertions)]
wincon::FreeConsole();
Expand Down
86 changes: 86 additions & 0 deletions deucalion/src/w32module.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
use anyhow::{format_err, Result};

use winapi::{
shared::{minwindef::HMODULE, ntdef::HANDLE},
um::{
errhandlingapi::GetLastError,
handleapi::CloseHandle,
libloaderapi::FreeLibrary,
processthreadsapi::GetCurrentProcessId,
tlhelp32::{
CreateToolhelp32Snapshot, Module32First, Module32Next, MODULEENTRY32, TH32CS_SNAPMODULE,
},
},
};

use log::info;

struct TH32Handle(HANDLE);

impl TH32Handle {
unsafe fn new(handle: HANDLE) -> Result<Self> {
if handle.is_null() {
return Err(format_err!(
"Failed to call CreateToolhelp32Snapshot: {}",
GetLastError()
));
}
Ok(TH32Handle(handle))
}
}
impl Drop for TH32Handle {
fn drop(&mut self) {
unsafe {
let _ = CloseHandle(self.0);
}
}
}

unsafe fn get_ref_count(hmodule: HMODULE) -> Result<u32> {
let pid = GetCurrentProcessId();
let snapshot_handle = TH32Handle::new(CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid))?;

let mut me32: MODULEENTRY32 = core::mem::zeroed();
let me32_size = std::mem::size_of::<MODULEENTRY32>() as u32;
me32.dwSize = me32_size;

if Module32First(snapshot_handle.0, &mut me32) == 0 {
return Err(format_err!(
"Failed to call Module32First: {}",
GetLastError()
));
}

let mut more_modules: bool = true;

while more_modules {
if hmodule == me32.hModule {
if me32.GlblcntUsage == 0xFFFF {
continue;
}
return Ok(me32.GlblcntUsage);
}
more_modules = Module32Next(snapshot_handle.0, &mut me32) > 0;
}
Err(format_err!("Could not find ref count for current module"))
}

pub unsafe fn drop_ref_count_to_one(hmodule: HMODULE) -> Result<()> {
let count = get_ref_count(hmodule)?;
if count <= 1 {
return Ok(());
}
info!(
"Ref count is {count}. Calling FreeLibrary {} extra time(s)...",
count - 1
);
for _ in 0..count - 1 {
if FreeLibrary(hmodule) == 0 {
return Err(format_err!(
"Failed to call FreeLibrary: {}",
GetLastError()
));
};
}
Ok(())
}

0 comments on commit f7362be

Please sign in to comment.