Dissecting DCOM partie 1
Ceci est le premier article de la série "Dissecting DCOM". Cet article a pour objectif de fournir une introduction aux principes de base des protocoles COM et DCOM, ainsi qu'une analyse détaillée des échanges réseau du protocole DCOM.
Aucune connaissance préalable n'est requise. Les articles suivants se pencheront sur les mécanismes d'autorisation et d'énumération sur COM/DCOM. Cette série d'articles vise à regrouper les connaissances publiques sur DCOM afin de fournir les outils nécessaires à la recherche de vulnérabilités sur DCOM.
Vous souhaitez améliorer vos compétences ? Découvrez nos sessions de formation ! En savoir plus
Introduction
COM et DCOM sont des concepts qui apparaissent dans divers contextes, allant des techniques d'élévation de privilèges sous Windows aux protocoles industriels comme OPC. Bien qu'elle soit fondamentale pour Windows, COM reste une technologie obscure et énigmatique pour beaucoup. Profondément implantée dans Windows et intégrée de manière transparente au système, elle intervient régulièrement dans des actions communes.
Lorsque j'ai entrepris cette recherche, ma connaissance de COM et DCOM était assez minimale. Bien que Microsoft fournisse de la documentation, des détails cruciaux - tels que le fonctionnement interne de l'activation des objets - restaient obscurs ou incomplets.
Cet article vise à fournir des bases solides sur COM et DCOM avant d'explorer les subtilités du processus d'activation. Notre objectif est de démystifier les mécanismes qui permettent les appels de méthodes sur des machines distantes.
Mais avant cela, prenons un peu de recul historique pour comprendre comment cette technologie a évolué.
Les origines de DCOM
COM et DCOM trouvent leurs origines dans les premières versions de Windows, émergeant parallèlement à la fonctionnalité de fenêtres redimensionnables de Windows 2.0.
L'une des premières applications de communication inter-processus sous Windows fut le presse-papier inter-processus, une fonctionnalité fondamentale mais efficace permettant aux processus d'interagir du point de vue de l'expérience utilisateur. Introduit en 1987, Dynamic Data Exchange (DDE) facilitait ce processus, mais fut en partie remplacé par Object Linking and Embedding (OLE) 1.0 en 1990. Remarquablement, OLE existe encore des décennies plus tard.
Avec l'évolution des besoins logiciels, des mécanismes plus flexibles sont devenus nécessaires pour prendre en charge des fonctionnalités complexes, comme l'intégration d'un tableur Excel dans un document Word tout en conservant sa capacité d'édition.

Le besoin de composants réutilisables et faiblement couplés a conduit à l'adoption du modèle de développement basé sur les composants (Component-Based Development ou CBD en anglais), un concept souvent associé à l'ingénierie logicielle moderne, mais qui trouve son origine avec COM.
COM (Component Object Model) a introduit une architecture flexible permettant aux développeurs d'interagir avec des objets uniquement via leurs interfaces, ajoutant une couche d'abstraction aux complexités d'implémentation. Cette approche a servi de base à de nombreuses technologies construites sur COM, notamment OLE 2.0, ActiveX, DirectX, Windows Shell, Browser Helper Objects, COM+, et, finalement, DCOM.
Une caractéristique clé de COM est le concept de location transparency - la capacité d'interagir avec un objet sans connaître son emplacement physique. Que l'objet se trouve dans le même thread, le même processus ou sur une machine distante, l'utilisateur peut interagir avec lui en utilisant uniquement l'interface fournie.
Avec la version bêta de Windows 95, qui a introduit la prise en charge native du TCP/IP, Internet Explorer et l'adoption massive du World Wide Web, le besoin de composants logiciels distribués s'est accru. Les principes fondamentaux de COM ont donc été étendus, donnant naissance à Distributed COM (DCOM), permettant la communication entre composants logiciels à travers le réseau.
Cependant, la communication distribuée a introduit des défis supplémentaires que DCOM devait résoudre :
- Marshalling – La sérialisation et la désérialisation des paramètres des méthodes et valeurs de retour.
- Garbage Collection – La gestion des références d'objets, garantissant leur nettoyage lorsqu'ils ne sont plus nécessaires ou en cas d'erreurs.
Gardez ces concepts à l'esprit, car ils seront explorés plus en détail par la suite.
Par la suite, plusieurs protocoles ont été construits sur DCOM, notamment :
- Windows Client Certificate Enrollment Protocol (MS-WCCE)
- Component Object Model Plus (COM+) Protocol (MS-COM)
- Disk Management Remote Protocol (MS-DMRP)
- Virtual Disk Service (VDS) Protocol (MS-VDS)
- Windows Management Instrumentation Remote Protocol (MS-WMI)
- Open Platform Communications (OPC, anciennement OLE for Process Control)
Le dernier élément de la liste, OPC, est encore largement utilisé dans les technologies industrielles, ce qui explique pourquoi une grande partie du contenu relatif à DCOM traite de ce sujet.
En résumé, DCOM est essentiellement COM sur le réseau.
Quelques définitions
Avant d'aller plus loin, définissons quelques identifiants clés souvent rencontrés avec COM et DCOM :
- CLSID (Class Identifier) : Un identifiant global unique (GUID) qui identifie de manière unique une classe COM.
- ex : 49B2791A-B1AE-4C90-9B8E-E860BA07F889
- ProgID (Programmatic Identifier) : Un nom pour la classe COM.
- ex : MMC20.Application
- AppID (Application Identifier) : Un identifiant regroupant plusieurs classes COM liées.
- ex : 49B2791A-B1AE-4C90-9B8E-E860BA07F889

Énumération
Registre
Étant donné que les objets COM sont stockés dans le Registre Windows, ils peuvent être facilement énumérés à l'aide de la commande suivante :
PS C:\Users\user> reg query "HKCR\CLSID\"
HKEY_CLASSES_ROOT\CLSID\CLSID
HKEY_CLASSES_ROOT\CLSID\{0000002F-0000-0000-C000-000000000046}
HKEY_CLASSES_ROOT\CLSID\{00000300-0000-0000-C000-000000000046}
HKEY_CLASSES_ROOT\CLSID\{00000301-A8F2-4877-BA0A-FD2B6645FB94}
HKEY_CLASSES_ROOT\CLSID\{00000303-0000-0000-C000-000000000046}
[...]
Ensuite, pour chaque CLSID, plusieurs clés et valeurs sont nécessaires au système pour instancier la classe. Deux clés en particulier indiquent où la classe est implémentée :
- LocalServer32 : La classe est implémentée dans un fichier exécutable.
- InProcServer32 : La classe est implémentée dans une bibliothèque dynamique (DLL).
De la même manière que les CLSIDs, les ProgIDs et AppIDs peuvent être listés en utilisant les commandes suivantes :
PS C:\Users\user> reg query "HKLM\SOFTWARE\Classes\"
[...]
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AADJ
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AADJCSP
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AboveLockAppLaunchCallback
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AccClientDocMgr.AccClientDocMgr
[...]
PS C:\Users\user> reg query "HKCR\AppID\"
[...]
HKEY_CLASSES_ROOT\AppID\{00021401-0000-0000-C000-000000000046}
HKEY_CLASSES_ROOT\AppID\{000C101C-0000-0000-C000-000000000046}
HKEY_CLASSES_ROOT\AppID\{0010890e-8789-413c-adbc-48f5b511b3af}
[...]
Heureusement, James Forshaw a développé un outil très pratique pour énumérer toutes sortes d'informations sur COM : OleView.NET.
OleView.net

