Showing posts with label hooking. Show all posts
Showing posts with label hooking. Show all posts

Monday, February 16, 2009

System call hooking - I

In this post I will be telling you about system call hooking by patching the System Service Descriptor Table (SSDT). But before that let's see what SSDT actually is, who uses it and other BLAH! BLAH!

SSDT is created during the initialization of NTOSKRNL and is used by KiSystemService() to look up entry points of native APIs. KiSystemService is the handler for INT 2Eh/ SYSENTER. Now let us take a look at the structure of this table.

typedef struct SERVICE_DESCRIPTOR_TABLE {

PNTPROC pServiceTable; // Array of entry points

PULONG pdwCounterTable; // Array of usage counters

ULONG dwServiceLimit;     // No. of table entries

PUCHAR pArgumentTable;     // Array of byte counts

} SERVICE_DESCRIPTOR_TABLE, *PSERVICE_DESCRIPTOR_TABLE;

There are two service descriptor tables present in the system: KeServiceDescriptorTable and KeServiceDescriptorTableShadow. Ntoskrnl exports the KeServiceDescriptorTable but not the shadow one. Both of them are defined as an array of SERVICE_DESCRIPTOR_TABLE. Something like SERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable[NoOfTables].

In both KeServiceDescriptorTable and KeServiceDescriptorTableShadow, the first table (KeServiceDescriptorTable[0] and KeServiceDescriptorTableShadow[0]) contains addresses of Nt APIs.

Let's suppose that we have to hook NtCreateFile. Obviously, we need a mechanism to replace the address of the entry point of NtCreateFile with address of our hook function. Let's do it step by step.

Step 1: Finding an entry for any given function in the SSDT (KeServiceDescriptorTable). Entry for any function 'func' is given by KeServiceDescriptorTable[0].pServiceTable[*(PULONG) ((PUCHAR) func + 1 ))]

Step 2: Read the value present in the entry corresponding to NtCreateFile and save it.

Step 3: Change the value for that entry with address of your hook function.

Apart from the above steps, you need to disable to the write protect bit that is set before writing to the table and then enable it again.

I intentionally did not put the code here! J

Sunday, February 15, 2009

Hooking has its disadvantages!

I actually wanted to write on how to hook the SSDT. But then I realized why not give a warning of why you should not do a thing and then go on to actually tell you how to do that wrong thing. Many of us think that once you hook the SSDT we become the master and we can almost do anything on the system. But at what cost do we do this? Do we go on to make the system unstable? Or it does not really make a difference because we get our work done, and as others already say that Windows crashes anyways, so why should I care much? In my opinion, the stability of the system should not be hampered with. And hooking makes the system unstable.

I will tell you two main things that I can think of because of which you should not hook:

  1. The most obvious reason that comes to our mind is: Hooking is not supported on 64 bit Windows.
  2. Drivers that hook the SSDT cannot unload.
  • If your driver unloads when some function in your driver is still executing, you can be sure of a BSOD. Assume that the function in ntdll.dll calls your hook function in the driver and then you call the original function. Let's say before the original function returns to your hook function, your driver unloads. This will clear the execute flag from the pages that were previously used by your driver's code. And when the original function returns, you will get a BSOD.
  • The chaining of multiple hooks can cause problem. Let's say a driver hooks a function 'F' and changes the entry in SSDT for function 'F' to point to a hook function 'H1' and saves the address of original function 'F'. Let's say a second driver now comes and hooks the same function 'F'. This time, however, SSDT will contain the address of 'H1'. The second driver reads that address and saves it and then goes on to set the address of its own hook function 'H2' in the SSDT. Till now everything is fine. But what if the first driver decides to unload? It will simply replace the address that it had preciously read and saved. Now, SSDT will once again point to the original function 'F'. One problem that comes up is that the hook of the second driver stops getting called. The second (a more serious problem) arises when the second driver decides to unload after the first driver. It patches the SSDT back with what it had read and saved. So, it sets the address of 'H1' in SSDT. Now when the call for function 'F' comes, the OS tries to call function 'H1' because SSDT contains its address. But the function 'H1' does not exist anymore and hence you get a BSOD.

Having told this, I will now go on to tell about how to actually patch the SSDT in a new post.