9

I have to use the On-Screen Keyboard of Windows 7 for typing:

(In case you haven't used it yet, you can get it via: All Programs -> Accessories -> Ease of Access -> On-Screen Keyboard

or simply search for "osk.exe")

On-Screen Keyboard

It offers a feature to "hover" about the buttons. Microsoft describes it as the following:

In hovering mode, you use a mouse or joystick to point to a key for a predefined period of time, and the selected character is typed automatically.

There is my specific problem. The predefined period of time is too long to be useful for me. The minimum amount of time is 0.5 seconds (max. 3 seconds).

Is there any way to alter this value to something < 0.5? For example via editing the registry?

Edit: The entry HKEY_CURRENT_USER\Software\Microsoft\Osk\HoverPeriod cannot be set lower than 500 ms.

Edit (2): I think the only way to fix my problem, is to decompile the .exe (I guess it's written in C, or?) and change the minimum time. Then I have to compile it again. Is this procedure even workable? What things could fail?

Any helpful tip would be great!

7
  • 1
    Recompiling is going to be a hard thing, it will be 1) mostly unreadable (even if you use Microsoft's Symbols) and 2) you don't know where it does that check so you may get around if you find a variable assigned to 500 or 0.5 but then still you have to track down the path where it flows and 3) you still have to get the whole thing recompiled which is often not possible due to bad decompilation. Sadly, debugging is also not possible unless you have a debug cable and attach your computer to another one... Mar 26, 2012 at 19:47
  • I think it would be wise just to leave it as it is. One character every half second isn't that bad, and if it gets too fast mistakes will start to occur.
    – cutrightjm
    Mar 29, 2012 at 17:02
  • Since I can not conveniently edit my comment on this post, this might help some people who know C# or other languages to write a patch for this: daniweb.com/hardware-and-software/microsoft-windows/threads/…
    – cutrightjm
    Mar 29, 2012 at 17:09
  • @fnst: If you really are interested in speed, consider Dasher. I'll outline it in my answer... Mar 29, 2012 at 18:08
  • @ekaj: That just embeds the application, as far as I can tell. Can you tell us how that would help? Mar 29, 2012 at 18:46

4 Answers 4

7

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.

8
  • @harrymc: If you have read Using Process Monitor, digging into the for the ETL event reading out that value stack trace gives us: you would have known that I checked the stack trace for the ETL event. I guess you are talking about your own answers here? Because of answering with a high quantity, your answers seriously lack some quality. Consider improving and/or removing your answers instead of placing quick'n dirty answers or silly comments that don't intent to improve the Q&A; you can guess which approach is going to help the community the most... Mar 28, 2012 at 17:24
  • 1
    @harrymc: (1) Where does it say I am cracking? I'm just showing a starting point here, I did not fail and I've shown out that extra equipment or homework is necessary to proceed forward. The quality is in my answer, the quantity has to be done by the reader or when I come across a remote debugging set-up. (2) Googling Process Monitor and WinDBG is no rocket science. (3) Thanks for the compliment, perhaps I should explain how assembly works in my answer too? Mar 28, 2012 at 18:00
  • @harrymc: My answer is a good starting point. Your mistake lies in not providing enough details, as shown by both your answer and comments in this question. You just found it necessary to place yet another comment that does not intent to improve my answer or does not tell what is wrong with it, it's gonna take you some more time to put up an answer that shows effort instead of being too generic. I don't see how your The decompilation help. Once located, you should patch the binary code. is useful, I'd rather prefer ultra-long and a take-home exercise instead of hair-scratching... Mar 28, 2012 at 18:29
  • @harrymc: You're assuming it is of general purpose; but, if you would have checked its references and dependencies you would have seen that it does not destroy any behavior past overwriting its own configuration, which is loaded solely from that registry key. I have checked its references and dependencies, so I know the uses. Are you going to delete your last comment too? ;) Mar 29, 2012 at 12:09
  • If you have really cracked it, then you are just a few minutes away from creating a patched osk. Why not finish the job and let the poster judge ?
    – harrymc
    Mar 29, 2012 at 18:02
2
+50

I am afraid that most decompilers will not produce a good enough result that can be recompiled.

The decompilation can only help to pinpoint the area that HKEY_CURRENT_USER\Software\Microsoft\Osk\HoverPeriod is used, so as to find out where this value is read and where the 500 ms limit is enforced.

Once located, you should patch the binary code so as to disable the test and enforce HoverPeriod to be smaller. Patching the binary is much more feasible than recompiling.

