一:背景

一直在用 WinDbg 调试用户态程序,并没有用它调试过 内核态,毕竟不是做驱动开发,也没有在分析 dump 中需要接触用内核态的需求,但未知的事情总觉得很酷,加上最近在看 《深入解析 Windows 操作系统》 一书,书中有不少案例需要深入到 内核态 ,所以这篇准备整理一下如何用 WinDbg 调试 C# 内核态吧。

操作环境:

  • Windbg Preview
  • 宿主机:Windows 10
  • 虚拟机:Windows 10

二:搭建内核态调试

1. 基本原理

操作系统的引导程序 BootMgrWinLoad 内置了调试模式,支持以 COM 接口互通,所以我们需要先添加一种可供调试的启动项,供引导程序 BootMgr 启动时弹框让我们选择。

2. 配置调试启动项

大家可以在 https://msdn.itellyou.cn/ 下载一个完整版的 Window10 ISO 包,这里就不细说了,启动虚拟机进入 Windows10 ,以管理员模式打开 CMD 窗口,执行如下 四条命令 来编辑 bcd (Boot Configuration Data)


bcdedit /dbgsettings serial baudrate:115200 debugport:1
bcdedit /copy {current} /d WinDbg
bcdedit /displayorder {current} {ID}
bcdedit /debug {ID} ON

注意一下,这里的 {ID} 是 CMD 上生成的 GUID,这是你的启动项唯一键,别名是 WinDbg, 在我的界面上大概是这个样子:

3. 配置 COM 接口

这里有几个步骤要注意了,大致如下:

1) 把打印机选项移除了,因为它占用了 COM1 接口。

2) 新增一个 串行端口

3)在 使用命名管道 中填入 \\.\pipe\com_1, 同时勾选 轮询时主动放弃CPU

设置完之后点击确定,完整截图如下:

4. 配置 Windbg Preview

我们把 WinDbg 打开,选择 Attach to kernel 选项,然后选择 COM 模式,设置 Baud Rate = 115200 ,然后是 Port=\\.\pipe\com_1 ,配置完之后点击 OK, 完整截图如下:

如果一切正常的话,Windbg 应该是如下输出,等待COM连接状态。


Microsoft (R) Windows Debugger Version 10.0.25136.1001 AMD64
Copyright (c) Microsoft Corporation. All rights reserved. Waiting for pipe \\.\pipe\com_1
Waiting to reconnect...

5. 启动虚拟机

这些都配置完之后,我们重新启动虚拟机,在 BootMgr 阶段会出现两个引导项,其中一个就是在 小项2 时配置的,我们选择它就好了,完整截图如下:

稍等片刻后 WinDbg 会显示连接成功,在进入初始化时会 int 3 中断, 如果你真的到了这一步,那恭喜你!!!



