Click here to Skip to main content
15,886,873 members
Articles / Programming Languages / C#

Dealing with DCOM Hardening, Part 2: Disassembling and Reassembling a .NET DLL

Rate me:
Please Sign up or sign in to vote.
5.00/5 (8 votes)
15 Nov 2023CPOL6 min read 4.2K   6   8
Mitigate problems caused by DCOM hardening, by reverse engineering a non-compliant .NET app
In this article, I explain how to mitigate the problems caused by DCOM hardening, by reverse engineering a non-compliant .NET application. The approach I take here is to identify the source of the problem, disassemble the offending component, and then re-assemble the program.

Introduction

In my previous article, I explained the non-invasive ways in which you could mitigate the client side impact of DCOM hardening. However, there may be scenarios where that is not possible and you as a developer come into the picture.

Before we get started, I do want to mention that this involves what my kids call ‘hacking’ and is therefore not something you should never do in a stable production system with vendor support for obvious reasons. We are talking about a scenario where there is no possible other support, and the only two options are a) stay down until the entire system is migrated, or b) hobble on until the entire system is migrated.

In this scenario, we have a .NET application on a Windows 2008R2 system that refuses to connect to a server via DCOM. This one was a very small EXE with a ton of libraries and components that get loaded when it starts. This is pretty typical for business applications which are often modular and designed to work with a plethora of different interfaces that may or may not apply to this particular system.

I should also point out there are no guarantees. Getting an application to work in a manner that was not intended is a task that comes without instruction manual. We don’t know how the application was designed in the first place, so we have to first try to figure that out, and then see if we can do anything to mitigate.

Background

In my previous article, I explained that this problem can be fixed if the OS is still supported, or if the application uses default settings. Given that we have an application that doesn't work, the 1 thing we can safely assume is that ‘somewhere’, there is a win32 COM API being called with non-default authentication specification because we already know that changing the DCOM settings (either defaults or component specific ones via DCOMCnfg) didn’t work. The most obvious candidate is somewhere, someone is calling CoInitializeSecurity with bad parameters. The easiest way to establish this is using the ‘strings’ utility from SysInternals on a file to determine this, and using powershell to automate this for the entire folder.

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

As it happens, in this case that returns a hit. There is one component being used which does an explicit call to CoInitializeSecurity:

Image 1

To avoid problems, I've decided to hide the name of the specific component. For the rest of this article, I'm going to rename it to DodgyDll.dll. Having identified the culprit, we're going to have to look at it in more detail. We can do this in several ways. One approach is to use reflector.

Image 2If we look at the declaration for CoInitializeSecurity:

C++
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
);

We see the authentication level is set to 1 (RPC_C_AUTHN_LEVEL_NONE) and the impersonation level to 2 (RPC_C_IMP_LEVEL_IDENTIFY). We'd need this to be 5 (RPC_C_AUTHN_LEVEL_PKT_INTEGRITY) and 3 (RPC_C_IMP_LEVEL_IMPERSONATE) respectively, according to the documentation of the vendor of the server.

Having identified the problem, now we have to make that happen.

Disassembling and Reassembling the DLL

If you have Visual Studio installed, you already have ildasm on your system. If you don't, then you can get it for free by installing the Windows SDK. ildasm is a disassembly tool which can take a .NET module and convert it back to .NET intermediate language. It will also extract the embedded resource file.

Image 3

You can open the il file in Notepad, and find the CoInitializeSecurity function call. Basically, you see the different values being loaded on the stack, in the order in which CoInitializeSecurity expects them before the function call is made. The 5th and 6th values on the stack are the ones causing the problem. Because IL is fairly easy to read and understand, it's also easy enough to edit.

The instructions starting with ld load something on the stack. Simply counting the number of times something is loaded on the stack makes it easy to identify the problematic values 1 and 2, which need to be 5 and 3. All we need to do is edit the values.

Image 4

That's it. Now, we have to reverse the process and create a DLL again. However, note that we need to do this on the target system where we got the DLL from. The reason is that ilasm will create a dependency on a .NET version, and using the wrong version of ilasm will create a DLL which may be incompatible with the application that uses it. Luckily, when the .NET framework is installed on a system, ilasm and other tools are installed along with it.

