Professional Rootkits (Programmer to Programmer)
Before proceeding into the hook logic, a limitation of process injection should be mentioned. This limitation has to do with function declarations. In kernel-level hooking, you can simply include ntddk.h to declare the original function, and then cut, paste, and modify the original function prototype from ntddk.h to create the declaration for the new hook function. However, where do you get prototype information without a header file? There is a fair possibility the function you wish to hook is undocumented, with no header file and no sample code that shows calls to the target function. There’s even the possibility that the function you wish to hook isn’t even exported.
These problems can be remedied with IDA. As mentioned in Chapter 1, IDA is a disassembler that parses machine code into assembly code. If you open the target DLL with IDA, you can use the menu option Navigate
.text:7C926B07 public RtlGUIDFromString .text:7C926B07 RtlGUIDFromString proc near .text:7C926B07 .text:7C926B07 var_14 = byte ptr –14h .text:7C926B07 var_12 = byte ptr –12h .text:7C926B07 var_10 = byte ptr –10h .text:7C926B07 var_E = byte ptr –0Eh .text:7C926B07 var_C = byte ptr –0Ch .text:7C926B07 var_A = byte ptr –0Ah .text:7C926B07 var_8 = byte ptr –8 .text:7C926B07 var_6 = byte ptr –6 .text:7C926B07 var_4 = dword ptr -4 .text:7C926B07 arg_4 = dword ptr 8 .text:7C926B07 arg_8 = dword ptr 0Ch
Though this might not be what you’re used to, it is a function prototype. Basically, this listing shows that RtlGUIDFromString receives two passed parameters, arg_4 and arg_8, and that both are 32-bit pointers. For reference, IDA classifies passed parameters as arg_x, and local stack variables as var_x.
Determining the return type can be a little more difficult. IDA displays
.text:7C926B82 retn 8
to indicate that the function is returning (and that 8 bytes must be popped from the stack to clean up after pushing the parameters arg_4 and arg_8). However, you need to look back to
.text:7C926B76 xor eax, eax
just before the return to determine that the function probably returns NTSTATUS.
The other advantage to using IDA is the ability to see the actual machine code for the function. This is actually required when the function is not exported. Here’s the process.
After loading the target DLL and finding a location to hook, select Options
Even though RtlGUIDFromString is exported, it can serve as an example of how to retrieve a machine code pattern. Using the ntdll.dll from Windows XP SP2 Home Edition, you can see the pattern:
55 8B EC 83 EC 14 56 8B 75 0C A1 34 C0 97 7C 8D 4D FA 51 8D 4D F8 51...
Some knowledge of assembly language programming will be required to recognize when a machine code pattern can begin to vary with use, but it’s usually safe to use a pattern representing the initial moves and pushes of a function. What is really important is the uniqueness of the pattern within the DLL. The pattern must be long enough to be unique within all versions of the target DLL; otherwise, a pattern-matching algorithm could hook the wrong function. If you downloaded Microsoft Visual C++ 2005 Express, you can open files as binary and search a DLL for a specific pattern. If there is only one instance, you’re in luck!
Категории