深入理解DCOM加固对客户端的影响

在某些特定情况下,开发者可能会遇到DCOM加固导致的客户端连接问题。本文将探讨在没有其他支持选项的情况下,如何通过修改.NET应用程序来解决这一问题。需要注意的是,这种做法并不推荐在有官方支持的稳定生产系统中使用,因为它可能涉及到所谓的“黑客”行为。讨论的是一种特殊情况,即系统无法获得支持,唯一的选择是要么等待系统迁移完成,要么在迁移过程中继续使用。

在之前的文章中,讨论了如果操作系统仍然受到支持,或者应用程序使用默认设置,那么问题可以得到解决。然而,面对一个无法正常工作的应用程序,可以确定的是,某个地方一定有一个win32 COM API被调用,并且使用了非默认的认证规范。已经知道,通过DCOMCnfg更改DCOM设置(无论是默认设置还是通过DCOMCnfg进行组件特定的设置)都无法解决问题。最明显的候选是某个地方有人调用了CoInitializeSecurity函数,并且参数设置不当。

为了确定这一点,可以使用SysInternals的strings工具对文件进行分析,并使用PowerShell自动化整个文件夹的分析过程。

PowerShell脚本示例

Get-ChildItem C:\temp\Lib -Filter "*.dll" -Recurse | foreach { $_.FullName; c:\temp\strings $_.FullName | where { $_ -match "CoInitializeSecurity" } }

在这个案例中,发现有一个组件在明确调用CoInitializeSecurity函数。为了避免问题,决定隐藏这个特定组件的名称。在本文的剩余部分,将把它重命名为DodgyDll.dll。确定了罪魁祸首之后,需要更详细地查看它。可以通过多种方式做到这一点。一种方法是使用reflector。

CoInitializeSecurity函数的声明

HRESULT CoInitializeSecurity( [in, optional] PSECURITY_DESCRIPTOR pSecDesc, [in] LONG cAuthSvc, [in, optional] SOLE_AUTHENTICATION_SERVICE *asAuthSvc, [in, optional] void *pReserved1, [in] DWORD dwAuthnLevel, [in] DWORD dwImpLevel, [in, optional] void *pAuthList, [in] DWORD dwCapabilities, [in, optional] void *pReserved3 );

可以看到认证级别被设置为1(RPC_C_AUTHN_LEVEL_NONE),而模拟级别被设置为2(RPC_C_IMP_LEVEL_IDENTIFY)。根据服务器供应商的文档,需要将其分别设置为5(RPC_C_AUTHN_LEVEL_PKT_INTEGRITY)和3(RPC_C_IMP_LEVEL_IMPERSONATE)。

反汇编和重新组装DLL

如果安装了Visual Studio,那么系统上已经有了ildasm。如果没有,可以通过安装Windows SDK免费获得它。ildasm是一个反汇编工具,可以将.NET模块转换回.NET中间语言。它还会提取嵌入的资源文件。可以在记事本中打开il文件,并找到CoInitializeSecurity函数调用。基本上,会看到不同的值被加载到堆栈上,按照CoInitializeSecurity函数调用之前期望的顺序。堆栈上的第5个和第6个值是造成问题的原因。因为IL相对容易阅读和理解,所以也很容易编辑。

以ld开头的指令将某物加载到堆栈上。简单地计算某物被加载到堆栈上的次数,就可以轻松识别出需要被修改为5和3的问题值1和2。所需要做的就是编辑这些值。

现在,需要反向操作,再次创建一个DLL。但是,需要注意的是,需要在获取DLL的目标系统上进行此操作。原因是ilasm会创建对.NET版本的依赖,使用错误的ilasm版本可能会创建一个与使用它的应用程序不兼容的DLL。幸运的是,当.NET框架安装在系统上时,ilasm和其他工具也会随之安装。

遇到的困难

当尝试这样做时,遇到了一个问题。使用的ilasm版本无法理解特定的行(确切地说是-nan)。当使用不同工具链中的工具时,这种事情是意料之中的。通过将ldc.r8 -nan(ind)修改为ldc.r8 (00 00 00 00 00 00 F8 FF),这个问题就可以轻松解决。

在进行了所需的更改之后,命令成功完成!在那种兴奋的情绪下,替换了DLL,启动了应用程序,但是……什么都没有发生。或者更确切地说,发生了以下情况:

这当然是有道理的。原始供应商使用了强名称签名,虽然可以逆向工程DLL并进行一些更改,但是重新签名并不是一个选项。

移除签名验证

想再次强调在文章开头所说的话:正在处理一个过时的系统,这个系统可能已经在进行迁移。已经处于一个没有最佳或良好选择的情况,正在尽最大努力应对最坏的情况。

再次提到这一点的原因是,在破坏了所有供应商支持的希望之后,又向前迈进了一步,也禁用了强名称验证,并削弱了应用程序的安全性。换句话说,将告诉系统不再关心程序集签名了。应该很明显,除非不这样做会导致更大的灾难,否则在任何情况下这都不是一个好主意。

事实证明,这相对简单,可以通过注册表来完成。需要创建以下键:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification\*,*] [HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\StrongName\Verification\*,*]

然后需要创建以下值:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework] "AllowStrongNameBypass"=dword:00000001 [HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework] "AllowStrongNameBypass"=dword:00000001

可以使用这些注册表键仅允许具有特定签名的程序集这样做,但在情况下,选择了一种全面的方法。

请注意:在情况下,简单地禁用强名称是足够安全的,因为那个服务器位于一个隔离的VLAN中,只允许特定的点对点连接,只有管理员和相关服务帐户才能登录到该系统。如果设置不够安全,可能仍然是个好主意,只为相关程序集选择性地禁用强名称签名。

没有找到一个合适的Microsoft文章,但展示了如何做到这一点。

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification\MyAssemblyName,publicKeyToken]

在绕过了强名称验证之后,可以启动应用程序,并且……成功了!应用程序终于可以连接到DCOM服务器,业务可以继续进行。

在本文中,展示了如何反汇编和重新组装.NET DLL,以便进行参数更改。在这种情况下,这是为了处理DCOM加固,但原理更普遍适用。

这种方法绝对不是解决问题的最佳方式,应该被视为“最后的手段”,但了解某些东西并在工具箱中拥有额外的选择总是好的。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485