Skip to content

Instantly share code, notes, and snippets.

@beppe9000
Forked from ultratrunks/DllInjector.cs
Created April 28, 2021 11:29
Show Gist options
  • Save beppe9000/c6a2933b63a6d137295ad5a627c6faef to your computer and use it in GitHub Desktop.
Save beppe9000/c6a2933b63a6d137295ad5a627c6faef to your computer and use it in GitHub Desktop.
Clean class in C# used for DLL injection
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace DllInjector
{
public static class DllInjector
{
#region Constants
public const int ERROR_UNHANDLED_EXCEPTION = -1;
public const int ERROR_NOT_DOS_PROGRAM = -2;
public const int ERROR_NOT_WINDOWS_PROGRAM = -3;
public const int ERROR_NO_OPTIONAL_HEADER = -4;
public const int ERROR_NO_IMPORT_TABLE = -5;
public const int ERROR_NO_IMPORT_DIRECTORY = -6;
public const int ERROR_MISMATCHED_ORDINALS = -7;
public const UInt32 INVALID_HANDLE_VALUE = 0xffffffff;
private const uint IMAGE_DOS_SIGNATURE = 0x5A4D; //MZ
private const string IMAGE_DOS_SIGNATURE_STRING = "MZ"; // MZ
private const uint IMAGE_OS2_SIGNATURE = 0x454E; // NE
private const uint IMAGE_OS2_SIGNATURE_LE = 0x454C; // LE
private const uint IMAGE_VXD_SIGNATURE = 0x454C; // LE
private const uint IMAGE_NT_SIGNATURE = 0x00004550; // PE00
private const uint IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b;
private const uint IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b;
private enum DirectoryEntries
{
IMAGE_DIRECTORY_ENTRY_EXPORT = 0, // Export Directory
IMAGE_DIRECTORY_ENTRY_IMPORT = 1, // Import Directory
IMAGE_DIRECTORY_ENTRY_RESOURCE = 2, // Resource Directory
IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3, // Exception Directory
IMAGE_DIRECTORY_ENTRY_SECURITY = 4, // Security Directory
IMAGE_DIRECTORY_ENTRY_BASERELOC = 5, // Base Relocation Table
IMAGE_DIRECTORY_ENTRY_DEBUG = 6, // Debug Directory
// IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7, // (X86 usage)
IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7, // Architecture Specific Data
IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8, // RVA of GP
IMAGE_DIRECTORY_ENTRY_TLS = 9, // TLS Directory
IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10, // Load Configuration Directory
IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11, // Bound Import Directory in headers
IMAGE_DIRECTORY_ENTRY_IAT = 12, // Import Address Table
IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13, // Delay Load Import Descriptors
IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14, // COM Runtime descriptor
} //private enum DirectoryEntries
[Flags]
public enum SnapshotFlags : uint
{
TH32CS_SNAPHEAPLIST = 0x00000001,
TH32CS_SNAPPROCESS = 0x00000002,
TH32CS_SNAPTHREAD = 0x00000004,
TH32CS_SNAPMODULE = 0x00000008,
TH32CS_SNAPMODULE32 = 0x00000010,
TH32CS_SNAPALL = (TH32CS_SNAPHEAPLIST | TH32CS_SNAPMODULE | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD),
TH32CS_INHERIT = 0x80000000,
NoHeaps = 0x40000000
}
[Flags]
public enum ProcessAccessFlags : uint
{
PROCESS_ALL_ACCESS = 0x001F0FFF,
PROCESS_TERMINATE = 0x00000001,
PROCESS_CREATE_THREAD = 0x00000002,
PROCESS_VM_OPERATION = 0x00000008,
PROCESS_VM_READ = 0x00000010,
PROCESS_VM_WRITE = 0x00000020,
PROCESS_DUP_HANDLE = 0x00000040,
PROCESS_CREATE_PROCESS = 0x000000080,
PROCESS_SET_QUOTA = 0x00000100,
PROCESS_SET_INFORMATION = 0x00000200,
PROCESS_QUERY_INFORMATION = 0x00000400,
PROCESS_QUERY_LIMITED_INFORMATION = 0x00001000,
SYNCHRONIZE = 0x00100000,
PROCESS_SUSPEND_RESUME = 0x800
}
[Flags]
public enum AllocationType
{
MEM_COMMIT = 0x1000,
MEM_RESERVE = 0x2000,
MEM_DECOMMIT = 0x4000,
MEM_RELEASE = 0x8000,
MEM_RESET = 0x80000,
MEM_PHYSICAL = 0x400000,
MEM_TOP_DOWN = 0x100000,
MEM_RESET_UNDO = 0x1000000,
MEM_WRITE_WATCH = 0x200000,
MEM_LARGE_PAGES = 0x20000000
}
[Flags]
public enum MemoryProtection
{
PAGE_EXECUTE = 0x10,
PAGE_EXECUTE_READ = 0x20,
PAGE_EXECUTE_READWRITE = 0x40,
PAGE_EXECUTE_WRITECOPY = 0x80,
PAGE_NOACCESS = 0x01,
PAGE_READONLY = 0x02,
PAGE_READWRITE = 0x04,
PAGE_WRITECOPY = 0x08,
PAGE_GUARD = 0x100,
PAGE_NOCACHE = 0x200,
PAGE_WRITECOMBINE = 0x400,
PAGE_TARGETS_INVALID = 0x40000000,
PAGE_TARGETS_NO_UPDATE = 0x40000000
}
[Flags]
public enum FreeType
{
Decommit = 0x4000,
Release = 0x8000,
}
#endregion // Constants
#region Structures
[StructLayout(LayoutKind.Sequential)]
public struct IMAGE_DOS_HEADER
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public char[] e_magic; // Magic number
public UInt16 e_cblp; // Bytes on last page of file
public UInt16 e_cp; // Pages in file
public UInt16 e_crlc; // Relocations
public UInt16 e_cparhdr; // Size of header in paragraphs
public UInt16 e_minalloc; // Minimum extra paragraphs needed
public UInt16 e_maxalloc; // Maximum extra paragraphs needed
public UInt16 e_ss; // Initial (relative) SS value
public UInt16 e_sp; // Initial SP value
public UInt16 e_csum; // Checksum
public UInt16 e_ip; // Initial IP value
public UInt16 e_cs; // Initial (relative) CS value
public UInt16 e_lfarlc; // File address of relocation table
public UInt16 e_ovno; // Overlay number
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public UInt16[] e_res1; // Reserved words
public UInt16 e_oemid; // OEM identifier (for e_oeminfo)
public UInt16 e_oeminfo; // OEM information; e_oemid specific
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public UInt16[] e_res2; // Reserved words
public Int32 e_lfanew; // File address of new exe header
public static int SizeOf { get { return Marshal.SizeOf(typeof(IMAGE_DOS_HEADER)); } }
public string e_magic_string
{
get { return new string(e_magic); }
}
public bool isValid
{
get { return e_magic_string == "MZ"; }
}
}
[StructLayout(LayoutKind.Sequential)]
public struct IMAGE_DATA_DIRECTORY
{
public UInt32 VirtualAddress;
public UInt32 Size;
}
[StructLayout(LayoutKind.Sequential)]
public struct IMAGE_FILE_HEADER
{
public UInt16 Machine;
public UInt16 NumberOfSections;
public UInt32 TimeDateStamp;
public UInt32 PointerToSymbolTable;
public UInt32 NumberOfSymbols;
public UInt16 SizeOfOptionalHeader;
public UInt16 Characteristics;
}
[StructLayout(LayoutKind.Sequential)]
public struct IMAGE_OPTIONAL_HEADER32
{
public UInt16 Magic;
public Byte MajorLinkerVersion;
public Byte MinorLinkerVersion;
public UInt32 SizeOfCode;
public UInt32 SizeOfInitializedData;
public UInt32 SizeOfUninitializedData;
public UInt32 AddressOfEntryPoint;
public UInt32 BaseOfCode;
public UInt32 BaseOfData;
public UInt32 ImageBase;
public UInt32 SectionAlignment;
public UInt32 FileAlignment;
public UInt16 MajorOperatingSystemVersion;
public UInt16 MinorOperatingSystemVersion;
public UInt16 MajorImageVersion;
public UInt16 MinorImageVersion;
public UInt16 MajorSubsystemVersion;
public UInt16 MinorSubsystemVersion;
public UInt32 Win32VersionValue;
public UInt32 SizeOfImage;
public UInt32 SizeOfHeaders;
public UInt32 CheckSum;
public UInt16 Subsystem;
public UInt16 DllCharacteristics;
public UInt32 SizeOfStackReserve;
public UInt32 SizeOfStackCommit;
public UInt32 SizeOfHeapReserve;
public UInt32 SizeOfHeapCommit;
public UInt32 LoaderFlags;
public UInt32 NumberOfRvaAndSizes;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public IMAGE_DATA_DIRECTORY[] DataDirectory;
}
[StructLayout(LayoutKind.Sequential)]
public struct IMAGE_OPTIONAL_HEADER64
{
public UInt16 Magic;
public Byte MajorLinkerVersion;
public Byte MinorLinkerVersion;
public UInt32 SizeOfCode;
public UInt32 SizeOfInitializedData;
public UInt32 SizeOfUninitializedData;
public UInt32 AddressOfEntryPoint;
public UInt32 BaseOfCode;
public UInt64 ImageBase;
public UInt32 SectionAlignment;
public UInt32 FileAlignment;
public UInt16 MajorOperatingSystemVersion;
public UInt16 MinorOperatingSystemVersion;
public UInt16 MajorImageVersion;
public UInt16 MinorImageVersion;
public UInt16 MajorSubsystemVersion;
public UInt16 MinorSubsystemVersion;
public UInt32 Win32VersionValue;
public UInt32 SizeOfImage;
public UInt32 SizeOfHeaders;
public UInt32 CheckSum;
public UInt16 Subsystem;
public UInt16 DllCharacteristics;
public UInt64 SizeOfStackReserve;
public UInt64 SizeOfStackCommit;
public UInt64 SizeOfHeapReserve;
public UInt64 SizeOfHeapCommit;
public UInt32 LoaderFlags;
public UInt32 NumberOfRvaAndSizes;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public IMAGE_DATA_DIRECTORY[] DataDirectory;
}
[StructLayout(LayoutKind.Sequential)]
public struct IMAGE_NT_HEADERS32
{
public UInt32 Signature;
public IMAGE_FILE_HEADER FileHeader;
public IMAGE_OPTIONAL_HEADER32 OptionalHeader32;
public static int SizeOf = Marshal.SizeOf(typeof(IMAGE_NT_HEADERS32));
}
[StructLayout(LayoutKind.Sequential)]
public struct IMAGE_NT_HEADERS64
{
public static int SizeOf = Marshal.SizeOf(typeof(IMAGE_NT_HEADERS64));
public UInt32 Signature;
public IMAGE_FILE_HEADER FileHeader;
public IMAGE_OPTIONAL_HEADER64 OptionalHeader64;
}
[StructLayout(LayoutKind.Sequential)]
public struct IMAGE_EXPORT_DIRECTORY
{
public UInt32 Characteristics;
public UInt32 TimeDateStamp;
public UInt16 MajorVersion;
public UInt16 MinorVersion;
public UInt32 Name;
public UInt32 Base;
public UInt32 NumberOfFunctions;
public UInt32 NumberOfNames;
public UInt32 AddressOfFunctions; // RVA from base of image
public UInt32 AddressOfNames; // RVA from base of image
public UInt32 AddressOfNameOrdinals; // RVA from base of image
public static int SizeOf = Marshal.SizeOf(typeof(IMAGE_EXPORT_DIRECTORY));
}
public struct MODULEENTRY32
{ //http://pastebin.com/BzD1jdmH
private const int MAX_PATH = 255;
internal uint dwSize;
internal uint th32ModuleID;
internal uint th32ProcessID;
internal uint GlblcntUsage;
internal uint ProccntUsage;
internal IntPtr modBaseAddr;
internal uint modBaseSize;
internal IntPtr hModule;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH + 1)]
internal string szModule;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH + 5)]
internal string szExePath;
}
#endregion // Structures
#region DllImports
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
private static extern bool ReadProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
out IMAGE_DOS_HEADER lpBuffer,
int nSize,
IntPtr lpNumberOfBytesRead
);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
private static extern bool ReadProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
out IMAGE_NT_HEADERS32 lpBuffer,
int nSize,
IntPtr lpNumberOfBytesRead
);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
private static extern bool ReadProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
out IMAGE_NT_HEADERS64 lpBuffer,
int nSize,
IntPtr lpNumberOfBytesRead
);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
private static extern bool ReadProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
out IMAGE_EXPORT_DIRECTORY lpBuffer,
int nSize,
IntPtr lpNumberOfBytesRead
);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
private static extern bool ReadProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
[Out] byte[] lpBuffer,
int nSize,
IntPtr lpNumberOfBytesRead
);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
private static extern bool ReadProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
[Out] ushort[] lpBuffer,
int nSize,
IntPtr lpNumberOfBytesRead
);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
private static extern bool ReadProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
[Out] uint[] lpBuffer,
int nSize,
IntPtr lpNumberOfBytesRead
);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseHandle(
IntPtr hObject
);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr CreateToolhelp32Snapshot(
SnapshotFlags dwFlags,
uint th32ProcessID
);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool Module32First(
IntPtr hSnapshot,
ref MODULEENTRY32 lpme
);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool Module32Next(
IntPtr hSnapshot,
ref MODULEENTRY32 lpme
);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess(
ProcessAccessFlags processAccess,
bool bInheritHandle,
uint processId
);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
public static extern IntPtr VirtualAllocEx(
IntPtr hProcess,
IntPtr lpAddress,
uint dwSize,
AllocationType flAllocationType,
MemoryProtection flProtect
);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
public static extern bool VirtualFreeEx(
IntPtr hProcess,
IntPtr lpAddress,
int dwSize,
FreeType dwFreeType
);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool WriteProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
byte[] lpBuffer,
int nSize,
out IntPtr lpNumberOfBytesWritten);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr CreateRemoteThread(
IntPtr hProcess,
IntPtr lpThreadAttributes,
uint dwStackSize,
IntPtr lpStartAddress,
IntPtr lpParameter,
uint dwCreationFlags,
out IntPtr lpThreadId
);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern UInt32 WaitForSingleObject(
IntPtr hHandle,
UInt32 dwMilliseconds
);
#endregion // DllImports
/// <summary>
/// Given a ProccesID, this routine will return the base address of the module specified by moduleName.
/// </summary>
/// <param name="processID"></param>
/// <param name="moduleName"></param>
/// <param name="errorCode"></param>
/// <returns>Returns NULL on failure.</returns>
public static IntPtr? GetProcessModuleHandle(uint processID, string moduleName, out int errorCode)
{
errorCode = 0;
IntPtr hSnapShot = IntPtr.Zero;
moduleName = moduleName.ToLower(); /// Process/Module names are not case sensitive.
try
{
/// Getting snapshot of current running processes so we can search through thier loaded modules.
hSnapShot = CreateToolhelp32Snapshot(SnapshotFlags.TH32CS_SNAPMODULE | SnapshotFlags.TH32CS_SNAPMODULE32, processID);
if ((uint)hSnapShot == INVALID_HANDLE_VALUE)
{
errorCode = Marshal.GetLastWin32Error();
return null;
}
/// Creating space to hold our MODULEENTRY32 structure
MODULEENTRY32 mod = new MODULEENTRY32() { dwSize = (uint)Marshal.SizeOf(typeof(MODULEENTRY32)) };
/// Retrieving the first module out of our snap shot.
if (!Module32First(hSnapShot, ref mod))
{
errorCode = Marshal.GetLastWin32Error();
return null;
}
do
{
if (mod.szModule.ToLower() == moduleName)
{
return mod.modBaseAddr;
}
}
while (Module32Next(hSnapShot, ref mod));
/// Did not find the module in the specified process.
return IntPtr.Zero;
}
catch
{
errorCode = ERROR_UNHANDLED_EXCEPTION;
return null;
}
finally
{
if (hSnapShot != IntPtr.Zero)
{
CloseHandle(hSnapShot);
}
}
}
public static IntPtr? GetProcessProcAddress(IntPtr hProcess, uint processID, string moduleName, string procName, out int errorCode)
{
errorCode = 0;
try
{
/// Get handle to the Kernel32.dll library thats located inside the process specified by ProcessID
IntPtr? ret = GetProcessModuleHandle((uint)processID, "Kernel32.dll", out errorCode);
if (ret == null) { return null; }
IntPtr hKernel32 = (IntPtr)ret;
/// Retrieving the dos header of our Kernel32 library module inside of the process indicated by hProcess
IMAGE_DOS_HEADER dos_header;
if (!ReadProcessMemory(hProcess, hKernel32, out dos_header, IMAGE_DOS_HEADER.SizeOf, IntPtr.Zero))
{
errorCode = Marshal.GetLastWin32Error();
return null;
}
/// checking to make sure this is a DOS program
if (dos_header.e_magic_string != IMAGE_DOS_SIGNATURE_STRING)
{
errorCode = ERROR_NOT_DOS_PROGRAM;
return null;
}
//parse nt header
IntPtr nt_header_ptr = new IntPtr(dos_header.e_lfanew + hKernel32.ToInt32());
IMAGE_DATA_DIRECTORY[] DataDirectory;
if (IntPtr.Size == 4)
{
/// this is block is for 32-bit Architectures.
IMAGE_NT_HEADERS32 nt_header;
if (!ReadProcessMemory(hProcess, nt_header_ptr, out nt_header, IMAGE_NT_HEADERS32.SizeOf, IntPtr.Zero))
{
errorCode = Marshal.GetLastWin32Error();
return null;
}
/// Checking to make sure this is a windows program
if (nt_header.Signature != IMAGE_NT_SIGNATURE)
{
errorCode = ERROR_NOT_WINDOWS_PROGRAM;
return null;
}
//optional header (pretty much not optional)
if (nt_header.OptionalHeader32.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
{
errorCode = ERROR_NO_OPTIONAL_HEADER;
return null;
}
DataDirectory = nt_header.OptionalHeader32.DataDirectory;
}
else
{
/// this is block is for 64-bit Architectures.
IMAGE_NT_HEADERS64 nt_header;
if (!ReadProcessMemory(hProcess, nt_header_ptr, out nt_header, IMAGE_NT_HEADERS64.SizeOf, IntPtr.Zero))
{
errorCode = Marshal.GetLastWin32Error();
return null;
}
/// Checking to make sure this is a windows program
if (nt_header.Signature != IMAGE_NT_SIGNATURE)
{
errorCode = ERROR_NOT_WINDOWS_PROGRAM;
return null;
}
//optional header (pretty much not optional)
if (nt_header.OptionalHeader64.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC)
{
errorCode = ERROR_NO_OPTIONAL_HEADER;
return null;
}
DataDirectory = nt_header.OptionalHeader64.DataDirectory;
}
IMAGE_DATA_DIRECTORY EntryExport = DataDirectory[(int)DirectoryEntries.IMAGE_DIRECTORY_ENTRY_EXPORT];
if (EntryExport.Size == 0)
{
errorCode = ERROR_NO_IMPORT_TABLE;
return null; //no import table
}
if (EntryExport.VirtualAddress == 0)
{
errorCode = ERROR_NO_IMPORT_DIRECTORY;
return null; //no import directory
}
IntPtr pExports_ptr = new IntPtr(EntryExport.VirtualAddress + hKernel32.ToInt32());
IMAGE_EXPORT_DIRECTORY pExports;
if (!ReadProcessMemory(hProcess, pExports_ptr, out pExports, IMAGE_EXPORT_DIRECTORY.SizeOf, IntPtr.Zero))
{
errorCode = Marshal.GetLastWin32Error();
return null;
}
IntPtr functions_ptr = new IntPtr(hKernel32.ToInt32() + pExports.AddressOfFunctions);
IntPtr ordinals_ptr = new IntPtr(hKernel32.ToInt32() + pExports.AddressOfNameOrdinals);
IntPtr names_ptr = new IntPtr(hKernel32.ToInt32() + pExports.AddressOfNames);
uint[] functions = new uint[pExports.NumberOfFunctions];
if (!ReadProcessMemory(hProcess, functions_ptr, functions, (int)pExports.NumberOfFunctions * sizeof(uint), IntPtr.Zero))
{
errorCode = Marshal.GetLastWin32Error();
return null;
}
ushort[] ordinals = new ushort[pExports.NumberOfNames];
if (!ReadProcessMemory(hProcess, ordinals_ptr, ordinals, (int)pExports.NumberOfNames * sizeof(ushort), IntPtr.Zero))
{
errorCode = Marshal.GetLastWin32Error();
return null;
}
uint[] names = new uint[pExports.NumberOfNames];
if (!ReadProcessMemory(hProcess, names_ptr, names, (int)pExports.NumberOfNames * sizeof(uint), IntPtr.Zero))
{
errorCode = Marshal.GetLastWin32Error();
return null;
}
for (uint i = 0; i < ordinals.Length; i++)
{
uint ord = ordinals[i];
if (i >= pExports.NumberOfNames || ord >= pExports.NumberOfFunctions)
{
errorCode = ERROR_MISMATCHED_ORDINALS;
return null; // Mismatched ordinals
}
if (functions[ord] < EntryExport.VirtualAddress || functions[ord] >= EntryExport.VirtualAddress + EntryExport.Size)
{
IntPtr name_ptr = new IntPtr(hKernel32.ToInt32() + names[i]);
if (name_ptr != IntPtr.Zero)
{
byte[] name_buf = new byte[procName.Length + 1]; // +1 for terminating null '\0'
if (!ReadProcessMemory(hProcess, name_ptr, name_buf, name_buf.Length, IntPtr.Zero))
{
continue;
}
if (name_buf[name_buf.Length - 1] == 0) //check for partial name that does not end with terminating zero
{
string name = Encoding.ASCII.GetString(name_buf, 0, name_buf.Length - 1); //NB! buf length - 1
if (name == procName)
{
IntPtr pFunctionAddress = new IntPtr(hKernel32.ToInt32() + functions[ord]);
return pFunctionAddress;
}
}
}
}
}
return IntPtr.Zero;
}
catch
{
errorCode = ERROR_UNHANDLED_EXCEPTION;
return null;
}
}
public static bool InjectDll(uint processID, string dllPath, out int errorCode, uint DllExitWaitTime = 5000)
{
errorCode = 0;
IntPtr hProcess = IntPtr.Zero;
IntPtr hDllPathArg = IntPtr.Zero;
IntPtr hRemoteThread = IntPtr.Zero;
try
{
/// Get handle to the process identified by processID
hProcess = OpenProcess(ProcessAccessFlags.PROCESS_ALL_ACCESS, false, processID);
/// Error checking
if (hProcess == IntPtr.Zero) { errorCode = Marshal.GetLastWin32Error(); return false; }
/// Get Address of the LoadLibrary routine withint the process identified by processID
IntPtr? ret = GetProcessProcAddress(hProcess, processID, "Kernel32.dll", "LoadLibraryA", out errorCode);
if (ret == null) { return false; }
IntPtr hLoadLibrary = (IntPtr)ret;
/// Allocate some memory in the remote process to store the dllPath string argument.
hDllPathArg = VirtualAllocEx(
hProcess,
IntPtr.Zero,
(uint)(dllPath.Length + 1),
AllocationType.MEM_COMMIT,
MemoryProtection.PAGE_READWRITE
);
/// Error checking
if (hDllPathArg == IntPtr.Zero) { errorCode = Marshal.GetLastWin32Error(); return false; }
// write dll file path argument into remote process's memory space
IntPtr bytesWritten;
bool isSucceeded = WriteProcessMemory(
hProcess,
hDllPathArg,
ASCIIEncoding.ASCII.GetBytes(dllPath),
dllPath.Length + 1,
out bytesWritten
);
/// Error checking
if (!isSucceeded) { errorCode = Marshal.GetLastWin32Error(); return false; }
// invoke the LoadLibrary method in the remote process.
IntPtr dwThreadId;
hRemoteThread = CreateRemoteThread(hProcess, IntPtr.Zero, 0, hLoadLibrary, hDllPathArg, 0, out dwThreadId);
/// Error checking
if (hRemoteThread == IntPtr.Zero) { errorCode = Marshal.GetLastWin32Error(); return false; }
/// Waiting for thread to exit.
if (DllExitWaitTime > 0)
{
uint result = WaitForSingleObject(hRemoteThread, DllExitWaitTime);
}
return true;
}
catch
{
errorCode = ERROR_UNHANDLED_EXCEPTION;
return false;
}
finally
{
bool retBool;
if (hProcess != IntPtr.Zero)
{
if (hDllPathArg != IntPtr.Zero)
{
retBool = VirtualFreeEx(hProcess, hDllPathArg, 0, FreeType.Release);
}
retBool = CloseHandle(hProcess);
}
if (hRemoteThread != IntPtr.Zero)
{
retBool = CloseHandle(hRemoteThread);
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment