获取未记录的 COM 对象的接口定义

逆向工程 视窗 dll 职能 电脑 视窗 10
2021-07-06 00:57:27

我已经开始探索 COM 对象,最初我是通过 UAC 绕过方法来了解它的,但我想我的问题很笼统。一般的问题是:如何从注册表中的(提升的)CLSID 调用 COM 接口中的函数?. 解释我进行的研究和我接下来的具体问题。我将使用 IFileOperation COM(CLSID = 3AD05575-8857-4850-9277-11B85BDB8E09)和 ICMLuaUtil COM(CLSID = 3E5FC7F9-9A51-4367-9063-A120244FBEC7)作为本文的示例。

COM 对象列在注册表中的 下HKEY_CLASSES_ROOT\CLSID默认值具有 COM 名称和服务器 DLL 文件。

现在,为了列出我使用的与之关联的接口oleview,对于 IFileOperation,它显示了所有接口,但对于 ICMLuaUtil,它只显示了 .

即使在我获得接口名称之后,我也必须获得函数列表和签名,这可以从idl文件中提取这里提供的一个很好的答案展示了如何通过检查示例代码并搜索与idl文件sdk夹中的导入名称相同的文件,从接口名称获取其函数签名我尝试对这两个接口应用类似的方法,并取得了部分成功。

  1. 对于 IFileOperation,示例源有 4 个,其中没有一个idl在 sdk 文件夹中具有完全相同的文件。因此,我在文件夹中所有文件的内容中搜索IFileOperation导致获得所需文件的单词shobjidl_core.
  2. 不幸的是,我无法做同样的事情,ICMLuaUtil因为我不知道接口名称,我尝试了几种名称变体,但一无所获。

我尝试过的其他方法是:

  1. 从我在注册表中找到的 DLL 中提取所有文件(没有)
  2. COMViewer 应该显示附加信息,但它在我的 Windows 10 机器上不起作用(未启动),即使在兼容模式下也是如此。

我的问题是如何从(有时是未记录的)COM 对象到具体的接口定义,以便我可以在我的代码中使用它?UACMe项目对接口的具体定义ICMLuaUtil,因此必须有获得它的方法。获取这些函数签名的指南和步骤是什么?

3个回答

现在,不幸的是,这不可能是从 A 到 Z 的完整答案。但是对于 COM,只有几个步骤是真正特定于 COM 的。

您链接的项目显然对接口进行了逆向工程 ( elvint.h)。这首先意味着接口的名称不一定与 Microsoft 所称的名称匹配(但在您的情况下它们匹配)。但是,如果实现相应 COM 接口或其代理 DLL 的二进制文件是官方系统文件,则可以为它们获取 PDB 文件,即使 Microsoft 已严重减少公共符号,这通常也允许您为函数分配更有意义的名称/方法。

当然,链接项目的作者已经知道他们在寻找什么,并且似乎系统组件以某种方式“神奇地”能够绕过典型的 UAC 提升提示,即使人们应该期望它们显示一个。

现在假设他们发现连接管理器配置(与RAS相关)包含这样的功能,他们现在会继续执行您期望需要提升但不需要提升的操作。然后他们会查找加载到进程中的 DLL,并找到一个 InProc 服务器或一个将它们引导到 OutProc 服务器的代理。

如果查找步骤失败,他们可以简单地调查所有系统 DLL,寻找典型的 COM 导出函数(第一个是最明显的):

  • DllGetClassObject
  • DllCanUnloadNow
  • DllAddRef
  • DllRelease

...然后检查版本信息资源。有了这个pefile模块,这变成了一个简单的 Python 脚本工作。这基本上是您在 RCE 中始终采取的第一步:情报收集。它不是严格的 RCE(如筛选或操纵反汇编),但它是我迄今为止所做的所有 RCE 工作的内在部分。

但在您的情况下,您已经使用了 oleview.exe,因此知道最重要的信息:

在 cmlua.dll 中为 ICMLuaUtil 显示的信息

...这就是为什么我发现您的评论令人困惑:

不幸的是,我无法做同样的事情,ICMLuaUtil因为我不知道接口名称,我尝试了几种名称变体,但一无所获。

现在已经发现cmlua.dll它是实现我们感兴趣的(COM)对象的 DLL,我们可以继续将它加载到 IDA(或其他反汇编程序)中,我们将收到提示,从 Microsoft 的符号服务器加载调试符号。

一旦符号被加载,我们就会看到:

IDA 对应用调试符号的 cmlua.dll 函数的理解摘录

看起来很熟悉?

要获得 IDL,您需要将该CCMLuaUtil的 vtable 与它的 DLL 在要求该特定类时返回的接口指针相匹配调查DllGetClassObject将使您能够找出 IID。

现在从这里开始,这将是理解反汇编(或伪代码,如果你能负担得起反编译器插件)的意义相同的旧工作。


现在,如果幸运的话,如果有问题的 COM 服务器(通常是 DLL)包含一个 TYPELIB 资源,这是 IDL 的编译版本,因此我们可以节省大量时间,因此是快速访问 IDL 的最佳起点。cmlua.dll然而,因为我们不走运。

此外,如果您没有像 Windows 组件那样的符号,您将不得不深入了解反汇编,从这DllGetClassObject是众所周知的和有据可查的开始,即使对于外行来说也应该很容易理解。从那里开始,并了解任何 COM 接口的前三个方法都是从IUnknown那里继承的,然后尝试理解每个方法的实现(除了那些众所周知的前三个方法),并为它们分配希望有意义的名称函数及其参数。也就是说:如果没有调试符号,整个任务会变得有点乏味,但并非完全不可能。

好吧,答案很好,这只是展示如何在命令行中使用windbg 到达的补充

dbh 是windbg 安装中的一个实用程序,它可以加载任何二进制文件并使用它提供大量静态信息,而windbg cdb.exe 的命令行版本则可以在两个命令中获取方法(注意方法名称已被破坏)

C:\>dbh c:\Windows\System32\cmlua.dll  "x CCM*" | grep -i vf
    11            1002d58 :   CCMLuaUtil::`vftable'

C:\>cdb -c "dps cmlua.dll+2d58" -z c:\Windows\System32\cmlua.dll

Microsoft (R) Windows Debugger Version 10.0.16299.15 X86
Loading Dump File [c:\Windows\System32\cmlua.dll]


cmlua!_DllMainCRTStartup:
100061e7 8bff            mov     edi,edi

0:000> cdb: Reading initial command 'dps cmlua.dll+2d58'

10002d58  100042ad cmlua!CCMLuaUtil::QueryInterface
10002d5c  10004e82 cmlua!CCMLuaUtil::AddRef
10002d60  10004279 cmlua!CCMLuaUtil::Release
10002d64  10004346 cmlua!CCMLuaUtil::SetRasCredentials
10002d68  10004401 cmlua!CCMLuaUtil::SetRasEntryProperties
10002d6c  100044dd cmlua!CCMLuaUtil::DeleteRasEntry
10002d70  10004573 cmlua!CCMLuaUtil::LaunchInfSection
10002d74  100045e1 cmlua!CCMLuaUtil::LaunchInfSectionEx
10002d78  10004630 cmlua!CCMLuaUtil::CreateLayerDirectory
10002d7c  1000466e cmlua!CCMLuaUtil::ShellExec
10002d80  10004690 cmlua!CCMLuaUtil::SetRegistryStringValue
10002d84  10004701 cmlua!CCMLuaUtil::DeleteRegistryStringValue
10002d88  100055da cmlua!CCMLuaUtil::DeleteRegKeysWithoutSubKeys
10002d8c  10004767 cmlua!CCMLuaUtil::DeleteRegTree
10002d90  100048cc cmlua!CCMLuaUtil::ExitWindowsFunc
10002d94  10005c72 cmlua!CCMLuaUtil::AllowAccessToTheWorld
10002d98  100048d9 cmlua!CCMLuaUtil::CreateFileAndClose
10002d9c  1000560f cmlua!CCMLuaUtil::DeleteHiddenCmProfileFiles
10002da0  1000492a cmlua!CCMLuaUtil::CallCustomActionDll
10002da4  10004b6c cmlua!CCMLuaUtil::RunCustomActionExe
10002da8  10004c2c cmlua!CCMLuaUtil::SetRasSubEntryProperties
10002dac  10004d0e cmlua!CCMLuaUtil::DeleteRasSubEntry
10002db0  10004da7 cmlua!CCMLuaUtil::SetCustomAuthData
10002db4  10005cdb cmlua!CCMLuaUtil::`vector deleting destructor'
10002db8  00000000
10002dbc  10009138 cmlua!hProxyDll+0x10
10002dc0  10009188 cmlua!hProxyDll+0x60
10002dc4  00000000
10002dc8  69727453
10002dcc  6343676e
10002dd0  706f4368
10002dd4  20784579
0:000>

