Manual mapping is a commonly used method for injecting a DLL into a target process's memory without relying on traditional LoadLibrary and CreateRemoteThread WinAPI functions. It involves performing the loading and relocation of a DLL into a target process's own memory space.
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
namespace ManualMapInjection
{
class Program
{
static void Main(string[] args)
{
Process targetProcess = Process.GetProcessesByName("processName")[0];
IntPtr hProcess = OpenProcess(ProcessAccessFlags.All, false, targetProcess.Id);
byte[] dllBytes = File.ReadAllBytes("path/to/your/dll.dll");
IntPtr allocatedMemory = VirtualAllocEx(
hProcess,
IntPtr.Zero,
(uint)dllBytes.Length,
AllocationType.Commit | AllocationType.Reserve,
MemoryProtection.ReadWrite
);
WriteProcessMemory(
hProcess,
allocatedMemory,
dllBytes,
(uint)dllBytes.Length,
out IntPtr bytesWritten
);
IntPtr loadLibraryPtr = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
IntPtr hThread = CreateRemoteThread(
hProcess,
IntPtr.Zero,
0,
loadLibraryPtr,
allocatedMemory,
0,
IntPtr.Zero
);
WaitForSingleObject(hThread, 0xFFFFFFFF);
Console.WriteLine("DLL injection successful!");
CloseHandle(hThread);
CloseHandle(allocatedMemory);
CloseHandle(hProcess);
}
[DllImport("kernel32.dll")]
static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, AllocationType flAllocationType, MemoryProtection flProtect);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out IntPtr lpNumberOfBytesWritten);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
[DllImport("kernel32.dll", SetLastError = true)]
static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr hObject);
[Flags]
public enum ProcessAccessFlags : uint
{
All = 0x001F0FFF,
Terminate = 0x00000001,
CreateThread = 0x00000002,
VMOperation = 0x00000008,
VMRead = 0x00000010,
VMWrite = 0x00000020,
DupHandle = 0x00000040,
SetInformation = 0x00000200,
QueryInformation = 0x00000400,
Synchronize = 0x00100000
}
[Flags]
public enum AllocationType
{
Commit = 0x1000,
Reserve = 0x2000,
Decommit = 0x4000,
Release = 0x8000,
Reset = 0x80000,
TopDown = 0x100000,
WriteWatch = 0x200000,
Physical = 0x400000,
LargePages = 0x20000000
}
[Flags]
public enum MemoryProtection
{
NoAccess = 0x0001,
ReadOnly = 0x02,
ReadWrite = 0x04,
WriteCopy = 0x08,
Execute = 0x10,
ExecuteRead = 0x20,
ExecuteReadWrite = 0x40,
ExecuteWriteCopy = 0x80,
Guard = 0x100,
NoCache = 0x200,
WriteCombine = 0x400
}
}
}
This code reads the contents of the DLL file into memory, then uses VirtualAllocEx to allocate memory in the target process, followed by WriteProcessMemory to copy the DLL contents into the allocated process memory. Then GetProcAddress and CreateRemoteThread are used to call LoadLibrary in the target process with the address of the allocated memory as its parameter. After WaitForSingleObject is called to wait until the thread has completed, the code exits and the injected DLL should now be loaded in the target process.