One of the best sources of rootkit information is rootkit.com, and I have taken their basic class written by hogland et al, and extended it slightly to form a simple starting point for GSO members.
Most people are unfamilar with kernel mode programming, there is little accessable information about it, and most sources will say read the DDK help file.
In the end, driver development is about learning how to use the kernel api and understanding how kernel and userland fit together. Many of the usual userland niceties are gone, e.g. the c runtime library cannot be used, and no userland api calls work. If you make a mistake in the kernel, you see a BSOD...
For development in the kernel, the best way to experiment is by using a VMware virtual machine, and debugging it via a virtual com port, using windbg ("windbag").
See this link: hxxp://silverstr.ufies.org/lotr0/windbg-vmware.html for details on setting this up.
You will need a copy of the DDK ("Driver development kit"). Get the latest version (windows server 2003) and install all the samples that come with it. Generally driver work is done without an IDE (i.e. notepad...), but it is possible to get visual studio working with DDK via custom build events. Personally, i prefer notepad.
Also get a copy of windbg from microsoft.com (free) and a copy of dbgview from www.ntinternals.com (this should be run whilst rootkit is being installed to monitor dbgprint commands).
Now for the interesting stuff...
Whenever you call a userland api (e.g. CreateProcessW), it will eventually call a kernel mode api (in this case CreateProcessW from kernel32.dll calls NtCreateProcess from ntdll.dll, which calls the kernel api ZwCreateProcess).
If you look at the disassembly of ntdll functions, you will see most a just a stub that calls a kernel function...let's look at NtCreateProcess for a second.
.text:7C90D754 public NtCreateProcess .text:7C90D754 NtCreateProcess proc near ; CODE XREF: RtlCreateUserProcess+C1p .text:7C90D754 mov eax, 2Fh ; NtCreateProcess .text:7C90D759 mov edx, 7FFE0300h .text:7C90D75E call dword ptr [edx] .text:7C90D760 retn 20h .text:7C90D760 NtCreateProcess endp
All it has done is to load the value 0x2F into EAX and then it calls a function living at address 0x7FFE0300. If you look at this address you find it is a either an interrupt 2eh or a sysenter command (among some other commands to load function parameters into registers).
What this does, is to pass execution to a kernel function referenced by the position 0x2F in a kernel structure known as KeServiceDescriptorTable.
The KeServiceDescriptorTable is basically a big table of function pointers. So what this means is the true kernel function ZwCreateProcess lives at the address held in KeServiceDescriptorTable at position 0x2F.
This leads to the obvious idea that if we want to modify the behaviour of certain usermode api, we can modify the api that they rely on in the kernel, by putting a pointer to our own function in this table (aka kernel hooking).
The attached project shows this method in action. There are some slight complications. These function positions in KeServiceDescriptorTable change between versions of Windows. One solution to this, is to hard code the function position for the functions you wish to hook.
I found this to be a poor approach, since the rootkit would not survive a service pack upgrade.
Instead, I have written a function GetDllFunctionAddress which will extract the required function position from system dll's like ntdll.
This is not necessary for all function you wish to hook though. Some functions are exported by Ntoskrnl.exe, and you can get the position directly from this. However, my approach will work for all kernel api, so it probably is simpler to do it this way.
The key functions to study are DriverEntry and OnUnload. These expose the hooking methodology.
The main idea is shown in the following code:
RtlInitUnicodeString(&dllName, L"\\SystemRoot\\system32\\ntdll.dll");
functionAddress = GetDllFunctionAddress(functionName, &dllName);
position = *((WORD*)(functionAddress+1));
g_OriginalZwCreateProcessEx = (ZWCREATEPROCESSEX)(KeServiceDescriptorTable.ServiceTableBase[position]);
_asm
{
CLI //dissable interrupt
MOV EAX, CR0 //move CR0 register into EAX
AND EAX, NOT 10000H //disable WP bit
MOV CR0, EAX //write register back
}
(ZWCREATEPROCESSEX)(KeServiceDescriptorTable.ServiceTableBase[position]) = MyZwCreateProcessEx;
_asm
{
MOV EAX, CR0 //move CR0 register into EAX
OR EAX, 10000H //enable WP bit
MOV CR0, EAX //write register back
STI //enable interrupt
}In the function MyZwCreateProcessEx you will provide the addtional functionality that is required - i.e. you perform additional operations (e.g. not allow the process to be created if it is called iexplorer.exe) and the call the original function if required (g_OriginalZwCreateProcessEx).
I also attach a Visual Studio 7 project which will install the rootkit driver via the service manager. Usage is simple, type rootkit.exe load to install it, and rootkit.exe unload to uninstall.
I hope that this will provide members with a starting point to explore the world of kernel development.













