.NET程序啟動就報錯如何截獲初期化時的問題json(最新推薦)
一:背景
1. 講故事
前幾天訓練營里的一位朋友在復習課件的時候,程序一跑就報錯,截圖如下:
從給出的錯誤信息看大概是因為json格式無效導致的,在早期的訓練營里曾經(jīng)也有一例這樣的報錯,最后定位下來是公司的電腦安全軟件導致的,一旦有非托管調(diào)試器,安全軟件就會加密 runtimeconfig.json,最后導致程序無法正常被調(diào)試執(zhí)行。
此時相信有很多人想搞清楚,windbg 在那個時刻到底讀到了什么臟東西?到底經(jīng)歷了怎樣的驚魂時刻?
二:WinDbg 到底遇到了什么
1. 一個小案例
為了方便演示,寫一個簡單的 hello world
程序,代碼如下:
internal class Program { static void Main(string[] args) { Console.WriteLine("hello world!"); Debugger.Break(); Console.ReadLine(); } }
接下來將程序編譯之后觀察 runtimeconfig.json
內(nèi)容,截圖如下。
2. 如何用 windbg 觀察文件內(nèi)容
熟悉 win32 api 的朋友都知道,C# 的 ReadFile 底層會調(diào)用 win32 的 ReadFile 方法,方法簽名如下:
BOOL ReadFile( [in] HANDLE hFile, [out] LPVOID lpBuffer, [in] DWORD nNumberOfBytesToRead, [out, optional] LPDWORD lpNumberOfBytesRead, [in, out, optional] LPOVERLAPPED lpOverlapped );
方法的 lpBuffer 參數(shù)存放的就是讀取到的文件內(nèi)容。
這里還有一個問題就是 ReadFile 是在 dotnet 進程被初始化的時候讀取到內(nèi)存的,在這個初始化過程中會有一系列的加載,那到底在哪個時刻埋點呢?這時候可以借助 procmon 工具,觀察 runtimeconfig.json
的加載時機,截圖如下:
上面的卦中 runtimeconfig.json
的讀取是發(fā)生在 hostfxr.dll
加載之后,有了這些信息,思路就有了。
sxe ld hostfxr 獲取插入點。bp KERNELBASE!ReadFile 觀察第二個參數(shù)。
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
中的內(nèi)容,最后打開導出的文件,沒毛病。
3. 有沒有快捷的方式
剛才的操作確實能夠完成,但還是不爽,因為介入了第三方工具,所以能不能完全通過 windbg 顯示打開的 文件路徑
和對應的 文件內(nèi)容
呢?當然是可以的,只需關注如下兩個方法 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
文件內(nèi)容,參考腳本如下:
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
是內(nèi)部函數(shù) ntdll!NtReadFile
返回的RIP處。
最后用 windbg 執(zhí)行如下:
(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之后,很多東西都會豁然開朗,而不再像以前那樣人云亦云,高級調(diào)試這門救火技術
應該是高級程序員必須的進階之路。
到此這篇關于.NET程序啟動就報錯,如何截獲初期化時的問題json的文章就介紹到這了,更多相關.NET程序啟動就報錯,如何截獲初期化時的問題json內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
asp.net 通過UserAgent判斷智能設備(Android,IOS)
搜集了比較全的 智能設備 的 Agent,然后又寫了程序,需要的朋友可以參考下2011-10-10用javascript css實現(xiàn)GridView行背景色交替、鼠標劃過行變色,點擊行變色選中
前幾天在博問里發(fā)現(xiàn)有人問關于 GridView點擊行變色 的問題,突然想起很久很久以前,寫過一篇文章 一個簡單但常用的表格樣式--鼠標劃過行變色--簡潔實現(xiàn) ,是關于表格行顏色交替和鼠標指向時變色的,正好今天把那一篇補充和擴展一下2008-09-09