windows下的用户态调试的底层与上层实现
操作系统: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下的用户态调试的底层与上层实现的更多相关文章
- systemtap 用户态调试
#include <stdio.h> int main( void) { ; a=fun(,); printf("%d\n",a); } int fun(int a,i ...
- windows 下使用 mingw编译器 调试时 无法跟进源码
windows 下使用 mingw编译器 调试时 无法跟进源码 最近在公司使用QT 开发,官方在线下载的 安装的QT mingw 都是没有debug版本的 由于没有debug版本动态库 所以你调试的时 ...
- 总在用户态调试 C# 程序,终还是搭了一个内核态环境
一:背景 一直在用 WinDbg 调试用户态程序,并没有用它调试过 内核态,毕竟不是做驱动开发,也没有在分析 dump 中需要接触用内核态的需求,但未知的事情总觉得很酷,加上最近在看 <深入解析 ...
- [补] 如何在windows下用IDA优雅调试ELF
在windows下如何用IDA优雅调试ELF brief: 构建一个IDA-linux_server-docker镜像,优雅地IDA远程调试 使用传统虚拟机来运行一个linux程序就得跑一个完整的li ...
- 浅谈一下Windows下的用户权限
大学毕业后,选择做了苹果开发,一直是使用的Mac系统,所以对Windows的基本操作忘得几乎一干二净:因为做内网穿透的需要,要用到Windows下的权限问题,所以重新研究了一下Windows设置用户权 ...
- 如何在windows下用IDA优雅调试ELF
在windows下如何用IDA优雅调试ELF brief: 构建一个IDA-linux_server-docker镜像,优雅地IDA远程调试 使用传统虚拟机来运行一个linux程序就得跑一个完整的li ...
- windows下源码安装调试postgresql
环境:windows 10 postgresql版本:postgresql-9.6.5 使用工具:vs2017社区版 辅助工具:perl.diff.flex.bison 相关工具下载地址: perl下 ...
- Windows下搭建FFmpeg开发调试环境
背景 如果你是一个FFmpeg的使用者,那么绝大部分情况下只需要在你的程序中引用FFmpeg的libav*相关的头文件,然后在编译阶段链接相关的库即可. 但是如果你想调试FFmpeg内部相关的逻辑,或 ...
- 初探Windows用户态调试机制
我们在感叹Onlydbg强大与便利的同时,是否考虑过它实现的原理呢? 作为一个技术人员知其然必知其所以然,这才是我们追求的本心. 最近在学习张银奎老师的<软件调试>,获益良多.熟悉Wind ...
随机推荐
- git与svn对比
git 与 svn 对比 git的使用不需要联机 SVN集中式版本控制:每个人的版本都是提交到服务器,服务器坏了就雪崩.git分布式版本控制: 安全,每人本地有个版本库,每个人都可以充当‘服务器 它 ...
- Fancybox——学习(1)
转载:http://www.helloweba.com/view-blog-65.html Fancybox是一款优秀的jquery插件,它能够展示丰富的弹出层效果.前面我们有文章介绍了facybox ...
- asp.net mvc cooike 购物车 如何实现
先上代码: 1. ShoppingCartService 类 using System; using System.Collections.Generic; using System.Linq; us ...
- swift菜鸟入门视频教程-04-集合类型
本人自己录制的swift菜鸟入门,欢迎大家拍砖,有什么问题能够在这里留言. 主要内容: 数组(Arrays) 字典(Dictionaries) 集合的可变性(Mutability of Collect ...
- MVC实现类似QQ的网页聊天功能-Ajax(上)
说到QQ聊天,程序员首先想到的就是如何实现长连接,及时的接收并回馈信息.那么首先想到的就是Ajax,Ajax的运行机制是通过XMLHttpRequest向服务器发出异步请求,并接受数据,这样就可以实现 ...
- Linux中的小程序—— 进度条
在说正事之前,首先科普一下在什么是回车什么是换行? 我们通常所说的回车就是从一行的末尾跳到另一行的开头,但事实上这却是由回车和换行两个动作所完成的,也就是键盘上<enter>所完成的工作. ...
- Gradle的简介、安装与配置
Gradle介绍 Gradle是一个基于JVM的构建工具,它提供了: 像Ant一样,通用灵活的构建工具,对Ant的任务做了很好的集成 同Maven一样是基于约定的构建框架 强大的多工程构建支持.有广泛 ...
- Mac下如何不借助第三方工具实现NTFS分区的可写挂载
问题背景 我想很多使用Mac的同学都会遇到读写NTFS磁盘的问题,因为默认情况下Mac OSX对NTFS磁盘的挂载方式是只读(read-only)的,因此把一个NTFS格式的磁盘插入到Mac上,是只能 ...
- 移动端(IOS)iframe监听不到 onscroll 事件
问题描述: 我在一个页面A中有瀑布流,点击瀑布流中的图片需要进入到另外一个页面B,点击返回需要回到页面A中点击的位置,为了实现该效果所以在页面A中嵌入iframe,iframe指向页面B,页面B中同样 ...
- (转)Phonegap VS AppCan
简介 Phonegap PhoneGap是一个用基于HTML,CSS和JavaScript的,创建移动跨平台移动应用程序的快速开发平台.它使开发者能够利用iPhone,Android,Palm,Sym ...