操作系统:windows XP

调试器通过CreateProcess传入带有DEBUG_PROCESS和DEBUG_ONLY_THIS_PROCESS的dwCreationFlags创建被调试进程。这种情况下,进程创建的早期(执行NtCreateProcess或NtCreateProcessEx之前),调用DbgUiConnectToDbg()使调用线程和调试子系统建立连接。DbgUiConnectToDbg()内部调用ZwCreateDebugObject创建一个DEBUG_OBJECT内核对象,并将其句柄保存在当前线程环境块(TEB)的的DbgSsReserved[1]中。调试进程与被调试进程就是通过DEBUG_OBJECT进行交互的。之后该线程便被认作是调试工作线程。
 
调用NtCreateProcess或NtCreateProcessEx时,
NTSYSAPI
NTSTATUS
NTAPI
NtCreateProcess(

OUT PHANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN HANDLE ParentProcess,
IN BOOLEAN InheritObjectTable,
IN HANDLE SectionHandle OPTIONAL,
IN HANDLE DebugPort OPTIONAL,
IN HANDLE ExceptionPort OPTIONAL );
DbgSsReserved[1]中的句柄将传入,内核中进程创建函数PspCreateProcess会检查它是否为空,若不为空,则取得该句柄的对象指针(PDEBUG_OBJECT),并将其存储于新创建进程EPROCESS的DebugPort中。之后新创建进程便被认作是被调试进程。
 
之后PspCreateProcess调用MmCreatePeb创建进程环境块(PEB)时,MmCreatePeb会根据DebugPort是否为空,相应设置PEB中BeingDebugged字段。
 
另一种情况是调试器附加到被调试进程。通过调用 BOOL DebugActiveProcess(DWORD dwProcessId)完成。首先会调用DebugUiConnectToDbg使调用进程与调试子系统建立连接。之后调用ProcessIdToHandle取得句柄。之后调用NTDLL中的DbgUiDebugActiveProcess。该函数调用NtDebugActiveProcess并传入ProcessHandle和DebugObject的handle。NtDebugActiveProcess内部根据句柄取得要被调试进程的EPROCESS和用于调试的调试对象DEBUG_OBJECT,之后向调试对象发送杜撰的调试事件(在调试循环中再说),之后调用DbgkpSetProcessDebugObject将调试对象的指针存储到被调试进程EPROCESS的DebugPort中,并调用DbgkpMarkProcessPeb设置被调试进程PEB的BeingDebugged字段。当NtDebugActiveProcess成功返回后,DbgUiDebugActiveProcess调用DbgUiIssueRemoteBreakIn在被调试进程中创建远程中断线程(后述),使被调试进程中断到调试器中。
 
之后调试器和被调试程序便建立起了调试会话。
 
之后调试线程进入了调试循环。调试线程使用WaitForDebugEvent等待调试事件。
 
调试事件即被调试进程所发生的某些特殊动作。例如线程、进程的创建和销毁等,当然还有非常重要的异常事件。被调试进程通过调试子系统发送给调试器,此时,调试器的WaitForDebugEvent将结束等待,并相应处理调试事件。具体如下:
 
调试子系统内核部分设计了一系列的函数来采集调试事件,并将收集到的调试事件以DBGKM_APIMSG这样的结构存储在调试子系统的调试消息队列中。当被调试进程创建新的进程或线程时,将产生相应的调试事件。在进程管理器创建新线程时,最后将调用PspUserThreadStartup准备启动线程。在该函数中,会调用调试子系统内核函数DbgkCreateThread,DbgkCreateThread将检查DebugPort是否为空,若为空,则立即返回,若不为空,继续检查进程的用户态运行时间(UserTime)是否为0,从而判断是否为进程中第一个线程。若是,若是,则通过DbgkpSendApiMessage()向DebugPort发送DbgKmCreateProcessApi消息,若不是,则发送DbgKmCreateThreadApi消息。
 
NTSTATUS DbgkpSendApiMessage(IN OUT PDGBKM_APIMSG ApiMsg, IN PVOID Port, IN BOOLEAN SuspendProcess)
其中Port一般是DebugPort中的指向DEBUG_OBJECT的指针。SuspendProcess说明是否要挂起被调试进程。若SuspendProcess为真,则该函数调用DbgkpSuspendProcess挂起被调试进程。之后调用DbgkpQueueMessage,该函数根据参数决定是否需要等待,若需要,则通过等待函数,直到收到调试器回复后返回。若是发送杜撰消息,则无需等待直接返回。之后若挂起了调试进程,则调用DbgkpResumeProcess唤醒被调试进程。
 
DbgkpSuspendProcess调用KeFreezeAllThreads()冻结除被调试进程中产生调试事件的线程的所有线程。之后如上文,该线程调用DbgkpQueueMessage发送消息并在大部分情况下调用KeWaitForSingleObject等待调试器的返回。之后调试子系统会通知调试器读取调试事件。调试器调试线程WaitForDebugObject返回,调试线程处理调试事件。完成之后调用ContinueDebugEvent。之后调试子系统唤醒被调试进程在等待的那个线程。该线程醒来后,会调用KeThawAllThreads()唤醒被调试进程中的所有线程。

