Debug Hook

  • 命名

    关于这个命名是我自己这样说的,至于这种HOOK技术,先前在一个开源项目中叫做RemoteHook,我比较喜欢自己的这种命名,所以就叫Debug Hook。如果有错误,请指出。

  • 先来说说调试的原理

    在Windows操作系统,有两种方法可以来调试一个进程。

    1: CreateProcess()

    可以使用此函数来启动调试一个进程。

    CreateProcess(FileFullPath,NULL,NULL,NULL, false,DEBUG_PROCESS         |DEBUG_ONLY_THIS_PROCESS| CREATE_NEW_CONSOLE,
    NULL,NULL,&StartupInfo,&ProcessInfo) 
        

    2:DebugActiveProcess(ProcessID)

     可以使用此函数来附加到一个进程来进行调试。

    我们使用以上两种方法中的任何一种方法来调试一个进程,每当被调试进程发生调试事件的时候,OS都会暂停其运行。并向调试器报告相应的事件,调试器处理之后就可以继续运行。

  • 利用调试技术来HOOK API函数的相关步骤如下

    利用调试技术来HOOK API函数的相关步骤如下

    1对想要钩取的进程进行附加操作,使之成为被调试者。

    2将要钩取的API的起始地址的第一个字节修改为0xcc(或者使用硬件断点)。

    3当调用目标API的时候,控制权就转移到调试器进程。

    4执行需要的操作。

    5脱钩,将API 函数的第一个字节恢复。

    6运行相应的API。

      1 #include<Windows.h>
      2 #include<iostream>
      3 #include<stdio.h>
      4 
      5 using namespace std;
      6 
      7 LPVOID WriteFileAddress = NULL;
      8 CREATE_PROCESS_DEBUG_INFO CreateProcessDebugInfomation;
      9 BYTE INT3 = 0xCC, OldByte = 0;
     10 
     11 BOOL OnCreateProcessDebugEvent(LPDEBUG_EVENT pde)
     12 {
     13     // WriteFile()函数地址
     14     WriteFileAddress = GetProcAddress(GetModuleHandleA("kernel32.dll"), "WriteFile");
     15 
     16     // API Hook - WriteFile()
     17     //将WriteFile函数的首个字节改为0xcc
     18     memcpy(&CreateProcessDebugInfomation, &pde->u.CreateProcessInfo, sizeof(CREATE_PROCESS_DEBUG_INFO));
     19     ReadProcessMemory(CreateProcessDebugInfomation.hProcess, WriteFileAddress,
     20                       &OldByte, sizeof(BYTE), NULL);
     21     WriteProcessMemory(CreateProcessDebugInfomation.hProcess, WriteFileAddress,
     22                        &INT3, sizeof(BYTE), NULL);
     23 
     24     return TRUE;
     25 }
     26 
     27 BOOL OnExceptionDebugEvent(LPDEBUG_EVENT pDebugEvent)
     28 {
     29     CONTEXT Context;
     30     PBYTE lpBuffer = NULL;
     31     DWORD dwNumOfBytesToWrite, dwAddrOfBuffer, i;
     32     PEXCEPTION_RECORD pExceptionRecord = &pDebugEvent->u.Exception.ExceptionRecord;
     33 
     34     // BreakPoint exception 
     35     if( EXCEPTION_BREAKPOINT == pExceptionRecord->ExceptionCode )
     36     {
     37         // 发生异常的地方是否为我们要钩取的函数
     38         if( WriteFileAddress == pExceptionRecord->ExceptionAddress )
     39         {
     40             // #1. Unhook
     41             //   先恢复,以免进入死循环
     42             WriteProcessMemory(CreateProcessDebugInfomation.hProcess, WriteFileAddress,
     43                                &OldByte, sizeof(BYTE), NULL);
     44 
     45             // #2. 获得线程上下背景文  为了修改EIp的值,来使进程恢复正常运行
     46             Context.ContextFlags = CONTEXT_CONTROL;
     47             GetThreadContext(CreateProcessDebugInfomation.hThread, &Context);
     48 
     49             // #3. WriteFile() 根据ESP来获得WriteFile 函数的参数,以达到修改数据的目的
     50            
     51             ReadProcessMemory(CreateProcessDebugInfomation.hProcess, (LPVOID)(Context.Esp + 0x8),
     52                               &dwAddrOfBuffer, sizeof(DWORD), NULL);
     53 
     54             ReadProcessMemory(CreateProcessDebugInfomation.hProcess, (LPVOID)(Context.Esp + 0xC),
     55                               &dwNumOfBytesToWrite, sizeof(DWORD), NULL);
     56 
     57             // #4.
     58             lpBuffer = (PBYTE)malloc(dwNumOfBytesToWrite+1);
     59             memset(lpBuffer, 0, dwNumOfBytesToWrite+1);
     60 
     61             // #5. WriteFile() 
     62             ReadProcessMemory(CreateProcessDebugInfomation.hProcess, (LPVOID)dwAddrOfBuffer,
     63                               lpBuffer, dwNumOfBytesToWrite, NULL);
     64             printf("
    ### original string ###
    %s
    ", lpBuffer);
     65 
     66             // #6. 修改数据
     67             for( i = 0; i < dwNumOfBytesToWrite; i++ )
     68             {
     69                 if( 0x61 <= lpBuffer[i] && lpBuffer[i] <= 0x7A )
     70                     lpBuffer[i] -= 0x20;
     71             }
     72 
     73             printf("
    ### converted string ###
    %s
    ", lpBuffer);
     74 
     75             // #7. 调用原函数
     76             WriteProcessMemory(CreateProcessDebugInfomation.hProcess, (LPVOID)dwAddrOfBuffer,
     77                                lpBuffer, dwNumOfBytesToWrite, NULL);
     78             
     79            
     80             free(lpBuffer);
     81 
     82             // 设置EIP的值来实现正常运行,注意EIP的值为0xcc的下一条指令的地址。
     83             Context.Eip = (DWORD)WriteFileAddress;
     84             SetThreadContext(CreateProcessDebugInfomation.hThread, &Context);
     85 
     86             // 运行
     87             ContinueDebugEvent(pDebugEvent->dwProcessId, pDebugEvent->dwThreadId, DBG_CONTINUE);
     88             Sleep(0);
     89 
     90             // 再次钩取
     91             WriteProcessMemory(CreateProcessDebugInfomation.hProcess, WriteFileAddress,
     92                                &INT3, sizeof(BYTE), NULL);
     93 
     94             return TRUE;
     95         }
     96     }
     97 
     98     return FALSE;
     99 }
    100 
    101 void DebugLoop()
    102 {
    103     DEBUG_EVENT DebugEvent;
    104     DWORD dwContinueStatus;
    105 
    106     // 等待调试事件
    107     while( WaitForDebugEvent(&DebugEvent, INFINITE) )
    108     {
    109         dwContinueStatus = DBG_CONTINUE;
    110 
    111         // 调试事件为创建进程
    112         if( CREATE_PROCESS_DEBUG_EVENT == DebugEvent.dwDebugEventCode )
    113         {
    114             OnCreateProcessDebugEvent(&DebugEvent);
    115         }
    116         // 调试事件
    117         else if( EXCEPTION_DEBUG_EVENT == DebugEvent.dwDebugEventCode )
    118         {
    119             if( OnExceptionDebugEvent(&DebugEvent) )
    120                 continue;
    121         }
    122         // 调试进程退出
    123         else if( EXIT_PROCESS_DEBUG_EVENT == DebugEvent.dwDebugEventCode )
    124         {
    125           
    126             break;
    127         }
    128 
    129       
    130         ContinueDebugEvent(DebugEvent.dwProcessId, DebugEvent.dwThreadId, dwContinueStatus);
    131     }
    132 }
    133 
    134 int main(int argc, char* argv[])
    135 {
    136     DWORD dwProcessID;
    137     cout << "Input ProcessID" << endl;
    138     cin >> dwProcessID;
    139 
    140     // Attach Process
    141     
    142     if( !DebugActiveProcess(dwProcessID) )
    143     {
    144         printf("DebugActiveProcess(%d) failed!!!
    "
    145                "Error Code = %d
    ", dwProcessID, GetLastError());
    146         return 1;
    147     }
    148 
    149     // 调试事件循环
    150     DebugLoop();
    151 
    152     return 0;
    153 }

    参考《逆向工程核心原理》

原文地址:https://www.cnblogs.com/banchen/p/6696562.html