现在 dbh 有一个开关 -d 将输出损坏的名称,您可以利用该开关将参数打印到方法

C:\>echo off

for /F %i in ('dbh -d c:\Windows\System32\cmlua.dll  "x *CCM*"  ^| awk "{print $4}"') do  dbh c:\windows\system32\cmlua.
dll undec %i

?Release@CCMLuaUtil@@UAGKXZ =
public: virtual unsigned long __stdcall CCMLuaUtil::Release(void)

??_ECCMLuaUtil@@UAEPAXI@Z =
public: virtual void * __thiscall CCMLuaUtil::`vector deleting destructor'(unsigned int)

??0CCMLuaUtil@@QAE@XZ =
public: __thiscall CCMLuaUtil::CCMLuaUtil(void)

?AddRef@CCMLuaUtil@@UAGKXZ =
public: virtual unsigned long __stdcall CCMLuaUtil::AddRef(void)

?CreateFileAndClose@CCMLuaUtil@@UAGJPBGKKKK@Z =
public: virtual long __stdcall CCMLuaUtil::CreateFileAndClose(unsigned short const *,unsigned long,unsigned long,unsigne
d long,unsigned long)

?DeleteHiddenCmProfileFiles@CCMLuaUtil@@UAGJPBG@Z =
public: virtual long __stdcall CCMLuaUtil::DeleteHiddenCmProfileFiles(unsigned short const *)

??_GCCMLuaUtil@@UAEPAXI@Z =
public: virtual void * __thiscall CCMLuaUtil::`scalar deleting destructor'(unsigned int)

?SetRasSubEntryProperties@CCMLuaUtil@@UAGJPBG0KPAPAGK@Z =
public: virtual long __stdcall CCMLuaUtil::SetRasSubEntryProperties(unsigned short const *,unsigned short const *,unsign
ed long,unsigned short * *,unsigned long)

?QueryInterface@CCMLuaUtil@@UAGJABU_GUID@@PAPAX@Z =
public: virtual long __stdcall CCMLuaUtil::QueryInterface(struct _GUID const &,void * *)

?CCMLuaUtil_CreateInstance@@YGJABU_GUID@@PAPAX@Z =
long __stdcall CCMLuaUtil_CreateInstance(struct _GUID const &,void * *)

?ExitWindowsFunc@CCMLuaUtil@@UAGJXZ =
public: virtual long __stdcall CCMLuaUtil::ExitWindowsFunc(void)

?CreateLayerDirectory@CCMLuaUtil@@UAGJPBG@Z =
public: virtual long __stdcall CCMLuaUtil::CreateLayerDirectory(unsigned short const *)

?LaunchInfSectionEx@CCMLuaUtil@@UAGJPBG0K@Z =
public: virtual long __stdcall CCMLuaUtil::LaunchInfSectionEx(unsigned short const *,unsigned short const *,unsigned lon
g)

?ShellExec@CCMLuaUtil@@UAGJPBG00KK@Z =
public: virtual long __stdcall CCMLuaUtil::ShellExec(unsigned short const *,unsigned short const *,unsigned short const
*,unsigned long,unsigned long)

?DeleteRasEntry@CCMLuaUtil@@UAGJPBG0@Z =
public: virtual long __stdcall CCMLuaUtil::DeleteRasEntry(unsigned short const *,unsigned short const *)

?DeleteRegistryStringValue@CCMLuaUtil@@UAGJHPBG0@Z =
public: virtual long __stdcall CCMLuaUtil::DeleteRegistryStringValue(int,unsigned short const *,unsigned short const *)