Cet outil permet de lister les CLSIDs, ProgIDs, interfaces, permissions, bibliothèques de types, etc. En plus des fonctionnalités d'énumération, il permet également d'instancier des classes et d'effectuer des actions avancées.
OleView.NET est fourni avec un module PowerShell, installable via :
Install-Module OleViewDotNet
Instantiation
Maintenant que nous savons comment énumérer les classes COM, nous pouvons les instancier.
PowerShell permet d'exécuter du code .NET directement en utilisant différents types d'identifiants :
- CLSID
$object = [System.Activator]::CreateInstance([type]::GetTypeFromCLSID("49B2791A-B1AE-4C90-9B8E-E860BA07F889"))
- ProgID
$object = new-object -comobject Shell.Application
$object = [System.Activator]::CreateInstance([type]::GetTypeFromProgID("Shell.Application"))
Les méthodes et attributs peuvent être appelés directement depuis la variable $object :
$object.Document.ActiveView.ExecuteShellCommand("cmd",$null,"/c calc.exe","7")
Les classes peuvent également être instanciées à distance en spécifiant une adresse IP comme second paramètre :
$object = [System.Activator]::CreateInstance([type]::GetTypeFromProgID("Shell.Application","192.168.0.2"))
Nous avons vu de multiples méthodes pour instancier des classes en utilisant PowerShell. Cependant, il existe d'autres exécutables permettant de réaliser des actions similaires comme rundll32 :
rundll32.exe C:\Windows\System32\shell32.dll,SHCreateLocalServerRunDll {9aa46009-3ce0-458a-a354-715610a075e6}
rundll32.exe -sta {9aa46009-3ce0-458a-a354-715610a075e6}
Ensuite, les tâches planifiées offrent également une méthode de persistance intéressante. Ci-dessous un exemple de tâche planifiée au format XML instanciant une classe :
<Actions Context="LocalSystem">
<ComHandler>
<ClassId>{E4544ABA-62BF-4C54-AAB2-EC246342626C}</ClassId>
</ComHandler>
</Actions>
Un utilisateur standard peut enregistrer un nouveau CLSID dans la ruche HKCU, le faire pointer vers un exécutable arbitraire, puis instancier cette classe via une tâche planifiée ultérieurement.
En utilisant l'API Windows, les fonctions les plus courantes pour créer un objet sont :
- CoCreateInstance : crée un unique objet sur le poste local
HRESULT CoCreateInstance(
[in] REFCLSID rclsid,
[in] LPUNKNOWN pUnkOuter,
[in] DWORD dwClsContext,
[in] REFIID riid,
[out] LPVOID *ppv
);
- CoCreateInstanceEx : crée un objet à distance
HRESULT CoCreateInstanceEx(
[in] REFCLSID Clsid,
[in] IUnknown *punkOuter,
[in] DWORD dwClsCtx,
[in] COSERVERINFO *pServerInfo,
[in] DWORD dwCount,
[in, out] MULTI_QI *pResults
);
- CoGetClassObject : crée un objet Class Factory (sauf quelques exceptions) pouvant être utilisé pour instancier plusieurs objets
HRESULT CoGetClassObject(
[in] REFCLSID rclsid,
[in] DWORD dwClsContext,
[in, optional] LPVOID pvReserved,
[in] REFIID riid,
[out] LPVOID *ppv
);
Enfin, il est possible d'instancier des classes dans l'explorateur Windows en utilisant la syntaxe suivante :
explorer "shell:::{D4480A50-BA28-11d1-8E75-00C04FA31A86}"
Cette astuce peut aider à contourner AppLocker dans certains cas. La liste complète des raccourcis de l'explorateur peut être trouvée ici.
En interne, cette classe est instanciée en utilisant la commande suivante rundll32 C:\Windows\System32\shwebsvc.dll,AddNetPlaceRunDll
. D'autres classes similaires pourraient être intéressantes à examiner.
Interfaces
Selon les principes de l'ingénierie logicielle basée sur les composants, les classes COM exposent des interfaces, qui sont un ensemble de fonctions utilisées pour communiquer avec le client. Une classe COM peut exposer plusieurs interfaces, chacune étant identifiée par un IID (Interface Identifier), qui est un GUID unique.
Parmi toutes les interfaces disponibles, l'une d'entre elles est particulière : IUnknown. En effet, chaque classe COM doit implémenter l'interface IUnknown, et chaque interface doit en hériter.
L'interface IUnknown expose la méthode QueryInterface(), qui prend un IID en entrée et retourne un pointeur d'interface après avoir appelé la méthode AddRef (une autre méthode de l'interface IUnknown permettant de gérer le décompte des références à l'objet).
HRESULT QueryInterface(
REFIID riid,
void **ppvObject
);
Les interfaces sont décrites en utilisant le format IDL (Interface Definition Language) :
[object, uuid(673B0E01-4987-11d2-85C0-08001700C57F)]
interface ITest : IUnknown
{
ULONG Test1();
ULONG Test2();
}
Ainsi, pour chaque interface, les informations suivantes sont déclarées :
-
Le nom de l'interface, ex : ITest
-
Le nom de l'interface parente, ex : IUnknown
-
Pour chaque méthode, le prototype de la méthode, ex : Test1()
Le fichier IDL est ensuite utilisé pour générer une bibliothèque de types (Type Library, TLB en anglais) et d'autres fichiers de sortie à l'aide du compilateur MIDL. Le fichier TLB stocke des informations telles que les propriétés et les méthodes d'une classe COM ou DCOM sous un format binaire. Ce fichier est analysé à l'exécution par d'autres applications afin de déterminer les interfaces et les méthodes d'interface pouvant être appelées sur un objet. De cette manière, des clients et des serveurs écrits dans différents langages peuvent communiquer en analysant une bibliothèque de types d'objet. Nous verrons également que ce fichier peut être très utile pour rechercher des méthodes intéressantes.
Tous les fichiers TLB sont référencés dans le registre sous la clé suivante (exemple pour le CLSID 91e132a0-0df1-11d2-86cc-444553540000) : HKEY_CLASSES_ROOT\CLSID\{91e132a0-0df1-11d2-86cc-444553540000}\TypeLib.
Component types
Nous avons vu un peu plus tôt que les classes peuvent être implémentées de deux manières différentes :
- InProcServer32 : La classe est implémentée dans une bibliothèque dynamique (DLL, In-process)
- LocalServer32 : La classe est implémentée dans un fichier exécutable (Exe, Out-of-process)
In-process
Comme nous pouvons le deviner, les composants In-process s'exécutent à l'intérieur du processus qui a instancié l'objet. Dans la plupart des cas, ils sont définis dans des fichiers DLL (sauf s'ils sont instanciés depuis un ordinateur distant, voir DLL Surrogates pour plus de détails).
On peut identifier les DLL implémentant des objets COM grâce à la fonction exportée DllGetClassObject(), qui prend un CLSID en paramètre et retourne une Class Factory :
HRESULT DllGetClassObject(
[in] REFCLSID rclsid,
[in] REFIID riid,
[out] LPVOID *ppv
);
Les Class Factory permettent la création d'une instance d'un objet via la méthode IClassFactory::CreateInstance() :
HRESULT CreateInstance(
[in] IUnknown *pUnkOuter,
[in] REFIID riid,
[out] void **ppvObject
);
Enfin, on peut appeler des méthodes sur l'objet instancié.
Pour résumer ces étapes :
-
Appel de la fonction exportée DllGetClassObject(CLSID) depuis la DLL référencée dans le registre.
-
Obtention d'une Class Factory.
-
Appel de la méthode IClassFactory::CreateInstance(IID) sur la Class Factory en spécifiant l'IID de l'interface souhaitée.
-
Appel de la méthode finale sur l'interface de l'objet instancié.

Out-of-process
Les composants Out-of-process diffèrent dans la plupart des aspects. Tout d'abord, ils s'exécutent dans un processus différent sur votre ordinateur (ou un ordinateur distant via DCOM). Ils sont implémentés dans des fichiers exécutables (.exe).
Selon l'emplacement du serveur (local ou distant), les protocoles et les interfaces impliquées peuvent changer, mais le processus global reste similaire. En pratique, le protocole ALPC (un protocole utilisé pour les communications RPC locales) est remplacé par DCE-RPC, les interfaces et les méthodes sont également similaires (ISystemActivator et IRemoteSCMActivator).
Le processus d'activation de ce type de composant implique un nouveau composant : l'activateur DCOM, qui fait partie de RPCSS. Ainsi, RPCSS expose deux interfaces RPC :
- IActivation : Interface d'activation héritée.
- IRemoteSCMActivator (également connu sous le nom de ISystemActivator) : Interface d'activation pour les versions COM supérieures à 5.6.
Nous nous concentrerons ici sur l'activation à distance, car le processus d'activation local a déjà été expliqué en détail par James Forshaw dans cette excellente présentation.
Bien que l'activation d'objets localement et à distance soit conceptuellement similaire, différents mécanismes sont impliqués dans ce processus.
IOXIDResolver
La toute première étape de l'activation d'un objet consiste à contacter le résolveur d'objets pour obtenir les informations de liaison du serveur. Cela se fait en appelant la méthode ServerAlive2() de l'interface RPC native IOXIDResolver :

Cette méthode retourne les informations de liaison utilisées pour contacter le résolveur d'objets :

Comme vous pouvez le voir, le nom d'hôte de la machine ainsi que l'adresse IP de chaque interface réseau sont inclus dans la réponse. Ce comportement a été identifié pour la première fois par l'équipe d'Airbus Cybersecurity et décrit dans leur article de blog. Cela peut être très utile lors de la recherche de machines relais pour accéder à des sous-réseaux restreints, par exemple.
IActivation
Cette interface RPC native expose une seule méthode utilisée pour l'activation des objets : RemoteActivation. Cette interface est utilisée pour les versions plus anciennes de DCOM, mais elle est toujours présente.
Il est possible d'identifier cette interface sur le processus RPCSS.exe dans RPCView:

Cette méthode a pour prototype assez effrayant :
error_status_t RemoteActivation(
[in] handle_t hRpc,
[in] ORPCTHIS* ORPCthis,
[out] ORPCTHAT* ORPCthat,
[in] GUID* Clsid,
[in, string, unique] wchar_t* pwszObjectName,
[in, unique] MInterfacePointer* pObjectStorage,
[in] DWORD ClientImpLevel,
[in] DWORD Mode,
[in, range(1, MAX_REQUESTED_INTERFACES)]
DWORD Interfaces,
[in, unique, size_is(Interfaces)]
IID* pIIDs,
[in, range(0, MAX_REQUESTED_PROTSEQS)]
unsigned short cRequestedProtseqs,
[in, size_is(cRequestedProtseqs)]
unsigned short aRequestedProtseqs[],
[out] OXID* pOxid,
[out] DUALSTRINGARRAY** ppdsaOxidBindings,
[out] IPID* pipidRemUnknown,
[out] DWORD* pAuthnHint,
[out] COMVERSION* pServerVersion,
[out] HRESULT* phr,
[out, size_is(Interfaces), disable_consistency_check]
MInterfacePointer** ppInterfaceData,
[out, size_is(Interfaces), disable_consistency_check]
HRESULT* pResults
);
Ne fuyez pas, nous allons détailler chacun de ces paramètres :
- Clsid : L'identifiant de la classe que nous avons vu précédemment.
- pIIDs : Les identifiants d'interface demandés sur l'objet à créer.
- pOxid : L'OXID, un identifiant pour l'exportateur d'objet contenant cet objet (nous examinerons plus en détail ce composant plus tard).
- pObjectStorage : Peut contenir un OBJREF marshallisé (un peu plus de détails ci-dessous).
Les paramètres ORPCthis et ORPCthat sont des structures ajoutées par le protocole DCOM pour transporter des paramètres supplémentaires comme la gestion des versions (nous avons vu plus tôt que DCOM prend en charge différentes versions), des informations de causalité ou des données spécifiques à l'application.
L'OBJREF est une structure contenant un objet COM marshallisé envoyé au client, et utilisé pour créer un objet proxy qui sert de substitut à l'objet distant, permettant d'appeler des méthodes sur le réseau.
Le contenu et l'organisation de la structure dépendent du type d'OBJREF utilisé. Il existe quatre types d'OBJREF :
- OBJREF_STANDARD : Marshalling par référence.
- OBJREF_HANDLER
- OBJREF_CUSTOM : Marshalling par valeur.
- OBJREF_EXTENDED
La structure OBJREF dépend ensuite du type d'OBJREF défini dans les indicateurs de l'en-tête :
- OBJREF_STANDARD spécifie une référence à l'objet avec lequel vous souhaitez interagir dans le champ IPID (pointant vers le serveur hébergeant l'objet).
- OBJREF_CUSTOM intègre l'objet COM sous une forme marshallisée avec le CLSID de la classe utilisée pour ensuite unmarshaller les données sur le client.

Nous verrons par la suite comment cet OBJREF est utilisé pour interagir avec l'objet final dans les deux cas.
Bien que l'interface IActivation existe, et que le processus soit similaire, l'interface IRemoteSCMActivator est privilégiée pour les versions plus récentes de DCOM.
ISystemActivator (ou IRemoteSCMActivator)
Contrairement à l'interface IActivation, IRemoteSCMActivator divise le processus d'activation en deux fonctions :
- RemoteGetClassObject : utilisée par le client pour créer un OBJREF pour l'objet de fabrique de classe
HRESULT RemoteGetClassObject(
[in] handle_t rpc,
[in] ORPCTHIS* orpcthis,
[out] ORPCTHAT* orpcthat,
[in, unique] MInterfacePointer* pActProperties,
[out] MInterfacePointer** ppActProperties
);
- RemoteCreateInstance : utilisée par le client pour créer un OBJREF pour l'objet réel
HRESULT RemoteCreateInstance(
[in] handle_t rpc,
[in] ORPCTHIS* orpcthis,
[out] ORPCTHAT* orpcthat,
[in, unique] MInterfacePointer* pUnkOuter,
[in, unique] MInterfacePointer* pActProperties,
[out] MInterfacePointer** ppActProperties
);
Les deux fonctions prennent des propriétés d'activation en entrée et renvoient des informations pour se connecter à l'objet.
La structure des propriétés d'activation est divisée en un en-tête et des propriétés d'activation. L'en-tête contient diverses informations liées aux classes que vous souhaitez instancier, telles que les CLSID.
La structure des propriétés est la suivante :
struct InstantiationInfoData {
CLSID classId; #CLSID to create
DWORD classCtx;
DWORD actvflags; #Activation flags
long fIsSurrogate;
DWORD cIID;
DWORD instFlag;
IID *pIID; #List of interface IDs to query for
DWORD thisSize;
COMVERSION clientCOMVersion;
}
Par exemple, lors de l'instanciation à distance de la classe MMC20.Application avec RemoteGetClassObject(), la structure suivante InstantiationInfoData contenant le CLSID et l'IID de la fabrique de classe est envoyée au serveur :

Le serveur renvoie alors une réponse contenant un OBJREF_CUSTOM avec l'IID 000001a3-0000-0000-c000-000000000046, correspondant à IID_IActivationPropertiesOut, une structure spécifique contenant des informations sur l'activation de l'interface demandée.
Que se passe-t-il si je souhaite un OBJREF standard ? Eh bien, la réponse se trouve dans les profondeurs de cette structure.
La structure de la réponse est divisée en deux parties, le CustomHeader et les Properties, elles-mêmes divisées en deux parties :
- ScmReplyInfo : Une structure fournissant les informations nécessaires pour contacter l'exportateur d'objets distant (IRemUnknown2)
Remarque : À partir de ce moment, un canal RPC est établi entre le client et le résolveur d'objets sur un port RPC dynamique (ici 62076/TCP) envoyé par le serveur dans les String Bindings contenues dans la structure ScmReplyInfo.

- PropertiesOutput : Une structure contenant des pointeurs vers les interfaces demandées par le client que l'objet implémente, ainsi qu'un OBJREF (standard ou custom).
struct PropsOutInfo {
DWORD cIfs;
IID* piid;
HRESULT* phresults;
MInterfacePointer** ppIntfData;
}

Les étapes suivantes sont assez similaires à l'activation In-process. En effet, nous devons contacter le résolveur d'objets sur l'hôte distant afin d'accéder à l'objet ClassFactory. L'IPID de l'interface IRemUnknown2 (l'exportateur d'objets) est la seule information nécessaire pour la contacter.
L'interface IRemUnknown2 est analogue à l'interface IUnknown en local, elle possède également la méthode équivalente à QueryInterface() :
HRESULT RemQueryInterface2(
[in] REFIPID ripid,
[in] unsigned short cIids,
[in, size_is(cIids)] IID* iids,
[out, size_is(cIids)] HRESULT* phr,
[out, size_is(cIids)] PMInterfacePointerInternal* ppMIF
);
Comme vous l'avez peut-être déjà deviné, cette méthode prend en entrée l'IPID de l'interface avec laquelle vous souhaitez communiquer (ici IClassFactory que nous avons obtenue à partir de la structure PropertiesOut). Dans cet exemple, nous avons une fabrique de classe. Cependant, si votre classe n'implémente pas une interface de Class Factory, l'objet est alors contacté directement.

L'interface IClassFactory est ensuite interrogée via DCE-RPC directement pour créer l'instance de l'objet avec la méthode CreateInstance() :
HRESULT CreateInstance(
[in] IUnknown *pUnkOuter,
[in] REFIID riid,
[out] void **ppvObject
);
À ce stade de la recherche, je cherchais un OBJREF simple dans Wireshark, puis j'ai entendu l'OBJREF miauler à mon oreille :

Cette chaîne de caractère "MEOW" est la signature de l'OBJREF et en enregistrant ces données binaires dans un fichier, en supprimant le début et en les analysant avec OLEView.NET (Object > Hex Editor > From File), nous pouvons constater qu'il s'agit d'un OBJREF pour l'interface IUnknown :

Nous sommes maintenant prêts à appeler l'interface IUnknown de l'objet final afin d'interroger d'autres interfaces.
Conclusion
Dans cet article, nous avons exploré les différents types de composants impliqués dans COM/DCOM (Classes, Interfaces) et leurs identifiants (ProgIDs, CLSIDs, AppIDs, IIDs). Nous avons également discuté de la façon de les énumérer à l'aide d'outils natifs (PowerShell, Registre Windows) ou d'outils externes tels que OleView.NET.
Ensuite, nous avons décrit les différentes manières d'instancier une classe.
La prochaine fois, nous essaierons de comprendre la mécanique derrière l'appel de méthodes ou l'énumération d'objets ainsi que le mécanisme de permissions.