首页 > 其他分享 >10.1 调试事件读取寄存器

10.1 调试事件读取寄存器

时间:2023-10-04 09:00:45浏览次数:58  
标签:10.1 08X 读取 线程 context 寄存器 断点 0x% hThread

当读者需要获取到特定进程内的寄存器信息时,则需要在上述代码中进行完善,首先需要编写CREATE_PROCESS_DEBUG_EVENT事件,程序被首次加载进入内存时会被触发此事件,在该事件内首先我们通过lpStartAddress属性获取到当前程序的入口地址,并通过SuspendThread暂停程序的运行,当被暂停后则我没就可以通过ReadProcessMemory读取当前位置的一个字节机器码,目的是保存以便于后期的恢复,接着通过WriteProcessMemory向对端(void*)dwAddr地址写出一个0xCC断点,该断点则是int3停机指令,最后ResumeThread恢复这个线程的运行,此时程序中因存在断点,则会触发一个EXCEPTION_DEBUG_EVENT异常事件。

case CREATE_PROCESS_DEBUG_EVENT:
{
    // 获取入口地址 0x0 可以增加偏移到入口后任意位置
    DWORD dwAddr = 0x0 + (DWORD)de.u.CreateProcessInfo.lpStartAddress;

    // 暂停线程
    SuspendThread(de.u.CreateProcessInfo.hThread);

    // 读取入口地址处的字节码
    ReadProcessMemory(de.u.CreateProcessInfo.hProcess, (const void*)dwAddr, &bCode, sizeof(BYTE), &dwNum);

    // 在入口地址处写入 0xCC 即写入 INT 3 暂停进程执行
    WriteProcessMemory(de.u.CreateProcessInfo.hProcess, (void*)dwAddr, &bCC, sizeof(BYTE), &dwNum);

    // 恢复线程
    ResumeThread(de.u.CreateProcessInfo.hThread);
    break;
}

当异常断点被触发后,则下一步就会触发两次异常,第一次异常我们可以使用break直接跳过,因为此断点通常为系统断点,而第二次断点则是我们自己设置的int3断点,此时需要将该请求发送至OnException异常处理函数对其进行处理,在传递时需要给与&de调试事件,以及&bCode原始的机器码;

case EXCEPTION_DEBUG_EVENT:
{
    switch (dwCC_Count)
    {
        // 第0次是系统断点,这里我们直接跳过
    case 0:
        dwCC_Count++; break;

        // 第1次断点,我们让他执行下面的函数
    case 1:
        OnException(&de, &bCode); dwCC_Count++; break;
    }
}

异常事件会被流转到OnException(DEBUG_EVENT* pDebug, BYTE* bCode)函数内,在本函数内我们首先通过使用OpenProcess/OpenThread两个函数得到当前进程的句柄信息,接着使用SuspendThread(hThread)暂时暂停进程内线程的执行,通过调用ReadProcessMemory得到线程上下文异常产生的首地址,当得到首地址后,则可以调用GetThreadContext(hThread, &context)得到当前线程的上下文,一旦上下文被获取到则读者即可通过context.的方式得到当前程序的所有寄存器信息,为了让程序正常执行当读取结束后,通过WriteProcessMemory我们将原始机器码写回到内存中,并SetThreadContext设置当前上下文,最后使用ResumeThread运行该线程;

void OnException(DEBUG_EVENT* pDebug, BYTE* bCode)
{
    CONTEXT context;
    DWORD dwNum;
    BYTE bTmp;

    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pDebug->dwProcessId);
    HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, pDebug->dwThreadId);

    // 暂停指定的线程
    SuspendThread(hThread);

    // 读取出异常首地址
    ReadProcessMemory(hProcess, pDebug->u.Exception.ExceptionRecord.ExceptionAddress, &bTmp, sizeof(BYTE), &dwNum);

    context.ContextFlags = CONTEXT_FULL;
    GetThreadContext(hThread, &context);

    printf("\n");

    printf("EAX = 0x%08X  |  EBX = 0x%08X  |  ECX = 0x%08X  |  EDX = 0x%08X \n",
        context.Eax, context.Ebx, context.Ecx, context.Edx);
    printf("EBP = 0x%08X  |  ESP = 0x%08X  |  ESI = 0x%08X  |  EDI = 0x%08X \n\n",
        context.Ebp, context.Esp, context.Esi, context.Edi);

    printf("EIP = 0x%08X  |  EFLAGS = 0x%08X\n\n", context.Eip, context.EFlags);

    // 将刚才的CC断点取消,也就是回写原始指令集
    WriteProcessMemory(hProcess, pDebug->u.Exception.ExceptionRecord.ExceptionAddress, bCode, sizeof(BYTE), &dwNum);
    context.Eip--;

    // 设置线程上下文
    SetThreadContext(hThread, &context);

    // printf("进程句柄:   0x%08X \n", pDebug->u.CreateProcessInfo.hProcess);
    // printf("主线程句柄: 0x%08X \n", pDebug->u.CreateProcessInfo.hThread);
    printf("虚拟入口点: 0x%08X \n", pDebug->u.CreateProcessInfo.lpBaseOfImage);

    // 恢复线程执行
    ResumeThread(hThread);
    CloseHandle(hThread);
    CloseHandle(hProcess);
}

当这段程序被运行后,读者可看到如下图所示的输出信息,该进程中当前寄存器的状态基本上都可以被获取到;

本文作者: 王瑞
本文链接: https://www.lyshark.com/post/94ad4ba.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

标签:10.1,08X,读取,线程,context,寄存器,断点,0x%,hThread
From: https://www.cnblogs.com/LyShark/p/17741912.html

相关文章

  • 文心一言 VS 讯飞星火 VS chatgpt (105)-- 算法导论10.1 3题
    三、用go语言,仿照图10-2,画图表示依次执行操作ENQUEUE(Q,4)、ENQUEUE(Q,1)、ENQUEUE(Q,3)、DEQUEUE(Q)、ENQUEUE(Q,8)和DEQUEUE(Q)每一步的结果,队列初始为空,存储于数组Q[1..6]中。文心一言:在这个问题中,我们尝试使用Go语言来模拟队列的操作,并且展示每一步的结果。首先,我们需要定......
  • 文心一言 VS 讯飞星火 VS chatgpt (105)-- 算法导论10.1 3题
    三、用go语言,仿照图10-2,画图表示依次执行操作ENQUEUE(Q,4)、ENQUEUE(Q,1)、ENQUEUE(Q,3)、DEQUEUE(Q)、ENQUEUE(Q,8)和DEQUEUE(Q)每一步的结果,队列初始为空,存储于数组Q[1..6]中。文心一言:在这个问题中,我们尝试使用Go语言来模拟队列的操作,并且展示每一步的结果。首先,我们需要定义......
  • 笨办法学Python3 习题15 读取文件
    知识点:要读取文件内容,需要先执行打开文件命令// 先filetxt=open(filename)  再print(filetxt.read()) //注意文件内容不能有英文外的文字,否则报错 1fromsysimportargv#从系统模块导入到参数变量23script,filename=argv......
  • shell 循环读取文件中每一行的方法详解
    当需要在shell脚本中读取文件中的每一行进行处理时,可以使用while循环或for循环。下面将详细介绍这两种方法。 方法一:使用while循环使用while循环是一种常见的读取文件中每行的方法。该方法的基本语法如下:whilereadlinedo#处理每一行的代码done<filename其中,readline......
  • 文心一言 VS 讯飞星火 VS chatgpt (104)-- 算法导论10.1 2题
    二、用go语言,说明如何在一个数组A[1..n]中实现两个栈,使得当两个栈的元素个数之和不为n时,两者都不会发生上溢。要求PUSH和POP操作的运行时间为O(1)。文心一言:在这个问题中,我们要在一个数组A[1..n]中实现两个栈,使得当两个栈的元素个数之和不为n时,两者都不会发生上溢。这......
  • 文心一言 VS 讯飞星火 VS chatgpt (104)-- 算法导论10.1 2题
    二、用go语言,说明如何在一个数组A[1..n]中实现两个栈,使得当两个栈的元素个数之和不为n时,两者都不会发生上溢。要求PUSH和POP操作的运行时间为O(1)。文心一言:在这个问题中,我们要在一个数组A[1..n]中实现两个栈,使得当两个栈的元素个数之和不为n时,两者都不会发生上溢。......
  • 2023.10.1记录
    被NOIP提高组的题暴虐。[NOIP2000提高组]方格取数NOIP2000提高组]方格取数-洛谷|计算机科学教育新生态(luogu.com.cn)题意从一个\(n\timesn\)的矩阵的左上角走到右下角,只能往右边和下边走,选择两条路,把这两条路经过的单位的数字取走,每个单位的数字只能取一次,求最大能......
  • 上周热点回顾(9.25-10.1)
    热点随笔:· 在小公司编程是一种什么样的体验? (公众号_陶朱公Boy)· 一个混乱千万级软件项目 (烂人)· 《优化接口设计的思路》系列:第四篇—接口的权限控制 (sum墨)· C#开源且免费的Windows桌面快速预览神器-QuickLook (追逐时光者)· .NET开发工作效率提升利器-Cod......
  • Aveva Marine VBNET 编程系列====>读取drawing explorer的第2层级 Sub views
    接上期的内容,此次读取view的下一层几subview主要用到下面的方法获取view的第一个子级一个封装的类PublicClassDrawingExpolrerExPublicSharedFunctionDrawingHasViews(draftAppAsMarDrafting)AsBooleanDimvhAsMarElementHandleTry......
  • 2023.10.1
    今天,上午去挂水了,下午去搞之前一直没搞定的一道题目,终于搞清楚了之前我一直在犯得错误,那就是这道题是64位的,我以前做过的需要泄露libc的题目,只有ctfwiki上自带的例题(32位),所以用栈溢出调用函数的时候,按照以前的想法,参数是直接放在payload里,之后payload被读到栈上后,参数就是在栈上的......