??_7CCMLuaUtil@@6B@ =
const CCMLuaUtil::`vftable'

?LaunchInfSection@CCMLuaUtil@@UAGJPBG00H@Z =
public: virtual long __stdcall CCMLuaUtil::LaunchInfSection(unsigned short const *,unsigned short const *,unsigned short
 const *,int)

?SetCustomAuthData@CCMLuaUtil@@UAGJPBG00K@Z =
public: virtual long __stdcall CCMLuaUtil::SetCustomAuthData(unsigned short const *,unsigned short const *,unsigned shor
t const *,unsigned long)

?DeleteRasSubEntry@CCMLuaUtil@@UAGJPBG0K@Z =
public: virtual long __stdcall CCMLuaUtil::DeleteRasSubEntry(unsigned short const *,unsigned short const *,unsigned long
)

?DeleteRegTree@CCMLuaUtil@@UAGJHPBG@Z =
public: virtual long __stdcall CCMLuaUtil::DeleteRegTree(int,unsigned short const *)

?DeleteRegKeysWithoutSubKeys@CCMLuaUtil@@UAGJHPBGH@Z =
public: virtual long __stdcall CCMLuaUtil::DeleteRegKeysWithoutSubKeys(int,unsigned short const *,int)

?CallCustomActionDll@CCMLuaUtil@@UAGJPBG000PAK@Z =
public: virtual long __stdcall CCMLuaUtil::CallCustomActionDll(unsigned short const *,unsigned short const *,unsigned sh
ort const *,unsigned short const *,unsigned long *)

?SetRegistryStringValue@CCMLuaUtil@@UAGJHPBG00@Z =
public: virtual long __stdcall CCMLuaUtil::SetRegistryStringValue(int,unsigned short const *,unsigned short const *,unsi
gned short const *)

?SetRasCredentials@CCMLuaUtil@@UAGJPBG00H@Z =
public: virtual long __stdcall CCMLuaUtil::SetRasCredentials(unsigned short const *,unsigned short const *,unsigned shor
t const *,int)

?SetRasEntryProperties@CCMLuaUtil@@UAGJPBG0PAPAGK@Z =
public: virtual long __stdcall CCMLuaUtil::SetRasEntryProperties(unsigned short const *,unsigned short const *,unsigned
short * *,unsigned long)

?AllowAccessToTheWorld@CCMLuaUtil@@UAGJPBG@Z =
public: virtual long __stdcall CCMLuaUtil::AllowAccessToTheWorld(unsigned short const *)

?RunCustomActionExe@CCMLuaUtil@@UAGJPBG0PAPAG@Z =
public: virtual long __stdcall CCMLuaUtil::RunCustomActionExe(unsigned short const *,unsigned short const *,unsigned sho
rt * *)

这只是@0xC0000022L 答案的扩展。对于这个问题,我会在下面解释ICMLuaUtil COM接口,因为IFileOperation COM接口在shell32.dll,太大了;)

您提到了错误的 CLSID。在这里,我提供了它们的列表:

GUID CLSID_CmstpLua = {3E5FC7F9-9A51-4367-9063-A120244FBEC7}
GUID IID_ICmstpLua = {6EF07F29-F9B8-4DA4-B59E-13DEA060AD60}
GUID IID_ICmstpLua2 = {AE8AFD54-5B57-4961-8A9B-12ADF23B696A}

GUID CLSID_CMLuaUtil = {3E000D72-A845-4CD9-BD83-80C07C3B881F}
GUID IID_ICMLuaUtil = {6EDD6D74-C007-4E75-B76A-E5740995E24C}

如何在不使用任何第三方程序的情况下CLSID 中找到 DLL 文件路径HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{CLSID}在 RegEdit 中打开此注册表路径对于这种情况,请尝试使用以下命令:

REG Query "HKLM\SOFTWARE\Classes\CLSID\{3E000D72-A845-4CD9-BD83-80C07C3B881F}\InprocServer32" /VE
REG Query "HKLM\SOFTWARE\Classes\Interface\{6EDD6D74-C007-4E75-B76A-E5740995E24C}" /VE

路径将是%SystemRoot%\System32\cmlua.dll在 IDA(或任何反汇编器/反编译器)中打开它并加载 PDB 符号文件。使用Shift+转到函数窗口F3通过在该窗口中键入这些词来搜索构造函数析构函数在装配视图中打开该功能。必须有一个变量,比如const CCMLuaUtil::vftable因为你知道为什么双击它,您将在程序集视图中看到该 COM 类的布局。

CMLuaUtil_interface

装配视图有很多优点。汇编视图中,该类中的所有方法都按实际顺序排列,但功能窗口可能没有(根据设置)。这些方法实际上是作为函数指针放置的。对于 64 位二进制文​​件,dq每个方法之前都会有(qword 8 个字节)(在上面的屏幕截图中)。前三个方法继承IUnknown 接口如果您在 C 中编写该类(作为结构),则必须包括这三个。

请参阅另一个规范答案以获取进一步参考。可以在我的存储库GitHub 中看到此方法的真实示例:WslReverse,我在其中展示了LxssManager.DLL. 还有这个关于实用 C++ 反编译的视频| 侦察 2011 | Igor Skochinsky帮了我很多。