Developing WinDbg ExtEngCpp Extension in C++ – COM Interface – Part 2

In my previous post, we started to get familiar with ExtEngCpp types and functions. Now we gonna see how to use more “low-level” functions part of the COM interface.

As we can see below, there is a total of 27 interfaces as part of the base class ExtExtension accessible by g_Ext.

  1.     ExtCheckedPointer IDebugAdvanced m_Advanced;
  2.     ExtCheckedPointer<idebugclient m_Client;
  3.     ExtCheckedPointer<IDebugControl m_Control;
  4.     ExtCheckedPointer<IDebugDataSpaces m_Data;
  5.     ExtCheckedPointer<IDebugRegisters m_Registers;
  6.     ExtCheckedPointer<IDebugSymbols m_Symbols;
  7.     ExtCheckedPointer<IDebugSystemObjects m_System;
  8.  
  9.     // These derived interfaces may be NULL on
  10.     // older engines which do not support them.
  11.     // The checked pointers will automatically
  12.     // protect access.
  13.     ExtCheckedPointer<IDebugAdvanced2 m_Advanced2;
  14.     ExtCheckedPointer<IDebugAdvanced3 m_Advanced3;
  15.     ExtCheckedPointer<IDebugClient2 m_Client2;
  16.     ExtCheckedPointer<IDebugClient3 m_Client3;
  17.     ExtCheckedPointer<IDebugClient4 m_Client4;
  18.     ExtCheckedPointer<IDebugClient5 m_Client5;
  19.     ExtCheckedPointer<IDebugControl2 m_Control2;
  20.     ExtCheckedPointer<IDebugControl3 m_Control3;
  21.     ExtCheckedPointer<IDebugControl4 m_Control4;
  22.     ExtCheckedPointer<IDebugControl5 m_Control5;
  23.     ExtCheckedPointer<IDebugControl6 m_Control6;
  24.     ExtCheckedPointer<IDebugDataSpaces2 m_Data2;
  25.     ExtCheckedPointer<IDebugDataSpaces3 m_Data3;
  26.     ExtCheckedPointer<IDebugDataSpaces4 m_Data4;
  27.     ExtCheckedPointer<IDebugRegisters2 m_Registers2;
  28.     ExtCheckedPointer<IDebugSymbols2 m_Symbols2;
  29.     ExtCheckedPointer<IDebugSymbols3 m_Symbols3;
  30.     ExtCheckedPointer<IDebugSystemObjects2 m_System2;
  31.     ExtCheckedPointer<IDebugSystemObjects3 m_System3;
  32.     ExtCheckedPointer<IDebugSystemObjects4 m_System4;

In the previous article we created a function to read UNICODE_STRING because none of the data types had a function to process it, but if we look closely at the COM Interface there are functions able to read Unicode String (But not the structure itself like in our previous post) such as IDebugDataSpaces4::ReadUnicodeStringVirtual and IDebugDataSpaces4::ReadUnicodeStringVirtualWide.

  1.    g_Ext->m_Data4->ReadUnicodeStringVirtualWide(Object.Field("SeAuditProcessCreationInfo.ImageFileName").Field("Name").Field("Buffer").GetPtr(),
  2.                                                  sizeof(OutProcessObject->FullPath),
  3.                                                  (PWSTR)&OutProcessObject->FullPath,
  4.                                                  sizeof(OutProcessObject->FullPath) / sizeof(OutProcessObject->FullPath[0]),
  5.                                                  NULL);

Also a really important functionality when you are dealing with different address spaces, is to be able to change of context since each process as its own address space. There are different methods to do so using the IDebugSystemObjects and IDebugSystemObjects2 interfaces.

The first way is using IDebugSystemObjects::GetCurrentProcessId and IDebugSystemObjects::SetCurrentProcessId

  1. ULONG PreviousProcessId;
  2. //
  3. // Save the process id before changing the current context.
  4. //
  5. g_Ext->m_System->GetCurrentProcessId(&PreviousProcessId);
  6. g_Ext->m_System->SetCurrentProcessId((ULONG)NewProcessId);
  7.  
  8. //
  9. // […]
  10. //
  11.  
  12. //
  13. // Restore the previous process context
  14. //
  15.  g_Ext->m_System->SetCurrentProcessId(PreviousProcessId);
  16.  

The second approach, which is the one I prefer is by using the _EPROCESS pointer along with IDebugSystemObjects2::GetImplicitProcessDataOffset and IDebugSystemObjects2::SetImplicitProcessDataOffset.

  1. BOOLEAN
  2. PsParseHeader(
  3.     IN ExtRemoteTyped Object,
  4.     IN OUT PCACHED_PROCESS_OBJECT OutProcessObject
  5.     )
  6. {
  7.     ULONG64 ProcessDataOffset = 0ULL;
  8.     ExtRemoteTyped BaseImage;
  9.  
  10.     BOOLEAN Ret = FALSE;
  11.  
  12.     //
  13.     // Save, and change the current process.
  14.     //
  15.     if (g_Ext->m_System2->GetImplicitProcessDataOffset(&ProcessDataOffset) != S_OK) goto CleanUp;
  16.     if (g_Ext->m_System2->SetImplicitProcessDataOffset(OutProcessObject->ProcessObjectPtr) != S_OK) goto CleanUp;
  17.  
  18.     BaseImage = ExtRemoteTyped("(nt!_IMAGE_DOS_HEADER *)@$extin", OutProcessObject->ImageBase);
  19.  
  20.     BaseImage.OutFullValue(); // Dump the full node. Just like "dt"
  21.  
  22.     if (BaseImage.Field("e_magic").GetUshort() != IMAGE_DOS_SIGNATURE) goto CleanUp;
  23.  
  24.     Ret = TRUE;
  25.  
  26. CleanUp:
  27.     //
  28.     // Restore process context
  29.     //
  30.     if (ProcessDataOffset) g_Ext->m_System2->SetImplicitProcessDataOffset(ProcessDataOffset);
  31.  
  32.     return Ret;
  33. }

In the next part, we will cover more about memory functions and how to use the Debugger Markup Language (DML) efficiently.

Related articles:

Developing WinDbg ExtEngCpp Extension in C++ – Introduction – Part 1
Developing WinDbg ExtEngCpp Extension in C++ – COM Interface – Part 2
Developing WinDbg ExtEngCpp Extension in C++ – Memory & Debugger Markup Language (DML) – Part 3
Developing WinDbg ExtEngCpp Extension in C++ – Symbols – Part 4

2 thoughts on “Developing WinDbg ExtEngCpp Extension in C++ – COM Interface – Part 2

Comments are closed.