Microsoft Research Detours Package Pro 3.0 Retail » Developer.Team

Microsoft Research Detours Package Pro 3.0 Retail

Microsoft Research Detours Package Pro 3.0 Retail
Microsoft Research Detours Package 3.0 Retail


Detours is a library for intercepting binary functions on ARM, x86, x64, and IA64 machines. Detours is most commmonly used to intercept Win32 APIs calls within an application, such as to add debugging instrumentation. Interception code is applied dynamically at runtime. Detours replaces the first few instructions of the target function with an unconditional jump to the user-provided detour function. Instructions from the target function are placed in a trampoline. The address of the trampoline is placed in a target pointer. The detour function can either replace the target function or extend its semantics by invoking the target function as a subroutine through the target pointer to the trampoline.

Detours are inserted at execution time. The code of the target function is modified in memory, not on disk, thus enabling interception of binary functions at a very fine granularity. For example, the procedures in a DLL can be detoured in one execution of an application, while the original procedures are not detoured in another execution running at the same time. Unlike DLL re-linking or static redirection, the interception techniques used in the Detours library are guaranteed to work regardless of the method used by application or system code to locate the target function.

In addition to basic detour functionality, Detours also includes functions to edit the DLL import table of any binary, to attach arbitrary data segments to existing binaries, and to load a DLL into a new process. Once loaded into a process, the instrumentation DLL can detour any function in the process, whether in the application or the system libraries, such as the Windows APIs.

This technical overview of Detours is divided into four sections:

Interception of Binary Functions
Using Detours
Payloads and DLL Import Editing
Detouring 32-bit and 64-bit Processes

Interception of Binary Functions
The Detours library enables interception of function calls. Interception code is applied dynamically at runtime. Detours replaces the first few instructions of the target function with an unconditional jump to the user-provided detour function. Instructions from the target function are preserved in a trampoline function. The trampoline consists of the instructions removed from the target function and an unconditional branch to the remainder of the target function.

When execution reaches the target function, control jumps directly to the user-supplied detour function. The detour function performs whatever interception preprocessing is appropriate. The detour function can return control to the source function or it can call the trampoline function, which invokes the target function without interception. When the target function completes, it returns control to the detour function. The detour function performs appropriate postprocessing and returns control to the source function. Figure 1 shows the logical flow of control for function invocation with and without interception.



Figure 1. Control flow of invocation without Detours and with Detours.

--------------------------------------------------------------------------------

The Detours library intercepts target functions by rewriting their in-process binary image. For each target function, Detours actual rewrites two functions, the target function and the matching trampoline function, and one functon pointer, the target ppinter. The trampoline function is allocated dynamically by Detours. Prior to insertion of a detour, the trampoline contains only a single jump instruction to the target function. After insertion, the trampoline contains the initial instructions from the target function and a jump to the remainder of the target function.

The target pointer is initialized by the user to point to the target function. After a detour is attached to the target function, the target pointer is modified to point to the trampoline function. After the detour is detached from the target function, the target pointer is returned to point to the original target function.



Figure 2. Trampoline and target functions, before (on the left) and after (on the right) insertion of the detour.

--------------------------------------------------------------------------------

Figure 2 shows the insertion of a detour. To detour a target function, Detours first allocates memory for the dynamic trampoline function (if no static trampoline is provided) and then enables write access to both the target and the trampoline. Starting with the first instruction, Detours copies instructions from the target to the trampoline until at least 5 bytes have been copied (enough for an unconditional jump instruction). If the target function is fewer than 5 bytes, Detours aborts and returns an error code.

To copy instructions, Detours uses a simple table-driven disassembler. Detours adds a jump instruction from the end of the trampoline to the first non-copied instruction of the target function. Detours writes an unconditional jump instruction to the detour function as the first instruction of the target function. To finish, Detours restores the original page permissions on both the target and trampoline functions and flushes the CPU instruction cache with a call to the FlushInstructionCache API.

Using Detours
Two things are necessary in order to detour a target function: a target pointer containing the address of the target function and a detour function. For proper interception the target function, detour function, and the target pointer must have exactly the same call signature including number of arguments and calling convention. Using the same calling convention insures that registers will be properly preserved and that the stack will be properly aligned between detour and target functions

The code fragment in Figure 5 illustrates the usage of the Detours library. User code must include the detours.h header file and link with the detours.lib library.

#include <windows.h>
#include <detours.h>

static LONG dwSlept = 0;

// Target pointer for the uninstrumented Sleep API.
//
static VOID (WINAPI * TrueSleep)(DWORD dwMilliseconds) = Sleep;

// Detour function that replaces the Sleep API.
//
VOID WINAPI TimedSleep(DWORD dwMilliseconds)
{
    // Save the before and after times around calling the Sleep API.
    DWORD dwBeg = GetTickCount();
    TrueSleep(dwMilliseconds);
    DWORD dwEnd = GetTickCount();

    InterlockedExchangeAdd(&dwSlept, dwEnd - dwBeg);
}

// DllMain function attaches and detaches the TimedSleep detour to the
// Sleep target function.  The Sleep target function is referred to
// through the TrueSleep target pointer.
//
BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved)
{
    if (DetourIsHelperProcess()) {
        return TRUE;
    }

    if (dwReason == DLL_PROCESS_ATTACH) {
        DetourRestoreAfterWith();

        DetourTransactionBegin();
        DetourUpdateThread(GetCurrentThread());
        DetourAttach(&(PVOID&)TrueSleep, TimedSleep);
        DetourTransactionCommit();
    }
    else if (dwReason == DLL_PROCESS_DETACH) {
        DetourTransactionBegin();
        DetourUpdateThread(GetCurrentThread());
        DetourDetach(&(PVOID&)TrueSleep, TimedSleep);
        DetourTransactionCommit();
    }
    return TRUE;
}


Payloads and DLL Import Editing
In addition to APIs for attaching and detaching detours functions, the Detours package also include APIs for attaching arbitrary data segments, called payloads, to Windows binary files and for editing DLL import tables. The binary editing APIs in Detours are fully reversible; Detours stores recovery information within the binary to enable removal of the edits at any time in the future.

Format of a Windows PE binary file.

--------------------------------------------------------------------------------

Figure 3 shows the basic structure of a Windows Portable Executable (PE) binary file. The PE format for Windows binaries is an extension of COFF (the Common Object File Format). A Windows binary consists of a DOS compatible header, a PE header, a text section containing program code, a data section containing initialized data, an import table listing any imported DLLS and functions, an export table listing functions exported by the code, and debug symbols. With the exception of the two headers, each of the other sections of the file is optional and may not exist in a given binary.