You might need to repeat the effort if osk.exe is ever replaced by Windows Update (which I don't really expect to happen).

[EDIT]

To help you more on the way, here are some words on utilities and their usage.

You could either use a C-decompiler or a disassembler. The later type may be more useful, although it requires some small knowledge of the Intel instruction set. You will also need a good hex editor, and there are some that advertise disassembler capabilities (see link below).

project fenris advertises itself as "suite of tools suitable for code analysis, debugging, protocol analysis, reverse engineering, forensics, diagnostics, security audits, vulnerability research and many other purposes". Sounds good and recommended by many, but I have no experience with it.

REC Studio Decompiler attempts to produce a C-like representation of the code and data used to build the executable file.

Boomerang is a general, open source, retargetable decompiler of machine code programs.

Many more such utilities can be found by googling, or in :

wikibooks x86 Disassembly/Analysis Tools
wikibooks x86 Disassembly/Disassemblers and Decompilers
Open Directory : Disassemblers

A preliminary step is to disassemble osk. The resulting listing might be voluminous and require a good text-editor (normally notepad++ is enough).

Search for the string "HoverPeriod" (case insensitive). If you are lucky, the disassembler has identified it as a string and you can find it as-is. If not, you will need to search for it byte-by-byte. As a Unicode string it will look like H,0,o,0,v,0... where the letters should be replaced by their numerical codes.

Once you have found the "HoverPeriod" string, the disassembler should have placed a label somewhere before it. Use the name of this generated label to search for where it is used, to identify where it is retrieved from the registry and in which global variable is the result stored.

Once you have located the variable that holds the count, search for where it is used. What you will do depends on the format of the code that you will find. You can then decide on the patch you want.

For example, you may want to use the hex editor to replace in osk.exe a command such as :

move AX,<HoverPeriod milliseconds count variable>

into

mov AX,200       (your count of 200 milliseconds)

Be careful with differing command-lengths, where if the new command is shorter it will need to be padded-out with one-byte NOP instructions (no-operation) to the length of the old instruction.

Locating the command to patch in osk.exe may require searching if the offsets that the disassembler gives are in the code rather than in the exe file. If the hex editor doesn't support assembler search, do the disassembly while listing the original instruction bytes so you will know for which binary bytes to search for. Avoid searching for instructions that contain addresses, since addresses may be relocated in the exe, so rather search for a sequence of bytes near-to such an instruction.

You can create the new patch bytes either directly in the hex editor if it supports assembler. Or if it doesn't and you don't feel comfortable with Intel machine code, find an assembler to compile your new code and use its listing to get the compiled bytes to use for patching.

1
  • Changing the value won't work given that it is overwritten by a more generic function. Changing every value it gets from the registry will break the application. See my answer for this generic function. A hex editor won't work as a result, so it comes down to finding the right (de)assembler (or [de]compiler). Mar 29, 2012 at 10:20
1

May I suggest using AutoIt to automate the clicking?

The idea would be to monitor mouse idling when the cursor is within the on-screen window (e.g. in a control loop, checking at a regular interval whether cursor has changed position) and auto-click (call function SendClick) after, say, 100ms of inactivity.

Beats reverse engineering an .exe.

1
  • +1 for turning "I need it to click faster" into "I let it click faster the smart way". Apr 2, 2012 at 15:55
0

Maybe you don't have to recompile everything. In the game-world it's common to use trainers, which manipulate a value in memory when the program is running. If you find the minimum value in memory (0.5) and program something like a loader to make that number smaller, it could work.

3
  • That might work, only if the value is in the same location or the Xth value that has that value. In any case, T Search and Quick Memory Editor are two nice tools to try this with. You might want to search for 500 instead as that's how it loads it in, not as a float. Mar 29, 2012 at 12:13
  • Upon first try, it appears that osk.exe is not in the process list. This is because it is launched in the context on winlogon such that it works across users, you can get around this by launching the memory editor in the context of winlogon as well. Mar 29, 2012 at 12:17
  • See stackoverflow.com/questions/9868079/… and stackoverflow.com/a/3143055/47064 for an approach to do this, the easy approach is to replace osk.exe but that would only work if you create a launcher that launches both the memory editor and the backed up osk.exe. But then you'd have to consider that a loader would also need to do that. Seems this solution is getting as hard as disassembling and assembling, osk.exe is hard... :) Mar 29, 2012 at 12:21

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .