百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

如何获取 C#程序 内核态线程栈(c#获取线程状态)

bigegpt 2025-05-02 09:10 9 浏览

一:背景

1. 讲故事

在这么多的案例分析中,往往会发现一些案例是卡死在线程的内核态栈上,但拿过来的dump都是用户态模式下,所以无法看到内核态栈,这就比较麻烦,需要让朋友通过其他方式生成一个蓝屏的dump,这里我们简单汇总下。

二:如何生成内核态dump

1. 案例代码

为了方便演示,来一段简单的测试代码,目的就是观察 Console.ReadLine 方法的内核态栈。


internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("hello world!");

Console.ReadLine();
}
}

通过 任务管理器 或者 Process Explorer 默认抓取的dump都是 ntdll 之上的空间,可以用 k 来看一下。


0:000> k 3
# Child-SP RetAddr Call Site
00 000000d6`7c9fe328 00007ffe`61405593 ntdll!NtReadFile+0x14
01 000000d6`7c9fe330 00007ffd`50724782 KERNELBASE!ReadFile+0x73
02 000000d6`7c9fe3b0 00007ffe`215bc742 0x00007ffd`50724782

问题来了,如果我要看下 ntdll!NtReadFile 函数对应在内核态中的 nt!NtReadFile 方法怎么办呢?只能抓内核态dump,抓内核态dump的方式有很多,这里聊一下其中的两种方式。

2. 使用 notmyfault 抓取

说到 蓝屏 我相信有很多朋友都知道,简而言之就是内核态代码出bug导致系统崩溃,也有朋友知道通过增加一些配置可以在蓝屏的时候自动生成 dump 文件,这种 dump 文件就属于内核态,配置如下:

但这里有一个问题,操作系统不可能无缘无故的蓝屏,那怎么办呢?微软想了一个办法,人为的造蓝屏,所以提供了一个叫 notmyfault.exe 的工具, MSDN网址:
https://learn.microsoft.com/en-us/sysinternals/downloads/notmyfault

有了这些前置基础,接下来就可以操练一下,双击 notmyfault.exe 工具,崩溃原因选择默认的 High IRQL fault,最后点击 Crash 按钮,稍等片刻电脑就会蓝屏。截图如下:

我这里用的是一台物理的 迷你主机 测试,再次远程连接后,在 C:\Windows 下会生成一个 MEMORY.dmp 文件,截图如下:

拿到 dump 之后就可以用 windbg 中的 !process 之类的命令分析了,非常爽。


1: kd> !process 0 2 ConsoleApp1.exe
PROCESS ffffdb05c1641080
SessionId: 1 Cid: 1bc8 Peb: fd877dd000 ParentCid: 15ec
DirBase: 1b9ef3000 ObjectTable: ffffa105fc3d5280 HandleCount: 161.
Image: ConsoleApp1.exe

THREAD ffffdb05bf3c7080 Cid 1bc8.0924 Teb: 000000fd877de000 Win32Thread: ffffdb05c00d0ad0 WAIT: (Executive) KernelMode Alertable
ffffdb05c1902ef8 NotificationEvent

THREAD ffffdb05c0fc6080 Cid 1bc8.07c8 Teb: 000000fd877e4000 Win32Thread: 0000000000000000 WAIT: (UserRequest) UserMode Non-Alertable
ffffdb05be642ae0 NotificationEvent

THREAD ffffdb05be694080 Cid 1bc8.17dc Teb: 000000fd877e6000 Win32Thread: 0000000000000000 WAIT: (UserRequest) UserMode Non-Alertable
ffffdb05be645860 SynchronizationEvent
ffffdb05be646e60 SynchronizationEvent
ffffdb05be645d60 SynchronizationEvent

THREAD ffffdb05be7e2080 Cid 1bc8.1020 Teb: 000000fd877e8000 Win32Thread: 0000000000000000 WAIT: (UserRequest) UserMode Non-Alertable
ffffdb05b68b53a0 NotificationEvent
ffffdb05be651de0 SynchronizationEvent

1: kd> .thread ffffdb05bf3c7080
Implicit thread is now ffffdb05`bf3c7080

1: kd> k
*** Stack trace for last set context - .thread/.cxr resets it
# Child-SP RetAddr Call Site
00 fffff50f`606ed570 fffff800`52c1c9c0 nt!KiSwapContext+0x76
01 fffff50f`606ed6b0 fffff800`52c1beef nt!KiSwapThread+0x500
02 fffff50f`606ed760 fffff800`52c1b793 nt!KiCommitThreadWait+0x14f
03 fffff50f`606ed800 fffff800`52df04c4 nt!KeWaitForSingleObject+0x233
04 fffff50f`606ed8f0 fffff800`53010cdb nt!IopWaitForSynchronousIoEvent+0x50
05 fffff50f`606ed930 fffff800`52fcc9e8 nt!IopSynchronousServiceTail+0x50b
06 fffff50f`606ed9d0 fffff800`52ff9ae8 nt!IopReadFile+0x7cc
07 fffff50f`606edac0 fffff800`52e0f3f5 nt!NtReadFile+0x8a8
08 fffff50f`606edbd0 00007ffa`2fb4d124 nt!KiSystemServiceCopyEnd+0x25
09 000000fd`8797e108 00000000`00000000 0x00007ffa`2fb4d124

从卦中看,主线程的内核态栈中的 nt!NtReadFile 函数果然给找到了。

2. 使用 procdump

如果仅仅是看线程的内核态栈,我发现有一个非常简单的方式,就是在 procudump 中多加一个 mk 参数即可,截图如下:

接下来使用 Terminal 执行 procdump,输出如下:


PS C:\Users\Administrator\Desktop> procdump -ma -mk ConsoleApp -o D:\testdump

ProcDump v11.0 - Sysinternals process dump utility
Copyright (C) 2009-2022 Mark Russinovich and Andrew Richards
Sysinternals - www.sysinternals.com

[16:24:49] Dump 1 initiated: D:\testdump\ConsoleApp1.exe_230605_162449.dmp
[16:24:50] Dump 1 writing: Estimated dump file size is 57 MB.
[16:24:50] Dump 1 complete: 57 MB written in 0.1 seconds
[16:24:50] Dump 1 kernel: D:\testdump\ConsoleApp1.exe_230605_162449.Kernel.dmp
[16:24:50] Dump count reached.

从卦中看,当前生成了两个 dmp 文件,一个是用户态dump,一个是内核态dump,也能看到后者还不到 1M,和刚才用 notmyfault 生成的 500M dump 所存储的信息量相差甚远,但对我目前的场景来说已经够用了。

接下来打开
ConsoleApp1.exe_230605_162449.Kernel.dmp
文件,使用 !process 找到 ConsoleApp1.exe 的进程。


..................................................
For analysis of this file, run !analyze -v
nt!DbgkpLkmdSnapThreadInContext+0x95:
fffff804`5e688b51 488364242800 and qword ptr [rsp+28h],0 ss:0018:ffffe10d`62386fd8=ffffe10d5b8fa810
0: kd> !process 0 2 ConsoleApp1.exe
Unable to read _LIST_ENTRY @ fffff8045ea1e080
0: kd> .reload /user
Loading User Symbols
0: kd> !process 0 2 ConsoleApp1.exe
Unable to read _LIST_ENTRY @ fffff8045ea1e080

从卦中看居然报错了,那怎么办呢?办法肯定是有办法的,可以到用户态dump中寻找进程ID即可。


0:000> ~
. 0 Id: 3adc.5920 Suspend: 0 Teb: 000000d6`7cb98000 Unfrozen
1 Id: 3adc.2240 Suspend: 0 Teb: 000000d6`7cba0000 Unfrozen
2 Id: 3adc.514 Suspend: 0 Teb: 000000d6`7cba2000 Unfrozen
3 Id: 3adc.3c68 Suspend: 0 Teb: 000000d6`7cba4000 Unfrozen ".NET Finalizer"

拿到 3adc 进程号后再找下面的主线程,观察它的线程栈信息,输出如下:


0: kd> .process 3adc
Implicit process is now 00000000`00003adc
0: kd> !process
PROCESS ffffcf8d5d5b0080
SessionId: none Cid: 3adc Peb: d67cb97000 ParentCid: 4c80
DirBase: 367d95000 ObjectTable: ffff8e81710bbb40 HandleCount: <Data Not Accessible>
Image: ConsoleApp1.ex
VadRoot ffffcf8d5b20fcb0 Vads 90 Clone 0 Private 1529. Modified 941. Locked 2.
DeviceMap ffff8e8172645110
Token ffff8e815e216060
ReadMemory error: Cannot get nt!KeMaximumIncrement value.
fffff78000000000: Unable to get shared data
ElapsedTime 00:00:00.000
UserTime 00:00:00.000
KernelTime 00:00:00.000
QuotaPoolUsage[PagedPool] 153768
QuotaPoolUsage[NonPagedPool] 12648
Working Set Sizes (now,min,max) (14126, 50, 345) (56504KB, 200KB, 1380KB)
PeakWorkingSetSize 14033
VirtualSize 2101882 Mb
PeakVirtualSize 2101888 Mb
PageFaultCount 15757
MemoryPriority BACKGROUND
BasePriority 8
CommitCharge 1628
Job ffffcf8d53a102c0

THREAD ffffcf8d5ae14080 Cid 3adc.5920 Teb: 000000d67cb98000 Win32Thread: ffffcf8d54c3a3b0 RUNNING on processor 0
THREAD ffffcf8d4f63e080 Cid 3adc.2240 Teb: 000000d67cba0000 Win32Thread: 0000000000000000 INVALID
THREAD ffffcf8d69a32080 Cid 3adc.0514 Teb: 000000d67cba2000 Win32Thread: 0000000000000000 INVALID
THREAD ffffcf8d55003580 Cid 3adc.3c68 Teb: 000000d67cba4000 Win32Thread: 0000000000000000 INVALID

0: kd> .thread ffffcf8d5ae14080
Implicit thread is now ffffcf8d`5ae14080

0: kd> k
*** Stack trace for last set context - .thread/.cxr resets it
# Child-SP RetAddr Call Site
00 ffffe10d`62386fb0 fffff804`5e688a7b nt!DbgkpLkmdSnapThreadInContext+0x95
01 ffffe10d`623874f0 fffff804`5e01dcd0 nt!DbgkpLkmdSnapThreadApc+0x3b
02 ffffe10d`62387520 fffff804`5e01bb67 nt!KiDeliverApc+0x1b0
03 ffffe10d`623875d0 fffff804`5e01ad6f nt!KiSwapThread+0x827
04 ffffe10d`62387680 fffff804`5e01a613 nt!KiCommitThreadWait+0x14f
05 ffffe10d`62387720 fffff804`5e439c68 nt!KeWaitForSingleObject+0x233
06 ffffe10d`62387810 fffff804`5e411fe9 nt!IopSynchronousServiceTail+0x238
07 ffffe10d`623878b0 fffff804`5e20d9f5 nt!NtReadFile+0x599
08 ffffe10d`62387990 00007ffe`6390d184 nt!KiSystemServiceCopyEnd+0x25
09 000000d6`7c9fe328 00000000`00000000 0x00007ffe`6390d184


怎么样,上面的 nt!NtReadFile+0x599 函数就是。

三:总结

有时候真的需要去抓内核态dump,总有一些千奇百怪的问题,太难了,这里总结一下给后来人少踩坑吧。

相关推荐

当Frida来“敲”门(frida是什么)

0x1渗透测试瓶颈目前,碰到越来越多的大客户都会将核心资产业务集中在统一的APP上,或者对自己比较重要的APP,如自己的主业务,办公APP进行加壳,流量加密,投入了很多精力在移动端的防护上。而现在挖...

服务端性能测试实战3-性能测试脚本开发

前言在前面的两篇文章中,我们分别介绍了性能测试的理论知识以及性能测试计划制定,本篇文章将重点介绍性能测试脚本开发。脚本开发将分为两个阶段:阶段一:了解各个接口的入参、出参,使用Python代码模拟前端...

Springboot整合Apache Ftpserver拓展功能及业务讲解(三)

今日分享每天分享技术实战干货,技术在于积累和收藏,希望可以帮助到您,同时也希望获得您的支持和关注。架构开源地址:https://gitee.com/msxyspringboot整合Ftpserver参...

Linux和Windows下:Python Crypto模块安装方式区别

一、Linux环境下:fromCrypto.SignatureimportPKCS1_v1_5如果导包报错:ImportError:Nomodulenamed'Crypt...

Python 3 加密简介(python des加密解密)

Python3的标准库中是没多少用来解决加密的,不过却有用于处理哈希的库。在这里我们会对其进行一个简单的介绍,但重点会放在两个第三方的软件包:PyCrypto和cryptography上,我...

怎样从零开始编译一个魔兽世界开源服务端Windows

第二章:编译和安装我是艾西,上期我们讲述到编译一个魔兽世界开源服务端环境准备,那么今天跟大家聊聊怎么编译和安装我们直接进入正题(上一章没有看到的小伙伴可以点我主页查看)编译服务端:在D盘新建一个文件夹...

附1-Conda部署安装及基本使用(conda安装教程)

Windows环境安装安装介质下载下载地址:https://www.anaconda.com/products/individual安装Anaconda安装时,选择自定义安装,选择自定义安装路径:配置...

如何配置全世界最小的 MySQL 服务器

配置全世界最小的MySQL服务器——如何在一块IntelEdison为控制板上安装一个MySQL服务器。介绍在我最近的一篇博文中,物联网,消息以及MySQL,我展示了如果Partic...

如何使用Github Action来自动化编译PolarDB-PG数据库

随着PolarDB在国产数据库领域荣膺桂冠并持续获得广泛认可,越来越多的学生和技术爱好者开始关注并涉足这款由阿里巴巴集团倾力打造且性能卓越的关系型云原生数据库。有很多同学想要上手尝试,却卡在了编译数据...

面向NDK开发者的Android 7.0变更(ndk android.mk)

订阅Google官方微信公众号:谷歌开发者。与谷歌一起创造未来!受Android平台其他改进的影响,为了方便加载本机代码,AndroidM和N中的动态链接器对编写整洁且跨平台兼容的本机...

信创改造--人大金仓(Kingbase)数据库安装、备份恢复的问题纪要

问题一:在安装KingbaseES时,安装用户对于安装路径需有“读”、“写”、“执行”的权限。在Linux系统中,需要以非root用户执行安装程序,且该用户要有标准的home目录,您可...

OpenSSH 安全漏洞,修补操作一手掌握

1.漏洞概述近日,国家信息安全漏洞库(CNNVD)收到关于OpenSSH安全漏洞(CNNVD-202407-017、CVE-2024-6387)情况的报送。攻击者可以利用该漏洞在无需认证的情况下,通...

Linux:lsof命令详解(linux lsof命令详解)

介绍欢迎来到这篇博客。在这篇博客中,我们将学习Unix/Linux系统上的lsof命令行工具。命令行工具是您使用CLI(命令行界面)而不是GUI(图形用户界面)运行的程序或工具。lsoflsof代表&...

幻隐说固态第一期:固态硬盘接口类别

前排声明所有信息来源于网络收集,如有错误请评论区指出更正。废话不多说,目前固态硬盘接口按速度由慢到快分有这几类:SATA、mSATA、SATAExpress、PCI-E、m.2、u.2。下面我们来...

新品轰炸 影驰SSD多款产品登Computex

分享泡泡网SSD固态硬盘频道6月6日台北电脑展作为全球第二、亚洲最大的3C/IT产业链专业展,吸引了众多IT厂商和全球各地媒体的热烈关注,全球存储新势力—影驰,也积极参与其中,为广大玩家朋友带来了...