<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Pastukhov Aleksey</title>
    <description>The latest articles on Forem by Pastukhov Aleksey (@steelfactor).</description>
    <link>https://forem.com/steelfactor</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3874473%2F96013ba5-f022-4623-90ae-e5cbf4c964fb.png</url>
      <title>Forem: Pastukhov Aleksey</title>
      <link>https://forem.com/steelfactor</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/steelfactor"/>
    <language>en</language>
    <item>
      <title>Reverse Engineering rpcss.dll: Hunting for the ROT's Hidden Structure</title>
      <dc:creator>Pastukhov Aleksey</dc:creator>
      <pubDate>Wed, 06 May 2026 13:51:47 +0000</pubDate>
      <link>https://forem.com/steelfactor/reverse-engineering-rpcssdll-hunting-for-the-rots-hidden-structure-part-of-the-inside-the-2o36</link>
      <guid>https://forem.com/steelfactor/reverse-engineering-rpcssdll-hunting-for-the-rots-hidden-structure-part-of-the-inside-the-2o36</guid>
      <description>&lt;p&gt;&lt;strong&gt;Part IV(?) of the "Inside the Running Object Table" series&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When I started this research, I assumed finding the internal layout of the Running Object Table would be straightforward. Microsoft documents IRunningObjectTable at the API level — surely the implementation couldn't be far behind. I was wrong. What followed was a Ghidra session that turned up something far more interesting than I expected.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where does the ROT actually live?&lt;/strong&gt;&lt;br&gt;
First surprise: there is no rpcss.exe on disk.&lt;br&gt;
What Windows Task Manager shows as rpcss.exe is actually svchost.exe hosting rpcss.dll, classic service host pattern. The DLL lives at C:\Windows\System32\rpcss.dll and gets mapped into a dedicated svchost instance at boot. Every ROT operation your process makes through ole32.dll crosses an ALPC channel and lands in that DLL's code.&lt;br&gt;
So that's our target.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Loading rpcss.dll into Ghidra&lt;/strong&gt;&lt;br&gt;
Standard procedure — drag, drop, let the auto-analyzer run. The interesting part comes when you load the PDB. Microsoft publishes symbol files for most system DLLs through their public symbol server, and rpcss.dll is no exception.&lt;br&gt;
Grab symchk.exe from your Windows SDK Debuggers folder and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight batchfile"&gt;&lt;code&gt;&lt;span class="kd"&gt;symchk&lt;/span&gt; &lt;span class="kd"&gt;C&lt;/span&gt;:\Windows\System32\rpcss.dll &lt;span class="se"&gt;^
&lt;/span&gt;    &lt;span class="na"&gt;/s &lt;/span&gt;&lt;span class="kd"&gt;srv&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kd"&gt;C&lt;/span&gt;:\Symbols&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kd"&gt;https&lt;/span&gt;://msdl.microsoft.com/download/symbols
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Point Ghidra at the downloaded PDB and suddenly FUN_18006XXXX becomes something readable. This is where it gets interesting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First hit: CScmRotEntry&lt;/strong&gt;&lt;br&gt;
Searching the Symbol Table for ROT turns up the string u"ROTFlags" at address 180136070. One xref later, we're inside a large function. But the real find is in the Symbol Table itself:&lt;br&gt;
CScmRotEntry::GetAllowAnyClient&lt;br&gt;
Not CROTEntry. Not CRunningObjectTableEntry. CScmRotEntry - SCM stands for Service Control Manager. This tells us something immediately, the ROT isn't just a COM subsystem. It's wired into the service infrastructure at a deeper level than the documentation suggests.&lt;br&gt;
The decompilation of GetAllowAnyClient reveals the first concrete field offset:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uint&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mh"&gt;0x68&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// bit 1 = AllowAnyClient flag&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The real structure: LookupObjectInROT&lt;/strong&gt;&lt;br&gt;
Searching for CScmRot surfaces LookupObjectInROT - a function that takes ACTIVATION_PARAMS and walks the table looking for a matching object. From here we follow the call into CScmRot::GetObject, which is where the actual traversal happens.&lt;br&gt;
The decompilation reveals the first architectural surprise:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;cplVar13&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;longlong&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;longlong&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;lpCriticalSection&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mh"&gt;0x48&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;uVar9&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ROT is not a &lt;strong&gt;linked list&lt;/strong&gt;. It's a &lt;strong&gt;hash table&lt;/strong&gt; with 251 buckets (0xFB).&lt;br&gt;
Each bucket is a pointer to a chain of CScmRotEntry objects. The hash function is a simple rolling hash over the moniker bytes:&lt;br&gt;
chash = ((hash * 3) ^ byte) % 0xFB;&lt;br&gt;
Aint cryptographic n complex. Fast and collision-tolerant for the expected workload of a few dozen registered objects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Digging deeper: the class hierarchy&lt;/strong&gt;&lt;br&gt;
Listing all symbols with the CScmRot prefix turns up the full method table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CScmRot::EnumRunning
CScmRot::GetEntryFromScmReg
CScmRot::GetTimeOfLastChange
CScmRot::IsRunning
CScmRot::Register
CScmRot::Revoke
CScmRotEntry::CScmRotEntry
CScmRotEntry::GetProcessID
CScmRotEntry::IsValid
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things stand out. First, CScmRotEntry::CScmRotEntry it's a constructor, meaning this is a proper class with its own lifecycle. Second, CScmRotEntry::GetProcessID -every ROT entry stores the PID of the registering process. That field doesn't appear anywhere in the public API documentation.&lt;br&gt;
Opening the constructor reveals something else entirely: CScmRotEntry is not a flat structure. It inherits from a base class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CScmRotEntry
    └── CScmRotMgotEntryBase
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Mgot" itsa likely Marshaled Global Object Table. The base class constructor initializes most of the core fields:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;CScmRotMgotEntryBase&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;CScmRotMgotEntryBase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;CScmRotMgotEntryBase&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ulong&lt;/span&gt; &lt;span class="n"&gt;param_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ulong&lt;/span&gt; &lt;span class="n"&gt;param_2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;_MnkEqBuf&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;param_3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;CToken&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;param_4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ushort&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;param_5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tagInterfaceData&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;param_6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;param_7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ulong&lt;/span&gt; &lt;span class="n"&gt;param_8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;undefined8&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mh"&gt;0x08&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;       &lt;span class="c1"&gt;// pNext = NULL&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;undefined4&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mh"&gt;0x10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;       &lt;span class="c1"&gt;// ref count = 1&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tagInterfaceData&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mh"&gt;0x18&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;param_6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ushort&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mh"&gt;0x30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;param_5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c1"&gt;// display name&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mh"&gt;0x40&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;param_7&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;             &lt;span class="c1"&gt;// flags&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_MnkEqBuf&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mh"&gt;0x20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;param_3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// moniker eq buffer&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CToken&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mh"&gt;0x28&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;param_4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c1"&gt;// integrity token&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param_4&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;LOCK&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;param_4&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;         &lt;span class="c1"&gt;// manual AddRef&lt;/span&gt;
        &lt;span class="n"&gt;UNLOCK&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And CScmRotEntry adds its own fields on top:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ulong&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mh"&gt;0x50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x746f7263&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// magic: "crot"&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ulong&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mh"&gt;0x54&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;param_5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_FILETIME&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mh"&gt;0x58&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;param_4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// last change time&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tagInterfaceData&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mh"&gt;0x60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;param_12&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ulong&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mh"&gt;0x68&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;param_7&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="c1"&gt;// ROTFlags&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The complete structure map is being combining both constructors gives us the full layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;CScmRotMgotEntryBase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt;            &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;vtable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;       &lt;span class="c1"&gt;// +0x00&lt;/span&gt;
    &lt;span class="n"&gt;longlong&lt;/span&gt;         &lt;span class="n"&gt;pNext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        &lt;span class="c1"&gt;// +0x08  next in bucket chain&lt;/span&gt;
    &lt;span class="n"&gt;DWORD&lt;/span&gt;            &lt;span class="n"&gt;dwRefCount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// +0x10  starts at 1&lt;/span&gt;
    &lt;span class="n"&gt;tagInterfaceData&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pIFaceData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// +0x18  marshaled interface&lt;/span&gt;
    &lt;span class="n"&gt;_MnkEqBuf&lt;/span&gt;       &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pMnkEqBuf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// +0x20  moniker comparison buffer&lt;/span&gt;
    &lt;span class="n"&gt;CToken&lt;/span&gt;          &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pToken&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;       &lt;span class="c1"&gt;// +0x28  integrity level token&lt;/span&gt;
    &lt;span class="n"&gt;ushort&lt;/span&gt;          &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pwszName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;     &lt;span class="c1"&gt;// +0x30  display name (wide string)&lt;/span&gt;
    &lt;span class="n"&gt;longlong&lt;/span&gt;         &lt;span class="n"&gt;unk_0x38&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;     &lt;span class="c1"&gt;// +0x38&lt;/span&gt;
    &lt;span class="n"&gt;BYTE&lt;/span&gt;             &lt;span class="n"&gt;bFlags&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;       &lt;span class="c1"&gt;// +0x40  bit 0 = various flags&lt;/span&gt;
    &lt;span class="n"&gt;DWORD&lt;/span&gt;            &lt;span class="n"&gt;dwField_44&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// +0x44&lt;/span&gt;
    &lt;span class="n"&gt;DWORD&lt;/span&gt;            &lt;span class="n"&gt;dwField_48&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// +0x48&lt;/span&gt;
    &lt;span class="n"&gt;DWORD&lt;/span&gt;            &lt;span class="n"&gt;dwField_4c&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// +0x4c&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="c1"&gt;// Derived class&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;CScmRotEntry&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CScmRotMgotEntryBase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;DWORD&lt;/span&gt;            &lt;span class="n"&gt;dwMagic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="c1"&gt;// +0x50  0x746F7263 = "crot"&lt;/span&gt;
    &lt;span class="n"&gt;DWORD&lt;/span&gt;            &lt;span class="n"&gt;dwField_54&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// +0x54&lt;/span&gt;
    &lt;span class="n"&gt;_FILETIME&lt;/span&gt;        &lt;span class="n"&gt;ftLastChange&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// +0x58  registration timestamp&lt;/span&gt;
    &lt;span class="n"&gt;tagInterfaceData&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pIFaceData2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// +0x60  second interface data&lt;/span&gt;
    &lt;span class="n"&gt;DWORD&lt;/span&gt;            &lt;span class="n"&gt;dwROTFlags&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// +0x68  bit 1 = AllowAnyClient&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Three findings worth highlighting&lt;/strong&gt;&lt;br&gt;
The "crot" magic signature at +0x50. Every valid CScmRotEntry in memory carries the ASCII bytes c, r, o, t at this offset. This is almost certainly what CScmRotEntry::IsValid checks. For a memory scanner, this is a gift: you can locate entries by signature without knowing the head of the hash table.&lt;br&gt;
CToken uses manual reference counting. The increment at param_4 + 8 is wrapped in LOCK/UNLOCK - interlocked, not COM AddRef. This means tokens are shared across multiple ROT entries from the same process using a private refcount mechanism entirely separate from COM lifetime management.&lt;br&gt;
pwszName at +0x30 is the display name. This is the wide string you'd normally get from IMoniker::GetDisplayName. Reading it directly means a memory scanner doesn't need to deserialize tagInterfaceData or call any COM API to get human-readable moniker names — the string is right there in the entry.&lt;/p&gt;

&lt;p&gt;The security picture&lt;br&gt;
Walking CScmRot::GetObject surfaces three distinct access control mechanisms operating in sequence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;cRotEntryIsTrusted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plVar11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;RotMgotEntryIsAccessible&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plVar11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...)&lt;/span&gt;
&lt;span class="n"&gt;CToken&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;IsTokenILLower&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plVar11&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;plVar13&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;...)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Trust check, accessibility check, integrity level comparison in that order. When multiple entries match the same moniker, the one with the higher integrity level wins. A sandboxed process cannot shadow a medium-integrity registration. AppContainer entries get discarded entirely for out-of-container clients — we even found the log string in the code:&lt;br&gt;
&lt;code&gt;&lt;br&gt;
"Disregarding ROT entry registered by AppContainer"&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
The ROT has a real access control model. It's just not documented anywhere near as clearly as the public API suggests.&lt;/p&gt;

&lt;p&gt;Code and tooling: github.com/ssteelfactor-oss&lt;/p&gt;

&lt;p&gt;[to be continued...]&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>computerscience</category>
      <category>microsoft</category>
      <category>security</category>
    </item>
    <item>
      <title>KESTREL: AD enumeration that doesn't announce itself</title>
      <dc:creator>Pastukhov Aleksey</dc:creator>
      <pubDate>Tue, 05 May 2026 15:25:37 +0000</pubDate>
      <link>https://forem.com/steelfactor/ad-enumeration-that-doesnt-announce-itself-20oi</link>
      <guid>https://forem.com/steelfactor/ad-enumeration-that-doesnt-announce-itself-20oi</guid>
      <description>&lt;p&gt;The tooling problem is embarrassing&lt;br&gt;
Everyone in AD security uses BloodHound. It's good at what it does, attack paths, delegation chains, ACL edges. No complaints there.&lt;br&gt;
The problem is the how.&lt;br&gt;
SharpHound is a .NET assembly. It floods your network with LDAP traffic patterns that zero legitimate workstations produce. EDR picks it up immediately, not because it's exploiting anything exotic, but because the behavioral signature is basically a neon sign. ADRecon, PowerView, Python alternatives, it's the same story. The runtime is the fingerprint.&lt;br&gt;
Internal red teams and defenders are stuck in a ridiculous spot: you need to enumerate your own domain to find misconfigs before attackers do, but every tool available screams its presence. Unacceptable.&lt;br&gt;
The solution was already there. Since Windows 2000.&lt;br&gt;
Active Directory Service Interfaces, that is it. COM-based LDAP abstraction that Windows itself uses constantly. Group Policy uses it. MMC snap-ins use it. net user /domain uses it.&lt;br&gt;
The traffic it produces is indistinguishable from normal domain activity. Because it is normal domain activity.&lt;br&gt;
That's Kestrel's entire foundation.&lt;br&gt;
It is just native, pure C. No managed runtime. No wrappers.&lt;br&gt;
Direct COM vtable calls. No .NET. No PowerShell. No abstractions between you and the wire:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;cIDirectorySearch&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pSearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;ADsGetObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ldapPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;IID_IDirectorySearch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pSearch&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;ADS_SEARCHPREF_INFO&lt;/span&gt; &lt;span class="n"&gt;prefs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;prefs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;dwSearchPref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ADS_SEARCHPREF_SEARCH_SCOPE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;prefs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;vValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Integer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ADS_SCOPE_SUBTREE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;prefs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;dwSearchPref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ADS_SEARCHPREF_PAGESIZE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;prefs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;vValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Integer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;pSearch&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;lpVtbl&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;SetSearchPreference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pSearch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prefs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;pSearch&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;lpVtbl&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ExecuteSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pSearch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;hSearch&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the wire's perspective: authenticated LDAP bind, paged search requests. What every DC sees from every domain workstation, every minute, every day. You're invisible by default.&lt;br&gt;
v0.1 = just five passive modules&lt;br&gt;
ADWS Endpoint Detection^ raw TCP connect to port 9389 per DC. One SYN. No WCF handshake, no ADWS framing. Just: is this port open, yes or no.&lt;br&gt;
Computer Topology - full computer inventory, SPN decoding through a service-class table. MSSQLSvc → SQL Server, WSMAN → WinRM, TERMSRV → RDP. One LDAP query. Zero packets to target hosts.&lt;br&gt;
Delegation Risks: actually separates the three categories most tools conflate:&lt;/p&gt;

&lt;p&gt;Unconstrained (TRUSTED_FOR_DELEGATION on non-DC objects) - Kerberos ticket arrives with forwarded TGT. Serious.&lt;br&gt;
Constrained (msDS-AllowedToDelegateTo) - exact target SPNs enumerated.&lt;br&gt;
Protocol Transition / S4U2Self (UAC &amp;amp; 0x1000000) -- service gets a ticket for any domain user without their credentials. Different risk profile, reported separately. Most tools miss this distinction entirely.&lt;/p&gt;

&lt;p&gt;LAPS Coverage detects both legacy LAPS (ms-Mcs-AdmPwdExpirationTime) and Windows LAPS 2023+ (msLAPS-EncryptedPasswordHistory). Splits computers into managed/unmanaged with percentage breakdown. You will know exactly how exposed your local admin situation is.&lt;br&gt;
Stale Computers uses lastLogonTimestamp as primary reference. It replicates across DCs, unlike lastLogon which is per-DC only. Both values reported side by side.&lt;br&gt;
Engineering discipline matters&lt;br&gt;
Two things enforced that most open-source Windows tooling just ignores:&lt;br&gt;
SAL 2.0 annotations on every function signature. Not for decoration it's PREfast (/analyze) validates them at compile time. &lt;em&gt;Must_inspect_result&lt;/em&gt; on HRESULT-returning functions, &lt;em&gt;Outptr&lt;/em&gt; vs &lt;em&gt;Out&lt;/em&gt; where semantics differ. Contract violations caught before the code ever runs.&lt;br&gt;
Single rootDSE resolution: defaultNamingContext read once at startup, passed as parameter to all five scan functions. The naive approach binds rootDSE in each module separately. That's five redundant DC round-trips for data that doesn't change mid-scan. Obviously wrong. Fixed.&lt;br&gt;
Roadmap&lt;br&gt;
v0.1 is the foundation. Here's what's coming:&lt;br&gt;
v0.2 == raw SECURITY_DESCRIPTOR parsing via IDirectoryObject::GetObjectAttributes. Extended Rights GUID→name mapping built dynamically from CN=Extended-Rights,CN=Configuration. Full ACL edges on every AD object, no elevated privileges required.&lt;br&gt;
v0.3 == transitive group membership via LDAP_MATCHING_RULE_IN_CHAIN (OID 1.2.840.113556.1.4.1941). One query, full recursive chain. Zero client-side BFS.&lt;br&gt;
v0.4 == in-memory graph from ACL + membership + delegation data. JSON export for visualization.&lt;br&gt;
v0.5 == BFS path finder across the graph. Attack path analysis from any principal to Domain Admins. Shortest privilege escalation route, computed natively.&lt;/p&gt;

&lt;p&gt;What the point is: everything SharpHound does in managed code can be reproduced through interfaces Windows already exposes natively. Quietly. Without a detectable runtime. With full static analysis at build time.&lt;br&gt;
This should have existed years ago.&lt;br&gt;
→ &lt;a href="https://github.com/ssteelfactor-oss/Kestrel" rel="noopener noreferrer"&gt;Kestrel&lt;/a&gt;&lt;br&gt;
Parent project: NetEnum&lt;a href="https://github.com/ssteelfactor-oss/NetEnum" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>windows</category>
      <category>com</category>
      <category>scan</category>
      <category>adsi</category>
    </item>
    <item>
      <title>NetEnum: legitimate API scanning tool</title>
      <dc:creator>Pastukhov Aleksey</dc:creator>
      <pubDate>Sun, 19 Apr 2026 12:47:39 +0000</pubDate>
      <link>https://forem.com/steelfactor/netenum-legitimate-api-scanning-tool-17i8</link>
      <guid>https://forem.com/steelfactor/netenum-legitimate-api-scanning-tool-17i8</guid>
      <description>&lt;p&gt;NetEnum is a compact, purpose-built network and service enumeration tool, written in plain C, focused on one core idea: &lt;strong&gt;collecting intelligence through “legitimate” APIs and standard system interfaces&lt;/strong&gt; rather than noisy, signature-heavy probing. That design choice makes it especially useful in environments where you need &lt;strong&gt;reliable discovery&lt;/strong&gt; while keeping activity &lt;strong&gt;indistinguishable from normal administrative telemetry&lt;/strong&gt;—a practical advantage when EDR, IDS, and other detection layers are tuned to flag aggressive scanners.&lt;/p&gt;

&lt;h2&gt;
  
  
  What NetEnum is (and what it is not)
&lt;/h2&gt;

&lt;p&gt;Unlike classic scanners that spray packets, brute-force banners, or rely on exploit-style fingerprinting, NetEnum is intended to &lt;strong&gt;enumerate using the same mechanisms that real enterprise tooling uses&lt;/strong&gt;: vendor-supported endpoints, OS-provided management interfaces, and other approved channels. In other words, it aims to behave like routine operations—inventory, auditing, compliance checks—rather than “attack-like” reconnaissance.&lt;/p&gt;

&lt;p&gt;This makes NetEnum a good fit for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;internal asset inventory and continuous discovery,&lt;/li&gt;
&lt;li&gt;lab validation of monitoring baselines,&lt;/li&gt;
&lt;li&gt;security assessments where you want realistic operator behavior,&lt;/li&gt;
&lt;li&gt;blue team exercises that measure what can be learned from sanctioned interfaces alone.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why “legitimate API scanning” matters
&lt;/h2&gt;

&lt;p&gt;Modern corporate networks are full of valuable signals exposed through APIs: identity systems, management planes, cloud services, directory services, configuration endpoints, and monitoring stacks. Those systems exist specifically so administrators and automation can query them safely.&lt;/p&gt;

&lt;p&gt;NetEnum’s philosophy is simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Prefer official read paths&lt;/strong&gt; (documented endpoints, authenticated queries, normal tooling behaviors).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimize noisy traffic patterns&lt;/strong&gt; (avoid broad port blasting when high-confidence information is already available via an API).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduce anomalous fingerprints&lt;/strong&gt; (keep requests close to typical management and inventory workflows).&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Lower visibility to EDR / IDS (in the practical sense)
&lt;/h2&gt;

&lt;p&gt;EDR and IDS commonly trigger on patterns associated with classic scanning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;high-rate connection attempts across many ports/hosts,&lt;/li&gt;
&lt;li&gt;unusual protocols or malformed probes,&lt;/li&gt;
&lt;li&gt;repeated banner grabs,&lt;/li&gt;
&lt;li&gt;tool-specific packet signatures.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When enumeration is performed through &lt;strong&gt;standard API calls and normal management interfaces&lt;/strong&gt;, the observable footprint is often closer to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;legitimate admin scripts,&lt;/li&gt;
&lt;li&gt;IT automation,&lt;/li&gt;
&lt;li&gt;health checks and inventory tasks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That doesn’t mean “undetectable”—good monitoring can still catch unusual authentication patterns, abnormal query volumes, or access outside an expected role. But it does mean NetEnum is designed to &lt;strong&gt;avoid the obvious scanner-shaped telemetry&lt;/strong&gt; that many detection stacks prioritize.&lt;/p&gt;

&lt;h2&gt;
  
  
  Built for controlled, responsible use
&lt;/h2&gt;

&lt;p&gt;NetEnum is best used where you have permission and clear scope: your own infrastructure, sanctioned assessments, or test environments. The “legitimate API” approach is powerful precisely because it leverages trusted interfaces—so it should be paired with proper governance, logging, and access control. Used correctly, it becomes a high-signal inventory and visibility tool that complements (rather than replaces) traditional network scanning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;If your goal is to understand an environment with &lt;strong&gt;less noise and fewer detection spikes&lt;/strong&gt;, NetEnum is built around a modern enumeration strategy: &lt;strong&gt;learn as much as possible from the same APIs and management planes that enterprises already rely on&lt;/strong&gt;. That yields actionable discovery while keeping collection closer to normal operational behavior—an advantage in networks where EDR/IDS is sensitive to classic recon patterns.&lt;/p&gt;

&lt;p&gt;If you want, paste your README (or tell me the key features/modules you want highlighted), and I’ll tailor the post to match NetEnum’s exact capabilities and include a short “How it works” section without revealing anything unsafe.&lt;/p&gt;

&lt;p&gt;Link to: &lt;a href="https://github.com/ssteelfactor-oss/NetEnum" rel="noopener noreferrer"&gt;https://github.com/ssteelfactor-oss/NetEnum&lt;/a&gt;&lt;/p&gt;

</description>
      <category>windows</category>
      <category>com</category>
      <category>c</category>
      <category>scanning</category>
    </item>
    <item>
      <title>Part 3: putting it al l together</title>
      <dc:creator>Pastukhov Aleksey</dc:creator>
      <pubDate>Mon, 13 Apr 2026 17:24:59 +0000</pubDate>
      <link>https://forem.com/steelfactor/part-3-putting-it-al-l-together-2k9d</link>
      <guid>https://forem.com/steelfactor/part-3-putting-it-al-l-together-2k9d</guid>
      <description>&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;windows.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;objbase.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;CoInitializeEx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;COINIT_APARTMENTTHREADED&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;IRunningObjectTable&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pROT&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;IEnumMoniker&lt;/span&gt;        &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pEnum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;IBindCtx&lt;/span&gt;            &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pCtx&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;IMoniker&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pMon&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;ULONG&lt;/span&gt;     &lt;span class="n"&gt;fetched&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;GetRunningObjectTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pROT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;pROT&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;lpVtbl&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;EnumRunning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pROT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pEnum&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;CreateBindCtx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pCtx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pEnum&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;lpVtbl&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pEnum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pMon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;fetched&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;S_OK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;LPOLESTR&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SUCCEEDED&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pMon&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;lpVtbl&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;GetDisplayName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pMon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pCtx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;wprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;L"%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;CoTaskMemFree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;pMon&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;lpVtbl&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Release&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pMon&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;pCtx&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;lpVtbl&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Release&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pCtx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;pEnum&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;lpVtbl&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Release&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pEnum&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;pROT&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;lpVtbl&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Release&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pROT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;CoUninitialize&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compile with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight batchfile"&gt;&lt;code&gt;&lt;span class="kd"&gt;cl&lt;/span&gt; &lt;span class="kd"&gt;rot_enum&lt;/span&gt;.c &lt;span class="kd"&gt;ole32&lt;/span&gt;.lib
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What you'll actually see - on my comp the output looks like:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frmdtiweic2psadq2ssec.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frmdtiweic2psadq2ssec.png" alt="Image description: Running Object Table as is"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>windows</category>
      <category>security</category>
      <category>com</category>
      <category>c</category>
    </item>
    <item>
      <title>Part 2: How It Works Under the Hood</title>
      <dc:creator>Pastukhov Aleksey</dc:creator>
      <pubDate>Sun, 12 Apr 2026 12:16:14 +0000</pubDate>
      <link>https://forem.com/steelfactor/part-2-how-it-works-under-the-hood-4a87</link>
      <guid>https://forem.com/steelfactor/part-2-how-it-works-under-the-hood-4a87</guid>
      <description>&lt;p&gt;Before diggin into, it's useful to consider a question that most COM tutorials never address: where does the Running Object Table actually reside?&lt;br&gt;
The ROT isnt a data structure inside the calling process, nor is it a kernel object. &lt;/p&gt;

&lt;p&gt;It exists as a global, session-scoped table inside rpcss.exe, the RPC Subsystem process, and is shared by all processes running in the same Windows session.&lt;br&gt;
When code calls GetRunningObjectTable() func, it does not receive a direct pointer to the table. Instead, it receives a proxy object that implements the IRunningObjectTable interface. Every method invoked on this proxy is marshaled across a local RPC channel (ALPC) to rpcss.exe. The actual mapping of monikers to live objects never leaves that system process.&lt;/p&gt;

&lt;p&gt;As a result, every ROT operation: Register, Revoke, IsRunning, GetObject, etc is an inter-process call. The overhead is insignificant for occasional use, but it must be taken into account when these functions are invoked inside tight loops or performance-critical code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The API chain&lt;/strong&gt;&lt;br&gt;
The full enumeration path will be looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GetRunningObjectTable()
    └── IRunningObjectTable::EnumRunning()
            └── IEnumMoniker::Next()
                    └── IMoniker::GetDisplayName()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 1: Get a handle to the ROT&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;HRESULT&lt;/span&gt; &lt;span class="n"&gt;hr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;IRunningObjectTable&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pROT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;hr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GetRunningObjectTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pROT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Entry point - GetRunningObjectTable(). 1-argument is reserved and must be zero. On success it gives you IRunningObjectTable, proxy to rpcss.exe. Always check SUCCEEDED(hr) before proceeding; if the RPC channel to rpcss is broken, it fails.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Get an enumerator&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;IEnumMoniker&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pEnum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;hr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pROT&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;lpVtbl&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;EnumRunning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pROT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pEnum&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;EnumRunning() returns IEnumMoniker, a standard COM enumerator over the monikers currently registered in the table. &lt;br&gt;
