Getting started
Project repository with full code is accessible on GitHub
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:
- Intercept and monitor API calls.
- Modify input/output of functions as needed.
- 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
- When you call a WinAPI function, control is passed to
ntdll.dll
. -
ntdll.dll
uses a special routine likeKiFastSystemCall
to pass control to the Windows kernel. - Inside the kernel, a lookup table called the System Service Dispatch Table (SSDT) is used to locate the actual implementation of the function.
- The function executes in kernel mode.
- Once complete, control is returned back to user mode.
How DLL Injection Works
Steps to Inject a DLL
Open the Target Process:
UseOpenProcess
to get a handle to the target process with sufficient privileges.Allocate Memory in the Target Process:
CallVirtualAllocEx
to reserve space in the target process for the DLL path or custom code.Write the DLL Path:
UseWriteProcessMemory
to copy the DLL path or custom code into the allocated memory.Load the DLL:
Locate the address ofLoadLibraryA
orLoadLibraryW
usingGetProcAddress
, and then useCreateRemoteThread
to execute it in the target process. This loads the DLL into the process.Execute the DLL Code:
Once the DLL is loaded, itsDllMain
function is called by the process's loader.
What Happens After Injection
- Your DLL is loaded into the target process's address space via
LoadLibrary
. - The Windows PE loader calls your DLLβs
DllMain
entry point. - Any code in your DLL, such as hooks or logging, starts running in the context of the target process.
Full flow of this program
-
Injects a native C library into a native running process, such as
notepad.exe
. - The injected library loads the CoreCLR runtime into the target process.
- It then loads a managed C# DLL into the process's address space and calls its entry point method (
Main
). - 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
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);
}
}
}
Top comments (0)