Windows x64 Process Injection via Ghostwriting with Dynamic Configuration
Currently only tested on Windows 10 Home Build 19042
Requires Winim. To install run:
nimble install winim
For a DLL with echo statements:
nim debugbuild
For a DLL without echo statements:
nim build
GhostWriting is a Windows Process Injection technique first publically mentioned in 2007 by c0de90e7. It achieves code execution within the context of a thread without opening a handle to the process or writing to it's virtual memory. It achieves this by manipulating register context for a specific thread in combination with specific gadgets that prevent the thread from crashing after an operation. For more information on GhostWriting, see https://github.com/c0de90e7/GhostWriting.
Technically, no this isn't GhostWriting as described by c0de90e7 since I'm opening a handle to the process nor am I simply enumerating windows to get the threadID. But I find the technique is way more stable when opening a handle to the process and allows for use of volatile registers in the Write Primative. Also, I wanted to advance my understand of Nim, so I went out of my way to write winAPI calls, dynamically resolve syscalls at run-time, enumerating the Stack's base address, etc. It would be trivial to implement the original method if you want 😉
GhostWriting, as described by c0de90e7, required the use of non-volatile registers for it's write primatives. However, these are hard to find in current Windows dlls commonly loaded by processes (ntdll, kernel32.dll, etc), and therefore, limited in number. The use of volatile registers comes with some limitations. This is because resuming the thread will often have other threads clobbering your register state, resulting in (most-likely) the process to crash. Some ways to get around this issue are to either manipulate at the process level, find a process with a single thread, or find a thread that is currently suspended.
Since this repository is for educational purposes, I've decided to use a volatile write primative and to simply open a handle to the process and suspend it, preventing any clobbering of register contexts.
GhostWriting gives us the ability to write/execute ROP/JOP chains to/in a target thread's virtual address space. This can be useful to sneakily achieve arbitrary computation within a process whilst simultaneously bypassing CFG and CIG, along with the benefits of only opening a handle to a single thread with no writes. However, hard-coding re-useable code chains, gadgets, and payloads can be limiting, and having the ability to load in gadgets, payloads, and re-useable code chains at run-time could serve to be benificial to the technique. In my attempt to implement dynamic configurability, I've decided to use JSON.
An example of a configuration can be seen in defaults.nim. Below are the JSON keys and their underlying fields to use.
A list of RW memory to use. The Stack is always created.
Field | Required? | Description |
---|---|---|
Label | Yes | The Name of the Memory to be referenced |
BaseAddress | Yes | The base address of the memory |
Size | Yes | The size of the memory |
Padding | Yes | The padding to increment the memory addresses by for successive writes |
A list of payloads to write to the target thread.
Field | Required? | Description |
---|---|---|
Label | Yes | The name of the Payload to be referneced in the Re-Useable Code Chain |
Bytes | Yes | The byte sequence of the payload |
StoreLocation | Yes | Which section of memory to store the payload. This can be the Stack or an arbitrary section of RW memory referenced under Memorys. |
StoreOffset | Yes | The offset from the StoreLocation's Base Address to write the payload. |
A list of gadgets to be used in the injection. Requires atleast 1 Sink Gadget (jmp -2) and 1 Main Store (Write Primative).
Field | Required? | Description |
---|---|---|
Name | Yes | The name of the Gadget, to be refernced in the Re-Useable Code Chain. |
BytePattern | Yes | The byte pattern of the gadget. |
GadgetModule | Yes | The module where the gadget resides. |
ModuleOffset | Yes | The offset within the module where the gadget resides. |
GadgetType | Only for Sink and MainStore Gadgets | The type of operation the gadget performs. |
Volatile | Yes | The volatiliy of the registers used by the gadget. |
DestinationRegister | Only for MainStore Gadgets | The destination register of the gadget. |
SourceRegister | Only for MainStore Gadgets | The source register of the gadget. |
The Context to use to start the execution of the Re-Usable Code Chain
Field | Required? | Description |
---|---|---|
Target | Yes | The Target Memory Address to signal the end of execution. |
RIP | Yes | The starting memory address for the RIP register. |
RSP | Yes | The starting memory address for the RSP register. |
The sub-fields of the above keys
Field | Required? | Description |
---|---|---|
Type | Yes | The type of memory address. |
Value | Yes | The value of the respective Type. For example, a value for Type Gadget would reference a named Gadget. |
Offset | No | The offset from the value. |
Type | Description |
---|---|
Gadget | A loaded Gadget |
Memory | A loaded RW Memory |
Int | A raw integer |
The ROP/JOP chain to be written to the target thread. The program keeps track of the current address to write to, incrementing by the designated padding in the Memory section. For the Stack, the padding is set to 1.
Field | Required? | Description |
---|---|---|
Type | Yes | The type of memory address. |
Location | Yes | The referenced Memory to write to. For example, a value of "Stack" would write to the Stack. |
Value | Yes | The value of the respective Type. For example, a value for Type Gadget would reference a named Gadget. |
GadgetOffset | Optional | The Offset from the Gadget's address to write. |
Module | Only for Function Types | The module containing the referenced function. |
Section | Only for CodeCaveRVA Types | The section for the RVA of the code cave |
MemoryOffset | Only for Memory Types | The offset from the refernced Memory's base address |
Type | Description |
---|---|
DONTCARE | The Value at the current address doesn't matter. Increments the current address by the referenced Memorys's padding * the specified value. |
SHADOWSPACE | Useful for Function Calls. Writes 0x20 0's to the referenced Memory's current address |
Gadget | A Loaded Gadget |
Int | A raw integer |
Memory | A loaded memory's base address |
Function | A function's address |
FunctionRVA | The relative virtual address of a function in a referenced module |
Module | A loaded module's base address |
ModuleSize | A loaded module's size |
CodeCave | A code cave in a referenced module |
CodeCaveRVA | The relative virtual address of a code cave in a referenced module |
Payload | A payload's base address |
PayloadSize | A payload's size |
I'm still working on an example JOP Chain. Hopefully that doesn't break too many things 😆