comwindbgrcw

Getting RCW value of System.__ComObject in windbg script


I am trying to write a Windbg script where i have 1k addresses in a file. For each address, at offset 0x30 is a COM object.

I want to get all native pointers from COM object. I know how to do it manually like below. I am having trouble for iterating it in script.

From a System.__ComObject, !do <comobject> gives RCW: in text. Dumping RCW using !DumpRCW gives me IUnknown pointer that i need.

Name:        System.__ComObject
MethodTable: 00007ffcf2941330
EEClass:     00007ffcf22264b0
RCW:         000001d3634f3460
Size:        32(0x20) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
00007ffcf2949de8  40005b2        8        System.Object  0 instance 0000000000000000 __identity
00007ffcf294d1f8  400045c       10 ...ections.Hashtable  0 instance 0000000000000000 m_ObjectToDataMap

0:000> !DumpRCW /d 000001d35a9e0d70
Managed object:             000001d37976a708
Creating thread:            000001d35d552a60
IUnknown pointer:           000001d31e63ce28
COM Context:                000001dffecab0f8
Managed ref count:          1
IUnknown V-table pointer :  00007ffcd3f0edb8 (captured at RCW creation time)
Flags:                      
COM interface pointers:
              IP          Context               MT Type
000001d31e63ce20 000001dffecab0f8 00007ffc949869c0 NativeClass.ClassX
000001d31e63ce28 000001dffecab0f8 00007ffc949868e0 NativeClass.ClassX

For script, the issue is :

How to get RCW value from ComObject using script ? The fields in System.__ComObject are null.

Script that i have so far:

0:000> .foreach /f ( obj "d:\windbg\debug1.allmanagedtxs.small.txt") { .printf "%p\n", obj; !do poi(${obj}+0x30) }
000001d378daa6d8
Name:        System.__ComObject
MethodTable: 00007ffcf2941330
EEClass:     00007ffcf22264b0
RCW:         000001d3634f3460
Size:        32(0x20) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
00007ffcf2949de8  40005b2        8        System.Object  0 instance 0000000000000000 __identity
00007ffcf294d1f8  400045c       10 ...ections.Hashtable  0 instance 0000000000000000 m_ObjectToDataMap
000001d37976a728
Name:        System.__ComObject
MethodTable: 00007ffcf2941330
EEClass:     00007ffcf22264b0
RCW:         000001d35a9e0d70
Size:        32(0x20) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
00007ffcf2949de8  40005b2        8        System.Object  0 instance 0000000000000000 __identity
00007ffcf294d1f8  400045c       10 ...ections.Hashtable  0 instance 0000000000000000 m_ObjectToDataMap

Solution

  • I Hate to parse strings :) but here is a recipe again for parsing strings it is on a live session adapt it to parse from file

    /// <reference path="JSProvider.d.ts" />
    function log(x) {
        host.diagnostics.debugLog(x + "\n")
    }
    function exec(cmdstr) {
        return host.namespace.Debugger.Utility.Control.ExecuteCommand(cmdstr);
    }
    function rcw(first) {
        var obs = exec("!DumpHeap -short -type System.__ComObject")
        for (i of obs) {
            var cstr = "!do -nofields " + i
            foo = exec(cstr)
            for (j of foo) {
                if (j.includes("RCW") == true) {
                    blah = exec("!DumpRCW " + j.substr(j.lastIndexOf(" ") + 1))
                    for (k of blah) {
                        if (k.includes("IUnknown pointer") == true) {
                            log(k)
                        }
                    }
                }
            }
        }
    }
    

    executing this on a live target

    .load jsprovider 
    .scriptload  foo.js
    0:007> dx @$scriptContents.rcw()
    IUnknown pointer:           00000227da903bf0
    IUnknown pointer:           00000227da73e618
    IUnknown pointer:           00000227da73dd10
    IUnknown pointer:           00000227f4a765f0
    IUnknown pointer:           00000227f4a77888
    IUnknown pointer:           00000227f4a74ea0
    @$scriptContents.rcw()
    

    actual clickety click notice the 3bf0

    0:007> !DumpHeap -short -type System.__ComObject
    00000227dc23b218
    00000227dc23f620
    00000227dc23f640
    00000227dc25e7d0
    00000227dc25faa0
    00000227dc25fac0
    0:007> !DumpObj /d 00000227dc23b218
    Name:        System.__ComObject
    MethodTable: 00007ffda24adad8
    EEClass:     00007ffda2492608
    RCW:         00000227da7450e0
    Size:        32(0x20) bytes
    File:        C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
    Fields:
                  MT    Field   Offset                 Type VT     Attr            Value Name
    00007ffda2518948  40005b8        8        System.Object  0 instance 0000000000000000 __identity
    00007ffda251bb18  4000462       10 ...ections.Hashtable  0 instance 0000000000000000 m_ObjectToDataMap
    0:007> !DumpRCW /d 00000227da7450e0
    Managed object:             00000227dc23b218
    Creating thread:            00000227da6e30b0
    IUnknown pointer:           00000227da903bf0
    COM Context:                00000227da72c668
    Managed ref count:          1
    IUnknown V-table pointer :  00007ffdc3252190 (captured at RCW creation time)
    Flags:                      
    COM interface pointers:
                  IP          Context               MT Type
    00000227da903bf0 00000227da72c668 00007ffd4a1b5c88 TestDispatchUtility.DispatchUtility+IDispatchInfo
    

    btw the binary used is from here