{"id":25692648,"url":"https://github.com/x0reaxeax/ghostwriting64","last_synced_at":"2025-08-21T06:34:25.772Z","repository":{"id":278838342,"uuid":"934798343","full_name":"x0reaxeax/GhostWriting64","owner":"x0reaxeax","description":"PoC implementation of the GhostWriting injection technique for x64 Windows","archived":false,"fork":false,"pushed_at":"2025-02-18T12:31:26.000Z","size":45,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-02-22T01:31:02.823Z","etag":null,"topics":["defense-evasion","ghostwriting","injection","pentesting","poc","popcalc","process-injection","redteam","shellcode-execute","shellcode-injection","windows","windows-x64","wpm-less-wpm","x86-64"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/x0reaxeax.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","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":"2025-02-18T12:25:26.000Z","updated_at":"2025-02-18T19:41:11.000Z","dependencies_parsed_at":"2025-02-22T01:31:07.401Z","dependency_job_id":"f8cbcd26-9323-45aa-89bb-487d5ef35e72","html_url":"https://github.com/x0reaxeax/GhostWriting64","commit_stats":null,"previous_names":["x0reaxeax/ghostwriting64"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/x0reaxeax%2FGhostWriting64","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/x0reaxeax%2FGhostWriting64/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/x0reaxeax%2FGhostWriting64/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/x0reaxeax%2FGhostWriting64/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/x0reaxeax","download_url":"https://codeload.github.com/x0reaxeax/GhostWriting64/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240573478,"owners_count":19822849,"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":["defense-evasion","ghostwriting","injection","pentesting","poc","popcalc","process-injection","redteam","shellcode-execute","shellcode-injection","windows","windows-x64","wpm-less-wpm","x86-64"],"created_at":"2025-02-24T23:28:03.804Z","updated_at":"2025-02-24T23:28:04.799Z","avatar_url":"https://github.com/x0reaxeax.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GhostWriting-x64\n## PoC implementation of the GhostWriting injection technique\n\n### What does this do?\nThe idea behind this technique is to utilize thread context-altering APIs and `MOV` gadgets to achieve process injection, and full execution takeover.  \nWIN32 APIs [`GetThreadContext()`](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreadcontext) and [`SetThreadContext()`](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadcontext) are used for this purpose.\nThe target thread must be in a `RUNNING` state, and the possibility of other threads interfering with the target thread must be taken into consideration.  \nThis PoC doesn't address either of those issues, however, both can be resolved quite easily. \nThe injector tries to find a loop gadget (`jmp $`) in the target process as soon as possible, in order to prevent the thread from executing state altering functions, like `Sleep()`.\n\nThe injector will also by default completely discard the target's stack and allocate a new one.\nIt will also by default discard all acquired gadgets and create a **\"Hijack Control Gadget\"**, which is basically just a package of all required gadgets, in one location.\n\nSee [Gadgets](#gadgets) and [Execution Options](#execution-options) for more information.\n\n### RemoteAPI\n[`RemoteAPI.h`](https://github.com/x0reaxeax/GhostWriting64/blob/master/GhostWriting-x64/RemoteAPI.h) contains \"remote\" alternatives to some commonly used WINAPI functions, like `VirtualAlloc()` or `WriteProcessMemory()`.\nWhile most of these are executed simply by crafting a context ready for execution of the target API function residing in the remote process, the `rWriteProcessMemory()` is an exception, as it doesn't rely on it's equivalent API call at all. Instead, to achieve writing to a remote process, a `MOV R/M8, R8` gadget is used as a foundation for off-brand cross-process `memcpy()` clone.  \n\nFull list of currently implemented RemoteAPI functions:\n*  `rVirtualAlloc `\n\t* Equivalent `VirtualAlloc()`.\n* `rVirtualProtect`\n\t* Equivalent of `VirtualProtect()`.\n* `rVirtualFree`\n\t* Equivalent of `VirtualFree()`.\n* `rWriteProcessMemory`\n\t* Custom implementation of an cross-process `memcpy()`.\n* `rLoadLibraryA`\n\t* Equivalent of `LoadLibraryA()`.\n* `r_puts`\n\t* Equivalent of `puts()`.\n* `rDirectInvoke`\n\t* Custom invoker that calls arbitrary functions by their addresses.\n\n### Gadgets\nThere are two `MOV` gadgets used in this demo - `MOV R/M8, R8` (`MOV8` gadget) and `MOV R/M64, R64` (`MOV64` gadget). These are dynamically searched for in the target process, and can be different each time the PoC is executed, as the injector searches for different possible combinations of the **ModR/M** byte, so the source and destination registers can differ. The search is done using a WIN32 function `ReadProcessMemory()`. ~~In theory, there's a way around this, but since this is not GhostReading, this is simply out of scope for now~~ \nHowever, in [`Defs.h`](https://github.com/x0reaxeax/GhostWriting64/blob/master/GhostWriting-x64/Defs.h), there is a functionality that will use hardcoded offsets to gadgets in `NTDLL`. This eliminates the need of `PROCESS_VM_OPERATION` and `PROCESS_VM_READ` access rights.  \n\n### Execution Options\nThere are a few options in [`Defs.h`](https://github.com/x0reaxeax/GhostWriting64/blob/master/GhostWriting-x64/Defs.h) that can be enabled to change some key factors on how the injector works:\n* `KEEP_ORIGINAL_STACK` \n* `READ_PROC_ADDR_LOCAL`\n* `STEALTH`\n\n#### `KEEP_ORIGINAL_STACK`:\n* This option, despite it's name only mentioning the stack, will prevent discarding and replacing the original stack with a newly crafted one, but will also disable the use of \"Hijack Control Gadget\", which replaces all of the 3 necessary gadgets that were previously acquired from the process:\n\t* `MOV8` gadget\n\t* `MOV64` gadget\n\t* Loop gadget\n\n#### `READ_PROC_ADDR_LOCAL`:\n* Enabling this will result in function addresses being fetched locally, via `GetModuleHandle()` + `GetProcAddress()` combo, this will also allow for dropping the handle to the target process immediately after hijacking the execution, as the RemoteAPI functions won't enumerate the target's loaded Core DLLs to resolve the function addresses from them. This should be left disabled if any weird hooks/relocations are present, which could cause differences between the Core DLL address mappings between the injector and it's target.\n\n#### `STEALTH`:\n* This option automatically enables both `KEEP_ORIGINAL_STACK` and `READ_PROC_ADDR_LOCAL`, with addition of relying on hardcoded `NTDLL` offsets to all required gadgets. This requires manually searching for all required gadgets inside `NTDLL`, and updating the offsets to these gadgets within the injector. This is highly unstable and should be generally avoided.\n\n## FAQ\n### Can you please speak English?\nYes, the main purpose of this PoC is to demonstrate a write primitive that doesn't call `WriteProcessMemory`, `NtWriteVirtualMemory`, `CreateRemoteThread`, or simply any APIs commonly used for WPM during process injection. This is utilized to pop a calc.\n\n### Will this crash the target program?\nIt depends on the actions performed by the target.\nUsing the [RemoteAPIs](#remoteapi) will generally not crash the program, but will leave it in an internally unusable state, executing infinite loop.\n  \n\n### Can I see how it works without running it?\nThere is a slightly different implementation of this technique that I demonstrated a while ago, you can [watch it on YouTube](https://www.youtube.com/watch?v=fo3-J4jhuB4)\n\n## Sources\nThis PoC doesn't reuse any code from the listed or any other sources. I simply wanted to write my own implementation of this technique, because I find it interesting.  \nI politely borrowed the idea, but all of the code was written from scratch.  \nhttp://blog.txipinet.com/2007/04/05/69-a-paradox-writing-to-another-process-without-openning-it-nor-actually-writing-to-it/\nhttps://i.blackhat.com/USA-19/Thursday/us-19-Kotler-Process-Injection-Techniques-Gotta-Catch-Them-All-wp.pdf\n\n## Tested on\n* Windows 10 21H2, 22H2\n* Windows 10 22H2\n\n## DISCLAIMER\nThis project is licensed under the **MIT License**. The content of this repository exists purely for **educational purposes**.\n\n\u003e Written with [StackEdit](https://stackedit.io/).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fx0reaxeax%2Fghostwriting64","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fx0reaxeax%2Fghostwriting64","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fx0reaxeax%2Fghostwriting64/lists"}