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

Retrieving the Operating System Idle Time, Uptime and Last Input Time

Download this project (Visual Studio 2005)


In this C# programming tutorial here at Geekpedia, we're venturing into unmanaged code again. It's the popular user32.dll that has the GetLastInputInfo() function which interests us in this tutorial. The application will work with Windows 2000, XP, Server 2003, Server 2008 and Vista.

Start by creating a form with 3 Labels: lblIdleTime, lblSystemUptime and lblLastInput. Also add a Timer tmrIdle. Set the Interval property to 1000 (1 second) and the Enabled property to True. Every time this timer ticks, we'll check the last input time and the system uptime. Thus setting the timer to tick every 1 second is a pretty good interval for checking this, accurate but not an overkill.


Now let's write some code. Since we're using an unmanaged library, first comes the additional using statement:



using System.Runtime.InteropServices;

Next comes the signature function and the definition of the struct that is passed to it:


// Unmanaged function from user32.dll
[DllImport("user32.dll")]
static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);

// Struct we'll need to pass to the function
internal struct LASTINPUTINFO
{
    public uint cbSize;
    public uint dwTime;
}

Now it's time to double-click the tmrIdle Timer object so that we get to its Tick event. Here comes the main code, which is self-explanatory thanks to the comments:


private void tmrIdle_Tick(object sender, EventArgs e)
{
    // Get the system uptime
    int systemUptime = Environment.TickCount;
    // The tick at which the last input was recorded
    int LastInputTicks = 0;
    // The number of ticks that passed since last input
    int IdleTicks = 0;

    // Set the struct
    LASTINPUTINFO LastInputInfo = new LASTINPUTINFO();
    LastInputInfo.cbSize = (uint)Marshal.SizeOf(LastInputInfo);
    LastInputInfo.dwTime = 0;

    // If we have a value from the function
    if (GetLastInputInfo(ref LastInputInfo))
    {
        // Get the number of ticks at the point when the last activity was seen
        LastInputTicks = (int)LastInputInfo.dwTime;
        // Number of idle ticks = system uptime ticks - number of ticks at last input
        IdleTicks = systemUptime - LastInputTicks;
    }

    // Set the labels; divide by 1000 to transform the milliseconds to seconds
    lblSystemUptime.Text = Convert.ToString(systemUptime / 1000) + " seconds";
    lblIdleTime.Text = Convert.ToString(IdleTicks / 1000) + " seconds";
    lblLastInput.Text = "At second " + Convert.ToString(LastInputTicks / 1000);
}

Retrieving the operating system uptime is done through managed code (Environment.TickCount), however the last activity time is retrieved through the unmanaged GetLastInputInfo() function that we prepared earlier. From then on, calculating the last input ticks is simple math: subtract the last activity milliseconds from the system uptime and there you have it.