Microsoft (R) Windows Debugger Version 10.0.25136.1001 AMD64
Copyright (c) Microsoft Corporation. All rights reserved. Waiting for pipe \\.\pipe\com_1
Waiting to reconnect...
Connected to Windows 10 10240 x64 target at (Thu Sep 1 23:23:35.235 2022 (UTC + 8:00)), ptr64 TRUE
Kernel Debugger connection established. (Initial Breakpoint requested) ************* Path validation summary **************
Response Time (ms) Location
Deferred srv*c:\mysymbols_fix*https://msdl.microsoft.com/download/symbols
Error D:\net5\ConsoleApp1\Debug
Deferred srv*c:\mysymbols*https://msdl.microsoft.com/download/symbols
Symbol search path is: srv*c:\mysymbols_fix*https://msdl.microsoft.com/download/symbols;D:\net5\ConsoleApp1\Debug;srv*c:\mysymbols*https://msdl.microsoft.com/download/symbols
Executable search path is:
Windows 10 Kernel Version 10240 MP (1 procs) Free x64
Edition build lab: 10240.17394.amd64fre.th1_st1.170427-1347
Machine Name:
Kernel base = 0xfffff802`a3c7b000 PsLoadedModuleList = 0xfffff802`a3fa0070
System Uptime: 0 days 0:00:00.092
nt!DebugService2+0x5:
fffff802`a3dcfca5 cc int 3

因为是初始化中断,接下来在 WinDbg 命令面板中先用 g 执行,让操作系统继续跑下去,稍等片刻就会进入到 Windows 10 的操作界面。

6. netcore 测试

前段时间写了一篇文章,聊到了 ReadFile 从用户态切到内核态的过程,还画了一张图。

现在可以调试 内核态 那何不试试看呢??? 哈哈,说干就干,先上一段测试代码。


static void Main(string[] args)
{
var i = 0; File.WriteAllText(@"C:\1.txt", "hello world!");
while (true)
{
var str = File.ReadAllText(@"C:\1.txt");
Console.WriteLine($"{i++}, content={str.Length}");
Thread.Sleep(1000);
} Console.ReadLine();
}

为了方便观察用户态栈,我在虚拟机中的 Windows10 系统上安装一个 WinDbg10,目的就是拦截 ntdll!NtReadFile 函数时输出 用户态栈

bp ntdll!NtReadFile "k 10;gc"

可以看到每次只要程序输出一次,windbg10 都能成功拦截,接下来在宿主机的 WinDbg Preview 中先输入 .reload 重新加载下符号,目的就是方便看到用户态上的 ntdll.dll 函数名,但不一定好使,碰碰运气吧,接下来输入 nt!NtReadFile 观察内核态栈。

bp nt!NtReadFile

从新老Windbg截图中,可以清晰的看到,这个的 Child-SP 线程栈终于对接上了,也就验证了图上所说:ntdll!NtReadFile (用户态网关) -> nt!KiSystemServiceCopyEnd(内核态调度中心) -> nt!NtReadFile (内核态处理函数)

好了,本篇就先说这么多,希望对大家有帮助,也是对自己的一个总结。

总在用户态调试 C# 程序,终还是搭了一个内核态环境的更多相关文章

  1. linux 用户态和内核态以及进程上下文、中断上下文 内核空间用户空间理解

    1.特权级         Intel x86架构的cpu一共有0-4四个特权级,0级最高,3级最低,ARM架构也有不同的特权级,硬件上在执行每条指令时都会对指令所具有的特权级做相应的检查.硬件已经提 ...

  2. linux 用户态 内核态

    http://blog.chinaunix.net/uid-1829236-id-3182279.html 究竟什么是用户态,什么是内核态,这两个基本概念以前一直理解得不是很清楚,根本原因个人觉得是在 ...

  3. 在ubuntu下真机调试android程序出现设备没有访问权限

    今天把android的开发环境从windows平台切换到了ubuntu上. java jdk android-adt android-ndk都下好,环境变量都配好之后, 在调试程序的时候,出现设备没有 ...

  4. Linux 用户态和内核态

    1.特权级特权级用来管理和控制程序执行.如Intel x86架构的CPU,有0~3四个特权级,0级最高,3级最低.硬件在执行每条指令时都会检查指令具有的特权级.硬件提供了特权级使用机制,对操作系统来说 ...

  5. Linux内核态、用户态简介与IntelCPU特权级别--Ring0-3

    一.现代操作系统的权限分离: 现代操作系统一般都至少分为内核态和用户态.一般应用程序通常运行于用户态,而当应用程序调用系统调用时候会执行内核代码,此时会处于内核态.一般的,应用程序是不能随便进入内核态 ...

  6. 2.2.1 用户态、内核态的形成 -《zobolの操作系统学习札记》

    内核态的出现,让计算机系统的权力向操作系统高度集中了. 操作系统分出内核态和用户态,就是为了进行不同等级的权限管理, 从而更好的适应多用户多任务并发的工作环境. 用户态和内核态的来源 在早期的单进程单 ...

  7. Linux内核态抢占机制分析

    http://blog.sina.com.cn/s/blog_502c8cc401012pxj.html [摘要]本文首先介绍非抢占式内核(Non-Preemptive Kernel)和可抢占式内核( ...

  8. Linux内核态抢占机制分析(转)

    Linux内核态抢占机制分析  http://blog.sina.com.cn/s/blog_502c8cc401012pxj.html 摘 要]本文首先介绍非抢占式内核(Non-Preemptive ...

  9. Linux内核态抢占机制分析【转】

    转自:http://blog.csdn.net/yiyeguzhou100/article/details/53097665 目录(?)[-] 1非抢占式和可抢占式内核的区别 21 用户态抢占User ...

随机推荐

  1. 开始讨论离散型随机变量吧!《考研概率论学习之我见》 -by zobol

    上一文中,笔者给出了随机变量的基本定义:一个可测映射,从结果空间到实数集,我们的目的是为了引入函数这个数学工具到考研概率论中,但是我们在现实中面对的一些事情结果,映射而成的随机变量和其对应的概率值,并 ...

  2. 从0到1搭建一款页面自适应组件(Vue.js)

    组件将根据屏幕比例及当前浏览器窗口大小,自动进行缩放处理. 建议在组件内使用百分比搭配flex进行布局,以便于在不同的分辨率下得到较为一致的展示效果.使用前请注意将body的margin设为0,否则会 ...

  3. svn :不能打开文件“/data/svn/repo/format”: 权限不够

    解决方法:关闭selinux vi /etc/sysconfig/selinux 将其中的SELINUX=enforcing 改为SELINUX=disabled  即可.

  4. 数组基础篇(对应C++ Primer plus 4.10)

    概要:数组是由一组同类型的元素组成的集合,在内存上是一片连续的存储空间.C++提供了三种数组的表示方法:普通数组,模板类vector(C++98 新增的标准模板库STL提供该模板类)和模板类array ...

  5. # Vue3 setup 函数

    Vue3 setup 函数 vue2 和 vue3 开发的区别 首先,目前来说 vue3 发布已经有一段时间了,但是呢,由于还处于优化完善阶段,对于 vue3 开发项目的需求不是很高,主要还是以 vu ...

  6. go语言学习笔记-初识Go语言

    Go语言是怎样诞生的? Go语言的创始人有三位,分别是图灵奖获得者.C语法联合发明人.Unix之父肯·汤普森(Ken Thompson).Plan 9操作系统领导者.UTF-8编码的最初设计者罗伯·派 ...

  7. DBSync新增对MongoDB、ES的支持

    数据库同步工具DBSync近日进行了升级,最新版本为V1.9,新增了对MongoDB.Elasticseach(ES)的支持,具体情况:1.支持同型库之间的同步,如:MongoDB至MongoDB,E ...

  8. Tapdata 实时数据中台在智慧教育中的实践

      摘要:随着教育信息化的推进,智慧校园建设兴起,但在实施过程中面临数据孤岛.应用繁多.数据再利用等方面挑战,而 Tapdata 的实时数据中台解决方案,能够高效地解决智慧校园实施中的基础数据问题. ...

  9. Mvcapi解决H5请求接口跨域问题

    using Newtonsoft.Json;using System;using System.Collections.Generic;using System.Linq;using System.N ...

  10. ApiDay001 __02 Java_StringBuilder

    Java 核心API StringBuilder String 类型的连接性能不好,Java提供了StringBuilder解决字符串连接性能问题. 简单理解 StringBuilder性能好!(重点 ...