Detecting Windows NT/2K process execution

Environment: VC6 SP4, NT4 SP4, Windows 2000

Abstract

Intercepting and tracing process execution is a very useful mechanism for implementing NT Task Manager-like applications and systems that require manipulations of external processes. Notifying interested parties upon starting of a new processes is a classic problem of developing process monitoring systems and system-wide hooks. The Win32 API provides a set of great libraries (PSAPI and ToolHelp [1]) that allow you to enumerate processes currently running in the system. Although these APIs are extremely powerful they don't permit you to get notifications when a new process starts or ends up. This article provides an efficient and robust technique based on a documented interface for achieving this goal.

Solution

Luckily, NT/2K provides a set of APIs, known as "Process Structure Routines" [2] exported by NTOSKRNL. One of these APIs PsSetCreateProcessNotifyRoutine() offers the ability to register system-wide callback function which is called by OS each time when a new process starts, exits or has been terminated. The mentioned API can be employed as an easy to implement method for tracking down processes simply by implementing a NT kernel-mode driver and a user mode Win32 control application. The role of the driver is to detects process execution and notifies the control program about these events.

Requirements

  • Provide a simple, efficient, reliable and thread-safe mechanism for monitoring process execution
  • Resolve synchronization issues between the driver and the user mode application
  • Build an easy to use and extend OOP user-mode framework
  • Allow registering and un-registering of the callback as well as ability to dynamically load and unload the kernel driver

How it works

The control application register the kernel mode driver under HKLM\SYSTEM\CurrentControlSet\Services and dynamically loads it. The kernel driver then creates a named event object that is used to signal the user-mode application when new event has been fired (i.e. process starts or ends up). The control application opens the same event object and creates a listening thread that waits on this event. Next, the user mode application sends a request to the driver to start monitoring. The driver invokes PsSetCreateProcessNotifyRoutine(), which accepts two parameters. One of them specifies the entry point of a caller-supplied callback routine, responsible for receiving all notifications from Windows. Upon a notification, that takes place in the callback, the driver signals that event in order to inform the user-mode application that something has happened. The control application then gets the data for that particular event from the driver and stores it in a special queue container for further processing. If there is no need for detecting process execution anymore the user mode application sends a request to the driver to stop monitoring. The driver then deactivates the observing mechanism. Later the control mode application can unload the driver and un-register it.

Design and implementation

NT Kernel mode driver (ProcObsrv)

The entry point DriverEntry() (ProcObsrv.c) performs the driver's initialization only. The I/O manager calls this function when the driver is loaded. Since PsSetCreateProcessNotifyRoutine() allows to un-register the callback I implemented the actual process of registration and un-registration in the driver's dispatch routine. This allows me dynamically to start and stop the monitoring activities by using a single IOCTL (control code IOCTL_PROCOBSRV_ACTIVATE_MONITORING). Once the callback is registered each time when a process starts or terminates the OS calls user supplied ProcessCallback(). This function populates a buffer that will be picked up by the user mode application. Next the driver signals the named event object, thus the user-mode application that waits on it will be informed that there is available information to be retrieved.

Control application (ConsCtl)

For the sake of simplicity I decided to provide a simple console application, leaving the implementation of the fancy GUI stuff to you. Designing an application to be multithreaded allows that application to scale and be more responsive. On the other hand, it is very important to take into account several considerations related to synchronizing the access to information provided by the publisher (i.e. kernel driver) and retrieved by the subscriber (i.e. control application). The other important key point is that a detecting system must be reliable, and makes sure that no events are missed out. To simplify the design process, first I needed to assign the responsibilities between different entities in the user mode application, responsible for handling the driver. However it isnt difficult to do it by answering to these questions [5]:

  1. What are the processes in the system?
  2. What are the roles in the framework?
  3. Who does what and how do they collaborate?

The following is a UML class diagram, that illustrates the relations between classes:

CApplicationScope implements a singleton and wraps up the main interface to the framework. It exposes two public methods that start and stop the monitoring process.

class CApplicationScope  
{
   ... Other Other details ignored for the sake of simplicity  ...
public:
  // Initiates process of monitoring process
  BOOL StartMonitoring(PVOID pvParam);
  // Ends up the whole process of monitoring
  void StopMonitoring();
};

CProcessThreadMonitor is the thread that waits on the created by the driver event to be signaled. As soon as process has been created or ended up, the driver signals this event object and CProcessThreadMonitor's thread wakes up. Then the user mode application retrieves the data from the driver. Next, the data is appended to queue container (CQueueContainer) using its method Append().

