windbgsos

Windbg managed objects poi for arrays first element, second element


I can use poi in windbg scripting to traverse the fields and then print the field i am interested in. For e.g. if i have all objects of type X which has field X.y.z where z is an array, where y is at offset 0x10 and z is at offset 0x8. I can write

.foreach ( dSM { !dumpheap -short -type X})
 { 
    .printf "%p\n", poi(poi(${dSM}+0x10)+0x8); 
    !dumparray poi(poi(${dSM}+0x10)+0x8)     
}

Now i want to print first/second element of all these arrays, how can i do that ?

using !do poi(poi(poi(${dSM}+0x10)+0x8)) does not work.

0:045> !DumpArray /d 000001d3b96787a8
Name:        ABC[]
MethodTable: 00007ffc951e76e0
EEClass:     00007ffcf22f4480
Size:        56(0x38) bytes
Array:       Rank 1, Number of elements 4, Type CLASS
Element Methodtable: 00007ffc951e6cc0
[0] 000001d3b9678788
[1] null
[2] null
[3] null
0:045> !dumpobj /d poi(000001d3b96787a8)
<Note: this object has an invalid CLASS field>
Invalid object

Array class is:

:045> !DumpClass /d 00007ffcf22f4480
Class Name:      System.Object[]
mdToken:         0000000002000000
File:            C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
Parent Class:    00007ffcf22f5018
Module:          00007ffcf2221000
Method Table:    00007ffcf2949e80
Vtable Slots:    18
Total Method Slots:  1c
Class Attributes:    2101  
Transparency:        Transparent
NumInstanceFields:   0
NumStaticFields:     0

Solution

  • Given this program:

    using System;
    
    namespace WinDbgArrayAccess
    {
        class Program
        {
            static void Main()
            {
                Program[] justAnArray = new Program[20];
                for (int i =0; i<justAnArray.Length;i++) justAnArray[i] = new Program();
                Console.WriteLine("Access the elements of the array in WinDbg now!");
                Console.ReadLine();
            }
        }
    }
    

    You can see

    0:006> !DumpArray /d 0336243c
    Name:        WinDbgArrayAccess.Program[]
    MethodTable: 01914db0
    EEClass:     71967820
    Size:        92(0x5c) bytes
    Array:       Rank 1, Number of elements 20, Type CLASS
    Element Methodtable: 01914d60
    [0] 03362498
    [1] 033624a4
    [2] 033624b0
    [3] 033624bc
    [4] 033624c8
    [5] 033624d4
    ...
    

    Now you need to find those numbers somewhere in the memory. Since we hardly have a different starting point, let's start at the array's address:

    0:006> dp 0336243c L10
    0336243c  01914db0 00000014 03362498 033624a4
    0336244c  033624b0 033624bc 033624c8 033624d4
    0336245c  033624e0 033624ec 033624f8 03362504
    0336246c  03362510 0336251c 03362528 03362534
    

    Now, 01914db0 is the type of the object (called Method Table, MT). 0x14 is 0n20, which is the size of the array. And after that, it seems we have the elements, 03362498, 033624a4, 033624b0 etc.

    How do we access that programmatically? Well, it's easy now:

    0:006> .printf "%p",poi(0336243c+(2+3)*$ptrsize)
    033624bc
    

    Where 2 is to skip MT and Length and 3 is the index of the array, giving you the 4th element.