{"id":27143,"date":"2007-04-24T10:00:00","date_gmt":"2007-04-24T10:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2007\/04\/24\/what-is-the-underlying-object-behind-a-com-interface-pointer\/"},"modified":"2007-04-24T10:00:00","modified_gmt":"2007-04-24T10:00:00","slug":"what-is-the-underlying-object-behind-a-com-interface-pointer","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20070424-00\/?p=27143","title":{"rendered":"What is the underlying object behind a COM interface pointer?"},"content":{"rendered":"<p>\nWhen you&#8217;re debugging,\nyou might have a pointer to a COM interface and want to know\nwhat the underlying object is.\nNow, sometimes this trick won&#8217;t work because the interface pointer\nactually points to a stub or proxy,\nbut in the case where no marshalling is involved, it works great.\n(This technique also works for many C++ compilers for\nany object that has virtual methods and therefore a vtable.)\n<\/p>\n<p>\nRecall that\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2004\/02\/05\/68017.aspx\">\nthe layout of a COM object<\/a> requires that the\npointer to a COM interface point to the object&#8217;s vtable,\nand it&#8217;s the vtable that is the key.\n<\/p>\n<pre>\n0:000&gt; dv\n            pstm = 0x000c7568\n0:000&gt; dt psf\nLocal var @ 0x7cc2c Type IStream*\n0x000c7568\n   +0x000 __VFN_table : 0x1c9c8e84\n<\/pre>\n<p>\nOkay, so far all we know is that our <code>IStream&nbsp;*<\/code>\nlives at <code>0x000c7568<\/code> and its vtable is\n<code>0x1c9c8e84<\/code>.\nWhose stream implementation is it?\n<\/p>\n<pre>\n0:000&gt; ln 0x1c9c8e84\n(1c9c8e84)   ABC!CAlphaStream::`vftable'\n<\/pre>\n<p>\nAha, it&#8217;s a <code>CAlphaStream<\/code> from <code>ABC.DLL<\/code>.\nLet&#8217;s take a look at it:\n<\/p>\n<pre>\n0:000&gt; dt ABC!CAlphaStream 0x000c7568\n   +0x000 __VFN_table : 0x1c9c8e84 <font COLOR=\"blue\">\/\/ our vtable<\/font>\n   +0x004 m_cRef           : 480022128\n   +0x008 lpVtbl           : 0x1c9d2d30\n   +0x00c lpVtbl           : 0x00000014\n   +0x010 m_pszName        : 0x000c7844 \"??????????\"\n   +0x014 m_dwFlags        : 0x3b8\n   +0x018 m_pBuffer        : 0x00000005\n   +0x01c m_cbBuffer       : 705235565\n   +0x020 m_cbPos          : 2031674\n<\/pre>\n<p>\n&#8220;Hey, how did you get the debugger to dump <code>m_pszName<\/code>\nas a string?&#8221;\nIf you issue the <code>.enable_unicode 1<\/code> command,\nthen the debugger will treat pointers to <code>unsigned short<\/code>\nas if they were pointers to Unicode strings.\n(By default, only pointers to <code>wchar_t<\/code> are treated\nas pointers to Unicode strings.)\n<\/p>\n<p>\nOkay, back to the structure dump.\nIt doesn&#8217;t look right at all.\nThe reference count is some absurd value,\nthe vtable at offset <code>0x00c<\/code> is a bogus pointer,\nthe name in <code>m_pszName<\/code> is garbage,\npretty much every field aside from the initial vtable and\nthe vtable at offset <code>0x008<\/code> is blatantly wrong.\n<\/p>\n<p>\nWhat happened?\nWell, clearly we were given a &#8220;<code>q<\/code>&#8221; pointer;\ni.e., a pointer to one of the vtables other than the first one.\nWe have to adjust the pointer so it points to the start of the\nobject instead of the middle.\n<\/p>\n<p>\nHow do we do this adjustment?\nThere&#8217;s the methodical way and the quick-and-dirty way.\n<\/p>\n<p>\nThe methodical way is to use the\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2004\/02\/06\/68695.aspx\">\nadjustor thunks<\/a>\nto tell you how much the pointer needs to be adjusted\nin order to move from a secondary vtable to the primary one.\n(This assumes that the primary <code>IUnknown<\/code> implementation\nis the first base class.\nThis is not guaranteed to be the case but it usually is.)\n<\/p>\n<pre>\n0:000&gt; dps 1c9c8e84 l1\n1c9c8e84  1c9eb08e ABC![thunk]:CAlphaStream::QueryInterface`adjustor{8}'\n<\/pre>\n<p>\nAha, this adjustors adjust by eight bytes, so we just need to subtract\neight from our pointer to get the object&#8217;s starting address.\n<\/p>\n<pre>\n0:000&gt; dt ABC!CAlphaStream 0x000c7560<font COLOR=\"blue\">-8<\/font>\n   +0x000 __VFN_table : 0x1c9c8ee8\n   +0x004 m_cRef           : 2\n   +0x008 lpVtbl           : 0x1c9c8e84\n   +0x00c lpVtbl           : 0x1c9c8e70\n   +0x010 m_pszName        : 0x1c9d2d30 \"Scramble\"\n   +0x014 m_dwFlags        : 0x14\n   +0x018 m_pBuffer        : 0x000c7844\n   +0x01c m_cbBuffer       : 952\n   +0x020 m_cbPos          : 5\n<\/pre>\n<p>\nAh, that looks much nicer.\nNotice that the reference count is a more reasonable value of two,\nthe name pointer looks good,\nthe buffer size and position appear to be much more realistic.\n<\/p>\n<p>\nNow, I don&#8217;t bother with the whole adjustor thunk thing.\nInstead I rely on the principle of\n&#8220;<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2007\/04\/23\/2215961.aspx\">Assume it&#8217;s mostly correct<\/a>&#8220;:\nAssume that the object is not corrupted and just adjust the pointer by\neye until the fields line up.\nLet&#8217;s take another look at the original (bad) dump:\n<\/p>\n<pre>\n0:000&gt; dt ABC!CAlphaStream 0x000c7568\n   +0x000 __VFN_table : 0x1c9c8e84\n   +0x004 m_cRef           : 480022128\n   +0x008 lpVtbl           : 0x1c9d2d30\n   +0x00c lpVtbl           : 0x00000014\n   +0x010 m_pszName        : 0x000c7844 \"??????????\"\n   +0x014 m_dwFlags        : 0x3b8\n   +0x018 m_pBuffer        : 0x00000005\n   +0x01c m_cbBuffer       : 705235565\n   +0x020 m_cbPos          : 2031674\n<\/pre>\n<p>\nThis obviously doesn&#8217;t smell right, but what do we have to do\nto get things to line up?\nWell, we know that the vtable we have must go into one of the\nother two vtable slots, either the one at offset <code>0x008<\/code>\nor the one at offset <code>0x00c<\/code>.\nIf we moved it to offset <code>0x00c<\/code>,\nthen that would move the <code>0x00000014<\/code> currently at\noffset <code>0x00c<\/code> down twelve bytes, placing it at\noffset <code>0x018<\/code>, right at <code>m_pBuffer<\/code>.\nBut obviously <code>0x00000014<\/code> is not a valid buffer\npointer, so <code>0x00c<\/code> can&#8217;t be the correct adjustment.\nOn the other hand, if we put our vtable at offset <code>0x008<\/code>,\nthen that would move <code>0x000c7844<\/code> into the\n<code>m_pBuffer<\/code> position, which is not too unreasonable.\nTherefore, I would guess that the adjustor is eight,\nyielding the same structure dump that we got by dumping the\nvtable to see the adjustor.\n<\/p>\n<p>\nIn real life, I tend to pay attention to the vtables, the\nreference count,\nand any string members because it&#8217;s usually pretty easy to see\nwhether you got them right.\n(Vtables reside in code.\nReference counts tend to be small integers.\nStrings are, well, strings.)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>When you&#8217;re debugging, you might have a pointer to a COM interface and want to know what the underlying object is. Now, sometimes this trick won&#8217;t work because the interface pointer actually points to a stub or proxy, but in the case where no marshalling is involved, it works great. (This technique also works for [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[26],"class_list":["post-27143","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-other"],"acf":[],"blog_post_summary":"<p>When you&#8217;re debugging, you might have a pointer to a COM interface and want to know what the underlying object is. Now, sometimes this trick won&#8217;t work because the interface pointer actually points to a stub or proxy, but in the case where no marshalling is involved, it works great. (This technique also works for [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/27143","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=27143"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/27143\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=27143"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=27143"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=27143"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}