CQueueContainer is a thread-safe queue controller that offers an implementation of the Monitor/Condition variable pattern. Its main purpose is to provide a thread-safe semaphore realization of a queue container. This is how the method Append() works:

  1. Lock access to the aggregated STL deque object
  2. Add the data item
  3. Signal m_evtElementAvailable event object
  4. Unlock the deque

And here is its actual implementation:

// Insert data into the queue
BOOL CQueueContainer::Append(const QUEUED_ITEM& element)
{
  BOOL bResult = FALSE;
  DWORD dw = ::WaitForSingleObject(m_mtxMonitor, INFINITE);
  bResult = (WAIT_OBJECT_0 == dw);
  if (bResult)
  {
    // Add it to the STL queue
    m_Queue.push_back(element);
    // Notify the waiting thread that there is
    // available element in the queue for processing
    ::SetEvent(m_evtElementAvailable);
  }//
  ::ReleaseMutex(m_mtxMonitor);
  return bResult;
}

Since it is designed to notify when there is an element available in the queue, it aggregates an instance of CRetreivalThread, which waits until an element becomes available in the local storage. This is its pseudo implementation:

  1. Wait on m_evtElementAvailable event object
  2. Lock access to the STL deque object
  3. Extract the data item
  4. Unlock the deque
  5. Process the data that has been retrieved from the queue

Here is the method invoked when something has been added to the queue:

// Implement specific behavior when kernel mode driver 
// notifies the user-mode app
void CQueueContainer::DoOnProcessCreatedTerminated()
{
  QUEUED_ITEM element;
  // Initially we have at least one element for processing
  BOOL bRemoveFromQueue = TRUE;
  while (bRemoveFromQueue)
  {
    DWORD dwResult = ::WaitForSingleObject( m_mtxMonitor,
                                            INFINITE );
    if (WAIT_OBJECT_0 == dwResult)
    {
       bRemoveFromQueue = (m_Queue.size() > 0); 
       // Is there anything in the queue
       if (bRemoveFromQueue)
       {
          // Get the element from the queue
          element = m_Queue.front();	
          m_Queue.pop_front();
       } // if
       else
          // Let's make sure that the event hasn't been 
          // left in signaled state if there are no items 
          // in the queue
          ::ResetEvent(m_evtElementAvailable);
    } // if
    ::ReleaseMutex(m_mtxMonitor);
    // Process it only there is an element 
    // that has been picked up
    if (bRemoveFromQueue)	
       m_pHandler->OnProcessEvent( &element, m_pvParam );
    else
       	break;
  } // while
}

CCustomThread - To help manage the complexity of maintaining raw threads I encapsulated all thread's related activities in an abstract class. It provides a pure virtual method Run(), that must be implemented by any specific thread class (e.g. CRetrievalThread and CProcessThreadMonitor). CCustomThread is designed to ensure that thread function returns when you want the thread to terminate as the only way to make sure that all thread's resources are cleaned up properly. It offers a means to shut any of its instances down by signaling a named event m_hShutdownEvent.

CCallbackHandler is an abstract class that has been designed to provide interface for performing user-supplied actions when process is created or terminated. It exposes a pure virtual method OnProcessEvent(), which must be implemented according to the specific requirements of the system. In the sample code you will see a class CMyCallbackHandler, that inherits from CCallbackHandler and implements OnProcessEvent() method. One of the parameters pvParam of OnProcessEvent() method allows you to pass any kind of data, thats why is declared as PVOID. In the sample code a pointer to an instance of CWhatheverYouWantToHold is passed to the OnProcessEvent(). You might want to use this parameter to pass just a handle to a window, that could be used for sending a message to it inside OnProcessEvent() implementation.

class CCallbackHandler
{
public:
  CCallbackHandler();
  virtual ~CCallbackHandler();
  // Define an abstract interface for receiving notifications
  virtual void OnProcessEvent(
     PQUEUED_ITEM pQueuedItem, 
     PVOID        pvParam
     ) = 0;
};

Compiling the sample code

You need to have MS Platform SDK installed on your machine. Provided sample code of the user-mode application can be compiled for ANSI or UNICODE. In case you would like to compile the driver you have to install Windows DDK as well.

Running the sample

It is not to worry if you don't have Windows DDK installed, since the sample code contains a compiled debug version of ProcObsrv.sys kernel driver as well as it source code. Just place control program along with the driver in single directory and let it run. For demonstration purposes, the user mode application dynamically installs the driver and initiates process of monitoring. Next, you will see 10 instances of notepad.exe launched and later on closed. Meanwhile you can peek at the console window and see how the process monitor works. If you want you can start some program and see how the console will display its process ID along with its name.

Conclusion

This article demonstrated how you can employ a documented interface for detecting NT/2K process execution. However it is by far not the only one solution to this issue and certainly might miss some details. However, I hope you would find it helpful for some real scenarios.

References:

  1. Single interface for enumerating processes and modules under NT and Win9x/2K, Ivo Ivanov
  2. Windows DDK Documentation, Process Structure Routines
  3. Nerditorium, Jim Finnegan, MSJ January 1999
  4. Windows NT Device Driver Development, Peter G. Viscarola and W. Anthony Mason
  5. Applying UML and Patterns, Craig Larman
  6. Using predicate waits with Win32 threads, D. Howard, C/C++ Users Journal, May 2000

Downloads

Download source - 33Kb


Comments

  • Replica Oakley Urgency low price for sale

    Posted by yheagoqox on 07/01/2013 09:41pm

    Ray Ban Clearance ,Oakley sunglasses are often men and women the depth on the main company is known world wide, to ensure the optical quality, it might beautify just about any clothes you wear. Many stars wear, an alternative way to Brown, women's Oakley sunglasses on the tungsten iridium new glasses can filter the harmful sunshine, and also to shield the photographer's camera eyes flashing. Fake ray bans ,Oakley sunglasses will probably be impressive, and in addition to a transparent overall look turned out to run results in that this person you selected an internet business to become new rather wind. Oakley sunglasses designed each year to change, like almost every other styles. However, different alternatives, not just a practical fashion occasions. Discount Oakley Eyepatch 2 ,Oakley eyewear in addition provide an excellent look of a wanted criminal. Nearly all shade of Oakley is surely a blend of beauty and security that can help protect the prospects worth. In the hot summer, discount Oakley sunglasses can't tolerate wearing a thin short spring and summer fashion, as you move the spread of an two of charming eyes, confident light. Here, you want to remind the key point is it is stored where, placed sunglasses are a must mirror up, to better protect the lens. The phenomenon of destructive interference depends on the refractive index in the lens (ie, the degree of deviation) occurs, the light from your air over the material, but in addition utilizes the thickness from the lens. Oakley sunglasses sunglasses is fairly good burden. For example, the exact use, while using visual appearance, but in addition in good agreement with all the successful. Is not going to get enough sun and flying debris protection, she or he will look stylish wearing these glasses. A real professional sports mirror using a unique personality, a full range of functionality to win the respect of various celebrities around the globe. Recently introduced the "wearable electronics" to collect weapons to provide Bluetooth solutions, and implantation in the solution framework to reduce the necessitie of the headset, headphone, line and wire. In reality, the women is pure as if they are besides elegant and modern, but additionally very comfortable to use, durable, cost-effective price tag. The pilot sunglasses is probably the most favored recently in males and females styles. Oakley sunglasses, a type of this style, the regular brown shadows, they might almost match any equipment.

    Reply
  • Allonnanvam

    Posted by Allonnanvam on 06/07/2013 07:08pm

    自家カラーコンタクトレンズのメンマだろう。メンマ増量ラーメンまであるから驚きだ。スープ、チャーシューともにやさしい味わい。 理由は、「形は機能に従う」という哲学に基づく知的なデザインにあります。アイテムは小さなキーポーチから、大型のボストンまでラインナップ。レスポートサックならではの豊富なバリ…。 2009年に行われたフィルムコンサート「What コーチ コーチ財布,コーチ アウトレット,コーチバッグ,コーチ,COACH a コーチ メンズ コーチ財布,コーチ アウトレット,コーチバッグ,コーチ,COACH beautiful www.coachgugou.com コーチ財布,コーチ アウトレット,コーチバッグ,コーチ,COACH memory」では、オープニングを飾る第1曲目として披露された。ライブ本編の1曲目が「揺れる想い」以外の曲で始まるのは初めてのこと。アカペラから始まって、サビの部分で盛り上がる。 確認・確保の早期実施、実在の在庫より余裕を持った少ない数をサイトに載せるなどの方法をとっています。最善を尽くしますが、商品をお届けできない場合がございますのでご了承下さい。また、生体の管理には万全を期しておりますが、ご注文から発送日までの間にコンディションにより発送できない場合もございますので重ねてご了承下さい。 地球の応接間(「ステート図書館」はこういう感じのものを作りたいといったときに、一目でステートの使い方がわかる。ステートが何ものかというのはキャラ製作関連のサイトを見てください。)MUGEN(右側に「代理公開」と書いてある所)。

    Reply
  • hundreds of thousands of companies instantly also been baffling instead of the systematization The the a specific Suntech suppliers

    Posted by moontiomue on 11/18/2012 04:06pm

    The routes of despatching of the monogram instinct of bitch greetings telephone shanghai escort care to expect her husband

    Reply
  • and the the old heave-ho of thousands of workers In augmentation the companys managing director team turnover tide Payment a stretch Suntech frighten

    Posted by kingsxpigbe on 11/16/2012 11:24pm

    Good beijing massage health and cheery every age good fortuity unbroken sailing oodles of paper money

    Reply
  • departments no door to collect the debtbut a brobdingnagian supplier every age door Dunning So distant Suntech on account of us six

    Posted by moontiowrd on 11/15/2012 08:17am

    Nature gain and flowers resourceful passive to grace shanghai escort it easy for the treatment of you at this stage when you undo the news

    Reply
  • The investigation is also below manner the is plausible to follow the lesson of the to the industry at liberty of luxurious penalties

    Posted by moontiosaf on 11/12/2012 07:40pm

    postings things being what they are escort shanghai sleazy starting the New Year banknotes till I have booked to flash into no subject how high the quotation the

    Reply
  • executive part nom de plume said In response to the bind Suntech had to cut off performance sense of

    Posted by gbctrcdqsk on 11/01/2012 07:40pm

    in days of yore released shanghai escort involved in the photovoltaic mammoth Suntech facingthe highest retributive tariffs the combined strain status

    Reply
  • howto prevent from installing of files

    Posted by Legacy on 10/14/2003 12:00am

    Originally posted by: Van

    Hi all,
    This article is great for me.
    Thank you Ivo Ivanov.
    I have problem and I think you can help me.
    Your example detect execution of file and now I would like to prevent from installing (copying) from CD-ROM (or floppy) into my harddisk. I think I must use your ProcObsrv driver and I have to change something/somefunctions.
    Please give me ideas how can I detect installing/copying instead of excution.
    By the way please tell me where I can download DDK free. I wonder what files I need to build your ProcObsrv driver. It is neccessary to have ntddk.h only ?

    Help me please.
    Thanks
    Van.

    Reply
  • Comments Test

    Posted by Legacy on 04/02/2003 12:00am

    Originally posted by: Webmaster

    Comment Test - This is a test

    Reply
  • PsSetCreateProcessNotifyRoutine before execution?

    Posted by Legacy on 03/19/2003 12:00am

    Originally posted by: D

    Hi,
    i want to control running of a particular executeable. I.e, prevent it from starting depending on external conditions.

    If i were to implement a program that utilises PsSetCreateProcessNotifyRoutine... would i have to terminate the program after it had started running? I dont think forcibly terminating a process after it has begun is a good idea.

    I'm not being very clear about this... I'll try again..

    Does the function :
    1)get called before the executable is invoked? if so, then i could ( i suppose) stop it from running..
    or
    2)is the executeable invoked and then the psSetNoti.. fn() is called ?

    1) would be good, but 2) would not as i would have to terminate the process mid-load.

    If anyone could give an answer or some pointers, i'd appreciate it.

    D.

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: November 20, 2014 @ 2:00 p.m. ET / 11:00 a.m. PT Are you wanting to target two or more platforms such as iOS, Android, and/or Windows? You are not alone. 90% of enterprises today are targeting two or more platforms. Attend this eSeminar to discover how mobile app developers can rely on one IDE to create applications across platforms and approaches (web, native, and/or hybrid), saving time, money, and effort and introducing apps to market faster. You'll learn the trade-offs for gaining long …

  • Live Event Date: October 29, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Are you interested in building a cognitive application using the power of IBM Watson? Need a platform that provides speed and ease for rapidly deploying this application? Join Chris Madison, Watson Solution Architect, as he walks through the process of building a Watson powered application on IBM Bluemix. Chris will talk about the new Watson Services just released on IBM bluemix, but more importantly he will do a step by step cognitive …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds