[an error occurred while processing this directive]
Issue dated - 7th April 2003


Previous Issues




 Network Sites
  IT People
  Network Magazine
  Business Traveller
  Exp. Hotelier & Caterer
  Exp. Travel & Tourism
  Exp. Backwaters
  Exp. Pharma Pulse
  Exp. Healthcare Mgmt.
  Express Textile
 Group Sites
  Indian Express
  Financial Express

Front Page > TechSpace > Story Print this Page|  Email this page

API monitoring unleashed - I

Tech Forum - Dr. Nitin Paranjpe

Often, applications need to be monitored. Say, you need to know how an application is performing and need to keep a track on the resource usage. This is quite possible if you are the author of the application or have control over the source tree. What if the application is a third-party application? How can you plan to monitor a complete black box? This article will target this area and show you various ways in which this can be achieved. Even though the APIs used in this article are documented in the Microsoft developer network (MSDN), you won’t find a correct code snippet that shows you how to use them. And when you read the documentation, you will yourself notice that it is quite complicated to understand what has been written, forget about knowing how to use it! That’s why I would like to say that whatever appears in the form of program code from now on is all “undocumented” stuff. Like all undocumented code, this code is not supported by the vendor and can change across versions.

The need
Before we even get started with understanding how to achieve the above, first let us try and understand properly why one would require to do this, or, what the “business benefit” would be. Even when I learned this technique, I was working on a project that required me to monitor a particular set of APIs. Although my scope was the entire system and monitoring each and every application running, we will limit the scope of this article to monitoring just one running application. Here are a few reasons why one would require doing so:

1. To log how the application is using a particular API. Now, this API could also be your written function exposed by some custom COM component or library dll. In a normal case, you will have to write the entire logging code inside your dll. But with the API monitoring system, you can actually keep this logging code generic and keep the monitoring specific to a running process.

2. To change the behaviour of a particular API. Say you need to disable all calls to a particular API. For example, user32.dll has an exported API called OpenFile, in order for you to disable a particular application from using this API, you can override the OpenFile API and write your own code (in case of disabling it, returning a failure value to the caller). In this way, two things are highlighted, first, you can disable any such API from any dll, and second, you can override the default behaviour of a particular API and provide your own functionality.

The method of injecting code
Before we start of with understanding how to ‘inject’ code into a running process, let us try and understand how applications work and how process memory is organised. If this explanation gets too complicated, you can skip this part and jump to the next section, ‘Writing the code’.

Import Table
Internal Shared Memory
Process Stack and Heap
Export Table

The above diagram gives a brief idea of how memory is allocated for any running process in the Windows environment

Every process has sections in memory as seen in the diagram. When the process starts, the global/shared data is loaded in the ‘Internal Shared Memory’ area. It has been called ‘Internal’ because the data is global within the process but not outside the process boundary. After this, the ‘Import Table’ and the ‘Export Table’ are populated for this process. This information comes from the binary of the process. Basically, the Import Table and the Export Table have the following meaning:

  • Import Table: The Import Table lists all the dlls that the process will be using. From now on, I will refer to dlls as “Modules”. It not only lists all the modules that the process will use, but also pointers to functions. Keep this point in mind, because we will be digging into this “Import Table” and changing the function pointer to our function. Although the mechanism to do so sounds pretty simple and straightforward, when you take a look at the code you will notice that it is in fact not the case.
  • Export Table: The Export Table lists all the functions and the respective function pointers that the running process will export. This is true if the process itself is a dynamic link library.
  • Process Stack and Heap are locations that are used by the process dynamically. It is on the stack that all function pointer tables and the respective variables required for an entering function are stored.

The method that we will use to inject a particular code will run in the following manner. Later, I will show you the respective code for the steps given below:

1. Develop a dll that will contain an exported function for the API, which you require to monitor/override.

2. Get a process id to a running process, which you need to modify.

3. Open the process with respect to the process id using the OpenProcess API.

4. Create a remote thread inside the running process to control the LoadLibrary functionality of the running process.

5. Execute this thread to ensure that the running process loads your dll into its memory.

6. Once your dll is loaded, and when the dll is attaching, get a pointer to the import list inside the running process. This part is a bit tricky and will require an understanding of how to iterate an Import Table list. To make life easier, there are helper APIs available, which allow you to do this. This will be explained in detail when explaining the code.

7. Now after getting a pointer to the import function and a pointer to the function itself, replace this pointer with a pointer to your function from the dll.

After following the above steps, you will observe that any call to the particular API will result in your function being called. In this way you can monitor or override any API from any Module, provided that you know the name of the Module.

A little clarity
Now that I have explained the steps involved, let’s go ahead and write the code to achieve this. Before we write the code, we need to make the following things very clear:

1. This code ‘injection’ system will only work in the context of the currently logged-in user. This clearly means that it is not possible to monitor an application running under a different user context. This also means that you cannot monitor or inject code into any application over a network and running under a different user context.

2. This system uses the OpenProcess API with the OPEN_ALL_ACCESS bit, which means that when you open the process, you need to be the administrator of the machine or the creator of the process. Also, you cannot open a process that has been created with a completely different security descriptor. There is a way to handle this situation but it might not work in all circumstances. There is something called “opening a process with debug privileges”, read up on it in MSDN.

So, what are the pieces that we need to code? For API Monitoring consider the following pieces of code:

1. Shared Module
This is the dll that will export our function for the corresponding API.

2. Injector Application
This is the executable, or the utility that we will write for code injection. This application basically accepts a process id of the application we need to monitor and injects our shared module inside the process space of that application.

3. [Optional] A device driver for new process creation/destruction notificationThis is an Optional component, which I will explain but won’t provide the source code. This is a device driver, which compiles with Microsoft Windows DDK using Microsoft Visual C++ 6.0 Compiler. This driver basically fires an event whenever a process has been created or destroyed.

This driver is important if you write a system-level injection code and need to know when a process is created or destroyed. I wrote a device driver for this (kernel-mode) because I couldn’t find an alternative for this in user-mode. Not even using Hooks! The actual code for demonstrating all that has been discussed above will be published next week.

(Note: Please Add "imagehlp.lib" to your library linking list.)

Your feedback, suggestions, requests for covering specific topics or issues are welcome. Please send feedback to techforum@mediline.co.in

About the Author:Dr Nitin Paranjape is the Chairman and MD of Maestros (Mediline). He is a consultant with many organisations, covering appropriate technology utilisation, business application of relevant technology, application architecture and audit as well as knowledge transfer. He has authored more than 650 articles on various technology-related subjects. He can be contacted at nitin@mediline.co.in
<Back to top>

Copyright 2003: Indian Express Group (Mumbai, India). All rights reserved throughout the world. This entire site is compiled in
Mumbai by The Business Publications Division of the Indian Express Group of Newspapers.
Please contact our Webmaster for any queries on this site.