hook技术--调试法hook

简介:

这种方法的具体hook实施比较灵活, 这里采用对目标API入口地址下断点,当调用时即
断下,截获参数内容后进行修改.这时可以通过修改eip的值让其跳转到任意地址.
这种方式没有文件等其他操作,它就相当于实现了一个最简单的调试器,而对被调试进程
进行修改内存是很正常的事件,因此被查杀可能性低
下面是测试将notepad的内容在保存文件时小写全部转为大写


DWORD debugHook(DWORD pid)
{
    HANDLE hProcess;//目标进程句柄
    HANDLE hThread;//线程句柄
    DEBUG_EVENT de; //调试事件
    CONTEXT thread_context;//线程上下文,包括各个寄存器值
    char* apiBase = 0;//API基址
                      //WriteFile的2个重要参数,要写入的内容和大小
    char *buffer;
    DWORD nNumberOfBytesToWrite;
    DWORD bufferBase;
    BYTE fakeCode = 0xcc;//int 3指令
    BYTE trueCode;        //保存原来的指令
    DWORD ret;
    if (!DebugActiveProcess(pid))
    {
        return GetLastError();
    }

    while (WaitForDebugEvent(&de, INFINITE))
    {
        switch (de.dwDebugEventCode)
        {
        case EXIT_PROCESS_DEBUG_EVENT:
            return 1;
        case CREATE_PROCESS_DEBUG_EVENT:
            //目标程序创建进程, 附加到调试器,都会发送该调试事件
            //获取进程句柄, 通过CreateProcessInfo 成员能获取更多信息
            hProcess = de.u.CreateProcessInfo.hProcess;
            hThread = de.u.CreateProcessInfo.hThread;
            //获取目标api地址,由于kernel32.dll加载到任何进程中基址都是一样的.所以直接获取本进程的也是一样的
            apiBase = (char*)GetProcAddress(GetModuleHandleA("kernel32.dll"), "WriteFile");
            //备份原来的指令
            ReadProcessMemory(hProcess, apiBase, &trueCode, sizeof(BYTE), &ret);
            //写入int 3指令
            WriteProcessMemory(hProcess, apiBase, &fakeCode, sizeof(BYTE), &ret);

            ContinueDebugEvent(pid, de.dwThreadId, DBG_CONTINUE);
            break;
        case EXCEPTION_DEBUG_EVENT:
            //异常事件,程序发生异常时将发送该调试事件
            //只关心我们设下的断点异常,其他一律不处理
            if (de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT)
            {
                if ((char*)de.u.Exception.ExceptionRecord.ExceptionAddress == apiBase)
                {
                    //恢复hook
                    WriteProcessMemory(hProcess, apiBase, &trueCode, sizeof(BYTE), &ret);
                    //获取上下文
                    thread_context.ContextFlags = CONTEXT_CONTROL;
                    GetThreadContext(hThread, &thread_context);
                    //恢复正常执行流程,即将eip调整到函数入口处
                    thread_context.Eip--;
                    SetThreadContext(hThread, &thread_context);
                    //获取WriteFile的参数lpBuffer和nNumberOfBytesToWrite
                    ReadProcessMemory(hProcess, (LPCVOID)(thread_context.Esp + 0xc), &nNumberOfBytesToWrite, 4, &ret);
                    buffer = (char*)malloc(sizeof(char)*nNumberOfBytesToWrite);
                    ReadProcessMemory(hProcess, (LPVOID)(thread_context.Esp + 0x8), &bufferBase, sizeof(DWORD), NULL);
                    ReadProcessMemory(hProcess, (LPCVOID)bufferBase, (LPVOID)buffer, nNumberOfBytesToWrite, &ret);

                    //转为大写
                    printf("
原始字符:
");
                    for (DWORD i = 0; i < nNumberOfBytesToWrite; i++)
                    {
                        printf("%c", buffer[i]);
                        if (buffer[i] <= 0x7a && buffer[i] >= 0x61)
                        {

                            buffer[i] -= 0x20;
                        }
                    }
                    WriteProcessMemory(hProcess, (LPVOID)(bufferBase), (LPCVOID)buffer, nNumberOfBytesToWrite, &ret);
                    free(buffer);
                    //继续运行程序
                    ContinueDebugEvent(pid, de.dwThreadId, DBG_CONTINUE);
                    Sleep(0); //释放本线程时间片

                    //重新勾住
                    WriteProcessMemory(hProcess, apiBase, &fakeCode, sizeof(byte), &ret);

                }
            }

            ContinueDebugEvent(pid, de.dwThreadId, DBG_CONTINUE);
            break;
        default:
            ContinueDebugEvent(pid, de.dwThreadId, DBG_CONTINUE);
            break;
        }

    }
}
原文地址:https://www.cnblogs.com/freesec/p/6555975.html