Link to home
Start Free TrialLog in
Avatar of SeanDurkin
SeanDurkinFlag for United States of America

asked on

Help with a keylogger detector

Hello! I'm trying to make a userland keylogger detector in C++ for Win32 (I'd like it to work for 2000 and XP, but solely XP would be tolerable), which detects all main userland keylogging methods (SetWindowsHookEx() and GetAsyncKeyState()).

My problem is that I'm trying to detect which process(es) have set a windows hook, and I've found that it is harder than I originally thought. At first, I tried to set a global WH_DEBUG hook to catch any WH_KEYBOARD hooks that were set, but it wouldn't allow me to view the process or thread id that set the original hook.

After a great deal of research, I came to the conclusion that I'd have to use an undocumented structure called the TEB (Thread Environment Block) to access the hook chain for every windows hook, and then I could get the process information from there. The information I found is located here:

http://zairon.wordpress.com/2006/12/06/any-application-defined-hook-procedure-on-my-machine/

The problem is that it's an undocumented structure, and I'm also messing around with the win32k subsystem, which I really shouldn't be doing. I was wondering three things: 1) Is this is the only way to go about it, and if it is, 2) how would I find out more information about the hook chains within Windows so that I could safely get access to the information I need? I'm doing this project simply to expand my knowledge about Windows programming and to get more experience, so 3) would it even be worth it to finish this project?

On a side note: I know this is possible, because I found a keylogger detector (that is for sale) that does this, but the original site was taken down for some reason. It can be found here:

http://software.techrepublic.com.com/download.aspx?docid=225314
Avatar of Mark_FreeSoftware
Mark_FreeSoftware
Flag of Netherlands image


hey SeanDurkin,

one way that comes to mind is this:

enumerate all processes,
in each process enumerate all dlls
for every dll look if you can find the setwindowshooksex import



you can also play around a bit with the hook WH_DEBUG, it will be the first hook in the hookchain

mark
Avatar of SeanDurkin

ASKER

Thanks for responding! Unfortunately, I've already considered both ways, and they didn't seem to quite accomplish what I want.

Looking for SetWindowsHookEx() function in the IAT would be something I could do, but I would have to find what type of hook is set, and I think the only way I can do that is by disassembling the file and going through and viewing the actual call. However, I realized that even if a program has code to make a SetWindowsHookEx() call, it doesn't mean the hook is actually enabled at that time (for instance, it could be code that executes when a button is pressed).

I also tried installing a WH_DEBUG hook, but the DEBUGHOOKINFO structure is as follows:

typedef struct {
    DWORD idThread;
    DWORD idThreadInstaller;
    LPARAM lParam;
    WPARAM wParam;
    int code;
} DEBUGHOOKINFO, *PDEBUGHOOKINFO;

There doesn't seem to be any way to get the id of the thread that installs the original hook (idThreadInstaller I believe either returns 0 or the id of the thread that installed the debug hook). I can't find any way of getting the id of the thread that installed the original WH_KEYBOARD hook, or how to traverse the hook chain from the first hook.

if the idThreadInstaller returns 0, you should try running this code from a driver

I believe it can be easily resolved with hookapi mechanism, if you don't know it please refer to here: http://www.codeproject.com/system/Paladin.asp, now you can hook the SetWindowsHookEx() api  and everytime when it's called you can simply get the handle or even name with GetModuleHandle or GetModuleFileName, since at that time your hookapi is in the same process space with the victim process.

Good luck.
Mark_FreeSoftware: Why would running the code from a driver have any effect? I haven't found any in-depth documentation on the WH_DEBUG hook (and idThreadInstaller), and the MSDN provides as little information as it can about hooks.

BeyondWu: I don't think I'd have a problem hooking SetWindowsHookEx(), even globally. The problem is that my program would act as a simple scanner for WH_KEYBOARD hooks, so a user could start it at any time and be able to find hooks that are set. If I'm hooking SetWindowsHookEx(), though, I won't find any processes that have already set a hook. I have heard of a way to use the registry to automatically load a DLL into each process when Windows starts, then use IPC with my main program (whenever it starts up) to get the processes that have set a global WH_KEYBOARD hook. I'm not sure how to do this, though, or even if it would work.

for that automatically dll mapping, you want to take a look at:

HKLM\Software\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs
Mark_FreeSoftware: Do you think the best way to go about this would be to use automatic DLL mapping and hook the SetWindowsHookEx() function globally?

the best way?


prevention is better than detection,

so writing a driver that monitors all hooks from boot till shutdown works better




and another tip:
don't focus _only_ on detecting hooks,

also look for suspicious network activity, and very frequent disk access from a program.


(please note there are programs that are not malicious but that are accessing the disk on a regular base)
Yeah, I think there are about 4 ways to log keystrokes with Windows programming in usermode, so I'm going to try to cover all ways with this program.

Just to clarify, though: I should write a driver that monitors hooks by hooking SetWindowsHookEx(), right? Or would I just install a global WH_DEBUG hook with driver code to monitor every thread's hooks (to look for WH_KEYBOARD or WH_KEYBOARD_LL), hoping it returns the correct idThreadInstaller? Because I'm still not sure it would return a valid id of the thread that installed the WH_KEYBOARD hook. How would I find that information out?
ASKER CERTIFIED SOLUTION
Avatar of Mark_FreeSoftware
Mark_FreeSoftware
Flag of Netherlands image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I think this is exactly what I need, but I'll definitely need to do further research. Any extra information you can give would be greatly appreciated (as neither QueryUserCounters nor NtUserQueryUserCounters is documented in the MSDN).