Advertisement
Guest User

Detours.cpp

a guest
Apr 8th, 2010
3,765
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.64 KB | None | 0 0
  1. #include "Detours.h"
  2.  
  3. namespace Detours
  4. {
  5.     namespace Internals
  6.     {
  7.         const unsigned char opcode_jmp_near = 0xE9;
  8.         const size_t szJumpNear = 0x05;
  9.  
  10.         struct _hook
  11.         {
  12.             void* lpFunc;
  13.             void* lpTrampoline;
  14.             size_t szData;
  15.  
  16.             _hook()
  17.                 : lpFunc(NULL),
  18.                   lpTrampoline(NULL)
  19.             { }
  20.         };
  21.  
  22.         _hook* _hooks;
  23.         size_t _sz_hooks;
  24.         size_t _pt_hooks;
  25.  
  26.         bool AddHook(void* lpFunc, void* lpTrampoline)
  27.         {
  28.             if(!_hooks)
  29.             {
  30.                 _sz_hooks = 16;
  31.                 _pt_hooks = 0;
  32.                 _hooks = new _hook[_sz_hooks];
  33.                 if(!_hooks)
  34.                     return false;
  35.             }
  36.  
  37.             if(_pt_hooks == _sz_hooks)
  38.             {
  39.                 _hook* new_hooks = new _hook[_sz_hooks * 2];
  40.                 if(!new_hooks)
  41.                     return false;
  42.  
  43.                 memcpy(new_hooks, _hooks, _sz_hooks * sizeof(_hook));
  44.                 _sz_hooks *= 2;
  45.                 delete [] _hooks;
  46.                 _hooks = new_hooks;
  47.             }
  48.  
  49.             _hooks[_pt_hooks].lpFunc = lpFunc;
  50.             _hooks[_pt_hooks].lpTrampoline = lpTrampoline;
  51.             _pt_hooks += 1;
  52.  
  53.             return true;
  54.         }
  55.  
  56.         #define FIND_BY_FUNCTION 1
  57.         #define FIND_BY_TRAMPOLINE 2
  58.  
  59.         _hook* _FindHookByFuncAddr(void* lpFunc, size_t* szOutIndex, unsigned char ucFindType)
  60.         {
  61.             if(szOutIndex != NULL)
  62.                 *szOutIndex = static_cast<size_t>(-1);
  63.             for(size_t i = 0; i < _pt_hooks; i++)
  64.                 if((ucFindType == FIND_BY_FUNCTION && _hooks[i].lpFunc == lpFunc)
  65.                 || (ucFindType == FIND_BY_TRAMPOLINE && _hooks[i].lpTrampoline == lpFunc))
  66.                 {
  67.                     if(szOutIndex != NULL)
  68.                         *szOutIndex = i;
  69.                     return &_hooks[i];
  70.                 }
  71.  
  72.             return NULL;
  73.         }
  74.  
  75.         void RemoveHook(void* lpFunc)
  76.         {
  77.             size_t current_hook_index = 0;
  78.             _hook* current_hook = _FindHookByFuncAddr(lpFunc, &current_hook_index, FIND_BY_FUNCTION);
  79.  
  80.             if(!current_hook)
  81.                 return;
  82.  
  83.             errno_t err = memmove_s(current_hook, _pt_hooks - current_hook_index,
  84.                                     current_hook + 1, _sz_hooks - current_hook_index + 1);
  85.             if(err != 0)
  86.                 return;
  87.  
  88.             _pt_hooks -= 1;
  89.         }
  90.  
  91.         void GetTrampoline(void* lpFunc, void** lppTrampoline)
  92.         {
  93.             if(!lppTrampoline)
  94.                 return;
  95.             *lppTrampoline = NULL;
  96.  
  97.             _hook* hook = _FindHookByFuncAddr(lpFunc, NULL, FIND_BY_FUNCTION);
  98.             if(hook)
  99.                 *lppTrampoline = hook->lpTrampoline;
  100.         }
  101.  
  102.         void SetHookSize(void* lpFunc, size_t szData)
  103.         {
  104.             _hook* hook = _FindHookByFuncAddr(lpFunc, NULL, FIND_BY_FUNCTION);
  105.             if(hook)
  106.                 hook->szData = szData;
  107.         }
  108.  
  109.         size_t GetHookSize(void* lpTrampoline)
  110.         {
  111.             _hook* hook = _FindHookByFuncAddr(lpTrampoline, NULL, FIND_BY_TRAMPOLINE);
  112.             if(hook)
  113.                 return hook->szData;
  114.         }
  115.  
  116.         size_t _CalculateDispacement(void* lpFirst, void* lpSecond)
  117.         {
  118.             return reinterpret_cast<char*>(lpSecond) - (reinterpret_cast<char*>(lpFirst) + 5);
  119.         }
  120.  
  121.         /* Analyses function code and returns the size in bytes which consists a whole instruction set - minimal greater
  122.          * than 5 bytes for jump near (0xe9)
  123.          * If function body is less than 5 bytes or current instruction set prevents detour the return value is 0 */
  124.         size_t _AnalyzeFunctionCode(void* lpFunc)
  125.         {
  126.             unsigned char prologue[] = { 0x8b, 0xff, 0x55, 0x8b, 0xec };
  127.             if(!memcmp(prologue, lpFunc, sizeof(prologue)))
  128.                 return 5;
  129.             return 0;
  130.         }
  131.  
  132.         /* Creates a trampoline to the function lpFunc in virtual process memory by copying first szDispacement function
  133.          * data and set a relative jump to the skipped part at the end */
  134.         void* _CreateTrampoline(void* lpFunc, size_t szDispacement)
  135.         {
  136.             void* lpPage = VirtualAlloc(NULL, szDispacement + szJumpNear, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  137.             if(!lpPage)
  138.                 return NULL;
  139.  
  140.             size_t szRelativeAddr = _CalculateDispacement(lpPage, lpFunc);
  141.             try
  142.             {
  143.                 errno_t err = memcpy_s(lpPage, szDispacement, lpFunc, szDispacement);
  144.                 if(err)
  145.                     throw err;
  146.                 err = memcpy_s(reinterpret_cast<char*>(lpPage) + szDispacement, sizeof(opcode_jmp_near), &opcode_jmp_near, sizeof(opcode_jmp_near));
  147.                 if(err)
  148.                     throw err;
  149.                 err = memcpy_s(reinterpret_cast<char*>(lpPage) + szDispacement + sizeof(opcode_jmp_near), sizeof(size_t), &szRelativeAddr, sizeof(size_t));
  150.                 if(err)
  151.                     throw err;
  152.             }
  153.             catch(errno_t err)
  154.             {
  155.                 VirtualFree(lpPage, szDispacement + szJumpNear, 0);
  156.                 return NULL;
  157.             }
  158.  
  159.             SetHookSize(lpFunc, szDispacement + szJumpNear);
  160.             return lpPage;
  161.         }
  162.  
  163.         /* Restores original function data from the trampoline */
  164.         void _RestoreFunction(void* lpFunc, void* lpTrampoline)
  165.         {
  166.             size_t szHook = GetHookSize(lpTrampoline) - szJumpNear;
  167.             DWORD dwProtect = PAGE_READWRITE;
  168.  
  169.             VirtualProtect(lpFunc, szHook, dwProtect, &dwProtect);
  170.             memcpy_s(lpFunc, szHook, lpTrampoline, szHook);
  171.             VirtualProtect(lpFunc, szHook, dwProtect, &dwProtect);
  172.         }
  173.  
  174.         /* Destroys a trampoline in virtual memory */
  175.         void _DestroyTrampoline(void* lpTrampoline)
  176.         {
  177.             size_t szData = GetHookSize(lpTrampoline);
  178.             VirtualFree(lpTrampoline, szData, 0);
  179.         }
  180.    
  181.         /* Set a relative long jump to the start an lpFunc which targets to lpTarget */
  182.         bool _SetLongJumpTo(void* lpFunc, void* lpTarget)
  183.         {
  184.             size_t szDispacement = _CalculateDispacement(lpFunc, lpTarget);
  185.             DWORD dwProtect = PAGE_READWRITE;
  186.  
  187.             VirtualProtect(lpFunc, szJumpNear, dwProtect, &dwProtect);
  188.             *reinterpret_cast<char*>(lpFunc) = 0xE9;
  189.             errno_t err = memcpy_s(reinterpret_cast<char*>(lpFunc) + 1, sizeof(size_t), &szDispacement, sizeof(size_t));
  190.             VirtualProtect(lpFunc, szJumpNear, dwProtect, &dwProtect);
  191.  
  192.             if(!err)
  193.                 return true;
  194.  
  195.             void* lpTrampoline = NULL;
  196.             GetTrampoline(lpFunc, &lpTrampoline);
  197.             if(lpTrampoline)
  198.                 _RestoreFunction(lpFunc, lpTrampoline);
  199.  
  200.             return false;
  201.         }
  202.     }
  203.  
  204.     DETOUR_RESULT HookFunction(void* lpFunc, void* lpDetour, void** lppOriginalFunctionTrampoline)
  205.     {
  206.         if(lppOriginalFunctionTrampoline == NULL)
  207.             return ERROR_TRAMPOLINE_MISSING;
  208.  
  209.         size_t szCopiedFuncBody = Internals::_AnalyzeFunctionCode(lpFunc);
  210.         if(szCopiedFuncBody == 0)
  211.             return ERROR_INVALID_FUNCTION_BODY;
  212.  
  213.         void* lpFunctionTrampoline = Internals::_CreateTrampoline(lpFunc, szCopiedFuncBody);
  214.         if(!lpFunctionTrampoline)
  215.             return ERROR_INSUFFICIENT_MEMORY;
  216.  
  217.         try
  218.         {
  219.             if(!Internals::AddHook(lpFunc, lpFunctionTrampoline))
  220.                 throw ERROR_INSUFFICIENT_MEMORY;
  221.  
  222.             if(!Internals::_SetLongJumpTo(lpFunc, lpDetour))
  223.                 throw ERROR_CODE_INJECTION_FAILED;
  224.         }
  225.         catch(DETOUR_RESULT result)
  226.         {
  227.             Internals::RemoveHook(lpFunc);
  228.             Internals::_DestroyTrampoline(lpFunctionTrampoline);
  229.             return result;
  230.         }
  231.  
  232.         *lppOriginalFunctionTrampoline = lpFunctionTrampoline;
  233.         return DETOURED_OK;
  234.     }
  235.  
  236.     void UnhookFunction(void* lpFunc)
  237.     {
  238.         void* lpTrampoline;
  239.         Internals::GetTrampoline(lpFunc, &lpTrampoline);
  240.         if(!lpTrampoline)
  241.             return;
  242.  
  243.         Internals::RemoveHook(lpFunc);
  244.         Internals::_RestoreFunction(lpFunc, lpTrampoline);
  245.     }
  246. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement