【问题标题】:How do I list the values of an enum from a memory dump using SOS and Windbg?如何使用 SOS 和 Windbg 从内存转储中列出枚举值?
【发布时间】:2020-02-13 16:49:24
【问题描述】:

我有一个附加到 windbg 的小型转储。迷你转储来自在 IIS 上运行的 .NET 4.6.1 ASP.NET 站点。我想获得我的枚举的定义,但是每当我获得类的 MethodTable 时,我都会得到以下内容。

0:000> !DumpMT /d 256db60c
EEClass:         256c773c
Module:          201fcfb0
Name:            MyDll.eDefaultRelatedObjects
mdToken:         02000029
File:            C:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\root\303e164d\216bec4f\assembly\dl3\bdb2a421\004bd941_fee1d501\MyDll.dll
BaseSize:        0xc
ComponentSize:   0x0
Slots in VTable: 23
Number of IFaces in IFaceMap: 3


0:000> !DumpClass /d 256c773c 
Class Name:      MyDll.eDefaultRelatedObjects 
mdToken:         02000029 
File:            C:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\root\303e164d\216bec4f\assembly\dl3\bdb2a421\004bd941_fee1d501\MyDll.dll 
Parent Class:    717f17cc 
Module:          201fcfb0 
Method Table:    256db60c 
Vtable Slots:    17 
Total Method Slots:  17 
Class Attributes: 101   
Transparency:        Critical 
NumInstanceFields:   1 
NumStaticFields:     0
      MT    Field   Offset                 Type VT     Attr    Value Name 
71c9f54c  400055f      124        System.Char[]  0   shared   static enumSeperatorCharArray
     >> Domain:Value  09671520:NotInit  306d85b0:0d8e822c 306da248:NotInit  306d98c0:NotInit  306dc868:138690b0 << 
71ca0994  400007d        4         System.Int32  1 instance           value__

我查看了 appdomains 中的值,但它们只是逗号。

0:000> !DumpObj /d 0d8e822c
Name:        System.Char[]
MethodTable: 71c9f54c
EEClass:     71874c84
Size:        14(0xe) bytes
Array:       Rank 1, Number of elements 1, Type Char (Print Array)
Content:     ,
Fields:
None

我需要做什么才能从堆上的对象中定义枚举?

编辑1: 如果有影响,我可以访问 PDB。

【问题讨论】:

    标签: .net enums windbg sos


    【解决方案1】:

    简单的事情优先:

    0:000> !DumpObj /d 0d8e822c
    [...]
    Content:     ,    
    

    您在这里所做的是:列出enumSeperatorCharArray 的值。它与您的枚举定义无关。所有枚举都有它。

    SOS 恕我直言,没有办法列出枚举定义。为此,您需要

    这是调试会话:

    0:006> .loadby sos clr
    0:006> .load D:\mylongpath\sosex.dll
    
    0:006> !dumpheap -type YourEnum
     Address       MT     Size
    02cf2480 01154dc4       12     
    
    Statistics:
          MT    Count    TotalSize Class Name
    01154dc4        1           12 DebuggingEnumDefinition.YourEnum
    Total 1 objects
    

    所以有一个对象,并且可以像您一样查看它。在输出的最后,您可以看到它的十进制值,即 65,不是很有帮助。

    0:006> !DumpObj /d 02cf2480
    Name:        DebuggingEnumDefinition.YourEnum
    [...]
    61bf42a8  4000001        4         System.Int32  1 instance       65 value__
    

    使用 SOSEX'!mdt,可以列出枚举常量:

    0:006> !mdt DebuggingEnumDefinition.YourEnum
    DebuggingEnumDefinition.YourEnum
        [s]enumSeperatorCharArray: char[]
            AppDomain 'DebuggingEnumDefinition.exe' (00c8dc18): <uninitialized>
        [s]enumSeperator: string
            AppDomain 'DebuggingEnumDefinition.exe' (00c8dc18): <Field def not loaded>
        value__: int
        [s]EnumVal1: DebuggingEnumDefinition.YourEnum
            AppDomain 'DebuggingEnumDefinition.exe' (00c8dc18): <Field def not loaded>
        [s]EnumVal2: DebuggingEnumDefinition.YourEnum
            AppDomain 'DebuggingEnumDefinition.exe' (00c8dc18): <Field def not loaded>
        [s]EnumVal3: DebuggingEnumDefinition.YourEnum
            AppDomain 'DebuggingEnumDefinition.exe' (00c8dc18): <Field def not loaded>
    

    其实我也预料到了数值。

    您还可以将!mdt 与对象的地址一起使用,这样您就可以得到它的常量和十六进制值(0x41 == 65):

    0:006> !mdt 02cf2480
    0x41 (EnumVal3) (DebuggingEnumDefinition.YourEnum)
    

    通过更改进程内存,您可能会生成枚举值的映射。

    下面会生成一个从 0 到 127 的循环:

    .for (r $t0=0; @$t0<0n128; r $t0 = @$t0+1) { }
    

    在循环内部,你可以改变枚举的值(我忘了 +4 是否取决于位数):

    ed 03402470+4 @$t0
    

    接下来,您可以使用!mdt 来分析修改后的值

    !mdt 03402470
    

    完整的命令是

    .for (r $t0=0; @$t0<0n128; r $t0 = @$t0+1) { ed 03402470+4 @$t0; !mdt 03402470}
    

    输出看起来像

    0x0 (EnumVal1) (DebuggingEnumDefinition.YourEnum)
    0x1 (EnumVal2) (DebuggingEnumDefinition.YourEnum)
    0x2 (DebuggingEnumDefinition.YourEnum)
    0x3 (DebuggingEnumDefinition.YourEnum)
    [...]
    0x7f (DebuggingEnumDefinition.YourEnum)
    

    接下来,您可能只过滤有效案例。请注意,我们可以通过包含 ) ( 来区分有效条目和无效条目。

    这就是 WinDbg 中的脚本变得有点丑陋的地方......

    .echo Just a test
    

    展示一些东西来说明原理。

    .shell -ci ".echo Just a test" findstr "Just"
    

    使用 DOS 命令findstr 过滤包含特定单词的行。

    接下来,将 .echo 替换为之前的完整命令,并将“Just”替换为 ) (。因为findstr 也是一个奇怪的程序,所以您实际上需要).(,否则它会将其视为两个单独的搜索词。

    .shell -ci ".for (r $t0=0; @$t0<0n128; r $t0 = @$t0+1) { ed 03402470+4 @$t0; !mdt 03402470}" findstr ").("
    

    还有yippieh,输出是:

    0x0 (EnumVal1) (DebuggingEnumDefinition.YourEnum)
    0x1 (EnumVal2) (DebuggingEnumDefinition.YourEnum)
    0x41 (EnumVal3) (DebuggingEnumDefinition.YourEnum)
    .shell: Process exited
    

    多么冒险!


    我用的源码,以防万一……

    using System;
    using System.Collections;
    
    namespace DebuggingEnumDefinition
    {
        class Program
        {
            static void Main()
            {
                var somwehere = new ArrayList() { YourEnum.EnumVal3 };
                Console.WriteLine("There should be an enum on the heap now.");
                Console.ReadLine();
                Console.WriteLine(somwehere[0]); // Just fix the unused variable issue
            }
        }
    
        enum YourEnum
        {
            EnumVal1,
            EnumVal2,
            EnumVal3=65
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-10-02
      • 2019-05-09
      • 2016-11-10
      • 2014-11-13
      • 2021-12-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多