Windows DLL Proxying/Hijacking

Reading Time: 7 minutes

Concept

A while back I was working on a add-in/plug-in for a software that would enhance it’s functionality. I found that the easiest and most pain free way of loading arbitrary code was via a method referred to as DLL ‘proxying‘ or ‘hijacking‘. This method is unfortunately abused and most commonly used in malware prompting Microsoft to outline ways to secure your applications when loading libraries to prevent such attacks. In this post I will run you through the process of how this method works, this will also help you gain a better understanding of the internal functionality of the Microsoft Windows Operating System.

Dynamic Link Library (DLL)

First, you may not know or be wondering. What are DLLs? DLL stands for Dynamic Link Library and they are the core libraries that contain functional code or resources used in Windows applications. They share the same Portable Executable (PE) file format as .EXE files. For this post I will touch briefly on the structure in order to explain the DLL proxying process.

Microsoft’s implementation of the shared library concept allows the use of written code amongst multiple applications. For example ‘ApplicationA‘ can load a library titled Common.DLL and call a function in that library that does the addition of two integers. Subsequently ‘ApplicationB‘ can also load that library and call the same function. The function in the library is effectively shared between the two apps. For this reason libraries expose functions which get stored in a structure called the export table inside the DLL. You can read more about the PE format here.

dll export table
Above is a screenshot showing the exported functions of a library called sample.dll

Windows DLL Loader

The Windows DLL Loader or known as the PE Loader is responsible for loading these libraries on either startup of a program or at runtime when they are required. When attempting to load a library it adheres to a defined search order. Below you can see the default order of which the loader attempts to search for the requested library to be loaded. The order will differ when safe DLL search mode is disabled.

Above is a diagram showing the default DLL search order in Windows.
  • Initially it will first attempt to look inside the process memory to determine if the library has been previously loaded.
  • Next it will look inside the KnownDLLs registry entry located at: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs to see if any match the name.
  • The subsequent location is the application directory. This directory is of importance to us for this method to work.

You can find a more detailed explanation of each location by reading through the Microsoft documentation.

How does DLL proxying or hijacking work?

The DLL search order can be exploited to trick a target application to load an illegitimate DLL library. This can occur if there is no explicit path specified when loading a library. For example, if an application wishes to load a DLL called Example.dll without specifying it’s location the Library Loader will commence a search using the ordered list. Once there is a file located with the exact library name it will be loaded into the running application’s process memory. The library loaded will then be prepared to have one of it’s exported functions executed.

To highjack this flow we can place a DLL library that we have crafted in a location that is early on in the search order. This will result in our DLL being loaded for execution rather than the original intended library which may be located further down the search list.

It is important to note that for this to work in a stable manner we must create what is known as a DLL wrapper to expose the same functions that are exported by the original DLL library. If we fail to do so when our library is loaded the function call intended will fail as it doesn’t exist.

Below is a diagram to demonstrate this where a application process wishes to call a function titled “FunctionA” in the library Example.DLL.

Here is the process outlined:

  • The Windows PE Loader will use the search order list and scan to locate a library called Example.DLL
  • It will fail to locate the library in process memory and the KnownDLLs registry entry finding a matching file in the application directory instead.
  • This file is not the original intended library but our wrapper DLL. The exported functions by the original DLL are mirrored in our wrapper using DLL Redirection which in layman’s terms tells the loader to look elsewhere for the origins of FunctionA.
  • The loader will then load Example_Org.DLL which was the original library intended to be loaded.
  • The loader will then locate the exported function FunctionA inside the export table of Example_Org.DLL and attempt to resolve it’s virtual memory address so it can be called and executed.

Locating susceptible DLLs

We can utilize a tool mentioned in one of my previous blog posts to locate libraries that are susceptible to such an attack. Process Monitor by Mark Russinovich has the ability to monitor library load calls and using a certain filter it is possible to discover DLLs that fall into that category.

In the example below I will explain how code execution can be acquired on Microsoft Teams by using DLL proxying/hijacking.

If we set the filter on Process Monitor to locate DLLs being loaded by Teams.exe with the Result of NAME NOT FOUND it can be observed that once the application is run we get quite a few matching results matching the criteria.

Creating a Wrapper/Proxy DLL Library

