{"id":16606847,"url":"https://github.com/mrexodia/dumpulator","last_synced_at":"2025-05-15T22:12:09.246Z","repository":{"id":40595010,"uuid":"430220430","full_name":"mrexodia/dumpulator","owner":"mrexodia","description":"An easy-to-use library for emulating memory dumps. Useful for malware analysis (config extraction, unpacking) and dynamic analysis in general (sandboxing).","archived":false,"fork":false,"pushed_at":"2024-02-02T13:14:58.000Z","size":768,"stargazers_count":802,"open_issues_count":11,"forks_count":44,"subscribers_count":20,"default_branch":"main","last_synced_at":"2025-05-09T21:48:26.767Z","etag":null,"topics":["cross-platform","debugging-tools","easy-to-use","emulator","hacktoberfest","malware","malware-analysis","malware-analyzer","malware-research","minidump","python","python3","reverse-engineering","sandbox","unicorn","unpacking","windows","windows-internals","x64"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mrexodia.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["mrexodia"]}},"created_at":"2021-11-20T22:14:25.000Z","updated_at":"2025-05-07T11:40:38.000Z","dependencies_parsed_at":"2024-02-08T22:32:47.068Z","dependency_job_id":null,"html_url":"https://github.com/mrexodia/dumpulator","commit_stats":{"total_commits":237,"total_committers":7,"mean_commits":"33.857142857142854","dds":"0.26582278481012656","last_synced_commit":"5f5e4b656683fc2627dd2393d6addf935289a6f3"},"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrexodia%2Fdumpulator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrexodia%2Fdumpulator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrexodia%2Fdumpulator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrexodia%2Fdumpulator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mrexodia","download_url":"https://codeload.github.com/mrexodia/dumpulator/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254430335,"owners_count":22069909,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cross-platform","debugging-tools","easy-to-use","emulator","hacktoberfest","malware","malware-analysis","malware-analyzer","malware-research","minidump","python","python3","reverse-engineering","sandbox","unicorn","unpacking","windows","windows-internals","x64"],"created_at":"2024-10-12T01:10:29.756Z","updated_at":"2025-05-15T22:12:04.232Z","avatar_url":"https://github.com/mrexodia.png","language":"C","readme":"# dumpulator\r\n\r\n**Note: This is a work-in-progress prototype, please treat it as such. Pull requests are welcome! You can get your feet wet with [good first issues](https://github.com/mrexodia/dumpulator/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)**\r\n\r\nAn easy-to-use library for emulating code in minidump files. Here are some links to posts/videos using dumpulator:\r\n\r\n- Introduction video with [OALabs](https://oalabs.openanalysis.net): [Dumpulator - Using Binary Emulation To Automate Reverse Engineering](https://youtu.be/4Pfu98Xx9Yo)\r\n- [Emulating malware with Dumpulator](https://rioasmara.com/2022/07/23/emulating-malware-with-dumpulator/)\r\n- [Emotet x64 Stack Strings Config Emulation | OALabs Research](https://research.openanalysis.net/emotet/emulation/config/dumpulator/malware/2022/05/19/emotet_x64_emulation.html)\r\n- [Native function and Assembly Code Invocation](https://research.checkpoint.com/2022/native-function-and-assembly-code-invocation/)\r\n- [Guloader string decryption (VEH)](https://research.openanalysis.net/guloader/emulation/dumpulator/veh/exceptions/2023/01/15/dumpulator-veh.html)\r\n- [Rhadamanthys | OALabs Research](https://research.openanalysis.net/rhadamanthys/config/ida/shifted%20pointers/peb/_list_entry/_ldr_data_table_entry/2023/01/19/rhadamanthys.html)\r\n- [\\[Case study\\] Decrypt strings using Dumpulator](https://kienmanowar.wordpress.com/2023/05/22/case-study-decrypt-strings-using-dumpulator/)\r\n\r\n\u003csub\u003eFeel free to send a pull request to add your article here!\u003c/sub\u003e\r\n\r\n\r\n## Examples\r\n\r\n### Calling a function\r\n\r\nThe example below opens `StringEncryptionFun_x64.dmp` (download a copy [here](https://github.com/mrexodia/dumpulator/releases/download/v0.0.1/StringEncryptionFun_x64.dmp)), allocates some memory and calls the decryption function at `0x140001000` to decrypt the string at `0x140017000`:\r\n\r\n```python\r\nfrom dumpulator import Dumpulator\r\n\r\ndp = Dumpulator(\"StringEncryptionFun_x64.dmp\")\r\ntemp_addr = dp.allocate(256)\r\ndp.call(0x140001000, [temp_addr, 0x140017000])\r\ndecrypted = dp.read_str(temp_addr)\r\nprint(f\"decrypted: '{decrypted}'\")\r\n```\r\n\r\nThe `StringEncryptionFun_x64.dmp` is collected at the entry point of the `tests/StringEncryptionFun` example. You can get the compiled binaries for `StringEncryptionFun` [here](https://github.com/mrexodia/dumpulator/releases/download/v0.0.1/StringEncryptionFun.7z)\r\n\r\n### Tracing execution\r\n\r\n```python\r\nfrom dumpulator import Dumpulator\r\n\r\ndp = Dumpulator(\"StringEncryptionFun_x64.dmp\", trace=True)\r\ndp.start(dp.regs.rip)\r\n```\r\n\r\nThis will create `StringEncryptionFun_x64.dmp.trace` with a list of instructions executed and some helpful indications when switching modules etc. Note that tracing _significantly_ slows down emulation and it's mostly meant for debugging.\r\n\r\n### Reading utf-16 strings\r\n\r\n```python\r\nfrom dumpulator import Dumpulator\r\n\r\ndp = Dumpulator(\"my.dmp\")\r\nbuf = dp.call(0x140001000)\r\ndp.read_str(buf, encoding='utf-16')\r\n```\r\n\r\n### Running a snippet of code\r\n\r\nSay you have the following function:\r\n\r\n```\r\n00007FFFC81C06C0 | mov qword ptr [rsp+0x10],rbx       ; prolog_start\r\n00007FFFC81C06C5 | mov qword ptr [rsp+0x18],rsi\r\n00007FFFC81C06CA | push rbp\r\n00007FFFC81C06CB | push rdi\r\n00007FFFC81C06CC | push r14\r\n00007FFFC81C06CE | lea rbp,qword ptr [rsp-0x100]\r\n00007FFFC81C06D6 | sub rsp,0x200                      ; prolog_end\r\n00007FFFC81C06DD | mov rax,qword ptr [0x7FFFC8272510]\r\n```\r\n\r\nYou only want to execute the prolog and set up some registers:\r\n\r\n```python\r\nfrom dumpulator import Dumpulator\r\n\r\nprolog_start = 0x00007FFFC81C06C0\r\n# we want to stop the instruction after the prolog\r\nprolog_end = 0x00007FFFC81C06D6 + 7\r\n\r\ndp = Dumpulator(\"my.dmp\", quiet=True)\r\ndp.regs.rcx = 0x1337\r\ndp.start(begin=prolog_start, end=prolog_end)\r\nprint(f\"rsp: {hex(dp.regs.rsp)}\")\r\n```\r\n\r\nThe `quiet` flag suppresses the logs about DLLs loaded and memory regions set up (for use in scripts where you want to reduce log spam).\r\n\r\n### Custom syscall implementation\r\n\r\nYou can (re)implement syscalls by using the `@syscall` decorator:\r\n\r\n```python\r\nfrom dumpulator import *\r\nfrom dumpulator.native import *\r\nfrom dumpulator.handles import *\r\nfrom dumpulator.memory import *\r\n\r\n@syscall\r\ndef ZwQueryVolumeInformationFile(dp: Dumpulator,\r\n                                 FileHandle: HANDLE,\r\n                                 IoStatusBlock: P[IO_STATUS_BLOCK],\r\n                                 FsInformation: PVOID,\r\n                                 Length: ULONG,\r\n                                 FsInformationClass: FSINFOCLASS\r\n                                 ):\r\n    return STATUS_NOT_IMPLEMENTED\r\n```\r\n\r\nAll the syscall function prototypes can be found in [ntsyscalls.py](https://github.com/mrexodia/dumpulator/blob/main/src/dumpulator/ntsyscalls.py). There are also a lot of examples  there on how to use the API.\r\n\r\nTo hook an existing syscall implementation you can do the following:\r\n\r\n```python\r\nimport dumpulator.ntsyscalls as ntsyscalls\r\n\r\n@syscall\r\ndef ZwOpenProcess(dp: Dumpulator,\r\n                  ProcessHandle: Annotated[P[HANDLE], SAL(\"_Out_\")],\r\n                  DesiredAccess: Annotated[ACCESS_MASK, SAL(\"_In_\")],\r\n                  ObjectAttributes: Annotated[P[OBJECT_ATTRIBUTES], SAL(\"_In_\")],\r\n                  ClientId: Annotated[P[CLIENT_ID], SAL(\"_In_opt_\")]\r\n                  ):\r\n    process_id = ClientId.read_ptr()\r\n    assert process_id == dp.parent_process_id\r\n    ProcessHandle.write_ptr(0x1337)\r\n    return STATUS_SUCCESS\r\n\r\n@syscall\r\ndef ZwQueryInformationProcess(dp: Dumpulator,\r\n                              ProcessHandle: Annotated[HANDLE, SAL(\"_In_\")],\r\n                              ProcessInformationClass: Annotated[PROCESSINFOCLASS, SAL(\"_In_\")],\r\n                              ProcessInformation: Annotated[PVOID, SAL(\"_Out_writes_bytes_(ProcessInformationLength)\")],\r\n                              ProcessInformationLength: Annotated[ULONG, SAL(\"_In_\")],\r\n                              ReturnLength: Annotated[P[ULONG], SAL(\"_Out_opt_\")]\r\n                              ):\r\n    if ProcessInformationClass == PROCESSINFOCLASS.ProcessImageFileNameWin32:\r\n        if ProcessHandle == dp.NtCurrentProcess():\r\n            main_module = dp.modules[dp.modules.main]\r\n            image_path = main_module.path\r\n        elif ProcessHandle == 0x1337:\r\n            image_path = R\"C:\\Windows\\explorer.exe\"\r\n        else:\r\n            raise NotImplementedError()\r\n        buffer = UNICODE_STRING.create_buffer(image_path, ProcessInformation)\r\n        assert ProcessInformationLength \u003e= len(buffer)\r\n        if ReturnLength.ptr:\r\n            dp.write_ulong(ReturnLength.ptr, len(buffer))\r\n        ProcessInformation.write(buffer)\r\n        return STATUS_SUCCESS\r\n    return ntsyscalls.ZwQueryInformationProcess(dp,\r\n                                                ProcessHandle,\r\n                                                ProcessInformationClass,\r\n                                                ProcessInformation,\r\n                                                ProcessInformationLength,\r\n                                                ReturnLength\r\n                                                )\r\n```\r\n\r\n### Custom structures\r\n\r\nSince `v0.2.0` there is support for easily declaring your own structures:\r\n\r\n```python\r\nfrom dumpulator.native import *\r\n\r\nclass PROCESS_BASIC_INFORMATION(Struct):\r\n    ExitStatus: ULONG\r\n    PebBaseAddress: PVOID\r\n    AffinityMask: KAFFINITY\r\n    BasePriority: KPRIORITY\r\n    UniqueProcessId: ULONG_PTR\r\n    InheritedFromUniqueProcessId: ULONG_PTR\r\n```\r\n\r\nTo instantiate these structures you have to use a `Dumpulator` instance:\r\n\r\n```python\r\npbi = PROCESS_BASIC_INFORMATION(dp)\r\nassert ProcessInformationLength == Struct.sizeof(pbi)\r\npbi.ExitStatus = 259  # STILL_ACTIVE\r\npbi.PebBaseAddress = dp.peb\r\npbi.AffinityMask = 0xFFFF\r\npbi.BasePriority = 8\r\npbi.UniqueProcessId = dp.process_id\r\npbi.InheritedFromUniqueProcessId = dp.parent_process_id\r\nProcessInformation.write(bytes(pbi))\r\nif ReturnLength.ptr:\r\n    dp.write_ulong(ReturnLength.ptr, Struct.sizeof(pbi))\r\nreturn STATUS_SUCCESS\r\n```\r\n\r\nIf you pass a pointer value as a second argument the structure will be read from memory. You can declare pointers with `myptr: P[MY_STRUCT]` and dereferences them with `myptr[0]`.\r\n\r\n## Collecting the dump\r\n\r\n~~There is a simple [x64dbg](https://github.com/x64dbg/x64dbg) plugin available called [MiniDumpPlugin](https://github.com/mrexodia/MiniDumpPlugin/releases)~~ The [minidump](https://help.x64dbg.com/en/latest/commands/memory-operations/minidump.html) command has been integrated into x64dbg since 2022-10-10. To create a dump, pause execution and execute the command `MiniDump my.dmp`.\r\n\r\n## Installation\r\n\r\nFrom [PyPI](https://pypi.org/project/dumpulator) (latest [release](https://github.com/mrexodia/dumpulator/releases)):\r\n\r\n```\r\npython -m pip install dumpulator\r\n```\r\n\r\nTo install from source:\r\n\r\n```\r\npython setup.py install\r\n```\r\n\r\nInstall for a development environment:\r\n\r\n```\r\npython setup.py develop\r\n```\r\n\r\n## Related work\r\n\r\n- [Dumpulator-IDA](https://github.com/michaeljgoodman/Dumpulator-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.\r\n- [wtf](https://github.com/0vercl0k/wtf): Distributed, code-coverage guided, customizable, cross-platform snapshot-based fuzzer designed for attacking user and / or kernel-mode targets running on Microsoft Windows\r\n- [speakeasy](https://github.com/mandiant/speakeasy): Windows sandbox on top of unicorn.\r\n- [qiling](https://github.com/qilingframework/qiling): Binary emulation framework on top of unicorn.\r\n- [Simpleator](https://github.com/ionescu007/Simpleator): User-mode application emulator based on the Hyper-V Platform API.\r\n\r\nWhat 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 actually _is_ a legitimate process environment).\r\n\r\n## Credits\r\n\r\n- [herrcore](https://twitter.com/herrcore) for inspiring me to make this\r\n- [secret club](https://secret.club)\r\n- [JetBrains](https://www.jetbrains.com/opensource/) for free PyCharm license!\r\n- [Image by GraphiqaStock](https://www.freepik.com/free-vector/virus-internet_1040653.htm) on Freepik\r\n","funding_links":["https://github.com/sponsors/mrexodia"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrexodia%2Fdumpulator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmrexodia%2Fdumpulator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrexodia%2Fdumpulator/lists"}