Where in the code does it find our key?
Using Process Monitor, digging into the for the ETL event reading out that value stack trace gives us:
"Frame","Module","Location","Address","Path"
...
"3","ntdll.dll","NtQueryValueKey + 0xa","0x7fbce17344a","C:\Windows\SYSTEM32\ntdll.dll"
"4","KERNELBASE.dll","LocalBaseRegQueryValue + 0x15d","0x7fbcb1a3e1d","C:\Windows\system32\KERNELBASE.dll"
"5","KERNELBASE.dll","RegQueryValueExW + 0xe9","0x7fbcb1a3c19","C:\Windows\system32\KERNELBASE.dll"
"6","ADVAPI32.dll","RegQueryValueExWStub + 0x1e","0x7fbcba412fe","C:\Windows\system32\ADVAPI32.dll"
"7","osk.exe","OSKSettingsManager::GetOskSetting + 0xc7","0x7f72356057f","C:\Windows\System32\osk.exe"
"8","osk.exe","OSKSettingsManager::Initialize + 0x6e","0x7f72355ffe2","C:\Windows\System32\osk.exe"
"9","osk.exe","OSKSettingsManager::GetOSKSettingsManager + 0x64","0x7f72355fee4","C:\Windows\System32\osk.exe"
"10","osk.exe","COskNativeHWNDHost::DetermineOSKWindowSizeAndLimits + 0x5a","0x7f72355d4fa","C:\Windows\System32\osk.exe"
"11","osk.exe","COskNativeHWNDHost::Initialize + 0xaa","0x7f72355d28e","C:\Windows\System32\osk.exe"
"12","osk.exe","PresentOSK + 0x112","0x7f723557882","C:\Windows\System32\osk.exe"
"13","osk.exe","wWinMain + 0x356","0x7f723557f16","C:\Windows\System32\osk.exe"
"14","osk.exe","operator new[] + 0x37a","0x7f723564b12","C:\Windows\System32\osk.exe"
"15","KERNEL32.DLL","BaseThreadInitThunk + 0x1a","0x7fbcd24298e","C:\Windows\system32\KERNEL32.DLL"
"16","ntdll.dll","RtlUserThreadStart + 0x1d","0x7fbce19e229","C:\Windows\SYSTEM32\ntdll.dll"
We can see that OSKSettingsManager::GetOskSetting
reads out the value.
So, what does that portion look like? Can we debug it?
Looking into that function with WinDBG, it accesses that registry key right before 000007f7 23560517
.
osk!OSKSettingsManager::GetOskSetting:
...
000007f7`2356050e ff15440bfeff call qword ptr [osk!_imp_RegOpenKeyExW (000007f7`23541058)]
000007f7`23560514 448bd8 mov r11d,eax
000007f7`23560517 85c0 test eax,eax
000007f7`23560519 751f jne osk!OSKSettingsManager::GetOskSetting+0x82 (000007f7`2356053a)
000007f7`2356051b 488b0b mov rcx,qword ptr [rbx]
...
Now, the problem here is that when I try to breakpoint at that location I can no longer type anything because osk.exe
adds itself to the input drivers. This can easily be seen by holding a modifier key like Alt on your keyboard, this lights it up in osk.exe
.
Looking through the code for additions or subtractions, I only see something happen with 40
hexadecimal which is 64
decimal. So that's also nothing related to the number.
It might be in one of the four cmp
(compare) instructions, but that would require debugging information. Or it could happen in a higher up function altogether, which would require more investigation. But without the ability to debug it without losing input capabilities, this is a very hard thing to do...
Seems that finding the right location will require a debug cable as the computer on which you debug loses its input capabilities, or is way too slow due to the overhead of debugging. As I don't currently have a laptop with a 1943 port, I'm unable to do this debugging myself. It would be able to do this, and yes, it would literally freeze your OS. Debugging an OS instead of an application is fun... ^^
Wait, we have access to the symbols! Can we find the offending code?
OSKSettingsManager::ClearTransferKey(void)
OSKSettingsManager::GetOSKSettingsManager(OSKSettingsManager * *)
OSKSettingsManager::GetOskSetting(ulong,ulong *)
OSKSettingsManager::GetOskSetting(ulong,ulong *,int)
OSKSettingsManager::Initialize(void)
OSKSettingsManager::NotifyListeners(ulong,ulong)
OSKSettingsManager::RegisterListener(void (*)(ulong,ulong))
OSKSettingsManager::SQMStartupSettings(void)
OSKSettingsManager::SetOskSetting(ulong,ulong)
OSKSettingsManager::SetOskSetting(ulong,ulong,int)
OSKSettingsManager::_HandleUpdateAllListeners(void)
OSKSettingsManager::_KeepSettingValueInBounds(ulong,ulong *,int)
OSKSettingsManager::`scalar deleting destructor'(uint)
Taking a closer look, you'll notice the offending function:
OSKSettingsManager::_KeepSettingValueInBounds(ulong,ulong *,int)
If we walk through that function we first see:
mov edi, edi
push ebp
mov ebp, esp
mov eax, [ebp+arg_4]
imul eax, 14h
cmp dword_4B7598[eax], 0
jz short loc_41BC36
Okay, this compares something and then jumps to another location. What's there?
pop ebp
retn 8
So, if the condition decides that it must jump it will just leave the function and not change anything.
So, how do we make it always leave the function?
Change the jz
instruction into a jmp
instruction which always do the jump, you can find it at relative offset 41BC10
. In case your program calculates offsets different, you need to know that it uses 401000
as a basis so subtracting gives us the absolute offset 1AC10
.
Please note that changing 74
(JZ
) in the hex editor to E9
(JMP
) won't work. You can't do this in a hex editor, you will need something that disassembles and reassembles the code but that's not necessarily easy to find (eg. IDA Professional which people actually pay for, can't produce proper c code or an executable. OllyDBG, commonly used in the patch community, can't even open the executable.). And then even, Microsoft might be protecting its executable against tampering, because this could be considered against the EULA; so, good luck!
Meh! This is hard, I just want to type fast using my mouse / eyes / ...
You should definitely check out Dasher which is way faster than an On-Screen Keyboard. It simply works by moving your mouse towards letters; horizontal movement determines the speed and vertical movement select the letters. With a dictionary built in it can even size the most likely letters to be bigger, it also tries to learn from your movement such that the speed and letters are really accustomed to your usage.
An image speaks more than a thousand words...
Of course this is rather small and not really fast as it's an example, but you could resize it to be at the right side of your screen such that it does not interfere with your screen. This allows you to type as fast as you can...
Here is a good example of how the predictions allow you to type any language more quickly:
Also note that the letters at the right are sorted in a specific order, such that the major direction (up, mid or down) chooses between the different types (lowercase, uppercase, numbers and punctuation); and then within such major direction, your minor direction will choose between A-Z, a-z, 0-9 and so on. I've used this in the past and was actually amazed by how fluent this is compared to other competitors...
Also note that Dasher has some configuration, so you might be able to adjust something you don't like.