Following the example above with Microsoft Teams we can choose one of the DLLs present in that list to perform this. In this demonstration I have chosen to go with the library VERSION.DLL. This library provides helper functionality that deals with files and file attributes.

A C++ Native DLL project will then need to be created that exposes the same functions exported by this library. I have provided an example project on GitHub we can use.

Opening the original DLL library in PeStudio we can observe the functions it has exported. Usually you can locate the original file (if it exists) in the System32 directory.

A screenshot showing the exported functions by the Version library

Our next step is to mirror these functions exported in our wrapper DLL library without copying any implementation over but instead redirecting them back to the original.

This can be achieved by using a command line tool I’ve created called PEExportGen which you can download from GitHub.

PEExportGen will take an import library, parse it’s export table and create a C++ header that contains export definitions that the C++ Compile Linker can use to create the wrapper DLL.

The output result of running VERSION.DLL through PEExportGen is a header will that we can include in our project DLL Proxy Project.

To demonstrate this proof of concept inside the DLL Entry Point we create a new thread to execute the following:

After this we can build the library, ready to be deployed.

The final step is renaming the original DLL Library to VERSION_orig.DLL and our newly compiled wrapper as the original’s name VERSION.DLL.

You can see in this screenshot the wrapper we have built does not contain a version number or description. The original however has this information.

Both files then can be dropped inside the application folder next to the Teams.exe executable. This directory is typically located at:

C:\Users\%USERPROFILE%\AppData\Local\Microsoft\Teams\current

Running the targeted Application

After the crafting and deployment of the wrapper DLL we can proceed to run the application Teams.exe. You should see a console window popup with our intended output. This demonstrates how arbitrary code can be executed inside a process with DLL proxying/hijacking.

Mitigation and Security

To prevent this type of hijacking there are a few steps you can take to ensure this risk is mitigated in your application. When you wish to load a library providing a full path is the best approach.

HMODULE handle = LoadLibrary("someLibrary.dll");

The above call to LoadLibrary will result in the search order to locate the library. The right way to load the library would be to supply its full file path.

HMODULE handle = LoadLibrary("C:\\Windows\\System32\\someLibrary.dll");

In some situations where the file path can not be determined it could be possible to locate the file yourself by checking it’s hash or digital signature (if it is signed).

There are other ways to omit searching certain paths by using the Flags attribute in LoadLibraryEx. Another common mistake developers may make is using LoadLibrary to determine if a Library exists on a system, this is not good practice and other avenues should be pursued to accomplish this.

Finally it is important to have the appropriate directory permissions for your application. If the app directory is not writeable it will reduce the risk significantly.

Conclusion

This method of code execution has been around for quite some time in Windows, I hope through reading this post you have a better understanding of how libraries are loaded. It can be evident without proper care this method can open up your program or application to vulnerabilities. It also however can be used in a non malicious way to load/modify/enhance an old legacy application for instance that might not work due to incompatibility or lack of interoperability.

Links & Resources

Unpacking Xamarin Android Mobile Applications

Reading Time: 5 minutes

Recap & Introduction

In my previous post I detailed how to decompile .NET code and explained how this was possible given the nature of the .NET platform. This post will walk you through how to unpack and decompile android mobile applications built on the Xamarin platform. Additionally I will also talk about a utility app I have created to automate the process. The procedure outlined in this guide will assist you in analysing and reviewing code inside Xamarin android applications.

Xamarin

If you have never heard of Xamarin it is an open-sourced platform for building Android and iOS apps with .NET and C#. For this post I’m going to focus on applications built with Xamarin for the Android OS. You can read more about Xamarin here for a deeper dive. Don’t get too invested in it though as Microsoft is looking to merge Xamarin.iOS and Xamarin.Android as apart of the .NET unification process with .NET 6.

The unpacking process

In order to demonstrate I’ve created a example Xamarin android app which you can clone from my blog demos repo. Build the android-xamarin-MobileApp project and test it works on your mobile device.

Let us start with a brief understanding on how these android apps are built. Similar to my explanation on how the .NET platform works below is a diagram that demonstrates that build process with Xamarin.

An overview of the build process from source code to a deployable application package.

