|
| 1 | +package main |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + "syscall" |
| 6 | + "unsafe" |
| 7 | + |
| 8 | + "golang.org/x/sys/windows" |
| 9 | +) |
| 10 | + |
| 11 | +var ( |
| 12 | + kernel32DLL = syscall.NewLazyDLL("kernel32.dll") |
| 13 | + loadLibraryW = kernel32DLL.NewProc("LoadLibraryW") |
| 14 | + virtualAllocEx = kernel32DLL.NewProc("VirtualAllocEx") |
| 15 | + writeProcessMemory = kernel32DLL.NewProc("WriteProcessMemory") |
| 16 | + createRemoteThread = kernel32DLL.NewProc("CreateRemoteThread") |
| 17 | + createToolhelp32Snapshot = kernel32DLL.NewProc("CreateToolhelp32Snapshot") |
| 18 | + process32FirstW = kernel32DLL.NewProc("Process32FirstW") |
| 19 | + process32NextW = kernel32DLL.NewProc("Process32NextW") |
| 20 | +) |
| 21 | + |
| 22 | +type PROCESSENTRY32 struct { |
| 23 | + DwSize uint32 |
| 24 | + CntUsage uint32 |
| 25 | + Th32ProcessID uint32 |
| 26 | + Th32DefaultHeapID uintptr |
| 27 | + Th32ModuleID uint32 |
| 28 | + CntThreads uint32 |
| 29 | + Th32ParentProcessID uint32 |
| 30 | + PcPriClassBase int32 |
| 31 | + DwFlags uint32 |
| 32 | + SzExeFile [syscall.MAX_PATH]uint8 |
| 33 | +} |
| 34 | + |
| 35 | +const ( |
| 36 | + MEM_RESERVE = 0x00002000 |
| 37 | + MEM_COMMIT = 0x00001000 |
| 38 | + TH32CS_SNAPPROCESS = 0x00000002 |
| 39 | +) |
| 40 | + |
| 41 | +func injectDLL(processID uint32, processHandle windows.Handle, dllPath string) (uintptr, error) { |
| 42 | + dllPathPtr, err := windows.UTF16PtrFromString(dllPath) |
| 43 | + if err != nil { |
| 44 | + return 0, err |
| 45 | + } |
| 46 | + |
| 47 | + remoteAlloc, _, err := virtualAllocEx.Call( |
| 48 | + uintptr(processHandle), |
| 49 | + 0, |
| 50 | + uintptr(len(dllPath)*2+2), |
| 51 | + uintptr(MEM_RESERVE|MEM_COMMIT), |
| 52 | + uintptr(windows.PAGE_READWRITE), |
| 53 | + ) |
| 54 | + if remoteAlloc == 0 { |
| 55 | + return 0, fmt.Errorf("VirtualAllocEx failed: %v", err) |
| 56 | + } |
| 57 | + logMessage(LOGLEVEL_INFO, fmt.Sprintf("PID: %d - VirtualAllocEx...\n", processID)) |
| 58 | + logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - Allocating memory at: 0x%x\n", processID, remoteAlloc)) |
| 59 | + |
| 60 | + bytesWritten := uint(0) |
| 61 | + _, _, err = writeProcessMemory.Call( |
| 62 | + uintptr(processHandle), |
| 63 | + remoteAlloc, |
| 64 | + uintptr(unsafe.Pointer(dllPathPtr)), |
| 65 | + uintptr(len(dllPath)*2+2), |
| 66 | + uintptr(unsafe.Pointer(&bytesWritten)), |
| 67 | + ) |
| 68 | + if bytesWritten == 0 { |
| 69 | + return 0, fmt.Errorf("PID: %d WriteProcessMemory failed: %v", processID, err) |
| 70 | + } |
| 71 | + logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - Bytes written: %d\n", processID, bytesWritten)) |
| 72 | + |
| 73 | + threadHandle, _, err := createRemoteThread.Call( |
| 74 | + uintptr(processHandle), |
| 75 | + 0, |
| 76 | + 0, |
| 77 | + uintptr(loadLibraryW.Addr()), |
| 78 | + remoteAlloc, |
| 79 | + 0, |
| 80 | + 0, |
| 81 | + ) |
| 82 | + if threadHandle == 0 { |
| 83 | + return 0, fmt.Errorf("PID: %d - CreateRemoteThread failed: %v", processID, err) |
| 84 | + } |
| 85 | + logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - CreateRemoteThread...\n", processID)) |
| 86 | + logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - Thread Handle: %d\n", processID, threadHandle)) |
| 87 | + defer syscall.CloseHandle(syscall.Handle(threadHandle)) |
| 88 | + |
| 89 | + logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - Waiting for thread to finish...\n", processID)) |
| 90 | + _, err = syscall.WaitForSingleObject(syscall.Handle(threadHandle), syscall.INFINITE) |
| 91 | + if err != nil { |
| 92 | + return 0, fmt.Errorf("PID: %d - WaitForSingleObject failed: %v", processID, err) |
| 93 | + } |
| 94 | + |
| 95 | + // Récupérer l'adresse de la DLL chargée dans le processus distant |
| 96 | + remoteDLLHandle, err := GetInjectedLibraryModuleHandle(processID, dllPath) |
| 97 | + if err != nil { |
| 98 | + return 0, fmt.Errorf("PID: %d - GetModuleHandle failed: %v", processID, err) |
| 99 | + } |
| 100 | + logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - DLL address in the remote process: 0x%x\n", processID, remoteDLLHandle)) |
| 101 | + |
| 102 | + return remoteDLLHandle, nil |
| 103 | +} |
| 104 | + |
| 105 | +func GetInjectedLibraryModuleHandle(processID uint32, injectedDllPath string) (uintptr, error) { |
| 106 | + handle, err := syscall.OpenProcess(windows.PROCESS_QUERY_INFORMATION|windows.PROCESS_VM_READ, false, processID) |
| 107 | + if err != nil { |
| 108 | + return 0, fmt.Errorf("PID: %d - error opening process: %w", processID, err) |
| 109 | + } |
| 110 | + defer syscall.CloseHandle(syscall.Handle(handle)) |
| 111 | + |
| 112 | + var modules [1024]windows.Handle |
| 113 | + var needed uint32 |
| 114 | + err = windows.EnumProcessModules(windows.Handle(handle), &modules[0], uint32(unsafe.Sizeof(modules)), &needed) |
| 115 | + if err != nil { |
| 116 | + return 0, fmt.Errorf("PID: %d - error enumerating process modules: %v", processID, err) |
| 117 | + } |
| 118 | + |
| 119 | + numModules := needed / uint32(unsafe.Sizeof(windows.Handle(0))) |
| 120 | + for i := uint32(0); i < numModules; i++ { |
| 121 | + var filename [windows.MAX_PATH]uint16 |
| 122 | + err = windows.GetModuleFileNameEx(windows.Handle(handle), modules[i], &filename[0], windows.MAX_PATH) |
| 123 | + if err == nil && windows.UTF16ToString(filename[:]) == injectedDllPath { |
| 124 | + return uintptr(modules[i]), nil |
| 125 | + } |
| 126 | + } |
| 127 | + return 0, nil |
| 128 | +} |
| 129 | + |
| 130 | +func callRemoteFunction(processID uint32, dllBaseAddress uintptr, functionName string, functionRVA uintptr) error { |
| 131 | + handle, err := syscall.OpenProcess(windows.PROCESS_QUERY_INFORMATION|windows.PROCESS_VM_READ, false, processID) |
| 132 | + if err != nil { |
| 133 | + return fmt.Errorf("PID: %d - error opening process: %w", processID, err) |
| 134 | + } |
| 135 | + defer syscall.CloseHandle(syscall.Handle(handle)) |
| 136 | + |
| 137 | + remoteFunctionAddress := dllBaseAddress + functionRVA |
| 138 | + |
| 139 | + threadHandle, _, err := createRemoteThread.Call( |
| 140 | + uintptr(handle), |
| 141 | + 0, |
| 142 | + 0, |
| 143 | + remoteFunctionAddress, |
| 144 | + 0, |
| 145 | + 0, |
| 146 | + 0, |
| 147 | + ) |
| 148 | + if threadHandle == 0 { |
| 149 | + return fmt.Errorf("PID: %d - CreateRemoteThread failed while calling '%s'- %v", processID, functionName, err) |
| 150 | + } |
| 151 | + defer syscall.CloseHandle(syscall.Handle(threadHandle)) |
| 152 | + |
| 153 | + return nil |
| 154 | +} |
| 155 | + |
| 156 | +func injectInProcess(processID uint32, processName string, dllPath string, dllFunction string) error { |
| 157 | + logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - Opening process %s with 0x%x access...\n", processID, processName, windows.PROCESS_CREATE_THREAD|windows.PROCESS_VM_WRITE|windows.PROCESS_VM_OPERATION)) |
| 158 | + processHandle, err := syscall.OpenProcess(windows.PROCESS_CREATE_THREAD|windows.PROCESS_VM_WRITE|windows.PROCESS_VM_OPERATION, false, processID) |
| 159 | + if err != nil { |
| 160 | + return fmt.Errorf("PID: %d - OpenProcess failed: %v", processID, err) |
| 161 | + } |
| 162 | + defer syscall.CloseHandle(processHandle) |
| 163 | + |
| 164 | + logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - Process Handle: 0x%x\n", processID, processHandle)) |
| 165 | + logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - Loading DLL: %s\n", processID, dllPath)) |
| 166 | + logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - DLL Path Length: %d\n", processID, len(dllPath))) |
| 167 | + |
| 168 | + dllBaseAddress, err := injectDLL(processID, windows.Handle(processHandle), dllPath) |
| 169 | + if err != nil { |
| 170 | + return fmt.Errorf("PID: %d - DLL injection failed: %v", processID, err) |
| 171 | + } |
| 172 | + logMessage(LOGLEVEL_INFO, fmt.Sprintf("PID: %d - DLL injected successfully.\n", processID)) |
| 173 | + |
| 174 | + FunctionRVA, err := findSymbolRVA(dllPath, dllFunction) |
| 175 | + if err != nil { |
| 176 | + return fmt.Errorf("PID: %d - Error finding symbol RVA: %v", processID, err) |
| 177 | + } |
| 178 | + logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - Function '%s' RVA: 0x%x\n", processID, dllFunction, FunctionRVA)) |
| 179 | + |
| 180 | + err = callRemoteFunction(processID, dllBaseAddress, dllFunction, uintptr(FunctionRVA)) |
| 181 | + if err != nil { |
| 182 | + |
| 183 | + return fmt.Errorf("PID: %d - Error calling remote function %v", processID, err) |
| 184 | + } |
| 185 | + logMessage(LOGLEVEL_INFO, fmt.Sprintf("PID: %d - Function '%s' successfully called.\n", processID, dllFunction)) |
| 186 | + |
| 187 | + return nil |
| 188 | +} |
0 commit comments