Windows下DebugHook例子,大道至简

xingyun86 2019-1-10 2094

命名

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

先来说说调试的原理

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

: CreateProcess()

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

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

:DebugActiveProcess(ProcessID)

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

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

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

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

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

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

4.执行需要的操作。

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

6.运行相应的API。

#include<Windows.h>
#include<iostream>
#include<stdio.h>
using namespace std;
LPVOID WriteFileAddress = NULL;
CREATE_PROCESS_DEBUG_INFO CreateProcessDebugInfomation;
BYTE INT3 = 0xCC, OldByte = 0;
BOOL OnCreateProcessDebugEvent(LPDEBUG_EVENT pde)
{
    // WriteFile()函数地址
    WriteFileAddress = GetProcAddress(GetModuleHandleA("kernel32.dll"), "WriteFile");
    // API Hook - WriteFile()
    //将WriteFile函数的首个字节改为0xcc
    memcpy(&CreateProcessDebugInfomation, &pde->u.CreateProcessInfo, sizeof(CREATE_PROCESS_DEBUG_INFO));
    ReadProcessMemory(CreateProcessDebugInfomation.hProcess, WriteFileAddress,
                      &OldByte, sizeof(BYTE), NULL);
    WriteProcessMemory(CreateProcessDebugInfomation.hProcess, WriteFileAddress,
                       &INT3, sizeof(BYTE), NULL);
    return TRUE;
}
BOOL OnExceptionDebugEvent(LPDEBUG_EVENT pDebugEvent)
{
    CONTEXT Context;
    PBYTE lpBuffer = NULL;
    DWORD dwNumOfBytesToWrite, dwAddrOfBuffer, i;
    PEXCEPTION_RECORD pExceptionRecord = &pDebugEvent->u.Exception.ExceptionRecord;
    // BreakPoint exception 
    if( EXCEPTION_BREAKPOINT == pExceptionRecord->ExceptionCode )
    {
        // 发生异常的地方是否为我们要钩取的函数
        if( WriteFileAddress == pExceptionRecord->ExceptionAddress )
        {
            // #1. Unhook
            //   先恢复,以免进入死循环
            WriteProcessMemory(CreateProcessDebugInfomation.hProcess, WriteFileAddress,
                               &OldByte, sizeof(BYTE), NULL);
            // #2. 获得线程上下背景文  为了修改EIp的值,来使进程恢复正常运行
            Context.ContextFlags = CONTEXT_CONTROL;
            GetThreadContext(CreateProcessDebugInfomation.hThread, &Context);
            // #3. WriteFile() 根据ESP来获得WriteFile 函数的参数,以达到修改数据的目的
           
            ReadProcessMemory(CreateProcessDebugInfomation.hProcess, (LPVOID)(Context.Esp + 0x8),
                              &dwAddrOfBuffer, sizeof(DWORD), NULL);
            ReadProcessMemory(CreateProcessDebugInfomation.hProcess, (LPVOID)(Context.Esp + 0xC),
                              &dwNumOfBytesToWrite, sizeof(DWORD), NULL);
            // #4.
            lpBuffer = (PBYTE)malloc(dwNumOfBytesToWrite+1);
            memset(lpBuffer, 0, dwNumOfBytesToWrite+1);
            // #5. WriteFile() 
            ReadProcessMemory(CreateProcessDebugInfomation.hProcess, (LPVOID)dwAddrOfBuffer,
                              lpBuffer, dwNumOfBytesToWrite, NULL);
            printf("\n### original string ###\n%s\n", lpBuffer);
            // #6. 修改数据
            for( i = 0; i < dwNumOfBytesToWrite; i++ )
            {
                if( 0x61 <= lpBuffer[i] && lpBuffer[i] <= 0x7A )
                    lpBuffer[i] -= 0x20;
            }
            printf("\n### converted string ###\n%s\n", lpBuffer);
            // #7. 调用原函数
            WriteProcessMemory(CreateProcessDebugInfomation.hProcess, (LPVOID)dwAddrOfBuffer,
                               lpBuffer, dwNumOfBytesToWrite, NULL);
            
           
            free(lpBuffer);
            // 设置EIP的值来实现正常运行,注意EIP的值为0xcc的下一条指令的地址。
            Context.Eip = (DWORD)WriteFileAddress;
            SetThreadContext(CreateProcessDebugInfomation.hThread, &Context);
            // 运行
            ContinueDebugEvent(pDebugEvent->dwProcessId, pDebugEvent->dwThreadId, DBG_CONTINUE);
            Sleep(0);
            // 再次钩取
            WriteProcessMemory(CreateProcessDebugInfomation.hProcess, WriteFileAddress,
                               &INT3, sizeof(BYTE), NULL);
            return TRUE;
        }
    }
    return FALSE;
}
void DebugLoop()
{
    DEBUG_EVENT DebugEvent;
    DWORD dwContinueStatus;
    // 等待调试事件
    while( WaitForDebugEvent(&DebugEvent, INFINITE) )
    {
        dwContinueStatus = DBG_CONTINUE;
        // 调试事件为创建进程
        if( CREATE_PROCESS_DEBUG_EVENT == DebugEvent.dwDebugEventCode )
        {
            OnCreateProcessDebugEvent(&DebugEvent);
        }
        // 调试事件
        else if( EXCEPTION_DEBUG_EVENT == DebugEvent.dwDebugEventCode )
        {
            if( OnExceptionDebugEvent(&DebugEvent) )
                continue;
        }
        // 调试进程退出
        else if( EXIT_PROCESS_DEBUG_EVENT == DebugEvent.dwDebugEventCode )
        {
          
            break;
        }
      
        ContinueDebugEvent(DebugEvent.dwProcessId, DebugEvent.dwThreadId, dwContinueStatus);
    }
}
int main(int argc, char* argv[])
{
    DWORD dwProcessID;
    cout << "Input ProcessID" << endl;
    cin >> dwProcessID;
    // Attach Process
    
    if( !DebugActiveProcess(dwProcessID) )
    {
        printf("DebugActiveProcess(%d) failed!!!\n"
               "Error Code = %d\n", dwProcessID, GetLastError());
        return 1;
    }
    // 调试事件循环
    DebugLoop();
    return 0;
}


×
打赏作者
最新回复 (0)
查看全部
全部楼主
返回