Package: dumpulator
dumpulatorNote: This is a work-in-progress prototype, please treat it as such. Pull requests are welcome! You can get your feet wet withgood first issuesAn easy-to-use library for emulating code in minidump files. Here are some links to posts/videos using dumpulator:Introduction video withOALabs:Dumpulator - Using Binary Emulation To Automate Reverse EngineeringEmulating malware with DumpulatorEmotet x64 Stack Strings Config Emulation | OALabs ResearchNative function and Assembly Code InvocationGuloader string decryption (VEH)Rhadamanthys | OALabs Research[Case study] Decrypt strings using DumpulatorFeel free to send a pull request to add your article here!ExamplesCalling a functionThe example below opensStringEncryptionFun_x64.dmp(download a copyhere), allocates some memory and calls the decryption function at0x140001000to decrypt the string at0x140017000:fromdumpulatorimportDumpulatordp=Dumpulator("StringEncryptionFun_x64.dmp")temp_addr=dp.allocate(256)dp.call(0x140001000,[temp_addr,0x140017000])decrypted=dp.read_str(temp_addr)print(f"decrypted: '{decrypted}'")TheStringEncryptionFun_x64.dmpis collected at the entry point of thetests/StringEncryptionFunexample. You can get the compiled binaries forStringEncryptionFunhereTracing executionfromdumpulatorimportDumpulatordp=Dumpulator("StringEncryptionFun_x64.dmp",trace=True)dp.start(dp.regs.rip)This will createStringEncryptionFun_x64.dmp.tracewith a list of instructions executed and some helpful indications when switching modules etc. Note that tracingsignificantlyslows down emulation and it's mostly meant for debugging.Reading utf-16 stringsfromdumpulatorimportDumpulatordp=Dumpulator("my.dmp")buf=dp.call(0x140001000)dp.read_str(buf,encoding='utf-16')Running a snippet of codeSay you have the following function:00007FFFC81C06C0 | mov qword ptr [rsp+0x10],rbx       ; prolog_start
00007FFFC81C06C5 | mov qword ptr [rsp+0x18],rsi
00007FFFC81C06CA | push rbp
00007FFFC81C06CB | push rdi
00007FFFC81C06CC | push r14
00007FFFC81C06CE | lea rbp,qword ptr [rsp-0x100]
00007FFFC81C06D6 | sub rsp,0x200                      ; prolog_end
00007FFFC81C06DD | mov rax,qword ptr [0x7FFFC8272510]You only want to execute the prolog and set up some registers:fromdumpulatorimportDumpulatorprolog_start=0x00007FFFC81C06C0# we want to stop the instruction after the prologprolog_end=0x00007FFFC81C06D6+7dp=Dumpulator("my.dmp",quiet=True)dp.regs.rcx=0x1337dp.start(begin=prolog_start,end=prolog_end)print(f"rsp:{hex(dp.regs.rsp)}")Thequietflag suppresses the logs about DLLs loaded and memory regions set up (for use in scripts where you want to reduce log spam).Custom syscall implementationYou can (re)implement syscalls by using the@syscalldecorator:fromdumpulatorimport*fromdumpulator.nativeimport*fromdumpulator.handlesimport*fromdumpulator.memoryimport*@syscalldefZwQueryVolumeInformationFile(dp:Dumpulator,FileHandle:HANDLE,IoStatusBlock:P[IO_STATUS_BLOCK],FsInformation:PVOID,Length:ULONG,FsInformationClass:FSINFOCLASS):returnSTATUS_NOT_IMPLEMENTEDAll the syscall function prototypes can be found inntsyscalls.py. There are also a lot of examples  there on how to use the API.To hook an existing syscall implementation you can do the following:importdumpulator.ntsyscallsasntsyscalls@syscalldefZwOpenProcess(dp:Dumpulator,ProcessHandle:Annotated[P[HANDLE],SAL("_Out_")],DesiredAccess:Annotated[ACCESS_MASK,SAL("_In_")],ObjectAttributes:Annotated[P[OBJECT_ATTRIBUTES],SAL("_In_")],ClientId:Annotated[P[CLIENT_ID],SAL("_In_opt_")]):process_id=ClientId.read_ptr()assertprocess_id==dp.parent_process_idProcessHandle.write_ptr(0x1337)returnSTATUS_SUCCESS@syscalldefZwQueryInformationProcess(dp:Dumpulator,ProcessHandle:Annotated[HANDLE,SAL("_In_")],ProcessInformationClass:Annotated[PROCESSINFOCLASS,SAL("_In_")],ProcessInformation:Annotated[PVOID,SAL("_Out_writes_bytes_(ProcessInformationLength)")],ProcessInformationLength:Annotated[ULONG,SAL("_In_")],ReturnLength:Annotated[P[ULONG],SAL("_Out_opt_")]):ifProcessInformationClass==PROCESSINFOCLASS.ProcessImageFileNameWin32:ifProcessHandle==dp.NtCurrentProcess():main_module=dp.modules[dp.modules.main]image_path=main_module.pathelifProcessHandle==0x1337:image_path=R"C:\Windows\explorer.exe"else:raiseNotImplementedError()buffer=UNICODE_STRING.create_buffer(image_path,ProcessInformation)assertProcessInformationLength>=len(buffer)ifReturnLength.ptr:dp.write_ulong(ReturnLength.ptr,len(buffer))ProcessInformation.write(buffer)returnSTATUS_SUCCESSreturnntsyscalls.ZwQueryInformationProcess(dp,ProcessHandle,ProcessInformationClass,ProcessInformation,ProcessInformationLength,ReturnLength)Custom structuresSincev0.2.0there is support for easily declaring your own structures:fromdumpulator.nativeimport*classPROCESS_BASIC_INFORMATION(Struct):ExitStatus:ULONGPebBaseAddress:PVOIDAffinityMask:KAFFINITYBasePriority:KPRIORITYUniqueProcessId:ULONG_PTRInheritedFromUniqueProcessId:ULONG_PTRTo instantiate these structures you have to use aDumpulatorinstance:pbi=PROCESS_BASIC_INFORMATION(dp)assertProcessInformationLength==Struct.sizeof(pbi)pbi.ExitStatus=259# STILL_ACTIVEpbi.PebBaseAddress=dp.pebpbi.AffinityMask=0xFFFFpbi.BasePriority=8pbi.UniqueProcessId=dp.process_idpbi.InheritedFromUniqueProcessId=dp.parent_process_idProcessInformation.write(bytes(pbi))ifReturnLength.ptr:dp.write_ulong(ReturnLength.ptr,Struct.sizeof(pbi))returnSTATUS_SUCCESSIf you pass a pointer value as a second argument the structure will be read from memory. You can declare pointers withmyptr: P[MY_STRUCT]and dereferences them withmyptr[0].Collecting the dumpThere is a simplex64dbgplugin available calledMiniDumpPluginTheminidumpcommand has been integrated into x64dbg since 2022-10-10. To create a dump, pause execution and execute the commandMiniDump my.dmp.InstallationFromPyPI(latestrelease):python -m pip install dumpulatorTo install from source:python setup.py installInstall for a development environment:python setup.py developRelated workDumpulator-IDA: This project is a small POC plugin for launching dumpulator emulation within IDA, passing it addresses from your IDA view using the context menu.wtf: Distributed, code-coverage guided, customizable, cross-platform snapshot-based fuzzer designed for attacking user and / or kernel-mode targets running on Microsoft Windowsspeakeasy: Windows sandbox on top of unicorn.qiling: Binary emulation framework on top of unicorn.Simpleator: User-mode application emulator based on the Hyper-V Platform API.What sets dumpulator apart from sandboxes like speakeasy and qiling is that the full process memory is available. This improves performance because you can emulate large parts of malware without ever leaving unicorn. Additionally only syscalls have to be emulated to provide a realistic Windows environment (since everything actuallyisa legitimate process environment).Creditsherrcorefor inspiring me to make thissecret clubJetBrainsfor free PyCharm license!Image by GraphiqaStockon Freepik