Dangerous Detours, Part 1: Introduction

Detours is a library that allows you to hook arbitrary functions by rewriting machine code. While a description of the exact implementation approach can be found in the corresponding paper as well as in numerous other sources, the basic idea is as follows:

  • In the to-be-hooked function, disassemble the first instructions until you have read at least 5 bytes. As instructions are variable length on x86, we may end up having to read more than 5 bytes to reach the next instruction boundary. Let the number of bytes read be n.
  • Allocate n+5 bytes of memory which will make up the trampoline.
  • Copy the n bytes from the to-be-hooked function to the trampoline, followed by a near jump to the to-be-hooked function + offset n (i.e. the first instruction after the instructions we copied)
  • Now overwrite the first 5 bytes of the to-be-hooked function with a near jump to the hook-function
  • The hook function may either return, so that the original function is never executed or instead jump to the trampoline

If we want to replace the to-be-hooked function, the execution flow is as follows:

  • Entering to-be-hooked function
  • Jump to hook function
  • Hook function does its work
  • Return to caller

The body of the to-be-hooked function is never executed.


        Caller function
       /          ^
      /           |
     v            |
  (via jmp        |
in to-be-hooked   |
  function)       |
     |            |
     v            | return
    Hook  --------+
  function
     

If instead the hook function, after having done its work, wants the original function to execute, the execution flow is as follows:

  • Entering to-be-hooked function
  • Jump to hook function
  • Hook function does its work
  • Jump to trampoline
  • Execute n bytes in trampoline
  • Jump to original function + offset n
  • Original function runs and finally returns

        Caller function
       /                ^
      /                  \
     v                    \
  (via jmp                 \
in to-be-hooked       To-be-hooked 
  function)             function
     |                      ^
     v                      |
    Hook  -------------> Trampoline
  function
     

Example: Replacing a function

As an example, we ‘replace’ OriginalFunction by AlternateFunction. The source code is as follows (error checking omitted):

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

__declspec(noinline)
static void OriginalFunction( PCWSTR Arg1, LONG Arg2 )
{
  wprintf( L"OriginalFunction(%s, %d)\n", Arg1, Arg2 );
}

__declspec(noinline)
static void AlternateFunction( PCWSTR Arg1, LONG Arg2 )
{
  wprintf( L"AlternateFunction(%s, %d)\n", Arg1, Arg2 );
}

int wmain()
{
  //
  // Install hook.
  //
  DetourTransactionBegin();
  DetourUpdateThread( GetCurrentThread() );
  
  PVOID Func = ( PVOID ) OriginalFunction;
  DetourAttach( 
      &Func, 
      AlternateFunction );

  DetourTransactionCommit();
  
  //
  // Call (hooked) function.
  //
  OriginalFunction( L"Hello", 42 );

  return 0;
}

The code is straightforward — we instruct Detours to hook OriginalFunction and call AlternateFunction instead. We do not make use of the trampoline. The output is:

AlternateFunction(Hello, 42)

Up to this point, everything works as advertised. And indeed there is little that can go wrong if we just want to ‘replace’ a function. If, however, we want the hook function eventually call the original function by making use of the trampoline, it gets more interesting, as we will see in Part 2.

Advertisements



Categories




About me

Johannes Passing, M.Sc., living in Berlin, Germany.

Besides his consulting work, Johannes mainly focusses on Win32, COM, and NT kernel mode development, along with Java and .Net. He also is the author of cfix, a C/C++ unit testing framework for Win32 and NT kernel mode, Visual Assert, a Visual Studio Unit Testing-AddIn, and NTrace, a dynamic function boundary tracing toolkit for Windows NT/x86 kernel/user mode code.

Contact Johannes: jpassing (at) acm org

Johannes' GPG fingerprint is BBB1 1769 B82D CD07 D90A 57E8 9FE1 D441 F7A0 1BB1.

LinkedIn Profile
Xing Profile
Github Profile

%d bloggers like this: