Windbg - 跟踪C ++ / VB6 / C#应用程序中的本机加密泄漏

时间:2016-02-09 18:51:58

标签: .net windbg

我目前正在尝试追踪C ++服务中的泄漏,该服务加载了使用windbg加载.NET库的VB6模块,截至目前,感觉我已经非常接近答案,但似乎无法锁定它。

从!heap -s开始,我确定了有问题的堆:

0:000> !heap -s
LFH Key                   : 0x48d335eb
Termination on corruption : ENABLED
  Heap     Flags   Reserv  Commit  Virt   Free  List   UCR  Virt  Lock  Fast 
                    (k)     (k)    (k)     (k) length      blocks cont. heap 
-----------------------------------------------------------------------------
Virtual block: 03d20000 - 03d20000 (size 00000000)
007a0000 00000002 1457472 1447856 1457472   7003  1888    94    1      e   LFH

鉴于此,我确定了堵塞它的原因:

0:000> !heap -stat -h 007a0000
 heap @ 007a0000
group-by: TOTSIZE max-display: 20
    size     #blocks     total     ( %) (percent of total busy bytes)
    298 cb166 - 20ec2090  (76.28)

启用gflags后,我会识别并调整分配的调用方式:

0:000> !heap -flt s 298
    <snip>
    604473b8 0055 0055  [00]   604473c0    00298 - (busy)
    <snip>

0:000> !heap -p -a  604473c0 
    address 604473c0 found in
    _HEAP @ 007a0000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        604473b8 0059 0000  [00]   604473c0    00298 - (busy)
        772a34e5 ntdll!RtlAllocateHeap+0x0000021d
        74c54568 rsaenh!ContAlloc+0x00000017
        74c7aa8f rsaenh!CopyKey+0x00000030
        74c7abd4 rsaenh!CPDuplicateKey+0x0000008b
        75584c4b advapi32!CryptDuplicateKey+0x0000007c

一旦我知道分配来自对CryptDuplicateKey的调用,我就会在这个调用的地方进行搜索。我们从不在代码中直接调用它,因此我再次使用WinDBG来确定如何调用它。

0:198> bp advapi32!CryptDuplicateKey+0x0000007c
0:198> g

Breakpoint 0 hit
eax=212bc380 ebx=22222222 ecx=26d0ddc8 edx=74c7ab49 esi=2f90bc10 edi=00000001
eip=75584c48 esp=26d0dd9c ebp=26d0dde8 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
ADVAPI32!CryptDuplicateKey+0x79:
75584c48 ff5624          call    dword ptr [esi+24h]  ds:002b:2f90bc34={rsaenh!CPDuplicateKey (74c7ab49)}

0:034> !clrstack
OS Thread Id: 0x12f24 (34)
ESP       EIP     
26d0de40 75584c48 [NDirectMethodFrameStandaloneCleanup: 26d0de40] System.Security.Cryptography.CapiNative+UnsafeNativeMethods.CryptDuplicateKey(Microsoft.Win32.SafeHandles.SafeCapiKeyHandle, IntPtr, Int32, Microsoft.Win32.SafeHandles.SafeCapiKeyHandle ByRef)
26d0de58 742aa535 Microsoft.Win32.SafeHandles.SafeCapiKeyHandle.Duplicate()
26d0de68 742ac382 System.Security.Cryptography.CapiSymmetricAlgorithm..ctor(Int32, Int32, Microsoft.Win32.SafeHandles.SafeCspHandle, Microsoft.Win32.SafeHandles.SafeCapiKeyHandle, Byte[], System.Security.Cryptography.CipherMode, System.Security.Cryptography.PaddingMode, System.Security.Cryptography.EncryptionMode)
26d0de98 742ab5b2 System.Security.Cryptography.AesCryptoServiceProvider.CreateDecryptor(Microsoft.Win32.SafeHandles.SafeCapiKeyHandle, Byte[])
26d0deb4 742ab521 System.Security.Cryptography.AesCryptoServiceProvider.CreateDecryptor(Byte[], Byte[])
26d0def0 1097028b CryptoLib.CryptoObject.DecryptMessage(System.String, System.String ByRef)

由于CryptoLib是我们的代码,我现在已经准备好泄漏的来源。显然,CreateDecryptor正在调用DuplicateKey,它正在泄漏大小为298的分配,所以我的思考过程是我们可能没有正确调用dispose。但是,当我在CryptoLib中检查这个区域的实现时,我发现:

using (var aes = new AesCryptoServiceProvider()) {
    aes.Key = vbKey
    aes.IV = vbIV
    byte[] decryptBuffer;
    using (var mstream = new MemoryStream()) {
        using (var decryptor = aes.CreateDecryptor(aes.Key, aes.IV)) {
            using (var cstream = new CryptoStream(mstream, decryptor, CryptoStreamMode.Write) {                            {
                cstream.Write(messagebuffer, 0, messagebuffer.Length);
                cstream.FlushFinalBlock(); 
            }
        }
        decryptBuffer = mstream.ToArray();
    }
    decryptedMessage = Encoding.GetEncoding(1252).GetString(decryptBuffer);
}

展望CreateDecryptor,看起来这一切都应该正确处理,然而,应用程序仍在从CreateDecryptor调用中收集1.1 GB的垃圾。

查看documentation for this,实现似乎是正确的,我似乎无法确定这些本机对象泄漏的原因。

图书馆另有表现,我只是无法弄清楚为什么这些对象没有处理掉。

0 个答案:

没有答案