Sign in to follow this  
irreversible

Keylogger obfuscation - would this work? (anti-keylogging discussion)

Recommended Posts

As far as I know, there are two general types of keyloggers in Windows - hook-based keyloggers and hardware interrupt based keyloggers. I can see no feasible way of detecting or fooling an interrupt-based keylogger; however, I think I might have an idea how to mess up a hook-based one. Since Windows won't allow enumerating all existing hooks in the system (which, to me, seems like a security fault), the only way to detect if a keylogger is active, is by monitoring RAM and HDD access/usage. However, if the aim weren't to detect the keylogger, but simply assume that one was running, it should be possible to obfuscate the data that it captures. Since a system-wide hook-based keylogger handles all keyboard events and interprets them as text as seen in the Windows message pipeline, sending key events to a window that cannot process them should also register in the keylogger while not using up almost any CPU time or intruding the system in any other way. If this is so, then it should be easy to obfuscate any logged text by responding in a separate system-wide hook to any given keyboard messages and sending a number of "dummy" key messages down the pipeline as a response (NOTE: this could also work if the keylogger was only logging events meant for a specific window if it were possible to make sure that a separate hook were to be guaranteed to be the last one in the chain and cancel all of the dummy messages; if anyone knows if this is possible, let me know). Also note that if the actual text is obfuscated with segments from real words, deobfuscation will be impossible. NOTE: keylogger detection seems to be far more difficult than obfuscation (not to mention much more error prone), which leaves only the issue of whether you're content with not knowing whether a keylogger is running on your computer as opposed to whether you're content with assuming that you're tricking it in case one is running on your computer. I haven't tested this - so far it's just an idea. My question is: would this work and how easy would it be to cheat it? This is an open discussion, so feel free to expand on the topic (of anti-keylogging) and provide any insight you might see suitable. Cheers! [Edited by - irreversible on October 9, 2006 4:12:13 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by Smit
Wouldn't sending lots of fake key press messages cause apps to start diaplying randem keys?