This is a snapshot: entries registered after this call won't appear, entries revoked before you iterate won't be missing from the snapshot either - enumerator captures state at the moment of the call.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Iterate&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;IMoniker&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pMon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;ULONG&lt;/span&gt; &lt;span class="n"&gt;fetched&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pEnum&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;lpVtbl&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pEnum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pMon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;fetched&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;S_OK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// process pMon&lt;/span&gt;
    &lt;span class="n"&gt;pMon&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;lpVtbl&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Release&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pMon&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next() func follows the standard COM enumerator contract: request items, get back how many were actually returned. &lt;br&gt;
Ask for one at a time it's simpler error handlingn. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Decode the moniker&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;IBindCtx&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pCtx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;CreateBindCtx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pCtx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;LPOLESTR&lt;/span&gt; &lt;span class="n"&gt;displayName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;pMon&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;lpVtbl&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;GetDisplayName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pMon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pCtx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;wprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;L"%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;CoTaskMemFree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GetDisplayName() requires a bind context. IBindCtx- even though we're only reading a name, not actually binding. The bind context carries parameters that affect how monikers resolve; for display purposes we pass a default one via CreateBindCtx(0, ...).&lt;br&gt;
Don't forget to free memory with callong CoTaskMemFree().&lt;/p&gt;

&lt;p&gt;To be continued&lt;/p&gt;

</description>
      <category>windows</category>
      <category>com</category>
      <category>security</category>
      <category>c</category>
    </item>
    <item>
      <title>Inside the Running Object Table: COM's Hidden Registry of Live Objects</title>
      <dc:creator>Pastukhov Aleksey</dc:creator>
      <pubDate>Sun, 12 Apr 2026 11:20:02 +0000</pubDate>
      <link>https://forem.com/steelfactor/inside-the-running-object-table-coms-hidden-registry-of-live-objects-3k64</link>
      <guid>https://forem.com/steelfactor/inside-the-running-object-table-coms-hidden-registry-of-live-objects-3k64</guid>
      <description>&lt;p&gt;&lt;strong&gt;Inside the Running Object Table: COM's Hidden Registry of Live Objects&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Introduction: Running Object Table, part I *&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;"...almost no developer ever looks at directly", by me.&lt;/p&gt;

&lt;p&gt;COM is a technology that many developers believe they understand until they encounter its less-documented internals. Most are familiar with the core concepts — interfaces, CoCreateInstance, and reference counting — yet the Component Object Model contains considerably more supporting infrastructure than its public API reveals. One of the least examined parts of this infrastructure is the Running Object Table, commonly abbreviated as ROT.&lt;/p&gt;

&lt;p&gt;The ROT is a system-wide registry that holds references to live COM objects. It does not store class information or factory objects; it contains only instantiated objects that have been explicitly registered as running and available for external access. In essence, it serves as the mechanism by which a COM server can declare that a particular object is active and can be located by name. A client that needs to connect to an already-running instance checks the ROT before creating a new object.&lt;/p&gt;

&lt;p&gt;This component plays a more important role than is commonly recognized. The ROT is the underlying mechanism used by GetObject() in VBScript, it enables Visual Studio to expose its automation model to external scripts, and it supports certain inter-process communication patterns in Windows without the need for explicit sockets or named pipes. At the same time, the ROT is an area that is frequently misunderstood and can be misused.&lt;br&gt;
Currently registered on a live Windows system, decoding of the monikers they expose, and analysis of what these findings indicate about the runtime behavior of COM.&lt;br&gt;
In C, without ATL, without MFC, without training wheels. Just enumerate what's actually registered on a live Windows system, decode the monikers i find, and talk about what the results reveal about COM's runtime model.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwryt1s0vlimxjimonn6k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwryt1s0vlimxjimonn6k.png" alt=" " width="659" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/steelfactor/part-2-how-it-works-under-the-hood-4a87"&gt;To be continued&lt;/a&gt;&lt;/p&gt;

</description>
      <category>windows</category>
      <category>com</category>
      <category>security</category>
      <category>c</category>
    </item>
  </channel>
</rss>
