• 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 }

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

  • 相关阅读:
    常见银行编码收集
    kafka集群在消息消费出现无法找到topic分区的处理解决
    find命令通过排序只保留最新的文件目录
    Git fetch和git pull的区别
    git 常用命令
    wordpress模板修改及函数说明
    webbench进行压力测试
    git存储用户名与密码
    导出putty配置
    一个成功的Git分支模型
  • 原文地址:https://www.cnblogs.com/banchen/p/6696562.html
Copyright © 2020-2023  润新知