Windbg 为数组第一个元素、第二个元素管理对象 poi
Windbg managed objects poi for arrays first element, second element
我可以在 windbg 脚本中使用 poi
来遍历字段,然后打印我感兴趣的字段。
例如如果我有所有类型为 X
的对象,其字段为 X.y.z
,其中 z
是一个数组,其中 y
位于偏移量 0x10
和 z
位于偏移 0x8
处。我会写
.foreach ( dSM { !dumpheap -short -type X})
{
.printf "%p\n", poi(poi(${dSM}+0x10)+0x8);
!dumparray poi(poi(${dSM}+0x10)+0x8)
}
现在我想打印所有这些数组的 first/second 个元素,我该怎么做?
使用 !do poi(poi(poi(${dSM}+0x10)+0x8))
无效。
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
数组class是:
: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
给出这个程序:
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();
}
}
}
可以看到
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
...
现在您需要在内存中的某处找到这些数字。由于我们几乎没有不同的起点,所以让我们从数组的地址开始:
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
现在,01914db0
是对象的类型(调用方法Table,MT)。 0x14
就是0n20
,也就是数组的大小。在那之后,我们似乎有了元素,03362498
、033624a4
、033624b0
等
我们如何以编程方式访问它?好了,现在很容易了:
0:006> .printf "%p",poi(0336243c+(2+3)*$ptrsize)
033624bc
其中 2
是跳过 MT 和 Length,3
是数组的索引,给你第 4 个元素。
我能够通过从数组
向前 poi(poi(array+10)+8)
和 poi(poi(array+10)+10)
偏移量获得前 2 个元素
0:298> .foreach (obj { !DumpHeap -short -live -mt 00007ffc951e7ab8}) { .printf "%p\n", ${obj}; !mex.do2 poi(poi(poi(poi(${obj}+0x10)+0x8)+0x10)+0x8); !mex.do2 poi(poi(poi(poi(${obj}+0x10)+0x8)+0x10)+0x10); }
000001d379ac94a0
[raw] 000001d379ac8bc8 "XYZ_String"
[raw] 000001d379ac8c88 "XYZ_String_2"
000001d379e87168
[raw] 000001d379e86888 "ABCD_String"
[raw] 000001d379e86948 "ABCD_String_2"
000001d3b972a218
我可以在 windbg 脚本中使用 poi
来遍历字段,然后打印我感兴趣的字段。
例如如果我有所有类型为 X
的对象,其字段为 X.y.z
,其中 z
是一个数组,其中 y
位于偏移量 0x10
和 z
位于偏移 0x8
处。我会写
.foreach ( dSM { !dumpheap -short -type X})
{
.printf "%p\n", poi(poi(${dSM}+0x10)+0x8);
!dumparray poi(poi(${dSM}+0x10)+0x8)
}
现在我想打印所有这些数组的 first/second 个元素,我该怎么做?
使用 !do poi(poi(poi(${dSM}+0x10)+0x8))
无效。
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
数组class是:
: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
给出这个程序:
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();
}
}
}
可以看到
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
...
现在您需要在内存中的某处找到这些数字。由于我们几乎没有不同的起点,所以让我们从数组的地址开始:
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
现在,01914db0
是对象的类型(调用方法Table,MT)。 0x14
就是0n20
,也就是数组的大小。在那之后,我们似乎有了元素,03362498
、033624a4
、033624b0
等
我们如何以编程方式访问它?好了,现在很容易了:
0:006> .printf "%p",poi(0336243c+(2+3)*$ptrsize)
033624bc
其中 2
是跳过 MT 和 Length,3
是数组的索引,给你第 4 个元素。
我能够通过从数组
向前poi(poi(array+10)+8)
和 poi(poi(array+10)+10)
偏移量获得前 2 个元素
0:298> .foreach (obj { !DumpHeap -short -live -mt 00007ffc951e7ab8}) { .printf "%p\n", ${obj}; !mex.do2 poi(poi(poi(poi(${obj}+0x10)+0x8)+0x10)+0x8); !mex.do2 poi(poi(poi(poi(${obj}+0x10)+0x8)+0x10)+0x10); }
000001d379ac94a0
[raw] 000001d379ac8bc8 "XYZ_String"
[raw] 000001d379ac8c88 "XYZ_String_2"
000001d379e87168
[raw] 000001d379e86888 "ABCD_String"
[raw] 000001d379e86948 "ABCD_String_2"
000001d3b972a218