
Динамически вызывать произвольный неуправляемый код из управляемого кода без PInvoke.
Динамическая замена PInvoke в Windows. DInvoke содержит мощные примитивы, которые можно разумно комбинировать для динамического вызова неуправляемого кода с диска или из памяти с высокой точностью. Это может использоваться для многих целей, таких как разбор PE-файлов, интеллектуальное динамическое разрешение API, динамическая загрузка PE-плагинов во время выполнения, инъекции в процессы и обход API-хуков.
Возможности:
Доклад на конференции (Оставаясь # и внедряя скрытые методы инъекций в .NET): https://www.youtube.com/watch?v=FuxpMXTgV9s
Записи в блоге:
Этот проект изначально создавался для SharpSploit (https://github.com/cobbr/SharpSploit). С разрешения автора(ов) он теперь размещён здесь как автономная библиотека и NuGet-пакет.
NuGet: https://www.nuget.org/packages/DInvoke/
В приведённом ниже примере показано, как использовать DInvoke для динамического поиска и вызова экспортируемых функций DLL.
///Author: b33f (@FuzzySec, Ruben Boonen)
using System;
using DynamicInvoke = DInvoke.DynamicInvoke;
namespace SpTestcase
{
class Program
{
static void Main(string[] args)
{
// Details
String testDetail = @"
#=================>
# Hello there!
# I find things dynamically; base
# addresses and function pointers.
#=================>
";
Console.WriteLine(testDetail);
// Get NTDLL base from the PEB
Console.WriteLine("[?] Resolve Ntdll base from the PEB..");
IntPtr hNtdll = DynamicInvoke.Generic.GetPebLdrModuleEntry("ntdll.dll");
Console.WriteLine("[>] Ntdll base address : " + string.Format("{0:X}", hNtdll.ToInt64()) + "\n");
// Search function by name
Console.WriteLine("[?] Specifying the name of a DLL (\"ntdll.dll\"), resolve a function by walking the export table in-memory..");
Console.WriteLine("[+] Search by name --> NtCommitComplete");
IntPtr pNtCommitComplete = DynamicInvoke.Generic.GetLibraryAddress("ntdll.dll", "NtCommitComplete", true);
Console.WriteLine("[>] pNtCommitComplete : " + string.Format("{0:X}", pNtCommitComplete.ToInt64()) + "\n");
Console.WriteLine("[+] Search by ordinal --> 0x260 (NtSetSystemTime)");
IntPtr pNtSetSystemTime = DynamicInvoke.Generic.GetLibraryAddress("ntdll.dll", 0x260, true);
Console.WriteLine("[>] pNtSetSystemTime : " + string.Format("{0:X}", pNtSetSystemTime.ToInt64()) + "\n");
Console.WriteLine("[+] Search by keyed hash --> 138F2374EC295F225BD918F7D8058316 (RtlAdjustPrivilege)");
Console.WriteLine("[>] Hash : HMACMD5(Key).ComputeHash(FunctionName)");
String fHash = DynamicInvoke.Generic.GetAPIHash("RtlAdjustPrivilege", 0xaabb1122);
IntPtr pRtlAdjustPrivilege = DynamicInvoke.Generic.GetLibraryAddress("ntdll.dll", fHash, 0xaabb1122);
Console.WriteLine("[>] pRtlAdjustPrivilege : " + string.Format("{0:X}", pRtlAdjustPrivilege.ToInt64()) + "\n");
// Search for function from base address of DLL
Console.WriteLine("[?] Specifying the base address of DLL in memory ({0:X}), resolve function by walking its export table...", hNtdll.ToInt64());
Console.WriteLine("[+] Search by name --> NtCommitComplete");
IntPtr pNtCommitComplete2 = DynamicInvoke.Generic.GetExportAddress(hNtdll, "NtCommitComplete");
Console.WriteLine("[>] pNtCommitComplete : " + string.Format("{0:X}", pNtCommitComplete2.ToInt64()) + "\n");
// Pause execution
Console.WriteLine("[*] Pausing execution..");
Console.ReadLine();
}
}
}
В приведённом ниже примере мы сначала вызываем OpenProcess обычным способом через PInvoke. Затем мы вызовем её несколькими способами с помощью DInvoke, чтобы продемонстрировать, что каждый механизм успешно выполняет неуправляемый код и обходит API-хуки.
///Author: TheWover
using System;
using System.Runtime.InteropServices;
using Data = DInvoke.Data;
using DynamicInvoke = DInvoke.DynamicInvoke;
using ManualMap = DInvoke.ManualMap;
namespace SpTestcase
{
class Program
{
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess(
Data.Win32.Kernel32.ProcessAccessFlags processAccess,
bool bInheritHandle,
uint processId
);
static void Main(string[] args)
{
// Details
String testDetail = @"
#=================>
# Hello there!
# I demonstrate API Hooking bypasses
# by calling OpenProcess via
# PInvoke then DInvoke.
# All handles are requested with
# PROCESS_ALL_ACCESS permissions.
#=================>
";
Console.WriteLine(testDetail);
//PID of current process.
uint id = Convert.ToUInt32(System.Diagnostics.Process.GetCurrentProcess().Id);
//Process handle
IntPtr hProc;
// Create the array for the parameters for OpenProcess
object[] paramaters =
{
Data.Win32.Kernel32.ProcessAccessFlags.PROCESS_ALL_ACCESS,
false,
id
};
// Pause execution
Console.WriteLine("[*] Pausing execution..");
Console.ReadLine();
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// Call OpenProcess using PInvoke
Console.WriteLine("[?] Call OpenProcess via PInvoke ...");
hProc = OpenProcess(Data.Win32.Kernel32.ProcessAccessFlags.PROCESS_ALL_ACCESS, false, id);
Console.WriteLine("[>] Process handle : " + string.Format("{0:X}", hProc.ToInt64()) + "\n");
// Pause execution
Console.WriteLine("[*] Pausing execution..");
Console.ReadLine();