Sunday, February 22, 2009

Injecting Code using CreateRemoteThread.

We all know that we try to do those things that we are barred from… J A normal human tendency! Or maybe a weird human tendency!

So let's first put down what we want to achieve:

  1. We want a way to inject some code in a process (of course I am not talking about our own process).
  2. How do we make it execute?

One line answers:

  1. We can load a DLL in the process to inject the code.
  2. We need to create a thread which will execute that piece of code.


 

Let's enumerate as to what we have that we can make use of:

  1. CreateRemoteThread API to create a thread in a process.
  2. LoadLibrary API to load a DLL.


 

CreateRemoteThread has a parameter which takes the address of the function to be executed when the thread starts. Can we somehow combine points 1 & 2 enumerated above? Yes, we can pass the address of LoadLibrary in CreateRemoteThread. But there is a catch! Don't just write LoadLibrary in the following manner:

CreateRemoteThread( …, LoadLibrary, …);

This is incorrect. You need to get the address of LoadLibrary in kernel32.dll using GetProcAddress and pass that address in CreateRemoteThread.

Next step is to tell LoadLibrary the name of the DLL which needs to be loaded. But remember one thing, you can't use a string allocated in your process in the process where the DLL needs to be loaded. So you need to allocate memory in the target process using VirtualAllocEx. And then copy the path of the DLL in the allocated space using WriteProcessMemory.

Upto this point we have discussed how to inject the code; by using CreateRemoteThread, LoadLibrary, GetProcAddress, VirtualAllocEx and WriteProcessMemory.

But where should we place the code in the DLL so that it gets executed? Afterall if you make some functions in DLL and export them, the target process will not call them anyways. Let's think of the first function that gets called in the DLL when it is loaded. It is DllMain with notification type DLL_PROCESS_ATTACH. You can place the code to be executed in DllMain under the case for DLL_PROCESS_ATTACH.

Simple! Isn't it? But this method faces a problem in Vista. This is because the CreateRemoteThread API does not work across sessions. So all process that run in a different session cannot be targeted using this method.

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.


 

Saturday, February 14, 2009

I don’t want to play in ‘Safe mode’

Safe mode is that chosen state of the Windows OS in which it is expected to run incase you face any problems while running in normal mode. The Windows OS is selective in starting the drivers in safe mode. Except for the boot time drivers, it chooses not to start any driver when a user chooses to boot the OS in safe mode. But what if you have a boot time driver? How do you prevent your driver from being loaded?

Actually it is pretty simple to detect in your driver whether the system is being booted in safe mode. The kernel exports a variable of type PULONG called InitSafeBootMode. Just declare the variable as extern PULONG InitSafeBootMode. In your driver, you can check the value of this variable. If it is 0, it means that the system has NOT been booted in safe mode. Value greater than 0 indicates that the system is booting in safe mode. There are three types of safe mode boot: Minimal (SAFEMODE_MINIMAL), Network (SAFEMODE_NETWORK) and DS Repair (SAFEMODE_DSREPAIR).

It is always a good practice to check this value in your driver and take a decision whether you are prepared to run in safe mode or not.

Queued Spin Locks- Spinning with discipline!

Most of you know about spin locks and yet many of you might not know about queued spin locks. Queued spin locks are available from Windows XP onwards. They are more efficient than the traditional spin locks. There are two advantages that queued spin locks offer:

  1. If multiple threads request the same lock, the threads are queued in the order of their request.
  2. Queued spin locks test and set a variable that is local to the current CPU, and hence generate less bus traffic.


 

How to use queued spin locks?


 

KSPIN_LOCK             qsl;

KLOCK_QUEUE_HANDLE    qh;

KeinitializeSpinLock( &qsl );

KeAcquireInStackQueuedSpinLock( &qsl, &qh );

// Do some work… Don't take too long.

// Remember that you are holding a spin lock

KeReleaseInStackQueuedSpinLock( &qh );


 

As opposed to KeAcquireSpinLock, the caller of KeAcquireInStackQueuedSpinLock does not need to store the current IRQL. This is automatically stored in the KLOCK_QUEUE_HANDLE structure when a call to KeAcquireInStackQueuedSpinLock is made.

Ah! One more thing: Don't ever use KeAcquireSpinLock and KeAcquireInStackQueuedSpinLock on the same spin lock!

Do you really need to hook it?

An evergreen question 'How should I hook...? I want to monitor/ block...' How many of us really look up before asking this question? Hooking has been a classic old way of doing things, but time changes and so do the techniques. Hooking is powerful, but it is bad. Use hooking when you have no other alternative. I have seen many people use hooking just out of ignorance; they don't know that a documented way exists to the same thing.

Remember the classic old tool Regmon? The initial versions of regmon used system call hooking. But then as newer techniques with better features supported got introduced, Regmon started using them. Regmon uses system call hooking till Windows XP and uses registry callback mechanism Windows 2003 onwards.


 

I like to give the example of registry filtering for making people understand when they should use hooking. Let's take 3 tasks:

  1. Monitoring registry calls.
  2. Blocking registry operations.
  3. Modifying data for a registry operation.


 

Let's first take the example of a person who has just started Windows programming and has become aware of the concept of hooking. The first thing that might come in his mind is that all three tasks are do-able by system call hooking of the registry operations. But is it really so? He needs to ask himself two things: Which versions of OS (NT/ 2K/ XP/ 2K3, Vista/ 2K8) do I need to support along with the platforms (x86/ x64/ IA64)? And if that answer includes x64 or IA64, his idea of system call hooking has blown apart by now. Because system call hooking is not supported on 64 bit Windows. A special component of the OS called the Patch Guard prevents system call hooking on 64 bit Windows. But be very sure that on NT and 2K you have no other mechanism other than hooking for doing any of the three tasks.

Before we go any further, let me just tell you that there is registry callback mechanism in Windows starting from Windows XP. But how useful it actually is depends on the functionality that we want to achieve. Anyways, let's take each task one by one.

  1. Monitoring registry calls: Just by the look of it, we feel that if registry callback mechanism is present the bare minimum support that it should provide is that of giving plain notification like callbacks with both the pre-operation callback and a post-operation callback. But life is not so good! The registry callback mechanism of Windows XP is like an engineering project that a student tries to get over with without thinking much about the required functionality. The point is that the registry callback mechanism in Windows XP does not even provide post callbacks for all operations. So what now? Does the developer have an option? Yes, of course. He should use system call hooking for Windows XP. But what about Windows XP x64? I have seen many people ask this question. But the fact is that Windows XP x64 is actually not Windows XP from the inside; it's just Windows XP from the outside. Windows XP x64 is build from the same source code as Windows 2003, and hence is different from Windows XP x86. So, all the functionality that Windows 2003 x64 has, Windows XP x64 also has. Now, what about Windows 2003, Vista and 2008? The registry callback mechanism in 2003 is better than XP but not as good as in Vista. But this task of monitoring most of the registry calls can be achieved in both OS by the callback mechanism.
  2. Blocking registry operations: As such the blocking of registry calls can be achieved by callback mechanism in XP, 2003 and Vista/ 2008. However, since the monitoring functionality itself cannot be achieved properly in XP, hooking still remains the option for XP. For 2003 and Vista/ 2008, the callback mechanism does a good job.
  3. Modifying data for a registry operation: This is one task that gets a little tricky and questionable. For XP, hooking still remains the technique for achieving this. For Vista/ 2008, the callback mechanism supports it properly. However, the problem comes for Windows 2003. You get stuck in both the techniques: The callback mechanism does not support modification of parameters (though the documentation said that the parameters could be modified. But that is wrong!) And if you choose hooking you won't be able to support Windows 2003 64 bit. Here comes a need for business decision! What does a customer require and what is do-able?

Above mentioned example is one of the simplest ones. However, in reality I have seen that some security products really need to hook. But again, they fail to provide that functionality in their 64 bit versions because the hooking mechanism fails there. Again, I have seen some people that do not want to do things in a documented fashion; they WANT to hook! This approach is not good. There can be an endless discussion on hooking vs. documented way, but I believe that the decision should be taken based on the functionality required and the built-in features available from the OS to do it in a documented fashion. Though interesting, but don't always put a hook because that may make you a crook!