Essentially your source code gets compiled into CIL (IL) instructions that are stored in Dynamic Link Library (DLL) managed assemblies. The android package builder then bundles these along with app resources and other data into an APK package. The package then can be installed either ad-hoc via sideloading or deployed to an app distribution platform such as the Google Play Store.

Build Process Changes

It is important to note that there are various options and settings that can influence what the APK contains. For example, when you are building you may select the option shown in the diagram below to bundle assemblies into native code. The tool tip displayed in Visual Studio suggests this option protects the managed assemblies from examination but you will soon see that this not so true.

To explain why this impacts the unpacking process I’ve created a diagram that shows the differences focusing on the steps that occur between the package bundler and the final output APK.

Unbundled Build (Default)

This option is the default when building an app. The package builder will utilize LZ4 Compression and create files with the .dll extension. These files contain the compressed assemble with a custom header file that consists of a magic identifier ‘XALZ’, an index into the internal assembly descriptor table and the uncompressed size of the assembly. The files will then be put into a directory titled assemblies and packaged into the APK.

A traditional Xamarin Android APK package build contents open in 7zip File Manager
Bundled Build

When selecting the “bundles assemblies into native code” option, the package builder will utilize another compression algorithm, this time using GZip to compress each of the assemblies into the data segment inside the shared library titled libmonodroid_bundle_app.so. The shared library is then stored inside the lib directory which is packaged into the final APK.

A Xamarin Android APK package with ‘bundle assemblies’ checked open in 7zip File Manager

You can probably observe that the unbundled build will be fairly straight forward to unpack. The latter however requires a little more effort. First we must parse the shared library object then decipher where the data is stored and extract this.

Unpacking Strategy

My approach to unpacking these libraries consists of two parts.

Firstly an APK can contain libraries targeting different architectures. These are organized in the the lib directory like:

I’ll be explaining the process with the the ARM64 version however the exact same process applies for ARM. Having a look at the libmonodroid_bundle_app.so inside IDA we can see that the .data section contains a list of RVA references to each of the packed assemblies. These actually point to a data structure we will call ‘bundle entry’.

Each bundle entry structure looks like this:

This is sufficient enough to provide us the name of each file along with compression sizes both packed/unpacked. The data pointer field however inside the file is empty, this is because at runtime that is dynamically populated by the system image loader. Although we can resolve this with some work a simpler option is to find the matching compressed segment.

This brings us to the second part which involves searching for the GZIP streams inside the .rodata section. We  can achieve this by searching the magic numbers 0x1f  0x8b which make up the first part of the 10-byte GZIP header. This method however may present false positives as there could be data anywhere in there containing a 0x1f  0x8b sequence so we need to check the uncompressed size present at the tail end of a GZIP stream which is a 4byte unsigned integer. If the uncompressed size present in the current bundle entry matches the one at the end of the found GZIP stream then we have a match.

Unpacking Tool – XamAsmUnZ

Luckly for you I’ve created a small CLI tool that does this all for you. All you need to do is extract the APK package with an archive tool such a 7Zip, provide the tool with either the assemblies directory or the location of the libmonodroid_bundle_app.so and the tool will take care of the rest.

You can find the repository for that here or the release binaries here.

  • Example usage for an “Unbundled” build
    • XamAsmUnZ -dir "C:\com.cihansol.mobileapp\assemblies"
  • Example usage for a “Bundled” build
    • XamAsmUnZ -elf "com.cihansol.mobileapp\lib\arm64-v8a\libmonodroid_bundle_app.so"

The output binaries can then be viewed inside a decompiler like dnSpy to inspect code and logic.

Conclusion

Unpacking Xamarin android apps are trivial and this can be useful for code analysis and reviews. Within this blog post, I have demonstrated how Xamarin apps are built and packaged for the Android environment. Through a personal outline I have shown the procedure involved in unpacking .NET assemblies which can later be decompiled back into source code. The significance of this blog post highlights that it is very easy to dissect mobile applications built on the Xamarin platform. We can see that the bundling option available through the build settings does not provide the security it is perceived to perform.

Further Reading & Relevant Links

Decompiling .NET Code

Reading Time: 7 minutes

Introduction