windows下的用户态调试的底层与上层实现的更多相关文章

  1. systemtap 用户态调试

    #include <stdio.h> int main( void) { ; a=fun(,); printf("%d\n",a); } int fun(int a,i ...

  2. windows 下使用 mingw编译器 调试时 无法跟进源码

    windows 下使用 mingw编译器 调试时 无法跟进源码 最近在公司使用QT 开发,官方在线下载的 安装的QT mingw 都是没有debug版本的 由于没有debug版本动态库 所以你调试的时 ...

  3. 总在用户态调试 C# 程序,终还是搭了一个内核态环境

    一:背景 一直在用 WinDbg 调试用户态程序,并没有用它调试过 内核态,毕竟不是做驱动开发,也没有在分析 dump 中需要接触用内核态的需求,但未知的事情总觉得很酷,加上最近在看 <深入解析 ...

  4. [补] 如何在windows下用IDA优雅调试ELF

    在windows下如何用IDA优雅调试ELF brief: 构建一个IDA-linux_server-docker镜像,优雅地IDA远程调试 使用传统虚拟机来运行一个linux程序就得跑一个完整的li ...

  5. 浅谈一下Windows下的用户权限

    大学毕业后,选择做了苹果开发,一直是使用的Mac系统,所以对Windows的基本操作忘得几乎一干二净:因为做内网穿透的需要,要用到Windows下的权限问题,所以重新研究了一下Windows设置用户权 ...

  6. 如何在windows下用IDA优雅调试ELF

    在windows下如何用IDA优雅调试ELF brief: 构建一个IDA-linux_server-docker镜像,优雅地IDA远程调试 使用传统虚拟机来运行一个linux程序就得跑一个完整的li ...

  7. windows下源码安装调试postgresql

    环境:windows 10 postgresql版本:postgresql-9.6.5 使用工具:vs2017社区版 辅助工具:perl.diff.flex.bison 相关工具下载地址: perl下 ...

  8. Windows下搭建FFmpeg开发调试环境

    背景 如果你是一个FFmpeg的使用者,那么绝大部分情况下只需要在你的程序中引用FFmpeg的libav*相关的头文件,然后在编译阶段链接相关的库即可. 但是如果你想调试FFmpeg内部相关的逻辑,或 ...

  9. 初探Windows用户态调试机制

    我们在感叹Onlydbg强大与便利的同时,是否考虑过它实现的原理呢? 作为一个技术人员知其然必知其所以然,这才是我们追求的本心. 最近在学习张银奎老师的<软件调试>,获益良多.熟悉Wind ...

随机推荐

  1. 黑马程序员_Java集合Map

    Map Map概述: 接口Map<k,v> 类型参数: k-此映射所维护的键的类型 v-映射值的类型 Map集合:该集合存储键值对.一对一对往理存.而且要保证键的唯一性. 嵌套类摘要: s ...

  2. HDU_2048——全错位排列递推公式

    Problem Description HDU 2006'10 ACM contest的颁奖晚会隆重开始了! 为了活跃气氛,组织者举行了一个别开生面.奖品丰厚的抽奖活动,这个活动的具体要求是这样的:首 ...

  3. 解耦——Hybrid H5跨平台性思考

    跨平台,是HTML5最重要的能力之一.而Hybrid H5因强依赖于具体App,往往不具有跨平台性.这时,将强依赖关系解耦,即可恢复HTML5的跨平台能力.近期我负责手Q红包打赏项目的前端开发,因项目 ...

  4. [LeetCode] 128. Longest Consecutive Sequence 解题思路

    Given an unsorted array of integers, find the length of the longest consecutive elements sequence. F ...

  5. 对象拷贝类PropertyUtils,BeanUtils,BeanCopier的技术沉淀

    功能简介 对象拷贝的应用现状简介: 业务系统中经常需要两个对象进行属性的拷贝,不能否认逐个的对象拷贝是最快速最安全的做法,但是当数据对象的属性字段数量超过程序员的容忍的程度,代码因此变得臃肿不堪,使用 ...

  6. JDBC编程之事务处理

    JDBC中的事务处理指的是事务的一致性等问题,例如插入一条数据(id,name,password)到表中,另一条数据(address,id)到另一张表中,并且两条数据是相关联的,那么假设第一条数据插入 ...

  7. 安装 Android 运行环境

    如果你恰好有一些旧的. 过时的 Android SDK 版本,请务必把所需的包更新至下面提到的版本并安装所有缺少的部分. 安装和配置 SDK 安装最新的 JDK. 使用 brew install an ...

  8. Android 使用ViewPager实现左右循环滑动图片

    ViewPager这个小demo实现的是可以左右循环滑动图片,下面带索引,滑到最后一页在往右滑动就要第一页,第一页往左滑动就到最后一页,先上效果图,用美女图片是我一贯的作风,呵呵 1.    首先看一 ...

  9. java单例模式(两种常用模式)

    单例模式是java中常见的设计模式 特点: 单例类只能有一个实例 单例类必须自己创建自己的唯一实例 单例类必须给所有的其他对象提供这一实例 单例模式是某个类只能有一个实例而且自动实例化并且向整个系统提 ...

  10. RPM包查询

    一.查询包是否安装 [root@localhost Packages]# rpm -q httpd            ---> 查询已安装的包(命令包名) #选项: #    -q    查 ...