• 断点拦截局部数据



      逆向开发经常有这个需求:拦截局部数据。一般的做法是hook,通过修改代码的流程来获得数据。还有一种办法是下断点调试。这里聊聊怎样通过下断点来拦截局部数据。

    零、原理简介

      下断点拦截数据,原理就是对目标进程进行下断点调试。

      设置断点的原理就是在某个地址写入0xCC。对某个地址设置断点之后,当被调试的目标进程运行到这个地址,就会报错抛出异常给我们的调试进程。我们的调试进程就可以拿到当前的环境数据。

      拿到数据之后,就要让目标进程继续正常执行了,这时候是先把0xCC恢复成原本的内容;然后EIP减一,让当前的指令重新正常执行;

      但这个时候断点已经恢复,想重复拦截数据的话就需要重新设置断点:设置单步标志,当前的指令重新正常执行之后,触发单步异常,这个时候再重新下断点就可以了。

    一、调试进程

    // 被调试的进程ID
    static DWORD g_processID = 0;
    
    // 将进程改为被调试状态
    DebugActiveProcess(g_processID);
    
    // 退出调试的时候,不关闭被调试进程
    BOOL kRet = DebugSetProcessKillOnExit(false);
    

    二、设置断点

    // 保存断点地址和对应的内存内容,用于恢复断点
    static map<DWORD, BYTE> g_mBpAddress2Content;
    
    // 添加断点,原理就是写入0xCC,程序运行到这里,会触发异常
    BOOL CBreakPointHelper::AddBreakPoint(DWORD address)
    {
        BYTE content;
        SIZE_T bytesRead;
        BOOL rRet = ReadProcessMemory(g_hProcess, (LPCVOID)address, &content, 1, &bytesRead);
    
        BYTE intInst = 0xCC;
        SIZE_T byteWriten;
        BOOL wRet = WriteProcessMemory(g_hProcess, (LPVOID)address, &intInst, 1, &byteWriten);
        if (wRet) g_mBpAddress2Content[address] = content;
    
        return rRet && wRet;
    }
    
    // 删除断点,原理就是把原本的内存内容写回去
    BOOL CBreakPointHelper::DelBreakPoint(DWORD address)
    {
        if (g_mBpAddress2Content.count(address) <= 0) return false; 
    	
        SIZE_T byteWriten;
        BYTE content = g_mBpAddress2Content[g_resetUserBpAddress];
        WriteProcessMemory(g_hProcess, (LPVOID)(address), &(content), 1, &byteWriten);
    
        return true;
    }
    

    三、监听消息

    DEBUG_EVENT debugEvent;
    while (WaitForDebugEvent(&debugEvent, INFINITE)) 
    {
        switch (debugEvent.dwDebugEventCode) 
        {
    	case EXCEPTION_DEBUG_EVENT:
                OnException(&debugEvent);
      	    break;
        }
    
        ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE);
    }
    

    四、处理异常

    void CBreakPointHelper::OnException(const DEBUG_EVENT* pEvent) 
    {
        const EXCEPTION_DEBUG_INFO* pInfo = &(pEvent->u.Exception);
        switch (pInfo->ExceptionRecord.ExceptionCode) 
        {
        case EXCEPTION_BREAKPOINT:   // 断点
    	OnBreakPoint(pEvent);
                break;
    	case EXCEPTION_SINGLE_STEP:  // 单步
                OnSingleStep(pEvent);
            break;
        }
    }
    
    void CBreakPointHelper::OnBreakPoint(const DEBUG_EVENT* pEvent)
    {
        // 获取当前地址
        const EXCEPTION_DEBUG_INFO* pInfo = &(pEvent->u.Exception);
        DWORD address = (DWORD)pInfo->ExceptionRecord.ExceptionAddress;
        g_resetUserBpAddress = address;
        DelBreakPoint(address);//删除断点,当前指令恢复正常
      
        // 获取环境
        CONTEXT context;
        context.ContextFlags = CONTEXT_FULL;
        GetThreadContext(hThread, &context);
      
        // 拦截数据
        BreakPointCB(address, &context);
      
        // 修改环境
        context.Eip -= 1;        // eip减一,重新执行当前指令
        context.EFlags |= 0x100; // 设置单步标记, 用于恢复断点 
        SetThreadContext(hThread, &context);
    }
    
    void CBreakPointHelper::OnSingleStep(const DEBUG_EVENT* pEvent)
    {
        // 恢复断点 
        AddBreakPoint(g_resetUserBpAddress);
    }
    
  • 相关阅读:
    NOIP2019 Emiya 家今天的饭 [提高组]
    Codeforces Round #663 (Div. 2) 题解
    树上差分入门
    Codeforces Round #664 (Div. 2) 题解
    [USACO19OPEN]Snakes
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
  • 原文地址:https://www.cnblogs.com/wwgk/p/14376362.html
Copyright © 2020-2023  润新知