When you build an native application your written source code gets compiled down to a language that can be understood by the target processor you’re developing for (eg. ARM), this is referred to as machine code or assembly. Decompiling such applications are not possible as there is information that gets lost during the compilation process which can not be recovered to produce the original written code. There are ways to decipher and make sense of such code such as disassembly however, that is not the focus of this blog post and I will cover that in another write up.

Disclaimer:  This post is written in good faith for educational purposes only. I’m not responsible for the misuse of the information provided here along with the use of the tools and methods mentioned. I also do not assume responsibility for the actions carried out with the knowledge provided. Please be aware of End-user license agreements before attempting to decompile a third party’s software or application code.

.NET Platform

Working with .NET we have the luxury to recover a lot of what was originally written. The compilation process is far more involved utilizing a runtime for execution, and the output result is referred to as “managed code”.

Below is a diagram I’ve created to display the process starting from your written source code all the way to where the target architecture executes the compiled binary. The power of .NET comes from its ability to run on many different architectures similar to Java. It also takes the burden of memory management and type safety away from the developer allowing the focus to be on the accomplishment of their specific task or problem.

For this example I’m going to use the C# programming language but this also applies to all other high-level languages supported by .NET.
  • Firstly, your written source code gets compiled by the C# Compiler generating Common Intermediate Language (CIL) formally known as IL. The compiler also generates metadata on your application that enables seamless integration of components. This methodology allows .NET languages to describe themselves automatically in a language-neutral manner, unseen by both the developer and the user. At this stage the CIL is able to be decompiled back into a state somewhat resembling what was originally written. Later on I will talk more on the tools available to do so.
  • The second half of the process happens at runtime. The Common Language Runtime (CLR) is responsible for this, taking care of tasks such as automatic memory management and employing security mechanism such as Code Access Security (CAS). It creates the environment that allows the JIT compiler to take the CIL produced and transform that into machine code targeted at the current running architecture. Essentially the compiled binaries that the .NET platform creates has the capability to run on different physical architectures and operating systems. Examples of these architectures are (x86, x86_64, ARM, ARM64).

Decompilation

There are various programs out there that let you decompile .NET assemblies which are both commercial and non-commercial. We will be using one that I’ve found which provides the best output and has powerful capabilities such as debugging.

dnSpy

dnSpy is a .NET debugger and assembly editor which lets you modify and decompile assemblies. You can find the latest version via the official GitHub repo.

Unlike other CLI decompilers dnSpy provides us with a nice user interface that mirrors that of Visual Studio.

Lets start with a simple .NET Console Application as example.

The above application will ask you to enter two passphrases. If the expected inputs are correct it will execute the function ProcessRequest() The passphrases for this example are dotnetdecompile and cihansol.com and are checked using a simple CRC32 hash calculation.

For demonstration I’ve compiled the app targeting .NET Core 3.1. The output directory contains various files, the one we are interested in is Sample Application.dll You may be wondering what the exe file is for. This gets generated because the platform targeted in this demo is Windows. This file is just a shim executable that serves the purpose to load our compiled CIL code inside of the DLL binary.

Decompiling

To decompile the compiled application with dnSpy it is as simple as dragging and dropping the file into the Graphical User Interface (GUI). Once loaded you can now begin to explore, analyze and debug the Portable Executable (PE) file that contains our application code. You can see that it automatically generates the correct C# source code with the same variable names and function names intact. There is a dropdown option (IL) which shows you the actual CIL code along with an option to output as Visual Basic if desired. There is other functionality provided as well which includes being able to explore/extract resources. For example, if you have an old legacy application which contains an embedded database resource file that you require because you have lost the source code or repository you can extract and recover that with dnSpy.

It’s also worth pointing out that there is a difference in the source code from an optimization point of view. Comparing the two might be useful if you are looking to see what the compiler has done with the code you have written and may in some cases help you write more efficient code.

Our written source code
dnSpy’s generated source code

Modifying

Firstly the input is captured for passphrase A and B. This is then passed through the check function CheckInputPP(). This function will then calculate the CRC32 hash for the input string comparing it to one of the hardcoded hashes keyAHash,keyBHash.  If the newly calculated passphrase hashes match the stored ones ProcessRequest() will be called to indicate we have passed this check. This is a very basic authentication example but I am sure you could think of more advance scenarios.

Above is a graph view of the application’s control flow along with the IL instructions generated by the compiler.

