WinDbg Script---显示RCW对象引用的COM对象

在调试.NET应用程序中的转储文件时,有时我们可能会遇到这样的情况:我们希望得到引用RCW对象的System.__ComObject包装器引用的COM对象。
你可能会认为抛弃这个系统。也许你能给出答案,但事实并非如此。

如下例子

Name: System.__ComObject

MethodTable: 79307098

EEClass: 790dfa34

Size: 16(0x10) bytes

GC Generation: 2

 (C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)

Fields:

      MT    Field  
Offset                 Type
VT     Attr    Value Name

79330740  400018a        4       
System.Object  0 instance 00000000
__identity

79333178  400027e        8 ...ections.Hashtable  0 instance 00000000 m_ObjectToDataMap

Where is the COM object???

因此,在使用私有符号时,我从《高级Windows调试和高级.NET调试》那里学到了一系列步骤。我首先想到的是,当需要再次使用该技术时,我会忘记这些步骤,所以我创建了一个脚本来完成这项工作。
根据SOS 4.5的公开测试版,有一个命令可以做到:!DumpRCW <RCW address>

此命令列出有关运行时可调用包装的信息。你可以用!DumpObj获取与托管对象对应的RCW地址。输出包含RCW保留的所有COM接口指针,这对于研究互操作性强的应用程序的生存期问题非常有用。

 

 

如果COM对象被释放,而RCW引用计数器没有减少(例如,Marshal.FinalReleaseComObject未调用),您将知道,因为脚本将显示无效地址,例如:

 

另一种情况:

 

脚本源代码如下:

$$
$$ =============================================================================
$$ COM_FROM_RCW_PUBLIC.TXT
$$
$$ Version: 1.2
$$
$$ Note: Create a folder called MyScripts where your WinDbg.exe is located and
$$       save the script there.
$$
$$ This script gives you the COM object used by System.__ComObject
$$
$$ Note: This is the Public version.
$$ Compatibility: Win32/Win64.
$$ PSSCORx or SOS required.
$$
$$ Usage: $$>a<myscripts\COM_FROM_RCW.txt  <address of System.__ComObject>
$$
$$ Mario Hewardt    
$$ Roberto Alexis Farah - http://blogs.msdn.com/debuggingtoolbox/
$$
$$ 3/5/2012 - Fixed problem with x64.
$$
$$ All my scripts are provided "AS IS" with no warranties, and confer no rights.
$$ =============================================================================
$$
$$ Checks if user is providing the argument.
.if(0 == ${/d:$arg1})
{

    .printf /D "\n<b> Please, provide the address of System.__ComObject as argument for the

script.</b>\n\n"
    .printf  "Usage: $$>a<myscripts\\COM_FROM_RCW_PUBLIC.txt <address of System.__ComObject>"
}
.else
{
    .catch
    {
        .printf /D "\n<b> Make sure you are using Symbols and PSSCOR or SOS is loaded...</b>\n

\n"

        $$ Let's get the address of the object - 0x4 and the low order WORD from that address.
        r @$t0 = wo(${$arg1}-0x4)

        $$ Gets Sync Block because we need the first syncblk field.
        $$ To do that we need to redirect the output to a file and parse the file.
        .logopen TEMP.LOG

        !syncblk @$t0

        .logclose

        $$ Now let's parse the output... We need token # 15
        $$ This is what we need:
        $$
        $$ Index SyncBlock MonitorHeld Recursion Owning Thread Info  SyncBlock Owner
        $$     3 100e502c <<<       0         0 00000000     none    12a32b3c System.__ComObject
     
        $$ Counter to count tokens. /pS didn't work as I expected...
        r @$t1 = 0
        r @$t2 = 0
          
        .foreach /f (obj "TEMP.LOG")
        {
             r @$t1 = @$t1 + 1

             $$ Is this field number 15? If yes we can ignore the other fields.    
             .if(0n15 == @$t1)
             {
                  .echo SyncBlock address = ${obj}

                  $$ Let's save our address. Keep in mind that this line can store
                  $$ garbage, like a field name from the output, if something goes wrong.
                  r @$t2 = ${obj}

                  .break
             }
        }

        $$ Protection against invalid pointers.
        .catch
        {
            .if(0n4 == @$ptrsize)
            {
                r @$t3 = poi(poi(poi(@$t2+0x1c)+@$ptrsize*0n3)+0x88)
            }
            .else
            {
                r @$t3 = poi(poi(poi(@$t2+0x28)+@$ptrsize*0n3)+0x100)
            }
        }

        .printf /D "\n<b>This is the COM object referenced by the RCW object from address

%p:</b>\n\n", @$t2

        dps @$t3 L10
    }
}

posted on 2020-11-24 08:05  活着的虫子  阅读(278)  评论(0编辑  收藏  举报

导航