Thursday 20 October 2011

How to Spy On a Windows Program: Tracking Main Window Activation

In this article I will walk you through the creation of a sample program that, each time I use any application on my pc, will record the application name, window title and time. While I do this, I will touch on techniques that, used for evil in spyware, are also applied with noble goals in areas like time tracking, application monitoring and computer-aided learning.
Practical information about this subject is hard to find. So, if you have ever been curious about how spyware programs work, how you can keep tabs on what a user does on a computer or how applications behave, read along.

Windows Architecture

To understand how you can “spy” on a running Windows program,  you first need to be familiar with the concept of event-driven applications.

Unlike applications that make function calls to obtain user input, Windows-based applications are event-driven. This simply means that they wait for the system to pass input to them.

The system passes all input for an application – for example, when the user types, moves the mouse, or clicks a control such as a scroll bar – to the various windows in the application. This input is passed in the form of messages. Besides the system, other applications can also generate windows messages.

If we could somehow inspect this message traffic, then we would have a way to know what it is that the system or other applications are asking any application to do. This is where you can put Windows Hooks to good use.

Windows Hooks

The MSDN documentation defines a hook as a point in the system message-handling mechanism where an application can install a subroutine to monitor the message traffic in the system and process certain types of messages before they reach the target window procedure.
There are different types of hooks, each providing access to different aspects of the system’s message handling mechanism. For example, keyboard hooks allow you to monitor keyboard messages (keyloggers make use this type of hook), mouse hooks allow you to monitor mouse messages and WindProc hooks allow you to monitor all messages processed by the Window Procedure, the message handling function in any window.

Armed with this knowledge, let’s go back to my sample program.

Tracking Window Activation

We know that when an application window becomes active, it is because the system sent it a message asking it to do so. Then, a way to track application usage is to install a system-wide hook that will inspect the messages the system sends to any application asking it to activate its main window.

To write my sample program I used C#, and to save time used an excellent Windows Hooks library written by Chris Wilson. In my sample program this is what I do:
  1. Install a global Shell hook. This type of hook allows me to intercept the messages sent by the system when a top-level window is activated.
  2. Upon intercepting a message indicating a top-level window activation, I record the time, the name of the application the window belongs to and the text displayed in the window’s title bar.
Sounds good? Let’s look at each step in detail.

The sample program is a Windows Form application with just one form.





Thanks to the excellent hooks library I am using (you can read more about it at The Code Project), all I need to do to be able to intercept top-level windows activation messages is subscribe to the WindowActivated event and install my shell hook. I subscribe to the event right inside the constructor for my only form.


public Form1()
{
InitializeComponent();
// Instantiate our GlobalHooks object
hooks = new GlobalHooks(this.Handle);
hooks.Shell.WindowActivated +=
new GlobalHooks.WindowEventHandler(hooks_ShellWindowActivated);
}
The hook is installed and uninstalled by pushing the “Start Monitoring” and “Stop Monitoring” buttons.
private void button1_Click(object sender, EventArgs e)
{
hooks.Shell.Start();
}
private void button2_Click(object sender, EventArgs e)
{
hooks.Shell.Stop();
}
Once the hook is installed, the message handling function of my form will start receiving not only messages directed to it, but also the messages intercepted by the shell hook.
Shell hooks intercept a variety of messages. Since I am just interested in top-level windows activations, I forward the messages to a utility function in the hooks library, which filters them and fires the WindowActivated event when the intercepted event indicates a top-level window activation.
protected override void WndProc(ref Message m)
{
// Send the messages to the library for filtering.
if (hooks != null)
hooks.ProcessWindowMessage(ref m);
base.WndProc(ref m);
}
Within the WindowActivated event handler, I use the window handle contained in the event arguments to lookup the application name and the window caption. Then I just display them in a listbox, together with the time the window was activated.
private void hooks_ShellWindowActivated(IntPtr Handle)
{
// Insert information at the top of the list.
listBox1.Items.Insert(0,"");
listBox1.Items.Insert(0, "Window caption: " + GetWindowCaption(Handle));
listBox1.Items.Insert(0,"Application: " + GetModuleName(Handle));
listBox1.Items.Insert(0,string.Format("Time: {0}", DateTime.Now.ToLongTimeString()));
listBox1.Items.Insert(0, "Window activation!");
}
You might have noticed how once you know when a top-level window was activated it becomes really easy to compute the time any application was actively used. I will leave the exercise to you.
Grabbing the window’s caption is accomplished with a call to the GetWindowText API function.
[DllImport("user32.dll")]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder title, int size);
private string GetWindowCaption(IntPtr Hwnd)
{
// This function gets the name of a window from its handle
StringBuilder caption = new StringBuilder(256);
GetWindowText(Hwnd, caption, 256);
return caption.ToString().Trim();
}
Obtaining the application’s executable name is a a little more involved, yet easy.
[DllImport("user32.dll", SetLastError = true)]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd,
out uint lpdwProcessId);
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess,
[MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwProcessId);
[DllImport("psapi.dll")]
public static extern uint GetModuleFileNameEx(IntPtr hProcess,
IntPtr hModule, [Out] StringBuilder lpBaseName,
[In] [MarshalAs(UnmanagedType.U4)] int nSize);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CloseHandle(IntPtr hHandle);
private string GetModuleName(IntPtr Hwnd)
{
uint processId = 0;
GetWindowThreadProcessId(Hwnd, out processId);
IntPtr hProcess = OpenProcess(ProcessAccessFlags.QueryInformation |
ProcessAccessFlags.VMRead, true, processId);
StringBuilder FileName = new StringBuilder(256);
GetModuleFileNameEx(hProcess, IntPtr.Zero, FileName, 256);
CloseHandle(hProcess);
return FileName.ToString().Trim();
}
And that is it. I hope you found the topic interesting and the sample useful. Here’s the source for the sample: HooksSample

No comments:

Post a Comment