4

总在用户态调试 C# 程序,终还是搭了一个内核态环境 - 一线码农

 2 years ago
source link: https://www.cnblogs.com/huangxincheng/p/16652322.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

一直在用 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, 在我的界面上大概是这个样子:

214741-20220903115817034-990423230.png

3. 配置 COM 接口

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

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

2) 新增一个 串行端口

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

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

214741-20220903115816993-299271444.png

4. 配置 Windbg Preview

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

214741-20220903115817004-605355194.png

如果一切正常的话,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 时配置的,我们选择它就好了,完整截图如下:

214741-20220903115817004-1309270752.png

稍等片刻后 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 从用户态切到内核态的过程,还画了一张图。

214741-20220903115817095-182256587.png

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


        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"

214741-20220903115817034-370387515.png

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

bp nt!NtReadFile

214741-20220903115817026-194363445.png

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

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


Recommend

  • 13
    • 微信 mp.weixin.qq.com 5 years ago
    • Cache

    Linux内核常用的动态调试手段

    本文介绍linux内核中几种常用的动态调试手段,也都是我常用的,都是在生产环境中直接使用, 不需要借助工具, 依照我的经验,去客户生产环境中解决问题,很多都不会预装perf、BPF工具,有的即使有perf这样的工具,也因为...

  • 23
    • 微信 mp.weixin.qq.com 5 years ago
    • Cache

    本地内核调试神器:livekd 使用总结

    说明:本文很早就发布在我的博客上了,当时总结的有些问题,本次重新整理完善后再次发布。 前言 有时候我们非常想知道当前系统内核的一些状态,比如查看当前系统加载了哪些驱动,查看某个...

  • 9

    前四节介绍如何定制自己的 linux 内核,以及如何利用 busybox 制作文件系统,如何使用 qemu 模拟器运行编译好的 linux 内核。上一节介绍了在没有界面和鼠标的 linux 环境下,如何使用 gdb 工具单步调试程序。linux 内核也可以看作是一个程序,所以本节将尝试使...

  • 8

    上一节粗略的介绍了如何下载和编译 linux 内核,可只是编译出内核没什么意思,能不能让它跑起来呢?当然可以,本节的内容就是让 linux 内核跑起来,并且在系统启动时,打印出我们的名字。qemu 模拟器打算让“linux内核跑起来”...

  • 11
    • taowusheng.cn 4 years ago
    • Cache

    gdb和qemu调试Linux内核

    gdb和qemu调试Linux内核 之前学习了利用KGDB双机调试内核,这种...

  • 16
    • taowusheng.cn 4 years ago
    • Cache

    双机调试Linux内核

    双机调试Linux内核环境配置。 利用KGDB双机调试内核centos 7 VMware 全程使用root用户 配置内核编译环境这种方式调试内核需要两台机器,一台用来运行Linux内核,另一台对内核进行调试。一般...

  • 11
    • 微信 mp.weixin.qq.com 4 years ago
    • Cache

    在生产环境中使用 eBPF 调试 GO 程序

    第 1 部分: 在生产环境中使用 eBPF 调试 Go 程序 这是本系列文章的第一篇,讲述了我们如何在生产环境中使用 eBPF 调试应用程序而无需重新编译/重新部署。这篇文章介绍了如何使用 gobpf 和 uprobe 来为 Go 程序...

  • 6

  • 8

    1.讲故事 前段时间有位朋友在微信上找到我,说他对一个商业的 C# 程序用 WinDbg 附加不上去,每次附加之后那个 C# 程序就自动退出了,问一下到底是怎么回事?是不是哪里搞错了,有经验的朋友应该知道,其实这是 商业程序 的反调...

  • 5

    作者:0x7F@知道创宇404实验室 日期:2023年2月27日 0x00 前言 windows内核调试常用于 windows 驱动开发调试、内核分析等,使用 WinDBG 可以很方便的进行本地内核调试,但本地内核调试存在较多的限制(如不能使用导...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK