mirror of
https://github.com/phra/PEzor
synced 2026-06-08 16:45:36 +00:00
170 lines
7.7 KiB
C#
170 lines
7.7 KiB
C#
//
|
|
// Author: B4rtik (@b4rtik)
|
|
// Project: Injector
|
|
// License: BSD 3-Clause
|
|
//
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
|
|
namespace Injector
|
|
{
|
|
public class CustomLoadLibrary
|
|
{
|
|
/// <summary>
|
|
/// Resolves LdrLoadDll and uses that function to load a DLL from disk.
|
|
/// </summary>
|
|
/// <author>Ruben Boonen (@FuzzySec)</author>
|
|
/// <param name="DLLPath">The path to the DLL on disk. Uses the LoadLibrary convention.</param>
|
|
/// <returns>IntPtr base address of the loaded module or IntPtr.Zero if the module was not loaded successfully.</returns>
|
|
public static IntPtr LoadModuleFromDisk(string DLLPath)
|
|
{
|
|
Natives.UNICODE_STRING uModuleName = new Natives.UNICODE_STRING();
|
|
Natives.RtlInitUnicodeString(ref uModuleName, DLLPath);
|
|
|
|
IntPtr hModule = IntPtr.Zero;
|
|
Natives.NTSTATUS CallResult = (Natives.NTSTATUS)Natives.LdrLoadDll(IntPtr.Zero, 0, ref uModuleName, ref hModule);
|
|
if (CallResult != Natives.NTSTATUS.Success || hModule == IntPtr.Zero)
|
|
{
|
|
return IntPtr.Zero;
|
|
}
|
|
|
|
return hModule;
|
|
}
|
|
|
|
public static IntPtr GetDllAddress(string DLLName, bool CanLoadFromDisk = false)
|
|
{
|
|
IntPtr hModule = GetLoadedModuleAddress(DLLName);
|
|
if (hModule == IntPtr.Zero && CanLoadFromDisk)
|
|
{
|
|
hModule = LoadModuleFromDisk(DLLName);
|
|
if (hModule == IntPtr.Zero)
|
|
{
|
|
throw new FileNotFoundException(DLLName + ", unable to find the specified file.");
|
|
}
|
|
}
|
|
else if (hModule == IntPtr.Zero)
|
|
{
|
|
throw new DllNotFoundException(DLLName + ", Dll was not found.");
|
|
}
|
|
|
|
return hModule;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper for getting the pointer to a function from a DLL loaded by the process.
|
|
/// </summary>
|
|
/// <author>Ruben Boonen (@FuzzySec)</author>
|
|
/// <param name="DLLName">The name of the DLL (e.g. "ntdll.dll" or "C:\Windows\System32\ntdll.dll").</param>
|
|
/// <param name="FunctionName">Name of the exported procedure.</param>
|
|
/// <param name="CanLoadFromDisk">Optional, indicates if the function can try to load the DLL from disk if it is not found in the loaded module list.</param>
|
|
/// <returns>IntPtr for the desired function.</returns>
|
|
public static IntPtr GetLibraryAddress(string DLLName, string FunctionName, bool CanLoadFromDisk = false)
|
|
{
|
|
IntPtr hModule = GetLoadedModuleAddress(DLLName);
|
|
if (hModule == IntPtr.Zero && CanLoadFromDisk)
|
|
{
|
|
hModule = LoadModuleFromDisk(DLLName);
|
|
if (hModule == IntPtr.Zero)
|
|
{
|
|
throw new FileNotFoundException(DLLName + ", unable to find the specified file.");
|
|
}
|
|
}
|
|
else if (hModule == IntPtr.Zero)
|
|
{
|
|
throw new DllNotFoundException(DLLName + ", Dll was not found.");
|
|
}
|
|
|
|
return GetExportAddress(hModule, FunctionName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper for getting the base address of a module loaded by the current process. This base address could be passed to GetProcAddress/LdrGetProcedureAddress or it could be used for manual export parsing.
|
|
/// </summary>
|
|
/// <author>Ruben Boonen (@FuzzySec)</author>
|
|
/// <param name="DLLName">The name of the DLL (e.g. "ntdll.dll").</param>
|
|
/// <returns>IntPtr base address of the loaded module or IntPtr.Zero if the module is not found.</returns>
|
|
public static IntPtr GetLoadedModuleAddress(string DLLName)
|
|
{
|
|
ProcessModuleCollection ProcModules = Process.GetCurrentProcess().Modules;
|
|
foreach (ProcessModule Mod in ProcModules)
|
|
{
|
|
if (Mod.FileName.ToLower().EndsWith(DLLName.ToLower()))
|
|
{
|
|
return Mod.BaseAddress;
|
|
}
|
|
}
|
|
|
|
return IntPtr.Zero;
|
|
}
|
|
/// <summary>
|
|
/// Given a module base address, resolve the address of a function by manually walking the module export table.
|
|
/// </summary>
|
|
/// <author>Ruben Boonen (@FuzzySec)</author>
|
|
/// <param name="ModuleBase">A pointer to the base address where the module is loaded in the current process.</param>
|
|
/// <param name="ExportName">The name of the export to search for (e.g. "NtAlertResumeThread").</param>
|
|
/// <returns>IntPtr for the desired function.</returns>
|
|
public static IntPtr GetExportAddress(IntPtr ModuleBase, string ExportName)
|
|
{
|
|
IntPtr FunctionPtr = IntPtr.Zero;
|
|
try
|
|
{
|
|
// Traverse the PE header in memory
|
|
Int32 PeHeader = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + 0x3C));
|
|
// Int16 OptHeaderSize = Marshal.ReadInt16((IntPtr)(ModuleBase.ToInt64() + PeHeader + 0x14));
|
|
Int64 OptHeader = ModuleBase.ToInt64() + PeHeader + 0x18;
|
|
Int16 Magic = Marshal.ReadInt16((IntPtr)OptHeader);
|
|
Int64 pExport = 0;
|
|
if (Magic == 0x010b)
|
|
{
|
|
pExport = OptHeader + 0x60;
|
|
}
|
|
else
|
|
{
|
|
pExport = OptHeader + 0x70;
|
|
}
|
|
|
|
// Read -> IMAGE_EXPORT_DIRECTORY
|
|
Int32 ExportRVA = Marshal.ReadInt32((IntPtr)pExport);
|
|
Int32 OrdinalBase = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x10));
|
|
// Int32 NumberOfFunctions = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x14));
|
|
Int32 NumberOfNames = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x18));
|
|
Int32 FunctionsRVA = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x1C));
|
|
Int32 NamesRVA = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x20));
|
|
Int32 OrdinalsRVA = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x24));
|
|
|
|
// Loop the array of export name RVA's
|
|
for (int i = 0; i < NumberOfNames; i++)
|
|
{
|
|
String FunctionName = Marshal.PtrToStringAnsi((IntPtr)(ModuleBase.ToInt64() + Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + NamesRVA + i * 4))));
|
|
if (FunctionName.ToLower() == ExportName.ToLower())
|
|
{
|
|
Int32 FunctionOrdinal = Marshal.ReadInt16((IntPtr)(ModuleBase.ToInt64() + OrdinalsRVA + i * 2)) + OrdinalBase;
|
|
Int32 FunctionRVA = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + FunctionsRVA + (4 * (FunctionOrdinal - OrdinalBase))));
|
|
FunctionPtr = (IntPtr)((Int64)ModuleBase + FunctionRVA);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// Catch parser failure
|
|
throw new InvalidOperationException("Failed to parse module exports.");
|
|
}
|
|
|
|
if (FunctionPtr == IntPtr.Zero)
|
|
{
|
|
// Export not found
|
|
throw new MissingMethodException(ExportName + ", export not found.");
|
|
}
|
|
return FunctionPtr;
|
|
}
|
|
}
|
|
}
|