The idea is to send a small number of dummy keypress notifications in response to each keypress. If you're typing fast, you're probably not typing faster than 4-6 characters per second (multiply by two for key-up and key-down events). Obfuscation would pump this to up to 12-16 keypress notifications (24-32 messages in total) per second. These are sent to a dummy window (which probably doesn't even have to be visible and is never active). I don't think you could hang or screw up the system in any way by doing that.

EDIT: few people type faster than 1-2 charaters/second on average (this assumes you think about what you're typing).

Share this post


Link to post
Share on other sites
What about installing a thunk into SetWindowsHook, SetWindowsHookEx, CallNextHookEx and monitoring all calls to those functions? That is, why not create your own windows hook enumerator using a function hook(s)? Have you searched phrack.org or rootkit.com for leads on writing counter keyloggers?

Share this post


Link to post
Share on other sites
Well, I'm not trying to write an anti-keylogger, but I have been fondling the idea of writing an obfuscator (for the heck of it, really). As I mentioned, it has the (so far, admittedly, potential) great advantage of being completely foolproof against hook-based keyloggers. I'll probably test this soon, but it'd interesting to see if it's also effective against GetAsyncKeyState() (thanks for the tip, MrEvil).

As for code injection and rootkitting - I don't want to do that (I'm not writing a commercial application, so I get to choose what I do and what I don't do). First of all, as far as I know, that would require driver-level access, which is way out of the scope of what I'm trying to accomplish. Secondly, there are probably utilities out there that already do that.

A hook-based obfuscator would be suitable when chatting or writing emails in a home environment with no "real computer nerds" about, who'd run something inbred enough to not be detectable anyway.

Although... is there a more hardware-driven approach of invoking a keyboard interrupt (such as one would expect to encounter when a key is actually pressed on the keyboard)? That is, can hardware interrupts be faked? I'm aiming for Win2000 and up.

It's the same with hiding processes - if someone really wanted to do that, they could take up the task and hide the process so that it wouldn't have any fingerprints in the system at all (apart from being run), thus being undetectable by any means other than monitoring the raw kernel thread chain. But again, that's a little hardcore for me.

Share this post


Link to post
Share on other sites
Quote:
Original post by irreversible
Quote:
Original post by Smit
Wouldn't sending lots of fake key press messages cause apps to start diaplying randem keys?


The idea is to send a small number of dummy keypress notifications in response to each keypress.

Once your malicious attacker figures out that the keypress notifications are in response to actual keys, he needs only take the first keypress from any group with identical timestamps to retrieve the actual key that was pressed. Suppose you type the following sentence:
      Here is a rabbit.

The attacker sees:
      H[qyt]e[rmz]r[rpq]e[qeq] i[mlp]s[tr3]
a[rwp] r[mnw]a[sdh]b[jko]b[cwa]i[aqs]t[yup].[pll]

This looks pretty obfuscated. But from a time-stamped perspective, the attacker sees:
  H[qyt] @ t = 0
e[rmz] @ t = 1
r[rpq] @ t = 2
e[qeq] @ t = 3
@ t = 4
i[mlp] @ t = 5
s[tr3] @ t = 6
{...}

Now it's much more obvious what you were typing in the first place.

Furthermore, if your attacker discovers that your keys are being unhandled by a dummy window, this looks very suspicious from his point of view. Why is the user sending keypresses to two windows at once, one of which is utterly incapable of doing anything?

hope that helps,

Share this post


Link to post
Share on other sites
kSquared - thanks for the pointer; although, I think the easy fix would be to broadcast certain (if not all) elements randomly. Sending five key notifications a seconds at random intervals should increase the average load only a little (which should thus remain insignificant) and flood the keylogger with up to 99% garbage.

Share this post


Link to post
Share on other sites
Quote:
Original post by irreversible
Well, I'm not trying to write an anti-keylogger, but I have been fondling the idea of writing an obfuscator (for the heck of it, really). As I mentioned, it has the (so far, admittedly, potential) great advantage of being completely foolproof against hook-based keyloggers. I'll probably test this soon, but it'd interesting to see if it's also effective against GetAsyncKeyState() (thanks for the tip, MrEvil).

As for code injection and rootkitting - I don't want to do that (I'm not writing a commercial application, so I get to choose what I do and what I don't do). First of all, as far as I know, that would require driver-level access, which is way out of the scope of what I'm trying to accomplish. Secondly, there are probably utilities out there that already do that.

A hook-based obfuscator would be suitable when chatting or writing emails in a home environment with no "real computer nerds" about, who'd run something inbred enough to not be detectable anyway.

Although... is there a more hardware-driven approach of invoking a keyboard interrupt (such as one would expect to encounter when a key is actually pressed on the keyboard)? That is, can hardware interrupts be faked? I'm aiming for Win2000 and up.

It's the same with hiding processes - if someone really wanted to do that, they could take up the task and hide the process so that it wouldn't have any fingerprints in the system at all (apart from being run), thus being undetectable by any means other than monitoring the raw kernel thread chain. But again, that's a little hardcore for me.


Imo, faking a hardware interrupt would be just as difficult, if not more difficult, than writing a driver. There are only a few interupts that can safely be called from user mode - int 3, int 4, int 21 - are the ones that quickly come to mind. Targetting W2K for code injection is easier than WXP much less WXP64 (W2K lacks DEP - Data Execution Prevention). Most of the approaches that I've seen for hiding processes involve some code injection - hooking CreateProcess (etc), hooking native API's in ntdll.dll, even altering the raw kernel thread chain as you put it. Each kernel process structure links to the next via a chain of LIST_ENTRY structures. So too with kernel thread structures. You can learn a lot about all this from rootkit.com (and phrack.org too but phrack code tends towards being a hack and thus isn't necessarily explained well, imo. That is, it assumes that you already know quite a lot about the subject matter). At any rate, don't let any of this hold you back.

Share this post


Link to post
Share on other sites
That's odd - I'm not catching anything in either hook or async mode when sending WM_KEYDOWN messages. Here's the code for sending the notifications:

DWORD keyval = (rand() % 256);
SendMessage(mainwindow, WM_KEYDOWN, keyval, (LPARAM)(1 | (1 << 30) | (keyval << 16)));

Keylogging works nicely - all real input is captured as expected.

Sending the messages to the desktop or any other window fail as well. Is this to be expected?

Share this post


Link to post
Share on other sites
Quote:
Original post by irreversible
EDIT: few people type faster than 1-2 charaters/second on average (this assumes you think about what you're typing).


I think you've got that wrong. All of the people I know can type atleast 10wps even when thinking about typing (and no, none of them are programmers and not all of them use the computer once a day.) I don't even know monkey-typers that type at less than 3wps.

Share this post


Link to post
Share on other sites
You should really talk in characters, not words per second. There's a world of difference between "I", "cat" and "inconsequential". I would say it takes the same time for me to type "I am a cat" as it takes me to write "inconsequential". BUT - writing certain words for the first time (such as "inconsequential") will claim an additional second or two to mentally map out the actual character squence on the keyboard (I'm pretty sure this holds true for most people). Plus, it is quite common that after each sentence, no matter how short or long (or also at more illogical/random breaks), most people tend to stop for up to several seconds to compose the next sentence beforehand and review the last sentence for completeness. Moreover - no one can type 10 wps (as you put it) for more than a couple of minutes in a row. It just doesn't happen. And hence my statement is more than valid if you consider it as a whole, also including the two key words, which are on average.

Incidentally, can anyone comment on my last post, because I really can't figure out why my keypress messages aren't being caught by the keylogger.

Share this post


Link to post
Share on other sites
Using SendInput() or (for simplicity's sake) keybd_event() works. However, in such a case it is impossible to filter out the keystroke before it does any real damage (it's forwarded to the window that currently has focus).

Furthermore, GetAsyncKeyState() is not fooled that way. It may be possible to use SetKeyboardState() to fool GetAsyncKeyState(), although my first crack at that doesn't seem to be working either.

In other words, this method seems to be quite useless...

EDIT:

in the meantime, doing something like this:

::PostMessage(HWND_BROADCAST, WM_KEYDOWN, keyval, (LPARAM)(1 | (1 << 30) | (keyval << 16)));
::PostMessage(HWND_BROADCAST, WM_KEYUP, keyval, (LPARAM)(1 | (1 << 30) | (keyval << 16)));

will not be registered by my hook or GetAsyncKeyState() keyloggers, but will be captured quite successfully by WinAMP Agent (which is sort of odd).

Share this post


Link to post
Share on other sites
The message injection techniques seem like really good ways to destroy certain classes of user assistance applications and perhaps IME's as well. There may also be issues with keyboards other than whatever kind the author has, e.g. your code may work fine on a US system with a standard keyboard but fall over and die with a dvorak keyboard or a Russian keyboard.

I don't know all the issues involved myself other than that kind of thing is *always* lots harder than it seems at first glance.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this