Wednesday, November 11, 2009

Call Hooking









































Prev don't be afraid of buying books Next






























Call Hooking



Call hooking is popular because it is so simple.
Programs make subroutine calls as a matter of course. In machine
language, these calls translate to variations of call or jump
instructions. They pass arguments to the target function using a
stack or CPU registers. The instruction always takes an address in
memory. The memory location is the starting address of the
subroutine code. When the subroutine is finished, the original code
location is restored and execution continues normally.




The trick behind call hooking is to alter
the address that the call jumps to. In this way an alternative
function can replace the original. Sometimes this is called
trampolining. Call hooking can be applied in several places: in
internal function calls within a program, at calls into DLLs, or
even to OS-supplied system calls. A call hook can emulate the
behavior of the original call (usually by eventually calling the
real function) so it will not be detected. Note that the call hook
can apply special logic to the original call. For example, if the
call is supposed to return the list of currently running processes,
the call hook can hide certain processes from view. This kind of
technique is standard practice when inserting backdoors into
systems. Utility packages that provide call hooks are standard
issue with many rootkits.





Hiding a Process



We must control what user-mode programs get in
response to system calls. If we can control system calls, we can
control what the task manager is able to find out about the system
through standard queries. This includes controlling access to the
process list.





Hooking a System Call



Our call hooking routine is very simple:




[View full size
image]









We save the old pointer to
ZwQuerySystemInformation. We replace the pointer in the
call table with a pointer to our own function,
NewZwQuerySystemInformation. When we actually overwrite
the function pointer, we disable interrupts temporarily. We do this
so we don't collide with another thread. Once we reenable the
interrupts, the system call hook is in place and will immediately
start to receive calls.





Structure of Our Basic Call Hook



This is the generic call hook. It does nothing
other than call the original function and return the results. So,
in effect, it does nothing at all. The
computer continues to function normally (with an unnoticeable
slowdown for the redirection):




[View full size
image]










Removing a Process Record




If our goal is to hide a process, we must
add some code to our call hook. Our new process hiding call hook
looks like this:




[View full size
image]










Figure
8-1 illustrates the way process records are stored in an
array.







Figure 8-1. How process records are
stored in an array.


















The code that removes an entry from the process
list follows:




[View full size
image]









Once we have "snipped" the entry, we return from
the function call. The task manager gets the modified structure and
skips the process record. We are now hiding the process.



We have illustrated that on Windows NT a device
driver can easily hook any system call. The standard format for a
device driver includes a DriverEntry function (the
equivalent of main() ). From here, any call hooks can be
installed.



The driver load routine takes pointers to the
original functions. These are stored globally for use. Interrupts
are disabled on the Intel x86 chip
using the __asm cli/sti instructions. During the time that
interrupts are disabled, the function addresses are replaced with
the Trojan versions in the service table. We use a handy
#define to find the correct offsets in the table. Once all
replacements are complete, we can safely reenable interrupts. When
unloading, we follow the same procedure as before, only we put back
the original function pointers.





Process Injection Alternative



Another method for hiding a subversive program
is to attach the subversive code to a process that is already
running. For example, we can create a remote thread in an existing
process. The remote thread runs the subversive program code. Once
again, the process list remains unaffected. This method is
completely effective from user mode and does not require kernel
access. The fact that this trick was used by the popular Back
Orifice 2000 program demonstrates its utility.















































Amazon






No comments: