.NET程序启动就报错,如何截获初期化时的问题json
一:背景
1. 讲故事
前几天训练营里的一位朋友在复习课件的时候,程序一跑就报错,截图如下:
从给出的错误信息看大概是因为json格式无效导致的,在早期的训练营里曾经也有一例这样的报错,最后定位下来是公司的电脑安全软件导致的,一旦有非托管调试器,安全软件就会加密 runtimeconfig.json,最后导致程序无法正常被调试执行。
此时相信有很多人想搞清楚,windbg 在那个时刻到底读到了什么脏东西?到底经历了怎样的惊魂时刻?
二:WinDbg 到底遇到了什么
1. 一个小案例
为了方便演示,写一个简单的 hello world
程序,代码如下:
internal class Program{static void Main(string[] args){Console.WriteLine("hello world!");Debugger.Break();Console.ReadLine();}}
接下来将程序编译之后观察 runtimeconfig.json
内容,截图如下。
2. 如何用 windbg 观察文件内容
熟悉 win32 api 的朋友都知道,C# 的 ReadFile 底层会调用 win32 的 ReadFile 方法,方法签名如下:
BOOL ReadFile([in] HANDLE hFile,[out] LPVOID lpBuffer,[in] DWORD nNumberOfBytesToRead,[out, optional] LPDWORD lpNumberOfBytesRead,[in, out, optional] LPOVERLAPPED lpOverlapped
);
方法的 lpBuffer 参数存放的就是读取到的文件内容。
这里还有一个问题就是 ReadFile 是在 dotnet 进程被初始化的时候读取到内存的,在这个初始化过程中会有一系列的加载,那到底在哪个时刻埋点呢?这时候可以借助 procmon 工具,观察 runtimeconfig.json
的加载时机,截图如下:
上面的卦中 runtimeconfig.json
的读取是发生在 hostfxr.dll
加载之后,有了这些信息,思路就有了。
- sxe ld hostfxr 获取插入点。
- bp KERNELBASE!ReadFile 观察第二个参数。
0:000> sxe ld hostfxr
0:000> g
ModLoad: 00007ffc`29b60000 00007ffc`29b8f000 C:\windows\System32\IMM32.DLL
ModLoad: 00007ffc`03660000 00007ffc`036ba000 C:\Program Files\dotnet\host\fxr\9.0.2\hostfxr.dll
ntdll!NtMapViewOfSection+0x14:
00007ffc`2b1ad9f4 c3 ret
0:000> bp KERNELBASE!ReadFile
0:000> g
Breakpoint 1 hit
KERNELBASE!ReadFile:
00007ffc`28822670 48895c2410 mov qword ptr [rsp+10h],rbx ss:0000006c`c8f7de88=00000259c2eb0000
0:000> r
rax=0000000000000000 rbx=0000000000000000 rcx=000000000000012c
rdx=00000259c2ec8ee0 rsi=0000000000000003 rdi=0000000000000000
rip=00007ffc28822670 rsp=0000006cc8f7de78 rbp=0000000000001000r8=0000000000001000 r9=0000006cc8f7df38 r10=00000259c2ec8ee0
r11=0000006cc8f7db38 r12=000000000000001b r13=0000000000001000
r14=0000000000000003 r15=00000259c2ec8ee0
iopl=0 nv up ei pl zr na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
KERNELBASE!ReadFile:
00007ffc`28822670 48895c2410 mov qword ptr [rsp+10h],rbx ss:0000006c`c8f7de88=00000259c2eb0000
0:000> pt
KERNELBASE!ReadFile+0xad:
00007ffc`2882271d c3 ret
0:000> dp 0000006cc8f7df38 L1
0000006c`c8f7df38 00000000`0000010c
0:000> db 00000259c2ec8ee0 L?10c
00000259`c2ec8ee0 7b 0d 0a 20 20 22 72 75-6e 74 69 6d 65 4f 70 74 {.. "runtimeOpt
00000259`c2ec8ef0 69 6f 6e 73 22 3a 20 7b-0d 0a 20 20 20 20 22 74 ions": {.. "t
00000259`c2ec8f00 66 6d 22 3a 20 22 6e 65-74 38 2e 30 22 2c 0d 0a fm": "net8.0",..
00000259`c2ec8f10 20 20 20 20 22 66 72 61-6d 65 77 6f 72 6b 22 3a "framework":
00000259`c2ec8f20 20 7b 0d 0a 20 20 20 20-20 20 22 6e 61 6d 65 22 {.. "name"
00000259`c2ec8f30 3a 20 22 4d 69 63 72 6f-73 6f 66 74 2e 4e 45 54 : "Microsoft.NET
00000259`c2ec8f40 43 6f 72 65 2e 41 70 70-22 2c 0d 0a 20 20 20 20 Core.App",..
00000259`c2ec8f50 20 20 22 76 65 72 73 69-6f 6e 22 3a 20 22 38 2e "version": "8.
00000259`c2ec8f60 30 2e 30 22 0d 0a 20 20-20 20 7d 2c 0d 0a 20 20 0.0".. },..
00000259`c2ec8f70 20 20 22 63 6f 6e 66 69-67 50 72 6f 70 65 72 74 "configPropert
00000259`c2ec8f80 69 65 73 22 3a 20 7b 0d-0a 20 20 20 20 20 20 22 ies": {.. "
00000259`c2ec8f90 53 79 73 74 65 6d 2e 52-75 6e 74 69 6d 65 2e 53 System.Runtime.S
00000259`c2ec8fa0 65 72 69 61 6c 69 7a 61-74 69 6f 6e 2e 45 6e 61 erialization.Ena
00000259`c2ec8fb0 62 6c 65 55 6e 73 61 66-65 42 69 6e 61 72 79 46 bleUnsafeBinaryF
00000259`c2ec8fc0 6f 72 6d 61 74 74 65 72-53 65 72 69 61 6c 69 7a ormatterSerializ
00000259`c2ec8fd0 61 74 69 6f 6e 22 3a 20-66 61 6c 73 65 0d 0a 20 ation": false..
00000259`c2ec8fe0 20 20 20 7d 0d 0a 20 20-7d 0d 0a 7d }.. }..}0:000> .writemem D:\testdump\1.txt 00000259c2ec8ee0 L?0x10c
Writing 10c bytes.
从上面的输出中果然看到了 runtimeconfig.json
中的内容,最后打开导出的文件,没毛病。
3. 有没有快捷的方式
刚才的操作确实能够完成,但还是不爽,因为介入了第三方工具,所以能不能完全通过 windbg 显示打开的 文件路径
和对应的 文件内容
呢?当然是可以的,只需关注如下两个方法 KERNELBASE!CreateFileW
和 KERNELBASE!ReadFile
即可,签名如下:
HANDLE CreateFileW([in] LPCWSTR lpFileName,[in] DWORD dwDesiredAccess,[in] DWORD dwShareMode,[in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes,[in] DWORD dwCreationDisposition,[in] DWORD dwFlagsAndAttributes,[in, optional] HANDLE hTemplateFile
);BOOL ReadFile([in] HANDLE hFile,[out] LPVOID lpBuffer,[in] DWORD nNumberOfBytesToRead,[out, optional] LPDWORD lpNumberOfBytesRead,[in, out, optional] LPOVERLAPPED lpOverlapped
);
在 CreateFileW 中我们提取 lpFileName
和返回的 handle
句柄,在 ReadFile 中提取 hFile
句柄 和 lpBuffer
文件内容,参考脚本如下:
sxe ld hostfxr;gbp KERNELBASE!CreateFileW+0x6a " .echo WriteFile----------------------------------; du /c100 @rbx; r @rax; gc"
bp KERNELBASE!ReadFile+0x73 ".echo ReadFile----------------------------------; r @rsi; da poi(@rsp+0x28); gc " ;
稍微说一下 KERNELBASE!CreateFileW+0x6a
是方法的ret处,可以通过 uf KERNELBASE!CreateFileW
计算得到,如下输出所示:
0:000> uf KERNELBASE!CreateFileW
KERNELBASE!CreateFileW:
00007ffc`33341410 4883ec58 sub rsp,58h
00007ffc`33341414 448b942488000000 mov r10d,dword ptr [rsp+88h]
...
00007ffc`3334147a c3 ret0:000> ? 00007ffc`3334147a - 00007ffc`33341410
Evaluate expression: 106 = 00000000`0000006a
这里的 KERNELBASE!ReadFile+0x73
是内部函数 ntdll!NtReadFile
返回的RIP处。
最后用 windbg 执行如下:
(3770.3164): Break instruction exception - code 80000003 (first chance)
ntdll!LdrpDoDebuggerBreak+0x30:
00007ffc`35a407a0 cc int 3
0:000> sxe ld hostfxr;g
ModLoad: 00007ffc`34250000 00007ffc`3427f000 C:\windows\System32\IMM32.DLL
ModLoad: 00007ffc`2deb0000 00007ffc`2df0a000 C:\Program Files\dotnet\host\fxr\9.0.2\hostfxr.dll
ntdll!NtMapViewOfSection+0x14:
00007ffc`35a0d9f4 c3 ret
0:000> bp KERNELBASE!ReadFile+0x73 ".echo ReadFile----------------------------------; r @rsi; da poi(@rsp+0x28); gc " ;
0:000> bp KERNELBASE!CreateFileW+0x6a " .echo WriteFile----------------------------------; du /c100 @rbx; r @rax; gc"
0:000> g
WriteFile----------------------------------
0000020d`1c77ace0 "D:\skyfly\20.20250116\src\Example\Example_20_1_1\bin\Debug\net8.0\Example_20_1_1.runtimeconfig.json"
rax=0000000000000128
ReadFile----------------------------------
rsi=0000000000000128
0000020d`1c778ee0 "{.. "runtimeOptions": {.. "t"
0000020d`1c778f00 "fm": "net8.0",.. "framework":"
0000020d`1c778f20 " {.. "name": "Microsoft.NET"
0000020d`1c778f40 "Core.App",.. "version": "8."
0000020d`1c778f60 "0.0".. },.. "configPropert"
0000020d`1c778f80 "ies": {.. "System.Runtime.S"
0000020d`1c778fa0 "erialization.EnableUnsafeBinaryF"
0000020d`1c778fc0 "ormatterSerialization": false.. "
0000020d`1c778fe0 " }.. }..}"
ReadFile----------------------------------
...
三:总结
有了windbg之后,很多东西都会豁然开朗,而不再像以前那样人云亦云,高级调试这门救火技术
应该是高级程序员必须的进阶之路。
相关文章:

.NET程序启动就报错,如何截获初期化时的问题json
一:背景 1. 讲故事 前几天训练营里的一位朋友在复习课件的时候,程序一跑就报错,截图如下: 从给出的错误信息看大概是因为json格式无效导致的,在早期的训练营里曾经也有一例这样的报错,最后定位下来是公司…...

nacos:服务注册原理
目录 NaCos服务注册原理1、AbstractAutoServiceRegistration功能和作用onApplicationEvent()方法start()方法 2、NacosAutoServiceRegistration功能和作用NacosAutoServiceRegistration.register()方法AbstractAutoServiceRegistration.register()方法 3、NacosServiceRegistry…...

基于开源AI大模型与S2B2C生态的个人品牌优势挖掘与标签重构研究
摘要:在数字文明时代,个人品牌塑造已从传统经验驱动转向数据智能驱动。本文以开源AI大模型、AI智能名片与S2B2C商城小程序源码为技术载体,提出"社会评价-数据验证-标签重构"的三维分析框架。通过实证研究发现,结合第三方…...
《React Native与Flutter:社交应用中用户行为分析与埋点统计的深度剖析》
React Native与Flutter作为两款备受瞩目的跨平台开发框架,正深刻地影响着应用的构建方式。当聚焦于用户行为分析与埋点统计时,它们各自展现出独特的策略与工具选择,这些差异和共性不仅关乎开发效率,更与社交应用能否精准把握用户需…...

polarctf-web-[简单rce]
考点: (1)RCE(eval函数) (2)执行函数(passthru函数) (3)/顶级(根)目录查看 (4)sort排序查看函数 题目来源:Polarctf-web-[简单rce] 解题: 代码审计 <?php/*PolarD&N CTF*/highlight_file(__FILE__);function no($txt){ # …...

深入理解 Cortex-M3 特殊寄存器
在上一篇文章中分享了 Cortex-M3 内核寄存器组的相关知识,实际上除了内核寄存器组外,CM3 处理器中还存在多个特殊寄存器,它们分别为 程序状态寄存器,中断/异常屏蔽寄存器 和 控制寄存器。 需要注意的是,特殊寄存器未经…...

[Java实战]Spring Boot 3 整合 Ehcache 3(十九)
[Java实战]Spring Boot 3 整合 Ehcache 3(十九) 引言 在微服务和高并发场景下,缓存是提升系统性能的关键技术之一。Ehcache 作为 Java 生态中成熟的内存缓存框架,其 3.x 版本在性能、功能和易用性上均有显著提升。本文将详细介绍…...

建筑物渗水漏水痕迹发霉潮湿分割数据集labelme格式1357张1类别
数据集中有增强图片详情看图片 数据集格式:labelme格式(不包含mask文件,仅仅包含jpg图片和对应的json文件) 图片数量(jpg文件个数):1357 标注数量(json文件个数):1357 标注类别数:1 标注类别名称:["water&qu…...
Doris和Clickhouse对比
目录 一、Doris和Clickhouse对比1. 底层架构**DorisClickHouse** 2. 运行原理DorisClickHouse 3. 使用场景DorisClickHouse 4. 优缺点对比总结 二、MPP架构和Shared-Nothing 架构对比1. 什么是 MPP 架构?定义特点典型代表 2. 什么是 Shared-Nothing 架构?…...

第二十二天打卡
数据预处理 import pandas as pd from sklearn.model_selection import train_test_splitdef data_preprocessing(file_path):"""泰坦尼克号生存预测数据预处理函数参数:file_path: 原始数据文件路径返回:preprocessed_data: 预处理后的数据集""&quo…...
Android Activity之间跳转的原理
一、Activity跳转核心流程 Android Activity跳转的底层实现涉及 系统服务交互、进程间通信(IPC) 和 生命周期管理,主要流程如下: startActivity() 触发请求 应用调用 startActivity() 时,通过 Inst…...
MATLAB 矩阵与数组操作基础教程
文章目录 前言环境配置一、创建矩阵与数组(一)直接输入法(二)特殊矩阵生成函数(三)使用冒号表达式创建数组 二、矩阵与数组的基本操作(一)访问元素(二)修改元…...
【Linux】第十六章 分析和存储日志
1. RHEL 日志文件保存在哪个目录中? 一般存储在 /var/log 目录中。 2. 什么是syslog消息和非syslog消息? syslog消息是一种标准的日志记录协议和格式,用于系统和应用程序记录日志信息。它规定了日志消息的结构和内容,包括消息的…...

解锁性能密码:Linux 环境下 Oracle 大页配置全攻略
在 Oracle 数据库运行过程中,内存管理是影响其性能的关键因素之一。大页内存(Large Pages)作为一种优化内存使用的技术,能够显著提升 Oracle 数据库的运行效率。本文将深入介绍大页内存的相关概念,并详细阐述 Oracle 在…...

Spark,在shell中运行RDD程序
在hdfs中/wcinput中创建一个文件:word2.txt在里面写几个单词 启动hdfs集群 [roothadoop100 ~]# myhadoop start [roothadoop100 ~]# cd /opt/module/spark-yarn/bin [roothadoop100 ~]# ./spark-shell 写个11测试一下 按住ctrlD退出 进入环境:spa…...

SAP学习笔记 - 开发11 - RAP(RESTful Application Programming)简介
上一章学习了BTP架构图,实操创建Directory/Subaccount,BTP的内部组成,BTP Cockpit。 SAP学习笔记 - 开发10 - BTP架构图,实操创建Directory/Subaccount,BTP的内部组成,BTP Cockpit-CSDN博客 本章继续学习S…...

数据防泄密安全:企业稳健发展的守护盾
在数字化时代,数据已成为企业最核心的资产之一。无论是客户信息、财务数据,还是商业机密,一旦泄露,都可能给企业带来不可估量的损失。近年来,数据泄露事件频发,如Facebook用户数据泄露、Equifax信用数据外泄…...

MySQL之基础索引
目录 引言 1、创建索引 2、索引的原理 2、索引的类型 3、索引的使用 1.添加索引 2.删除索引 3.删除主键索引 4.修改索引 5.查询索引 引言 当一个数据库里面的数据特别多,比如800万,光是创建插入数据就要十几分钟,我们查询一条信息也…...
Openshift节点Disk pressure
OpenShift 监控以下指标,并定义以下垃圾回收的驱逐阈值。请参阅产品文档以更改任何驱逐值。 nodefs.available 从 cadvisor 来看,该node.stats.fs.available指标表示节点文件系统(所在位置)上有多少可用(剩余…...

拉丁方分析
本文是实验设计与分析(第6版,Montgomery著傅珏生译)第4章随机化区组,拉丁方,以及有关的设计第4.2节的python解决方案。本文尽量避免重复书中的理论,着于提供python解决方案,并与原书的运算结果进行对比。您…...
Pomelo知识框架
一、Pomelo 基础概念 Pomelo 简介 定位:分布式游戏服务器框架(网易开源)。 特点:高并发、可扩展、多进程架构、支持多种通信协议(WebSocket、TCP等)。 适用场景:MMO RPG、实时对战、社交游戏等…...

软考软件设计师中级——软件工程笔记
1.软件过程 1.1能力成熟度模型(CMM) 软件能力成熟度模型(CMM)将软件过程改进分为以下五个成熟度级别,每个级别都定义了特定的过程特征和目标: 初始级 (Initial): 软件开发过程杂乱无章…...
基于事件驱动和策略模式的差异化处理方案
一、支付成功后事件驱动 1、支付成功事件 /*** 支付成功事件** author ronshi* date 2025/5/12 14:40*/ Getter Setter public class PaymentSuccessEvent extends ApplicationEvent {private static final long serialVersionUID 1L;private ProductOrderDO productOrderDO;…...

5.5.1 WPF中的动画2-基于路径的动画
何为动画?一般只会动。但所谓会动,还不仅包括位置移动,还包括角度旋转,颜色变化,透明度增减。动画本质上是一个时间段内某个属性值(位置、颜色等)的变化。因为属性有很多数据类型,它们变化也需要多种动画类比如: BooleanAnimationBase\ ByteAnimationBase\DoubleAnima…...
计算机网络:手机和基站之间的通信原理是什么?
手机与基站之间的通信是无线通信技术的核心应用之一,涉及复杂的物理层传输、协议交互和网络管理机制。以下从技术原理、通信流程和关键技术三个层面深入解析这一过程: 一、蜂窝网络基础架构 1. 蜂窝结构设计 基本原理:将服务区域划分为多个六边形“蜂窝小区”,每个小区由*…...
PostgreSQL常用DML操作的锁类型归纳
DML锁类型分析 本文对PostgreSQL的insert、 update、 truncate、 delete等常用DML操作的锁类型进行了归纳类比: 包括是否排他、 共享、 表级、 行级等的总结。 truncate :access exclusive mode(block all read/write)、table-le…...
Apache Flink 与 Flink CDC:概念、联系、区别及版本演进解析
Apache Flink 与 Flink CDC:概念、联系、区别及版本演进解析 在实时数据处理和流式计算领域,Apache Flink 已成为行业标杆。而 Flink CDC(Change Data Capture) 作为其生态中的重要组件,为数据库的实时变更捕获提供了强大的能力。 本文将从以下几个方面进行深入讲解: 什…...
数学复习笔记 8
前言 成为一个没有感情的刷题机器就可以变得很强了。 逆矩阵的运算 随便算一下就算出来了,没啥难的。主要是用天然可交换的矩阵来算。有三个天然可交换的矩阵,某矩阵和单位阵,该矩阵和它的伴随矩阵,该矩阵和它的逆矩阵。一定要…...
FunASR:语音识别与合成一体化,企业级开发实战详解
简介 FunASR是由阿里巴巴达摩院开源的高性能语音识别工具包,它不仅提供语音识别(ASR)功能,还集成了语音端点检测(VAD)、标点恢复、说话人分离等工业级模块,形成了完整的语音处理解决方案。 FunASR支持离线和实时两种模式,能够高效处理多语言音频,并提供高精度的识别结果。…...
rust-candle学习笔记11-实现一个简单的自注意力
参考:about-pytorch 定义ScaledDotProductAttention结构体: use candle_core::{Result, Device, Tensor}; use candle_nn::{Linear, Module, linear_no_bias, VarMap, VarBuilder, ops};struct ScaledDotProductAttention {wq: Linear,wk: Linear,wv: …...