What is a dead char? According to MSDN :
Some non-English keyboards contain character keys that are not expected to produce characters by themselves. Instead, they are used to add a diacritic to the character produced by the subsequent keystroke. These keys are called dead keys. The circumflex key on a German keyboard is an example of a dead key. To enter the character consisting of an “o” with a circumflex, a German user would type the circumflex key followed by the “o” key.
So, it is just a modifier rather than being a character on its own. Put into practice, following screen shot is taken from a Windows 7 x64 machine while trying to write ê in notepad.
Too many messages just for an ê char huh? Actually no! You should only take WM_KEY messages into account because only those messages are sent to your Notepad’s GUI Thread. Others? In this case WM_DEADCHAR and WM_CHAR are being sent by TranslateMessage.
What TranslateMessage does here is : “Seeing that Shift + 3 (^ symbol in my locale) is pressed, it sends a WM_DEADCHAR message to window and internally sets a flag in the kernel part. You may think it’s app spesific but no, just try running two instances of notepad and pressing the dead char (1 time) on the left and some other char (like e) on the right instance, you will see that notepad on the right gets accented e which proves that DEADCHAR status is saved into kernel.
So what? Story begins here… I have been testing our new product which will be released shortly and going crazy about a possible bug in the source code. Problem is related to printing chars with diacritics in Turkish Keyboard locale when one of our keylogger simulators is active. In order to get a better understanding of the problem, take a look at the folowing snip :
That little “Start” button on the right was messing up with my keyboard and I was not able to write the first letter of my name 🙂 I can hear you saying :”What do you expect dude? It’s a keylogger simulator and can easily mess the messages received by Notepad’s message pump!??” But no, it can’t, because it uses RegisterRawInputDevices in order to simulate a simple keylogger and this can not break some other windows message pump. RIDEV_INPUTSINK means “Send me a WM_INPUT message whenever a key is pressed whether or not I am the foreground window” Looks promising right? Yes it does, which makes it preferrable by most of the keyloggers around.
Why? Because the technique itself is free from DLLs, Hooks and etc. which simply works with WM_INPUT messages and it’s holy safe based on my experiences. And only way to stop it is hooking win32k!NtUserRegisterRawInputDevices. Eventhough I did not have the source code for simulator , i have written something alike and guess what? Result is exactly the same!
I decided to perform some cross check with DEADCHAR + A and result is as follows :
But why? There was nothing in the address space of Notepad It couldn’t be me breaking the system! Never say never, I started tracing the function top to bottom and saw that returning before ToAsciiEx was soving the problem!!!??? Why? I opened up MSDN and started searching “dead char bla bla”. Most significant excerpt was :
The parameters supplied to the ToAsciiEx function might not be sufficient to translate the virtual-key code, because a previous dead key is stored in the keyboard layout.
Definitely yes! But where was “WARNING : ToAsciiEx clears previously stored dead-char from the keyboard layout”? It was in IDA + WINDBG 🙂
Actually, branching 3 levels deep in windbg, I was just changing my mind and opening IDA but saw something shiny!
Who was calling it? win32k!NtUserTranslateMessage. This is the normal behaviour but who else was calling it is shown in the following two snips :
Digging a little further resulted with the following :
Voila! It was so close the the source of problem (which was already apparent at this point).
Further digging the ComposeDeadKeys showed that it was clearing the DeadChar flag whenever a new key was pressed!!! Just take a look at the following screenshot (I admit my hand writing is more messy than ComposeDeadKeys:))
To sum up :
See you on next post!