{"id":13511138,"url":"https://github.com/f-block/volatility-plugins","last_synced_at":"2025-03-30T20:32:35.852Z","repository":{"id":55275651,"uuid":"351093789","full_name":"f-block/volatility-plugins","owner":"f-block","description":null,"archived":false,"fork":false,"pushed_at":"2023-09-06T13:50:05.000Z","size":158,"stargazers_count":12,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-11-01T13:33:54.573Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/f-block.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2021-03-24T13:40:41.000Z","updated_at":"2024-05-15T06:20:46.000Z","dependencies_parsed_at":"2024-01-13T19:22:23.949Z","dependency_job_id":null,"html_url":"https://github.com/f-block/volatility-plugins","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/f-block%2Fvolatility-plugins","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/f-block%2Fvolatility-plugins/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/f-block%2Fvolatility-plugins/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/f-block%2Fvolatility-plugins/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/f-block","download_url":"https://codeload.github.com/f-block/volatility-plugins/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246379366,"owners_count":20767694,"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":[],"created_at":"2024-08-01T03:00:35.454Z","updated_at":"2025-03-30T20:32:35.580Z","avatar_url":"https://github.com/f-block.png","language":"Python","funding_links":[],"categories":["Volatility 3"],"sub_categories":["Plugins"],"readme":"# volatility-plugins\n\nTo use these plugins, simply place them in the `volatility3/framework/plugins/windows` subfolder.\n\n## Ptenum\n\nFor a detailed description see [here](https://insinuator.net/2021/12/release-of-pte-analysis-plugins-for-volatility-3/) and [here](https://insinuator.net/2022/09/some-experiments-with-process-hollowing/)\n\nThe corresponding memory dump can be downloaded from: https://fx.ernw.de/portal-seefx/~public/YzMxMzkxZDAtY2I0My00M2Q5LWIzZjMtNGIwYTcyNjIwMTgz?download\n\n\n## imgmalfind\n\nThe `imgmalfind` plugin identifies modifications to memory mapped image files in user space (DLLs, executables), such as hooks and patches. It comes with an allow-listing mechanism and some pre-defined rules, which, however, might not yet include your particular legitimate modifications (e.g., caused by an AV or EDR system). We will see later, how we can add these.\n\nThe execution of the plugin is straight forward, we can either scan all processes or focus on a particular process by providing the PID:\n\n```shell\nvol3 -f mem.dump windows.imgmalfind --pid 1912\n\nPID   Process  Section name(s)  First modified byte  Function(s)          Modified Module                Modified bytes Count\n1912  abc.exe  .text            0x7781eb90           EtwEventWrite + 0x0  \\Windows\\SysWOW64\\ntdll.dll    4\n\nOrig Data\n\t\n8b ff 55 8b ec 83 e4 f8\t..U.....\t\n0x7781eb90:\tmov\tedi, edi\n0x7781eb92:\tpush\tebp\n0x7781eb93:\tmov\tebp, esp\n0x7781eb95:\tand\tesp, 0xfffffff8\t\n\nNew Data\n\t\nc2 14 00 00 ec 83 e4 f8\t........\t\n0x7781eb90:\tret\t0x14\n0x7781eb93:\tadd\tah, ch\n0x7781eb95:\tand\tesp, 0xfffffff8\t\n```\n\nThe output is structured as follows. The first line (after the header) contains:\n\n- The Process `PID`\n- The Process name (`Process`).\n- The PE section(s) for the corresponding modification offset (`Section name(s)`).\n- The virtual address of the first modified byte (`First modified byte`).\n- A function name for the modified byte (`Function(s)`), if it can be resolved, including an offset from the start of the function (in this case `+ 0x0`, so the modification is rigth at the beginning).\n- The affected image file (`Modified Module`).\n- The total number of modified bytes (`Modified bytes Count`).\n\nSome notes on the first line:\n\n- There might be multiple results for the same modified image file, if multiple locations are modified, but not the data in between. This is especially the case with hooks.\n- The PE Section field can also contains the specific PE header, if applicable.\n- As modified bytes can spread across multiple PE sections, and in some cases one modified byte can belong to a PE header and a Section, we print each hit, which means this field can contain multiple entries. \n- Some modifications might be near certain functions, but not related to them. In the current implementation we simply look for the nearest function (below a given threshold) and print that function with the offset. This might, however, be a false positive and could be unrelated to the function resp. belonging to another, anonymous function. At least with offsets near the beginning of a known function, chances are good that the modification affects this particular function.\n- The `Modified bytes Count` is not equivalent to the range of bytes. So, if only the first and last byte of a 8 byte chunk is modified, this field contains the value `2`.\n\n\nAfter the first line, the rest is split into two parts: `Orig Data` and `New Data`. As the names suggest, the first part contains the original data, before any modifications, and the second part contains the identified modifications. Both are printed with a hexdump and disassembly output.\n\nIn the current example we see the effect of an ETW bypass. The first 4 bytes of the `EtwEventWrite` function were patched with a `ret 14`, preventing the function from writing any ETW event.\n\nA similar bypass can be seen in the following output:\n\n```shell\nPID   Process         Section name(s)  First modified byte  Function(s)           Modified Module              Modified bytes Count\n4936  powershell_ise  .text            0x7ff837f123e0       AmsiScanBuffer + 0x0  \\Windows\\System32\\amsi.dll   3  \n\nOrig Data\n\t\n4c 8b dc 49 89 5b 08 49\tL..I.[.I\t\n0x7ff837f123e0:\tmov\tr11, rsp\n0x7ff837f123e3:\tmov\tqword ptr [r11 + 8], rbx\t\n\nNew Data\n\t\n31 c0 c3 49 89 5b 08 49\t1..I.[.I\t\n0x7ff837f123e0:\txor\teax, eax\n0x7ff837f123e2:\tret\t\n0x7ff837f123e3:\tmov\tqword ptr [r11 + 8], rbx\t\n\n```\n\nThe first three bytes of the `AmsiScanBuffer` function have been patched with `return 0`, which means even malicious data that normally would have been scanned and identified as malicious would now stay unscanned and undetected.\n\nThe next example shows a hook placed by the [NetRipper](https://github.com/NytroRST/NetRipper/) project:\n\n```shell\nPID   Process     Section name(s)  First modified byte  Function(s)           Modified Module               Modified bytes Count\n7716  msedge.exe  .text            0x7fff27fa2320       send + 0x0            \\Windows\\System32\\ws2_32.dll  5  \n\nOrig Data\n\t\n48 89 5c 24 08 48 89 6c\tH.\\$.H.l\t\n0x7fff27fa2320:\tmov\tqword ptr [rsp + 8], rbx\t\n\nNew Data\n\t\ne9 6e ec fe ff 48 89 6c\t.n...H.l\t\n0x7fff27fa2320:\tjmp\t0x7fff27f90f93\t\n\nTarget:\n\tThe final target page is anonymous memory (either private or shared). Target VAD at 0x13cefb20000: \tprivate/shared\t\n44 89 4c 24 20 44 89 44\tD.L$.D.D\n24 18 48 89 54 24 10 89\t$.H.T$..\t\n0x13cefb271c0:\tmov\tdword ptr [rsp + 0x20], r9d\n0x13cefb271c5:\tmov\tdword ptr [rsp + 0x18], r8d\n0x13cefb271ca:\tmov\tqword ptr [rsp + 0x10], rdx\n```\n\nThe first 5 bytes of the `send` function have been overwritten with a jump to an anonymous memory region, containing a handler function of the NetRipper project.\n\n\nIn some cases, there might be output like this:\n\n```shell\nPID   Process         Section name(s)  First modified byte  Function(s)           Modified Module                                        Modified bytes Count\n7728  powershell.exe  .text            0x7ffeeb3c4000       N/A                   \\Windows\\Microsoft.NET\\Framework64\\v4.0.30319\\clr.dll  -1\n\nOrig Data\n\n\nNew Data\n\n48 c1 e9 0b 80 3c 08 ff\tH....\u003c..\n75 02 f3 c3 c6 04 08 ff\tu.......\nc3 66 66 66 66 66 66 66\t.fffffff\n0f 1f 84 00 00 00 00 00\t........\nf3 c3 66 66 66 66 66 66\t..ffffff\n0f 1f 84 00 00 00 00 00\t........\n90 90 66 66 66 66 66 66\t..ffffff\n0f 1f 84 00 00 00 00 00\t........\t\n0x7ffeeb3c4000:\tshr\trcx, 0xb\n0x7ffeeb3c4004:\tcmp\tbyte ptr [rax + rcx], 0xff\n0x7ffeeb3c4008:\tjne\t0x7ffeeb3c400c\n0x7ffeeb3c400a:\tret\t\n0x7ffeeb3c400c:\tmov\tbyte ptr [rax + rcx], 0xff\n0x7ffeeb3c4010:\tret\t\n0x7ffeeb3c4011:\tnop\tword ptr [rax + rax]\n0x7ffeeb3c4020:\tret\t\n0x7ffeeb3c4022:\tnop\tword ptr [rax + rax]\n0x7ffeeb3c4030:\tnop\t\n0x7ffeeb3c4031:\tnop\t\n0x7ffeeb3c4032:\tnop\tword ptr [rax + rax]\n```\n\nHere, we have a `Modified bytes Count` of `-1` and no `Orig Data`. This means, the original data is not available from the memory dump and we have nothing to compare the modified data against. In this case, the plugin simply prints the first 64 bytes and disassembly output for the corresponding page, but it might not contain the contain the actual modifications.\n\n\nAt last, let's examine the plugin options:\n\n- `--start` and `--end` allow to focus on a given memory range instead of the whole process address space. Note that the plugin uses Ptenum, so we work on page boundaries and the `--start` option requires a value that is a multiple of 0x1000 (e.g. `0x7ffeeb3c4000`).\n- `--precontext` and `--postcontext` enable the inclusion of additional bytes before/after the modified bytes. Both accept an integer as argument, specifying the number of bytes to additionally include in the modification-analysis.\n- `--disable-filtering` disables the allow-listing algorithm.\n- `--filters` expects a json file, containing additional filters for the allow-listing algorithm. The format is described below.\n\nBefore reporting a modification, the allow-listing logic is applied in order to discard benign modifications. One example for such a benign modification is shown below. It affects the Google Chrome browser and is a functionality for blocking unwanted/malicious third party DLLs. For more details and further benign hooks, see the paper.\n\n```shell\n6580    chrome.exe  .text   0x7ff876f4d5b0  ZwMapViewOfSection + 0x0    \\Windows\\System32\\ntdll.dll 16\n\nOrig Data\n    \n4c 8b d1 b8 28 00 00 00 L...(...\nf6 04 25 08 03 fe 7f 01 ..%.....\n0x7ff876f4d5b0: mov r10, rcx\n0x7ff876f4d5b3: mov eax, 0x28\n0x7ff876f4d5b8: test    byte ptr [0x7ffe0308], 1\n\nNew Data\n    \n48 b8 10 be aa 61 f8 7f H....a..\n00 00 ff e0 aa aa aa aa ........\n0x7ff876f4d5b0: movabs  rax, 0x7ff861aabe10\n0x7ff876f4d5ba: jmp rax\n0x7ff876f4d5bc: stosb   byte ptr [rdi], al\n0x7ff876f4d5bd: stosb   byte ptr [rdi], al\n0x7ff876f4d5be: stosb   byte ptr [rdi], al\n0x7ff876f4d5bf: stosb   byte ptr [rdi], al\n\nTarget:\n    The target page is an unmodified page. Target VAD: \\Program Files\\Google\\Chrome\\Application\\109.0.5414.75\\chrome_elf.dll at 0x7ff861a90000\n55 56 57 48 83 ec 60 48 UVWH..`H\n8d 6c 24 60 4c 89 c0 49 .l$`L..I\n0x7ff861aabe10: push    rbp\n0x7ff861aabe11: push    rsi\n0x7ff861aabe12: push    rdi\n0x7ff861aabe13: sub rsp, 0x60\n0x7ff861aabe17: lea rbp, [rsp + 0x60]\n0x7ff861aabe1c: mov rax, r8\n```\n\nIn contrast to the previous example, this time the hook points back to a mapped image file (and also unmodified page) and not anonymous memory, which might (but does not necessarily!) indicate a benign hook.\n\n\nThe plugin comes with pre-defined filters, but can be extended with the `--filters` option. It should be noted that currently we only support custom filters for hooks. The `--filters` option expects a json file containing a list of json objects with three fields:\n\n- The affected process(es)\n- The modified VAD/Memory-Mapped Image File(s)\n- The target VAD/Memory-Mapped Image File(s)\n\nFollowing a simple example of some custom filters. Note that the plugin interprets each field's value as a Perl-compatible regular expressions (PCRE).\n\n\n```json\n[\n  {\n    \"process\": \"^abc\\\\.exe$\",\n    \"modified_vad\": \"^\\\\\\\\windows\\\\\\\\system32\\\\\\\\ntdll\\\\.dll$\",\n    \"target_vad\": \"^\\\\\\\\path\\\\\\\\to\\\\\\\\dll\\\\\\\\abc\\\\.dll$\"\n  },\n  {\n    \"process\": \".\",\n    \"modified_vad\": \"^\\\\\\\\windows\\\\\\\\system32\\\\\\\\ntdll\\\\.dll$\",\n    \"target_vad\": \"^\\\\\\\\path\\\\\\\\to\\\\\\\\dll\\\\\\\\abc\\\\.dll$\"\n  },\n  {\n    \"process\": \".\",\n    \"modified_vad\": \".\",\n    \"target_vad\": \"\\\\\\\\super_legit\\\\.dll$\"\n  }\n]\n```\n\nThe first filter marks a hook as benign, if the process name is exactly `abc.exe`, the modified image has exactly the path `\\windows\\system32\\ntdll.dll` and the hook-target is a DLL with the path `\\path\\to\\dll\\abc.dll`.\nThe second filter is intended for AV and EDR systems and is similar to the first one, except the fact that it matches every process, as AVs and EDRs typically affect most/all processes.\nThe last filter is extremely permissive and not recommended for \"production use\": It matches every process and every modified image file, as long as the target is a DLL named `super_legit.dll`, no matter at which file location.\n\nNote:\n- Even if the path should be ignored, the leading backslashes are important, as otherwise the filter would in our example also match `not_really_super_legit.dll`.\n- Upper and lowercase does not have to be considered, all filters and the data from processes are all converted to lowercase before comparison.\n\n\nAs writing `json` involves more backslashes and is not for everybody, we can also use `yaml` and the tool `yq`:\n\n```shell\ncat filters.yml\n\n- process: ^abc\\.exe$\n  modified_vad: ^\\\\windows\\\\system32\\\\ntdll\\.dll$\n  target_vad: ^\\\\path\\\\to\\\\dll\\\\abc\\.dll$\n- process: .\n  modified_vad: ^\\\\windows\\\\system32\\\\ntdll\\.dll$\n  target_vad: ^\\\\path\\\\to\\\\dll\\\\abc\\.dll$\n- process: .\n  modified_vad: .\n  target_vad: \\\\super_legit\\.dll$\n\n\n\ncat filters.yml | yq \u003e filters.json\n\nvol3 -f mem.dump windows.imgmalfind --filters filters.json\n...\n```\n\nFor detailed information on the theory behind the plugin, see the [paper](https://dfrws.org/wp-content/uploads/2023/07/block-windowsmemoryforensics.pdf) resp. the [conference repository](https://github.com/f-block/DFRWS-USA-2023) for evaluation details.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ff-block%2Fvolatility-plugins","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ff-block%2Fvolatility-plugins","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ff-block%2Fvolatility-plugins/lists"}