記一次 .NET 某埋線管理系統 崩潰分析

2023-06-29 15:00:48

一:背景

1. 講故事

經常有朋友跟我反饋,說看你的文章就像看天書一樣,有沒有一些簡單入手的dump 讓我們先找找感覺,哈哈,今天就給大家帶來一篇入門級的案例,這裡的入門是從 WinDbg 的角度來闡述的,這個問題如果你通過 記紀錄檔,分析程式碼 的方式,可能真的無法解決,不信的話繼續往下看唄!

前段時間有位朋友微信上找到我,說他的程式崩潰了,也沒找出是什麼原因,然後就讓朋友抓一個崩潰的dump讓我看看。

二:WinDbg 分析

1. 崩潰原因在哪裡

在 windbg 中有一個自動化的分析命令 !analyze -v 可以尋找到 miniDumpWriteDump 時塞入的 PMINIDUMP_EXCEPTION_INFORMATION 資訊,結構如下:


typedef struct _MINIDUMP_EXCEPTION_INFORMATION {
  DWORD               ThreadId;
  PEXCEPTION_POINTERS ExceptionPointers;
  BOOL                ClientPointers;
} MINIDUMP_EXCEPTION_INFORMATION, *PMINIDUMP_EXCEPTION_INFORMATION;

這個命令執行時間可能很長,要稍等片刻


0:000> !analyze -v
*******************************************************************************
*                                                                             *
*                        Exception Analysis                                   *
*                                                                             *
*******************************************************************************
CONTEXT:  (.ecxr)
rax=0000000000000198 rbx=0000000000000001 rcx=0000000000000002
rdx=0000000039959600 rsi=0000000000000000 rdi=0000000039959600
rip=00007fffe1e4cba4 rsp=00000000010fc050 rbp=00000000010fc150
 r8=0000000000000000  r9=000000003999b640 r10=0000000000000018
r11=00000000010fc020 r12=0000000000000000 r13=00000000010fc370
r14=000000004b727aa0 r15=0000000000000020
iopl=0         nv up ei pl nz na pe nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
igxelpicd64+0x1fcba4:
00007fff`e1e4cba4 488b08          mov     rcx,qword ptr [rax] ds:00000000`00000198=????????????????
Resetting default scope

EXCEPTION_RECORD:  (.exr -1)
ExceptionAddress: 00007fffe1e4cba4 (igxelpicd64+0x00000000001fcba4)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 0000000000000000
   Parameter[1]: 0000000000000198
Attempt to read from address 0000000000000198

PROCESS_NAME:  xxx.exe

上面的崩潰點的組合語句 mov rcx,qword ptr [rax] 說的非常清楚,存取0區的 0000000000000198 地址必然會是存取違例,接下來簡單看一下組合程式碼。


0:000> ub igxelpicd64+0x00000000001fcba4
igxelpicd64+0x1fcb80:
00007fff`e1e4cb80 418b09          mov     ecx,dword ptr [r9]
00007fff`e1e4cb83 83f910          cmp     ecx,10h
00007fff`e1e4cb86 0f83bb0a0000    jae     igxelpicd64+0x1fd647 (00007fff`e1e4d647)
00007fff`e1e4cb8c 488d04cd21000000 lea     rax,[rcx*8+21h]
00007fff`e1e4cb94 4803c1          add     rax,rcx
00007fff`e1e4cb97 488d04c6        lea     rax,[rsi+rax*8]
00007fff`e1e4cb9b 4885c0          test    rax,rax
00007fff`e1e4cb9e 0f847c0c0000    je      igxelpicd64+0x1fd820 (00007fff`e1e4d820)

從組合程式碼看是一段 陣列操作 的邏輯,捋組合太累了,我們看下 igxelpicd64.dll 模組到底是誰寫的,用 lmvm 觀察下。


0:000> lmvm igxelpicd64
Browse full module list
start             end                 module name
00007fff`e1c50000 00007fff`e2cfe000   igxelpicd64   (export symbols)       igxelpicd64.dll
    Loaded symbol image file: igxelpicd64.dll
    Image path: C:\Windows\System32\DriverStore\FileRepository\iigd_dch.inf_amd64_ec5e4cdfcd3a62b8\igxelpicd64.dll
    Image name: igxelpicd64.dll
    Browse all global symbols  functions  data
    Timestamp:        Sat Jul 16 02:54:34 2022 (62D1B7EA)
    CheckSum:         010A00BB
    ImageSize:        010AE000
    File version:     31.0.101.3251
    Product version:  31.0.101.3251
    File flags:       0 (Mask 3F)
    File OS:          10004 DOS Win32
    File type:        2.8 Dll
    File date:        00000000.00000000
    Translations:     0409.04b0
    Information from resource tables:
        CompanyName:      Intel Corporation
        ProductName:      Intel HD Graphics Drivers for Windows(R)
        InternalName:     OpenGL
        OriginalFilename: ig7icd32
        ProductVersion:   31.0.101.3251
        FileVersion:      31.0.101.3251
        FileDescription:  OpenGL(R) Driver for Intel(R) Graphics Accelerator
        LegalCopyright:   Copyright (c) 1998-2018 Intel Corporation.

OpenGL(R) Driver for Intel(R) Graphics Accelerator 來看原來是用來渲染 2D,3D 向量圖形的工具包哈,這東西太底層了,沒玩過,不過有一點可以肯定的是這個 dll 是屬於 Intel 的,那為什麼會呼叫這個渲染功能呢? 這就需要觀察執行緒棧了。

2. 誰在呼叫渲染

崩潰有兩個場景,一個是崩潰前,一個是崩潰後,要看崩潰前的執行緒棧我們一定要知道崩潰前的狀況,這裡用 .ecxr 命令切換,簡化後如下:


0:000> .ecxr ; k
rax=0000000000000198 rbx=0000000000000001 rcx=0000000000000002
rdx=0000000039959600 rsi=0000000000000000 rdi=0000000039959600
rip=00007fffe1e4cba4 rsp=00000000010fc050 rbp=00000000010fc150
 r8=0000000000000000  r9=000000003999b640 r10=0000000000000018
r11=00000000010fc020 r12=0000000000000000 r13=00000000010fc370
r14=000000004b727aa0 r15=0000000000000020
iopl=0         nv up ei pl nz na pe nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
igxelpicd64+0x1fcba4:
00007fff`e1e4cba4 488b08          mov     rcx,qword ptr [rax] ds:00000000`00000198=????????????????
  *** Stack trace for last set context - .thread/.cxr resets it
 # Child-SP          RetAddr               Call Site
00 00000000`010fc050 00007fff`e1e4c500     igxelpicd64+0x1fcba4
...
07 00000000`010fd430 00007fff`e503b788     igxelpicd64!DumpRegistryKeyDefinitions+0x11865
08 00000000`010fd490 00000000`324147f6     opengl32!glReadPixels+0x88
...
0c 00000000`010fd6d0 00007ff7`f5a3185a     GSGlobeDotNet!GeoScene.Globe.GSOGlobe.ScreenToScene+0xa5
...
0e 00000000`010fe1b0 00007ff8`3285d810     System_Windows_Forms_ni!System.Windows.Forms.Control.OnMouseClick+0x9b
...

從執行緒棧看是使用者點選了滑鼠,進入了 GSGlobeDotNet.dll ,在讀取畫素的底層邏輯中拋了異常,然後到網上搜了一下,原來是繪製三維地球的工具包,這個