diff --git a/memflow-win32/src/win32/keyboard.rs b/memflow-win32/src/win32/keyboard.rs index ff4cf9e..7e5c5fc 100644 --- a/memflow-win32/src/win32/keyboard.rs +++ b/memflow-win32/src/win32/keyboard.rs @@ -116,6 +116,46 @@ impl Win32Keyboard { >( kernel: &mut Win32Kernel, ) -> Result<(Win32ProcessInfo, Address)> { + /* + ref: https://www.unknowncheats.me/forum/3359384-post23.html + Since Win11, key state bitmap has been moved into win32ksgd.sys + + Previously, Windows 10's win32kfull.sys would store the key buffer in gafAsyncKeyState + but, since Win11, the key buffer is now stored in win32ksgd.sys under gSessionGlobalSlots. + + There is a global session slot for each session active on the machine so we need to offset + the list with the target session. Currently, it is hardcoded to Session 1. + + Win10 key presence test: + + (*((_BYTE *)&gafAsyncKeyState + (virtual_key_code >> 2)) & (unsigned __int8)(1 << (2 * (virtual_key_code & 3)))) + + Win11 key presence test: + + *(_BYTE *)((virtual_key_code >> 2) + SGDGetUserSessionState() + 0x3690) & (1 << (2 * (virtual_key_code & 3))) + + It is worth exploring win32ksgd!SGDGetUserSessionState and win32ksgd!SGDGetSessionState + + __int64 SGDGetUserSessionState() + { + // Dereference the session state pointer + return *SGDGetSessionState(); + } + + void * SGDGetSessionState() + { + int CurrentProcessSessionId; + + CurrentProcessSessionId = GetCurrentProcessSessionId(); + if ( CurrentProcessSessionId ) + return (void *)*((void *)gSessionGlobalSlots + (unsigned int)(CurrentProcessSessionId - 1)); + else + return gLowSessionGlobalSlots; + } + + To replicate this via DRM, we need to find our session's gSessionGlobalSlot, dereference the pointer three times, and add the 0x3690 hardcoded offset. + + */ let win32kbase_module_info = kernel.module_by_name("win32kbase.sys")?; debug!("found win32kbase.sys: {:?}", win32kbase_module_info); @@ -150,25 +190,56 @@ impl Win32Keyboard { let user_process_info = kernel.process_info_by_pid(pid)?; let user_process_info_win32 = kernel.process_info_from_base_info(user_process_info.clone())?; - let mut user_process = kernel.process_by_info(user_process_info)?; - debug!( - "trying to find gaf signature in user proxy process `{}`", - user_process.info().name.as_ref() - ); + + // Win32k temporary session global driver was first introduced in 22H2 (10.0.22621.1) (2022-09-20) + // so we cannot be sure it will be active on all Win11 devices + if kernel.kernel_info.kernel_winver >= (10, 0, 22621).into() { + debug!("Windows 11 detected."); + + let win32ksgd_module_info = kernel.module_by_name("WIN32KSGD.SYS")?; + debug!("Found win32ksgd.sys: {:?}", win32ksgd_module_info); + + let mut user_process: crate::win32::Win32Process, Fwd<&mut V>, Win32VirtualTranslate> = kernel.process_by_info(user_process_info)?; + + let g_session_global_slots_offset = 0x3110; + debug!("gSessionGlobalSlot address: {:?}", win32ksgd_module_info.base + g_session_global_slots_offset); + + let g_session_global_slot_first_deref = user_process.virt_mem.read_addr_arch(win32ksgd_module_info.arch.into(), win32ksgd_module_info.base + g_session_global_slots_offset)?; + debug!("gSessionGlobalSlot 1st deref: {:?}", g_session_global_slot_first_deref); + + let g_session_global_slot_second_deref = user_process.virt_mem.read_addr_arch(win32ksgd_module_info.arch.into(), g_session_global_slot_first_deref)?; + debug!("gSessionGlobalSlot 2nd deref: {:?}", g_session_global_slot_second_deref); + + let g_session_global_slot_third_deref = user_process.virt_mem.read_addr_arch(win32ksgd_module_info.arch.into(), g_session_global_slot_second_deref)?; + debug!("gSessionGlobalSlot 3rd deref: {:?}", g_session_global_slot_third_deref); + + debug!("Key State Buffer Address: {:?}", g_session_global_slot_third_deref + 0x3690); + + Ok(( + user_process_info_win32, + g_session_global_slot_third_deref + 0x3690, + )) + } else { + let mut user_process = kernel.process_by_info(user_process_info)?; + debug!( + "trying to find gaf signature in user proxy process `{}`", + user_process.info().name.as_ref() + ); - // TODO: lazy + // TODO: lazy let export_addr = Self::find_gaf_pe(&mut user_process.virt_mem, win32kbase_module_info) .or_else(|_| Self::find_gaf_sig(&mut user_process.virt_mem, win32kbase_module_info))?; - debug!( - "found gaf signature in user proxy process `{}` at {:x}", - user_process.info().name.as_ref(), - export_addr - ); - - Ok(( - user_process_info_win32, - win32kbase_module_info.base + export_addr, - )) + debug!( + "found gaf signature in user proxy process `{}` at {:x}", + user_process.info().name.as_ref(), + export_addr + ); + + Ok(( + user_process_info_win32, + win32kbase_module_info.base + export_addr, + )) + } } fn find_gaf_pe(