Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I monitor activity in a process that I spawned?

I have been tasked with trying to monitor activity in all GUI programs spawned from an initial program and killing them when they become inactive for a set period of time. This cannot be system activity as we must close the programs even if the user is just using another program for a while (not spawned by the initial program). The application spawning processes is a .Net program and that will not change. I was able to use SetWindowsHookEx to set low level hooks (WH_KEYBOARD_LL and WH_MOUSE_LL) from .Net but was unsure of how to associate the messages with the processes I've started (Using System.Diagnostics.Process.) I could hook events from the application doing the hooking, but it would always fail when I tried to hook to a specific thread for a spawned program.

The closest I was able to come was by creating a C++ dll that calls SetWindowsHookEx on behalf of the .Net program. Using this method I am able to hook into the first thread of a spawned notepad.exe, but the callback function is never called. If I specify a thread id of 0 the callback is called when there is activity in the original application so I know the SetWindowsHookEx works in that case.

I don't fully understand hooking yet, but from what I have read this will not work because the dll callback function address will be meaningless to the hooked process. Is that the issue I am running into? If so, is there a way around this or can somebody please suggest an alternative to determining if a spawned process is actively being used?

.Net (C#) code:

private const int WH_MOUSE = 14;

[DllImport("TestHook.dll", EntryPoint="InitializeHook",  SetLastError=true, CharSet=CharSet.Unicode, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
private static extern bool InitializeHook(uint hookType, int threadID);

private void HookEm() {
    //...
    System.Diagnostics.Process testProcess = System.Diagnostics.Process.Start("notepad");
    if(!InitializeHook(WH_MOUSE, testProcess.Threads[0].Id)) // The notepad.exe thread I know hooks
        MessageBox.Show("Boom!");
    //...
}

C++ dll:

HHOOK hookValue;

bool InitializeHook(UINT hookID, int threadID) {
    //... Determining which callback to use
    hookValue = SetWindowsHookEx(hookID, (HOOKPROC)MouseHookCallback, _dllInstance, threadID);
    //...
    return hookValue != NULL
}

static LRESULT CALLBACK MouseHookCallback(int code, WPARAM wparam, LPARAM lparam) {
    //From what I can see, this is never touched when hooking a thread on an outside process
}

All of this is currently being done on a 32 bit Windows XP computer. I do understand that a separate 64 bit dll would be needed to work with 64 bit applications spawned.

like image 402
BlueBayliss Avatar asked Feb 03 '26 01:02

BlueBayliss


1 Answers

For anyone who encounters a similar issue, our final solution was to check the foreground window on an interval using GetWindowThreadProcessId(GetForegroundWindow(), ref foregroundWindowProcessId) and keeping a map of our spawned process ids. Each time this timer fires we set a boolean value to check in the function that calls CallNextHookEx since it has to be efficient/fast or windows will unhook us. We then use the boolean value above and the system hooks from SetWindowsHookEx to determine if the user is active in our application. No C++ dll was needed for this solution.

like image 58
BlueBayliss Avatar answered Feb 04 '26 14:02

BlueBayliss