.NET程序启动就报错,如何截获初期化时的问题json

news2025/5/16 4:33:28

一:背景

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 加载之后,有了这些信息,思路就有了。

  1. sxe ld hostfxr 获取插入点。
  2. 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=0000000000001000
 r8=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!CreateFileWKERNELBASE!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;g

bp 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              ret

0: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之后,很多东西都会豁然开朗,而不再像以前那样人云亦云,高级调试这门救火技术 应该是高级程序员必须的进阶之路。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2376581.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

nacos:服务注册原理

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

基于开源AI大模型与S2B2C生态的个人品牌优势挖掘与标签重构研究

摘要:在数字文明时代,个人品牌塑造已从传统经验驱动转向数据智能驱动。本文以开源AI大模型、AI智能名片与S2B2C商城小程序源码为技术载体,提出"社会评价-数据验证-标签重构"的三维分析框架。通过实证研究发现,结合第三方…

polarctf-web-[简单rce]

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

深入理解 Cortex-M3 特殊寄存器

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

[Java实战]Spring Boot 3 整合 Ehcache 3(十九)

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

建筑物渗水漏水痕迹发霉潮湿分割数据集labelme格式1357张1类别

数据集中有增强图片详情看图片 数据集格式&#xff1a;labelme格式(不包含mask文件&#xff0c;仅仅包含jpg图片和对应的json文件) 图片数量(jpg文件个数)&#xff1a;1357 标注数量(json文件个数)&#xff1a;1357 标注类别数&#xff1a;1 标注类别名称:["water&qu…

第二十二天打卡

数据预处理 import pandas as pd from sklearn.model_selection import train_test_splitdef data_preprocessing(file_path):"""泰坦尼克号生存预测数据预处理函数参数:file_path: 原始数据文件路径返回:preprocessed_data: 预处理后的数据集""&quo…

解锁性能密码:Linux 环境下 Oracle 大页配置全攻略​

在 Oracle 数据库运行过程中&#xff0c;内存管理是影响其性能的关键因素之一。大页内存&#xff08;Large Pages&#xff09;作为一种优化内存使用的技术&#xff0c;能够显著提升 Oracle 数据库的运行效率。本文将深入介绍大页内存的相关概念&#xff0c;并详细阐述 Oracle 在…

Spark,在shell中运行RDD程序

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

SAP学习笔记 - 开发11 - RAP(RESTful Application Programming)简介

上一章学习了BTP架构图&#xff0c;实操创建Directory/Subaccount&#xff0c;BTP的内部组成&#xff0c;BTP Cockpit。 SAP学习笔记 - 开发10 - BTP架构图&#xff0c;实操创建Directory/Subaccount&#xff0c;BTP的内部组成&#xff0c;BTP Cockpit-CSDN博客 本章继续学习S…

数据防泄密安全:企业稳健发展的守护盾

在数字化时代&#xff0c;数据已成为企业最核心的资产之一。无论是客户信息、财务数据&#xff0c;还是商业机密&#xff0c;一旦泄露&#xff0c;都可能给企业带来不可估量的损失。近年来&#xff0c;数据泄露事件频发&#xff0c;如Facebook用户数据泄露、Equifax信用数据外泄…

MySQL之基础索引

目录 引言 1、创建索引 2、索引的原理 2、索引的类型 3、索引的使用 1.添加索引 2.删除索引 3.删除主键索引 4.修改索引 5.查询索引 引言 当一个数据库里面的数据特别多&#xff0c;比如800万&#xff0c;光是创建插入数据就要十几分钟&#xff0c;我们查询一条信息也…

拉丁方分析

本文是实验设计与分析&#xff08;第6版&#xff0c;Montgomery著傅珏生译)第4章随机化区组&#xff0c;拉丁方&#xff0c;以及有关的设计第4.2节的python解决方案。本文尽量避免重复书中的理论&#xff0c;着于提供python解决方案&#xff0c;并与原书的运算结果进行对比。您…

软考软件设计师中级——软件工程笔记

1.软件过程 1.1能力成熟度模型&#xff08;CMM&#xff09; 软件能力成熟度模型&#xff08;CMM&#xff09;将软件过程改进分为以下五个成熟度级别&#xff0c;每个级别都定义了特定的过程特征和目标&#xff1a; 初始级 (Initial)&#xff1a; 软件开发过程杂乱无章&#xf…

5.5.1 WPF中的动画2-基于路径的动画

何为动画?一般只会动。但所谓会动,还不仅包括位置移动,还包括角度旋转,颜色变化,透明度增减。动画本质上是一个时间段内某个属性值(位置、颜色等)的变化。因为属性有很多数据类型,它们变化也需要多种动画类比如: BooleanAnimationBase\ ByteAnimationBase\DoubleAnima…

Andorid之TabLayout+ViewPager

文章目录 前言一、效果图二、使用步骤1.主xml布局2.activity代码3.MyTaskFragment代码4.MyTaskFragment的xml布局5.Adapter代码6.item布局 总结 前言 TabLayoutViewPager功能需求已经是常见功能了&#xff0c;我就不多解释了&#xff0c;需要的自取。 一、效果图 二、使用步骤…

26考研——中央处理器_指令流水线_流水线的冒险与处理 流水线的性能指标 高级流水线技术(5)

408答疑 文章目录 六、指令流水线流水线的冒险与处理结构冒险数据冒险延迟执行相关指令采用转发&#xff08;旁路&#xff09;技术load-use 数据冒险的处理 控制冒险 流水线的性能指标流水线的吞吐率流水线的加速比 高级流水线技术超标量流水线技术超长指令字技术超流水线技术 …

酒店旅游类数据采集API接口之携程数据获取地方美食品列表 获取地方美餐馆列表 景点评论

携程 API 接入指南 API 地址&#xff1a; 调用示例&#xff1a; 美食列表 景点列表 景点详情 酒店详情 参数说明 通用参数说明 请谨慎传递参数&#xff0c;避免不必要的费用扣除。 URL 说明&#xff1a;https://api-gw.cn/平台/API类型/ 平台&#xff1a;淘宝&#xff0c;京…

Lora原理及实现浅析

Lora 什么是Lora Lora的原始论文为《LoRA: Low-Rank Adaptation of Large Language Models》&#xff0c;翻译为中文为“大语言模型的低秩自适应”。最初是为了解决大型语言模在进行任务特定微调时消耗大量资源的问题&#xff1b;随后也用在了Diffusion等领域&#xff0c;用于…

【设计模式】- 创建者模式

单例模型 饿汉式 静态方法创建对象 public class Singleton {// 私有构造方法private Singleton(){}private static Singleton instance new Singleton();// 提供一个外界获取的方法public static Singleton getInstance(){return instance;} }静态代码块创建对象 public …