Now if we are in a situation where we don’t know the Passphrases the sample application is asking for so we can go in and modify the behavior to circumvent this check. This can be done by editing the method CheckInputPP() by right clicking and selecting Edit Method (C#).

We then can just return true from that function by editing the source code. This way there will be no hash check preformed and the result will always be true.

Once done you can hit Compile and save the edited assembly by going to File -> Save Module

A popup window will show with various modification options. What we want to do is make sure the Preserve Heap Offsets checkboxes are ticked and go ahead and press OK.

Now when we go to run the application you can see that no matter our input we get the desired outcome effectively bypassing that check.

This was a very basic text book example of modification. There can be more steps involved when dealing with larger code bases and sophisticated libraries but the general procedure is the same.

Protection

So far I’ve shown you how to decompile and modify a built .NET Core application. You might now be wondering, what is stopping someone from decompiling my application potentially comprising it’s security or stealing my source code? Firstly, it comes down to following best practice approaches like not storing connection strings, passwords, secret keys for sensitive resources in your application. That being said there are also other solutions such as obfuscating your code so it is harder for someone nefarious to dissect and decipher what is going on.

To briefly demonstrate this I will be using an obfuscator on our sample application called ConfuserEx. It has various protection mechanisms that you can enable once you load your .NET assembly, these including anti-debug and variable name scrambling.

Here is a screenshot of the same sample application we loaded previously into dnSpy however, this time it has been processed through ConfuserEx. You can observe that all the variables and functions have been obfuscated and jumbled making it very hard to figure out what is going on.

Code obfuscation is a fairly extensive topic. I will dive deeper into this subject in future blog posts explaining the implications in regards to performance, along with when not to use it challenging yourself into thinking. Is this the right approach?

Conclusion

Hopefully by now you have a better understanding of how the .NET platform works using the CLR to run your code cross platform and the disadvantages that brings in terms of code security. I’ve shown you how easy it can be to decompile and modify a built .NET application along with some solutions for code obscurity. The process I have discussed in this write up is significant to developers who want a better understanding of what is involved with creating applications on the .NET platform. Hence, this highlights the importance of keeping sensitive information out of client applications or utilize tools such as Azure KeyVault to protect keys & secrets.

For my next blog post I will walk through unpacking Xamarin mobile apps for code review and the process involved in extracting the compiled .NET assemblies.

Resources & Further Reading

Uncovering HP’s Potentially Unwanted Applications

Reading Time: 6 minutes

Background

I’m sure everyone reading this blog post has had experience with Potentially Unwanted Applications (PUA) or Potentially Unwanted Programs (PUP). You might have recently purchased a new laptop or PC and found that there are applications on it preinstalled that are annoying and unwanted. It really is a subjective topic, as one person might find these programs useful but another might find them irritating and classify them as bloatware. I’ve recently got a new HP laptop that came with various pre-installed OEM software. Some of them are useful like the recovery tools that allow OS reinstalls however I’m not a fan of the analytics and telemetry data that gets sent back without the users consent or in some cases is an opt-out feature. Most of them either don’t provide much value to the end user or just get in the way and are bothersome.

Introduction

The software or applications that are the most troubling are the ones that can not be removed. In this blog post I’m going to talk about one in particular that I noticed deployed by HP called Dynamic Audio. I will be walking through an in depth analysis using various programs and tools that I’ve picked up on over the years investigating how applications on windows function.

HP Dynamic Audio

HP Dynamic Audio is supposedly a new AI-based audio experience that tunes output to speech while suppressing background noise. The first thing I noticed is that it pre-installs itself into your Google Chrome browser and it is visible from the sidebar menu. You can see it says “Managed by your organization”

Google Chrome Managed
Google Chrome browser is managed by your organization

Clicking that button brings you to the management window inside of Google Chrome. Here you can see that HP has taken advantage of this functionality to force install the extension called HP Dynamic Audio. Now there is no way available to the end user to remove this extension from the UI and there are a few steps involved I will explain later including a script I wrote to do it. You can also take note of the permissions granted which allows this extension to read data on a number of websites.

dynamic audio chrome

Looking further into the extension we can see the websites it has access to and once again since the browser is in a managed state there is no option to turn this off or remove it from inside Chrome. This to me is unacceptable no matter what the software is. As an end user that owns a device you should have the right to remove or disable software like this especially if it has access to your data.

chrome extension hp dynamic audio

Removal Attempt

My first attempt to remove this from Google Chrome was to reinstall the browser. Since Chrome has the ability to synchronize settings this wasn’t a big issue for me. However, after a reboot it was back! So I decided to do a bit of googling and found many others in despair.

hp community post 1

hp community post 2

A simple reinstall and reboot wasn’t going to cut it. I needed to dive deeper into how and what was causing this extension to be force installed.

A deep dive

Google’s own documentation explains how to use the group policy system to enable the auto install of extensions for the use by organisations. This feature is used to enforce policies on there devices. There wasn’t adequate information in the documentation until I found a help centre article on how to stop the Chrome browser from being managed.

It was evident that whatever application/service/driver HP had installed, was writing to the registry key:

HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome\ExtensionInstallForcelist

We can see that there is an entry in that key 317 with a value of jjnlfodbdchgijlheopgehgnmekbndmf Looking at extension Id inside of Chrome we can see it matches and this is in fact the entry for ‘HP Dynamic Audio’.

registry key hp

Removing this registry entry wouldn’t fix the problem as it will get repopulated upon reboot. So there must been an application running that is writing to this address. In order to uncover this I used a program called Process Monitor by Mark Russinovich. I’ve used this tool in the past to analyse the behaviour of certain malware to see their affects on the OS. It allows you to monitor API calls and events that occur on Windows and for this case it was perfect.

Searching for that specific registry key path it uncovered a process called SECOMN64 which was accessing and creating key entries. Bingo we got something now!

Process Monitor

One of the benefits and great functionality of this tool is it allows you to see the stack at the time of the API call.

stack trace

Here we can see the SECOMN64 executable calling into the KernelBase library querying the RegCreateKeyExW WINAPI. We can follow the stack lower into the Windows Kernel but there is no need.

Now that we have the file path to SECOMN64.exe we can throw it into a dissembler and reverse engineer what is going on.

Interactive Dissembler (IDA)

The Interactive Disassembler (IDA) is a reverse engineering tool that can be used to dissect executables. It has a powerful dissembler that can take machine processer instructions and generate pseudo readable source code for you to understand and reverse engineer application functionality.

Looking at the strings inside the executable you can see there is the same extension id that we found in the registry key. There are also other strings there which indicate that there is some functionality to classify websites the user is currently on and also one called YoutubeCategoryClassifications which is interesting.

There is also some amusing debug error entries about force install failing.

Cross-referencing the string for the extension Id we can find the function responsible for its creation. Alternatively using the stack trace we can find the location of the exact call by offsetting from the loaded image base. To find or change that is via the Edit -> Segments -> Rebase program.

 

The PE Image executable inside of IDA was loaded at 0x140000000 therefore we simple add the offset shown in the stack trace window.

0x140000000 + 0x5480 = 0x140005480

This will bring us to exactly where we need you can see those WinApi calls we caught with Process Monitor. RegCreateKeyEx RegSetValueExW

Hitting F5 in IDA allows us to view the x86-64 assembly in a human readable pseudo code.

We now know what process is causing the install of this extension and what it’s doing to do that utilizing the ExtensionInstallForcelist ability inside of Google Chrome.

Windows Services

Looking at the Windows Services we can find a match for that executable and it seems to be named Sound Research SECOMN Service.

At the time of writing this blog post, setting the service Startup type to Disabled and deleting the relevant registry keys in the registry seems to remove this browser extension from being force installed into Chrome. I may write a subsequent post at some point in the future if I uncover other interesting information. Something that stood out to me whilst looking at another service in the same driver bundle was that there is some activity to suggest other web browsers might be impacted in a similar way.

ida code

Conclusion

It is disappointing how manufactures go about installing PUAs onto user machines and there should always be a choice to the end user to remove or disable what they do not want on their computers. I hope this deep dive gave some insight into how you may investigate activity of applications using tools such a Process Monitor and IDA.

I have created a windows batch script that automates the process of removing the Managed state of Chrome and disabling the service responsible for persisting the extension install below.

 

 

 

References & Resources