DEV Community

Rezo
Rezo

Posted on

DLL injection of managed code into native process

Getting started

Project repository with full code is accessible on GitHub

Link

DLL injection is a powerful technique that allows us to inject custom code into a third-party process. It can be useful in various scenarios.

DLL injection is often used by malware to inject code into running processes, such as system processes like svchost.exe or explorer.exe, and execute malicious functionality within them.

Malware usually resides inside existing process and acts as parasite to be harder to detect. It can use either DLL injection or full PE injection which is much more sophisticated method.


Extending Program Functionality with DLL Injection

DLL injection isn't just for malicious purposesβ€”it can also be a legitimate tool for extending existing program functionality. For example, you can use it to develop plugins for software.

Imagine you want to log every action that happens inside a process, such as:

  • Network calls
  • File system writes

By using function hooking, you can intercept method calls within the process after injecting your DLL.

Function hooking allows you to:

  1. Intercept and monitor API calls.
  2. Modify input/output of functions as needed.
  3. Extend a process's behavior dynamically without modifying its source code.

This makes DLL injection a versatile tool for developers, researchers, and security professionals alike.

For instance:

  • Hook the WriteFile function to capture details about file writes happening inside the process.
  • Log this information for debugging, monitoring, or analysis.

How WINAPI Works

When a Windows process (PE - Portable Executable) is started by the operating system's PE loader, it loads all essential libraries required for the process into its address space.

This includes libraries such as:

  • kernel32.dll
  • ntdll.dll
  • user32.dll

Each Windows process can obtain access (HANDLE) to libraries loaded into it using the GetModuleHandle method. It can then retrieve individual methods using GetProcAddress and call them.

  • kernel32.dll: Contains higher-level functions for tasks like memory management, file handling, and threading.
  • ntdll.dll: Contains lower-level counterparts, usually prefixed with "Nt", such as NtQuerySystemInformation, which retrieves information about running processes in the operating system.

The Flow of a WinAPI Call

  1. When you call a WinAPI function, control is passed to ntdll.dll.
  2. ntdll.dll uses a special routine like KiFastSystemCall to pass control to the Windows kernel.
  3. Inside the kernel, a lookup table called the System Service Dispatch Table (SSDT) is used to locate the actual implementation of the function.
  4. The function executes in kernel mode.
  5. Once complete, control is returned back to user mode.

How DLL Injection Works

Steps to Inject a DLL

  1. Open the Target Process:

    Use OpenProcess to get a handle to the target process with sufficient privileges.

  2. Allocate Memory in the Target Process:

    Call VirtualAllocEx to reserve space in the target process for the DLL path or custom code.

  3. Write the DLL Path:

    Use WriteProcessMemory to copy the DLL path or custom code into the allocated memory.

  4. Load the DLL:

    Locate the address of LoadLibraryA or LoadLibraryW using GetProcAddress, and then use CreateRemoteThread to execute it in the target process. This loads the DLL into the process.

  5. Execute the DLL Code:

    Once the DLL is loaded, its DllMain function is called by the process's loader.


What Happens After Injection

  1. Your DLL is loaded into the target process's address space via LoadLibrary.
  2. The Windows PE loader calls your DLL’s DllMain entry point.
  3. Any code in your DLL, such as hooks or logging, starts running in the context of the target process.

Full flow of this program

  1. Injects a native C library into a native running process, such as notepad.exe.
  2. The injected library loads the CoreCLR runtime into the target process.
  3. It then loads a managed C# DLL into the process's address space and calls its entry point method (Main).
  4. The C# DLL executes within the unmanaged process and calls the MessageBox function.

This DLL outputs current process information in a MessageBox after being injected into native process, in this case notepad.

After starting injector end result looks like this

Image description

Image description

NOTES:

To run this example you can clone repository and edit source code to include correct path to CoreCLR and injected library inside source code. Right now everything is hardcoded.
Code for injected DLL:


csharp
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace InjectLib.Managed
{
    public static class InjectLibManaged
    {
        const uint MB_OK = 0x00000000;
        const uint MB_ICONFIRMATION = 0x00000040; 

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern int MessageBox(IntPtr hWnd, string text, string caption, uint type);

        public static void Main()
        {
            var proc = Process.GetCurrentProcess();
            MessageBox(
                IntPtr.Zero,
                $"Hello from Process with Id: {proc.Id}, {proc.ProcessName}",
                "Hello from injected DLL",
                MB_OK | MB_ICONFIRMATION
            );

            Thread.Sleep(50000);
        }
    }
}



Enter fullscreen mode Exit fullscreen mode

Top comments (0)