详情

首页手游攻略 .NET程序启动就报错如何截获初期化时的问题json(最新推荐)实用指南

.NET程序启动就报错如何截获初期化时的问题json(最新推荐)实用指南

佚名 2026-09-10 10:30:01

平时做技术实践时,很多问题不是概念不会,而是细节没串起来。拿“.NET程序启动就报错如何截获初期化时的问题json(最新推荐)”来说,它看着像小点,放到项目里常会牵出环境、配置、兼容性和维护成本。下面按实际采用顺序,把思路、关键写法和容易踩坑的地方讲清楚,便于大家直接对照操作。

目录
  • 一:背景
    • 1. 讲故事
  • 二:WinDbg 到底遇到了什么
    • 1. 一个小案例
    • 2. 如何用 windbg 观察文件内容
    • 3. 有没有快捷的方式
  • 三:总结

    一:背景

    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:windowsSystem32IMM32.DLL
    ModLoad: 00007ffc`03660000 00007ffc`036ba000 C:Program Filesdotnethostfxr9.0.2hostfxr.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:testdump1.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:windowsSystem32IMM32.DLL
    ModLoad: 00007ffc`2deb0000 00007ffc`2df0a000 C:Program Filesdotnethostfxr9.0.2hostfxr.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:skyfly20.20250116srcExampleExample_20_1_1binDebugnet8.0Example_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的文章就介绍到这了,更多相关.NET程序启动就报错,如何截获初期化时的问题json内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多兼容脚本之家!

    您可能感兴趣的文章:

    • mac下idea启动web项目报错java.net.SocketException:socket closed问题
    • 解决java启动时报线程占用报错:Exception in thread “Thread-14“ java.net.BindException: Address already in use: bind
    • 在.NET Web API设置响应输出Json数据格式常用的两种方式详解
    • .NET Core控制台应用ConsoleApp读取appsettings.json设置文件

    相关资讯
    点击查看更多
    游戏推荐
    推荐专题
    热门阅读
    推荐下载