Skip to content

Commit

Permalink
Fixed invalid relative address calculation and improved signature search
Browse files Browse the repository at this point in the history
  • Loading branch information
WolverinDEV committed Mar 12, 2024
1 parent ca4c9fe commit e0355d8
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 173 deletions.
18 changes: 8 additions & 10 deletions driver/src/mouse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ use kdef::{
};
use obfstr::obfstr;
use valthrun_driver_shared::{
ByteSequencePattern,
MouseState,
Signature,
};
use winapi::{
km::wdm::DRIVER_OBJECT,
Expand Down Expand Up @@ -124,18 +124,16 @@ fn find_mouse_service_callback() -> anyhow::Result<MouseClassServiceCallbackFn>
let module_kdbclass = KModule::find_by_name(obfstr!("mouclass.sys"))?
.with_context(|| anyhow!("failed to locate {} module", obfstr!("mouclass.sys")))?;

let pattern =
ByteSequencePattern::parse(obfstr!("48 8D 05 ? ? ? ? 48 89 44")).with_context(|| {
obfstr!("Failed to compile MouseClassServiceCallback pattern").to_string()
})?;

NtOffsets::locate_function(
&module_kdbclass,
[/* Windows 11 */ Signature::relative_address(
obfstr!("MouseClassServiceCallback"),
&pattern,
obfstr!("48 8D 05 ? ? ? ? 48 89 44"),
0x03,
0x07,
)
)]
.iter()
.find_map(|sig| NtOffsets::locate_signature(&module_kdbclass, sig).ok())
.map(|v| unsafe { core::mem::transmute_copy(&v) })
.with_context(|| obfstr!("Failed to find MouseClassServiceCallback").to_string())
}

#[allow(unused)]
Expand Down
194 changes: 39 additions & 155 deletions driver/src/offsets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,12 @@ use alloc::{
format,
string::ToString,
};
use core::{
cell::SyncUnsafeCell,
ptr,
};
use core::cell::SyncUnsafeCell;

use anyhow::Context;
use kapi::{
Mdl,
PagePriority,
IO_READ_ACCESS,
MCT_CACHED,
KeGetCurrentIrql,
DISPATCH_LEVEL,
};
use kapi_kmodule::{
KModule,
Expand All @@ -26,9 +21,11 @@ use valthrun_driver_shared::{
SignatureType,
};
use winapi::{
ctypes::c_void,
km::wdm::KPROCESSOR_MODE,
shared::ntdef::PVOID,
um::winnt::{
IMAGE_SCN_MEM_DISCARDABLE,
IMAGE_SCN_MEM_READ,
},
};

/// Undocumented function/struct offsets
Expand All @@ -48,20 +45,16 @@ pub fn get_nt_offsets() -> &'static NtOffsets {
}

fn find_mm_verify_callback_function_flags_old(kernel_base: &KModule) -> anyhow::Result<usize> {
let pattern = ByteSequencePattern::parse(obfstr!(
"E8 ?? ?? ?? ?? 85 C0 0F 84 ?? ?? ?? ?? 48 8B 4D 00"
))
.with_context(|| {
obfstr!("Failed to compile MmVerifyCallbackFunctionFlags pattern").to_string()
})?;

NtOffsets::locate_function(
&kernel_base,
let sig = Signature::relative_address(
obfstr!("MmVerifyCallbackFunctionFlags"),
&pattern,
obfstr!("E8 ?? ?? ?? ?? 85 C0 0F 84 ?? ?? ?? ?? 48 8B 4D 00"),
0x01,
0x05,
)
);

NtOffsets::locate_signature(kernel_base, &sig).with_context(|| {
obfstr!("Failed to compile MmVerifyCallbackFunctionFlags pattern").to_string()
})
}

fn find_mm_verify_callback_function_flags_new(kernel_base: &KModule) -> anyhow::Result<usize> {
Expand Down Expand Up @@ -96,6 +89,7 @@ fn find_mm_verify_callback_function_flags_new(kernel_base: &KModule) -> anyhow::
}

pub fn initialize_nt_offsets() -> anyhow::Result<()> {
assert!(KeGetCurrentIrql() < DISPATCH_LEVEL);
let ntoskrnl = KModule::find_by_name(obfstr!("ntoskrnl.exe"))?
.with_context(|| obfstr!("failed to find kernel base").to_string())?;

Expand Down Expand Up @@ -186,39 +180,31 @@ impl NtOffsets {
module.file_name
);

let (section, mdl, inst_offset) = module
let (section, inst_offset) = module
.find_code_sections()?
.into_iter()
.find_map(|section| {
if !section.is_data_valid() {
if (section.characteristics & IMAGE_SCN_MEM_DISCARDABLE) != 0 {
/* Section is discardable and most likely has been discarded */
log::debug!(
" Skipping {} as it's discardable ({:X})",
section.name,
section.characteristics
);
return None;
}
if (section.characteristics & IMAGE_SCN_MEM_READ) == 0 {
/* Section is not readable */
log::debug!(
" Skipping {} as it's not readable ({:X})",
section.name,
section.characteristics
);
return None;
}

let mdl = Mdl::allocate(
section.raw_data_address() as *mut c_void,
section.size_of_raw_data,
false,
false,
ptr::null_mut(),
)?;

let mdl = mdl
.lock(KPROCESSOR_MODE::KernelMode, IO_READ_ACCESS)
.inspect_err(|_| log::warn!("Failed to lock section {}", section.name))
.ok()?;

let mdl = mdl
.map(
KPROCESSOR_MODE::KernelMode,
MCT_CACHED,
None,
PagePriority::NORMAL,
)
.inspect_err(|_| log::warn!("Failed to map locked section {}", section.name))
.ok()?;

if let Some(offset) = signature.pattern.find(mdl.as_slice()) {
Some((section, mdl, offset))
if let Some(offset) = signature.pattern.find(section.raw_data_unchecked()) {
Some((section, offset))
} else {
None
}
Expand All @@ -233,130 +219,28 @@ impl NtOffsets {
}

let value = unsafe {
(mdl.address() as *const ())
(section.raw_data_address() as *const ())
.byte_add(inst_offset)
.byte_add(signature.offset as usize)
.cast::<u32>()
.read_unaligned()
};
match &signature.value_type {
SignatureType::Offset => {
let value = value as usize;
log::trace!(" => {:X} (inst at {:X})", value, inst_offset);
Ok(value as usize)
Ok(value)
}
SignatureType::RelativeAddress { inst_length } => {
let value = section
.raw_data_address()
.wrapping_add(inst_offset)
.wrapping_add(*inst_length)
.wrapping_add_signed(value as isize) as usize;
log::trace!(
" => {:X} ({:X})",
value,
value - section.raw_data_address()
);
.wrapping_add_signed(value as i32 as isize);
log::trace!(" => {:X} ({:X})", value, value - module.base_address,);
Ok(value)
}
SignatureType::Pattern => unreachable!(),
}
}

pub fn locate_function<T>(
module: &KModule,
name: &str,
pattern: &dyn SearchPattern,
offset_rel_address: isize,
instruction_length: usize,
) -> anyhow::Result<T>
where
T: Sized,
{
let pattern_match = module
.find_code_sections()?
.into_iter()
.find_map(|section| {
// if let Some(memory) = LockedVirtMem::create(section.raw_data_address() as u64, section.size_of_raw_data, winapi::km::wdm::KPROCESSOR_MODE::UserMode, IO_READ_ACCESS, MCT_CACHED) {
// if let Some(offset) = pattern.find(memory.memory()) {
// Some(offset + section.raw_data_address())
// } else {
// None
// }
// } else {
// log::warn!(
// "Skipping {}::{} as section data could not be locked",
// module.file_name,
// section.name
// );
// None
// }
if let Some(data) = section.raw_data() {
if let Some(offset) = pattern.find(data) {
Some(offset + section.raw_data_address())
} else {
None
}
} else {
log::warn!(
"Skipping {}::{} as section data is not valid / paged out",
module.file_name,
section.name
);
None
}
})
.with_context(|| format!("failed to find {} pattern", name))?;

let offset = unsafe {
(pattern_match as *const ())
.byte_offset(offset_rel_address)
.cast::<i32>()
.read_unaligned()
};

let target = pattern_match
.wrapping_add_signed(offset as isize)
.wrapping_add(instruction_length);

log::debug!(
"{}::{} located at {:X} ({:X})",
module.file_name,
name,
target - module.base_address,
target
);
unsafe { Ok(core::mem::transmute_copy::<_, T>(&target)) }
}

pub fn locate_offset(
module: &KModule,
name: &str,
pattern: &dyn SearchPattern,
inst_offset: isize,
) -> anyhow::Result<usize> {
let pattern_match = module
.find_code_sections()?
.into_iter()
.find_map(|section| {
if let Some(data) = section.raw_data() {
if let Some(offset) = pattern.find(data) {
Some(offset + section.raw_data_address())
} else {
None
}
} else {
None
}
})
.with_context(|| format!("failed to find {} pattern", name))?;

let offset = unsafe {
(pattern_match as *const ())
.byte_offset(inst_offset)
.cast::<u32>()
.read_unaligned()
};

log::debug!("{}::{} resolved to {:X}", module.file_name, name, offset);
Ok(offset as usize)
}
}
20 changes: 12 additions & 8 deletions utils/kapi-kmodule/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ pub struct KModuleSection {
pub module_base: usize,
pub virtual_address: usize,
pub size_of_raw_data: usize,
pub characteristics: u32,
}

impl KModuleSection {
Expand All @@ -82,6 +83,7 @@ impl KModuleSection {
module_base: module.base_address,
virtual_address: header.VirtualAddress as usize,
size_of_raw_data: header.SizeOfRawData as usize,
characteristics: header.Characteristics,
}
}

Expand All @@ -90,19 +92,21 @@ impl KModuleSection {
unsafe { (imports.MmIsAddressValid)(self.raw_data_address() as *const () as PVOID) }
}

pub fn raw_data(&self) -> Option<&[u8]> {
if !self.is_data_valid() {
return None;
}

let buffer = unsafe {
pub fn raw_data_unchecked(&self) -> &[u8] {
unsafe {
core::slice::from_raw_parts(
self.raw_data_address() as *const u8,
self.size_of_raw_data as usize,
)
};
}
}

pub fn raw_data(&self) -> Option<&[u8]> {
if !self.is_data_valid() {
return None;
}

Some(buffer)
Some(self.raw_data_unchecked())
}

pub fn raw_data_address(&self) -> usize {
Expand Down

0 comments on commit e0355d8

Please sign in to comment.