Image 5

This will convert the intermediate language file back into a DLL. However when we try this, we hit a snag.

Image 6

The version of ilasm we use cannot understand that particular line (the -nan to be precise). Things like this are not wholly unexpected. When using tools from different tool chains, such things can happen. This is easy enough to fix by modifying ldc.r8 -nan(ind) to ldc.r8 (00 00 00 00 00 00 F8 FF). FWIW, this is a known issue at the time of writing, and is caused by a regression in ildasm.

After we make the required change, the command completes successfully! On that high, we swap out the DLL, fire up the application and.... nothing happens. Or rather, the following happens:

Image 7It makes sense of course. The original vendor used strong name signing, and while we can reverse engineer the DLL and make some changes, re-signing is not an option.

Removing Signature Verification

I want to re-iterate what I said at the beginning: we are working on a obsolete system, which is -hopefully- already having a migration ongoing. We're already in a situation where there are no best or good options left, and we're already making the best of a worst case situation.

The reason I mention this anew is that after destroying all hope of vendor support, we are going one step further and also disable strong name verification and hamstring application security. In other words, we're going to tell the system we don't care about assembly signing anymore. It should be obvious that under no circumstances is this ever a good idea except if not doing it is going to be a bigger disaster.

As it turns out, this is relatively simple., and can be done using the registry. You need to create the following keys:

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

And then you create the following values:

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

It is possible to use these registry keys to only allow this for assemblies with specific signatures, but in our case, we choose a blanket approach.

NOTE: In our case, simply disabling strong names is safe enough, because that server is in a segregated VLAN which only allows specific point to point connections, and only admins and the relevant service accounts can even log in on that system. If your setup is less secure, it may still be a good idea to selectively disable strong name signing only for the relevant assembly.

I did not find a proper Microsoft article but this link shows how it should be done.

<code>[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification\MyAssemblyName,publicKeyToken]</code>

Success

After bypassing the strong name verification, we can fire up the application and...

Image 8

Success! Our application can finally connect to the DCOM server and business can continue.

Points of Interest

In this article, I showed how you can dis-assemble and re-assemble a .NET DLL for the purpose of making parameter changes. In this case, it was for dealing with DCOM hardening, but the principle is more generally applicable.

This approach is definitely not the best for solving your problems, and should be considered a 'last resort' but it's always good to understand something and have an extra option in your toolbox.

History

  • 15th November, 2023: First version
  • 12th December, 2023: Second version. Added selective strong name disable

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Belgium Belgium
I am a former professional software developer (now a system admin) with an interest in everything that is about making hardware work. In the course of my work, I have programmed device drivers and services on Windows and linux.

I have written firmware for embedded devices in C and assembly language, and have designed and implemented real-time applications for testing of satellite payload equipment.

Generally, finding out how to interface hardware with software is my hobby and job.

Comments and Discussions

 
GeneralMy vote of 5 Pin
aeastham29-Nov-23 2:02
aeastham29-Nov-23 2:02 
SuggestionVery slick, but... Pin
dandy7220-Nov-23 9:09
dandy7220-Nov-23 9:09 
GeneralRe: Very slick, but... Pin
Bruno van Dooren20-Nov-23 20:27
mvaBruno van Dooren20-Nov-23 20:27 
GeneralRe: Very slick, but... Pin
dandy7221-Nov-23 2:36
dandy7221-Nov-23 2:36 
GeneralRe: Very slick, but... Pin
Bruno van Dooren4-Dec-23 4:30
mvaBruno van Dooren4-Dec-23 4:30 
GeneralRe: Very slick, but... Pin
dandy724-Dec-23 7:27
dandy724-Dec-23 7:27 
GeneralMy vote of 5 Pin
Ștefan-Mihai MOGA15-Nov-23 20:15
professionalȘtefan-Mihai MOGA15-Nov-23 20:15 
GeneralMy vote of 5 Pin
LightTempler15-Nov-23 5:01
LightTempler15-Nov-23 5:01 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.