記一次 .NET某收銀軟件 非託管泄露分析

一:背景

1. 講故事

在我的分析之旅中,遇到過很多程序的故障和殺毒軟件扯上了關係,有殺毒軟件導致的程序卡死,有殺毒軟件導致的程序崩潰,這一篇又出現了一個殺毒軟件導致的程序非託管內存泄露,真的是分析多了什麼鬼都能撞上。

前幾天有位朋友找到過,我他們的程序內存在慢慢的泄露,最後程序會出現崩潰,不知道是什麼導致的,讓我幫忙看一下怎麼回事,簡單分析後發現是非託管泄露,讓朋友開啓了ust並在內存超出預期時抓了一個dump下來,接下來就是分析了。

二:WinDbg 分析

1. 到底是哪裏的泄露

相信一直追這個系統的朋友應該知道怎麼判斷,很簡單, 看下 MEM_COMMITHEAP 指標即可,使用 !address -summary 命令輸出如下:


0:000> !address -summary

--- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
Heap                                    678          93bd0000 (   2.308 GB)  65.39%   57.71%
<unknown>                              2610          3005d000 ( 768.363 MB)  21.26%   18.76%
Free                                    515          1e133000 ( 481.199 MB)           11.75%
Image                                  1526          118f8000 ( 280.969 MB)   7.77%    6.86%
Other                                    19           804e000 ( 128.305 MB)   3.55%    3.13%
Stack                                   390           4900000 (  73.000 MB)   2.02%    1.78%
TEB                                      73             49000 ( 292.000 kB)   0.01%    0.01%
PEB                                       1              1000 (   4.000 kB)   0.00%    0.00%

--- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_COMMIT                             4477          c51f9000 (   3.080 GB)  87.25%   77.00%
MEM_FREE                                515          1e133000 ( 481.199 MB)           11.75%
MEM_RESERVE                             820          1ccc4000 ( 460.766 MB)  12.75%   11.25%


--- Largest Region by Usage ----------- Base Address -------- Region Size ----------
Heap                                        38be0000            fd0000 (  15.812 MB)
<unknown>                                     cc6000           7fd9000 ( 127.848 MB)
Free                                        f7590000           88bf000 ( 136.746 MB)
Image                                       5ab2c000            e41000 (  14.254 MB)
Other                                        8cee000           7fb0000 ( 127.688 MB)
Stack                                       14610000             fd000 (1012.000 kB)
TEB                                         ffe51000              1000 (   4.000 kB)
PEB                                         fffde000              1000 (   4.000 kB)

從卦中看,3G的提交內存,Heap 吃了 2.3G,也就表明是 NTHEAP 的泄露,這是一塊非託管內存區域,一般都是 C/C++ 語言用 malloc 或者 new 分配的內存,接下來深挖下 NTHEAP 即可,使用 !heap -s 命令。


0:000> !heap -s
SEGMENT HEAP ERROR: failed to initialize the extention
NtGlobalFlag enables following debugging aids for new heaps:
    stack back traces
LFH Key                   : 0x7c31b93c
Termination on corruption : DISABLED
  Heap     Flags   Reserv  Commit  Virt   Free  List   UCR  Virt  Lock  Fast 
                    (k)     (k)    (k)     (k) length      blocks cont. heap 
-----------------------------------------------------------------------------
00200000 08000002  178304 138172 178304  42165  1747    56    0     34   LFH
    External fragmentation  30 % (1747 free blocks)
006c0000 08001002    1088    224   1088     18     8     2    0      0   LFH
00590000 08041002     256      4    256      2     1     1    0      0      
006a0000 08001002    3136   1184   3136    153    82     3    0      0   LFH
    External fragmentation  12 % (82 free blocks)
00570000 08001002    1088    224   1088     18     8     2    0      0   LFH
...   
15710000 08001002 2185152 2179432 2185152    442  1323   139    0      0   LFH
...

從卦中信息看, 15710000 吃了2.18G,也就表明它是喫內存的主力,這裏簡單說一下,00200000 是默認的進程堆,除了這個之外都是用非託管代碼調用 Win32API 的 HeapCreate 方法創建出來的,接下來就得看下是什麼代碼創建的。

2. 到底是誰創建的

要想知道是誰創建的,一定要在註冊表中開啓 ust 選項,大家可以瞭解下 gflags.exe 工具,參考如下:


PS C:\Users\Administrator\Desktop> gflags /i Example_17_1_7.exe +ust
Current Registry Settings for Example_17_1_7.exe executable are: 00001000
    ust - Create user mode stack trace database

開啓之後 win32api 的 HeapAlloc 方法的內部中會到註冊表中看一下是否有 ust 值,如果有就會記錄分配的調用棧,這樣就知道是誰創建的,抓取dump後可以用windbg的 !gflag 命令看下是否開啓成功,參考輸出如下:


0:000> !gflag
Current NtGlobalFlag contents: 0x00001000
    ust - Create user mode stack trace database

接下來對 Heap=15710000 進行一個 block 分組,看下是否有一些有價值的信息。


0:000> !heap -stat -h 15710000
 heap @ 15710000
group-by: TOTSIZE max-display: 20
    size     #blocks     total     ( %) (percent of total busy bytes)
    2cb dea4 - 26dd40c  (9.58)
    2d7 c778 - 23675c8  (8.72)
    d0 26d64 - 1f8e140  (7.78)
    7c5 2c50 - 1584990  (5.30)
    cb 14449 - 10125e3  (3.96)
    83c 16c2 - bb6578  (2.89)
    cf9 bc4 - 98a1a4  (2.35)
    1f51 3da - 789dfa  (1.86)
    ...

從卦中數據看沒有哪個size佔用的特別高,接下來就依次從高往低看,發現都是和 prthook 有關,參考輸出如下:


0:000> !heap -flt s 2cb
    _HEAP @ 15710000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        1571f948 005d 0000  [00]   1571f960    002cb - (busy)
        15649d70 005d 005d  [00]   15649d88    002cb - (busy)
        ...
        3ec4b900 005d 005d  [00]   3ec4b918    002cb - (busy)
        3ec4bbe8 005d 005d  [00]   3ec4bc00    002cb - (busy)
        3ec4bed0 005d 005d  [00]   3ec4bee8    002cb - (busy)
        3ec4c1b8 005d 005d  [00]   3ec4c1d0    002cb - (busy)
        ...

0:000> !heap -flt s 2d7
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        15665550 005e 0000  [00]   15665568    002d7 - (busy)
        1566b930 005e 005e  [00]   1566b948    002d7 - (busy)
        1566df98 005e 005e  [00]   1566dfb0    002d7 - (busy)
        1566e288 005e 005e  [00]   1566e2a0    002d7 - (busy)
        ...
        39e3acc8 0061 0061  [00]   39e3ace0    002d7 - (busy)
        39e3c508 0061 0061  [00]   39e3c520    002d7 - (busy)
        39e3c810 0061 0061  [00]   39e3c828    002d7 - (busy)
        39e3cb18 0061 0061  [00]   39e3cb30    002d7 - (busy)
        39e3ce20 0061 0061  [00]   39e3ce38    002d7 - (busy)

0:000> !heap -p -a 3ec4c1b8
    address 3ec4c1b8 found in
    _HEAP @ 15710000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        3ec4c1b8 005d 0000  [00]   3ec4c1d0    002cb - (busy)
        771dd969 ntdll!RtlAllocateHeap+0x00000274
        153e7439 prthook!MyShowWindow+0x0001d1f9
        153e543c prthook!MyShowWindow+0x0001b1fc
        153476ab prthook+0x000276ab

0:000> !heap -p -a 39e3ce20
    address 39e3ce20 found in
    _HEAP @ 15710000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        39e3ce20 0061 0000  [00]   39e3ce38    002d7 - (busy)
        771dd969 ntdll!RtlAllocateHeap+0x00000274
        153e7439 prthook!MyShowWindow+0x0001d1f9
        153e543c prthook!MyShowWindow+0x0001b1fc
        153476ab prthook+0x000276ab

3. prthook 到底爲何方神聖

從前一節的卦中數據看,貌似 prthook 在不斷的彈框,在彈框中用 ntdll!RtlAllocateHeap 分配了非託管內存,那 prthook 到底是個啥呢?可以用 lmvm 看下。


0:000> lmvm prthook
Browse full module list
start    end        module name
15320000 155dc000   prthook    (export symbols)       prthook.dll
    Loaded symbol image file: prthook.dll
    Image path: C:\Windows\SysWOW64\prthook.dll
    Image name: prthook.dll
    Browse all global symbols  functions  data
    Timestamp:        Thu Jun 22 17:16:53 2017 (594B8B05)
    CheckSum:         001F4972
    ImageSize:        002BC000
    File version:     16.17.6.22
    Product version:  16.17.6.22
    File flags:       0 (Mask 3F)
    File OS:          40004 NT Win32
    File type:        2.0 Dll
    File date:        00000000.00000000
    Translations:     0804.04b0
    Information from resource tables:
        CompanyName:      Beijing VRV Software Co.,Ltd
        ProductName:      edp
        InternalName:     prthook
        OriginalFilename: prthook.dll_DB
        ProductVersion:   16, 17, 6, 22
        FileVersion:      16, 17, 6, 22
        FileDescription:  prthook_DB
        LegalCopyright:   Copyright (C) 2016 Beijing VRV Software Co.,Ltd
        Comments:         中英文版

從卦中數據看,prthook.dll 所屬公司爲 Beijing VRV Software Co.,Ltd,無語的是把這個第三方的dll放在Windows的系統目錄 C:\Windows\SysWOW64 下,容易讓人覺得有點 鳩佔鵲巢,接下來查一下百度,發現是 北信源 的,截圖如下:

有了這些信息,告訴朋友讓客戶把這個安全軟件卸載掉就可以了。

三:總結

程序的故障如果不是我們的代碼造成的,你想通過排查代碼找出問題是不可能的事情,追過這個系列的朋友應該深有體會,常見的外在因素有:

  • 殺毒軟件
  • 電磁輻射
  • 顯卡問題
图片名称
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章