Skip to content

Commit e925dab

Browse files
committed
yaml config & windows service mode
1 parent 5fc7995 commit e925dab

File tree

9 files changed

+444
-71
lines changed

9 files changed

+444
-71
lines changed

go.mod

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
module go-win-process-injector
1+
module goprocinjector
22

33
go 1.23.6
44

55
require (
6+
github.com/akamensky/argparse v1.4.0
67
github.com/shirou/gopsutil v3.21.11+incompatible
78
golang.org/x/sys v0.32.0
9+
gopkg.in/yaml.v3 v3.0.1
810
)
911

1012
require (

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
github.com/akamensky/argparse v1.4.0 h1:YGzvsTqCvbEZhL8zZu2AiA5nq805NZh75JNj4ajn1xc=
2+
github.com/akamensky/argparse v1.4.0/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA=
13
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
24
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
35
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
@@ -17,5 +19,7 @@ github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQ
1719
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1820
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
1921
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
22+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
23+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
2024
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
2125
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

goprocinjector.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
injector_log_level: "LOGLEVEL_INFO"
2+
injector_log_file: "C:\\Windows\\Temp\\goprocinjector.log"
3+
process_injections:
4+
- name: "ClipboardMonitor_WebBrowser"
5+
processes:
6+
- "firefox.exe"
7+
- "chrome.exe"
8+
process_injection_dll_path: "C:\\Users\\shado\\Desktop\\clipboardMonitor\\ClipboardMonitor.dll"
9+
process_injection_dll_function: "ClipboardMonitor"
10+
process_injection_refresh_interval: 5
11+
- name: "ClipboardMonitor_Explorer"
12+
processes:
13+
- "explorer.exe"
14+
process_injection_dll_path: "C:\\Users\\shado\\Desktop\\clipboardMonitor\\ClipboardMonitor.dll"
15+
process_injection_dll_function: "ClipboardMonitor"
16+
process_injection_refresh_interval: 30

injector.go

Lines changed: 42 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ var (
1414
virtualAllocEx = kernel32DLL.NewProc("VirtualAllocEx")
1515
writeProcessMemory = kernel32DLL.NewProc("WriteProcessMemory")
1616
createRemoteThread = kernel32DLL.NewProc("CreateRemoteThread")
17+
getThreadId = kernel32DLL.NewProc("GetThreadId")
1718
createToolhelp32Snapshot = kernel32DLL.NewProc("CreateToolhelp32Snapshot")
1819
process32FirstW = kernel32DLL.NewProc("Process32FirstW")
1920
process32NextW = kernel32DLL.NewProc("Process32NextW")
@@ -54,8 +55,8 @@ func injectDLL(processID uint32, processHandle windows.Handle, dllPath string) (
5455
if remoteAlloc == 0 {
5556
return 0, fmt.Errorf("VirtualAllocEx failed: %v", err)
5657
}
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))
58+
logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - VirtualAllocEx...", processID))
59+
logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - Allocating memory at: 0x%x", processID, remoteAlloc))
5960

6061
bytesWritten := uint(0)
6162
_, _, err = writeProcessMemory.Call(
@@ -66,9 +67,9 @@ func injectDLL(processID uint32, processHandle windows.Handle, dllPath string) (
6667
uintptr(unsafe.Pointer(&bytesWritten)),
6768
)
6869
if bytesWritten == 0 {
69-
return 0, fmt.Errorf("PID: %d WriteProcessMemory failed: %v", processID, err)
70+
return 0, fmt.Errorf("WriteProcessMemory failed: %v", err)
7071
}
71-
logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - Bytes written: %d\n", processID, bytesWritten))
72+
logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - Bytes written: %d", processID, bytesWritten))
7273

7374
threadHandle, _, err := createRemoteThread.Call(
7475
uintptr(processHandle),
@@ -80,40 +81,40 @@ func injectDLL(processID uint32, processHandle windows.Handle, dllPath string) (
8081
0,
8182
)
8283
if threadHandle == 0 {
83-
return 0, fmt.Errorf("PID: %d - CreateRemoteThread failed: %v", processID, err)
84+
return 0, fmt.Errorf("CreateRemoteThread failed: %v", err)
8485
}
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))
86+
logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - CreateRemoteThread...", processID))
87+
logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - Thread Handle: %d", processID, threadHandle))
8788
defer syscall.CloseHandle(syscall.Handle(threadHandle))
8889

89-
logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - Waiting for thread to finish...\n", processID))
90+
logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - Waiting for thread to finish...", processID))
9091
_, err = syscall.WaitForSingleObject(syscall.Handle(threadHandle), syscall.INFINITE)
9192
if err != nil {
92-
return 0, fmt.Errorf("PID: %d - WaitForSingleObject failed: %v", processID, err)
93+
return 0, fmt.Errorf("WaitForSingleObject failed: %v", err)
9394
}
9495

9596
// Récupérer l'adresse de la DLL chargée dans le processus distant
9697
remoteDLLHandle, err := GetInjectedLibraryModuleHandle(processID, dllPath)
9798
if err != nil {
98-
return 0, fmt.Errorf("PID: %d - GetModuleHandle failed: %v", processID, err)
99+
return 0, fmt.Errorf("GetModuleHandle failed: %v", err)
99100
}
100-
logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - DLL address in the remote process: 0x%x\n", processID, remoteDLLHandle))
101+
logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - DLL address in the remote process: 0x%x", processID, remoteDLLHandle))
101102

102103
return remoteDLLHandle, nil
103104
}
104105

105106
func GetInjectedLibraryModuleHandle(processID uint32, injectedDllPath string) (uintptr, error) {
106107
handle, err := syscall.OpenProcess(windows.PROCESS_QUERY_INFORMATION|windows.PROCESS_VM_READ, false, processID)
107108
if err != nil {
108-
return 0, fmt.Errorf("PID: %d - error opening process: %w", processID, err)
109+
return 0, fmt.Errorf("error opening process: %w", err)
109110
}
110111
defer syscall.CloseHandle(syscall.Handle(handle))
111112

112113
var modules [1024]windows.Handle
113114
var needed uint32
114115
err = windows.EnumProcessModules(windows.Handle(handle), &modules[0], uint32(unsafe.Sizeof(modules)), &needed)
115116
if err != nil {
116-
return 0, fmt.Errorf("PID: %d - error enumerating process modules: %v", processID, err)
117+
return 0, fmt.Errorf("error enumerating process modules: %v", err)
117118
}
118119

119120
numModules := needed / uint32(unsafe.Sizeof(windows.Handle(0)))
@@ -128,16 +129,16 @@ func GetInjectedLibraryModuleHandle(processID uint32, injectedDllPath string) (u
128129
}
129130

130131
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+
processHandle, err := syscall.OpenProcess(windows.PROCESS_QUERY_INFORMATION|windows.PROCESS_VM_READ, false, processID)
132133
if err != nil {
133-
return fmt.Errorf("PID: %d - error opening process: %w", processID, err)
134+
return fmt.Errorf("error opening process: %w", err)
134135
}
135-
defer syscall.CloseHandle(syscall.Handle(handle))
136+
defer syscall.CloseHandle(syscall.Handle(processHandle))
136137

137138
remoteFunctionAddress := dllBaseAddress + functionRVA
138139

139140
threadHandle, _, err := createRemoteThread.Call(
140-
uintptr(handle),
141+
uintptr(processHandle),
141142
0,
142143
0,
143144
remoteFunctionAddress,
@@ -146,43 +147,54 @@ func callRemoteFunction(processID uint32, dllBaseAddress uintptr, functionName s
146147
0,
147148
)
148149
if threadHandle == 0 {
149-
return fmt.Errorf("PID: %d - CreateRemoteThread failed while calling '%s'- %v", processID, functionName, err)
150+
return fmt.Errorf("CreateRemoteThread failed while calling '%s'- %v", functionName, err)
150151
}
151152
defer syscall.CloseHandle(syscall.Handle(threadHandle))
152153

154+
threadId, _, err := getThreadId.Call(uintptr(threadHandle))
155+
156+
if threadId == 0 {
157+
return fmt.Errorf("GetThreadId failed: %v", err)
158+
}
159+
160+
logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - Remote Thread ID: %d", processID, threadId))
161+
153162
return nil
154163
}
155164

156165
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))
166+
logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - Opening process %s with 0x%x access...", processID, processName, windows.PROCESS_CREATE_THREAD|windows.PROCESS_VM_WRITE|windows.PROCESS_VM_OPERATION))
158167
processHandle, err := syscall.OpenProcess(windows.PROCESS_CREATE_THREAD|windows.PROCESS_VM_WRITE|windows.PROCESS_VM_OPERATION, false, processID)
159168
if err != nil {
160-
return fmt.Errorf("PID: %d - OpenProcess failed: %v", processID, err)
169+
return fmt.Errorf("OpenProcess failed: %v", err)
161170
}
162171
defer syscall.CloseHandle(processHandle)
163172

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)))
173+
logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - Process Handle: 0x%x", processID, processHandle))
174+
logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - Loading DLL: %s", processID, dllPath))
175+
logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - DLL Path Length: %d", processID, len(dllPath)))
167176

168177
dllBaseAddress, err := injectDLL(processID, windows.Handle(processHandle), dllPath)
169-
if err != nil {
170-
return fmt.Errorf("PID: %d - DLL injection failed: %v", processID, err)
178+
if err != nil || dllBaseAddress == 0 {
179+
if err == nil {
180+
err = fmt.Errorf("DLL base address is 0")
181+
}
182+
return fmt.Errorf("DLL injection failed: %v", err)
171183
}
172-
logMessage(LOGLEVEL_INFO, fmt.Sprintf("PID: %d - DLL injected successfully.\n", processID))
184+
logMessage(LOGLEVEL_INFO, fmt.Sprintf("PID: %d - DLL injected successfully.", processID))
173185

174186
FunctionRVA, err := findSymbolRVA(dllPath, dllFunction)
175187
if err != nil {
176-
return fmt.Errorf("PID: %d - Error finding symbol RVA: %v", processID, err)
188+
return fmt.Errorf("error finding symbol RVA: %v", err)
177189
}
178-
logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - Function '%s' RVA: 0x%x\n", processID, dllFunction, FunctionRVA))
190+
logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - Function '%s' RVA: 0x%x", processID, dllFunction, FunctionRVA))
179191

180192
err = callRemoteFunction(processID, dllBaseAddress, dllFunction, uintptr(FunctionRVA))
181193
if err != nil {
182194

183-
return fmt.Errorf("PID: %d - Error calling remote function %v", processID, err)
195+
return fmt.Errorf("error calling remote function %v", err)
184196
}
185-
logMessage(LOGLEVEL_INFO, fmt.Sprintf("PID: %d - Function '%s' successfully called.\n", processID, dllFunction))
197+
logMessage(LOGLEVEL_DEBUG, fmt.Sprintf("PID: %d - Function '%s' successfully called.", processID, dllFunction))
186198

187199
return nil
188200
}

logger.go

Lines changed: 89 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,106 @@ package main
22

33
import (
44
"fmt"
5+
"os"
6+
"path/filepath"
7+
"strings"
58
"time"
69
)
710

811
const (
9-
LOGLEVEL_ERROR = 0
12+
LOGLEVEL_DEBUG = 0
1013
LOGLEVEL_INFO = 1
1114
LOGLEVEL_WARNING = 2
12-
LOGLEVEL_DEBUG = 3
15+
LOGLEVEL_ERROR = 3
16+
LOGLEVEL_FATAL = 4
17+
18+
LOGLEVEL_DEV_DEBUG_VERBOSE = -1
19+
)
20+
21+
var (
22+
logFile *os.File
23+
currentLogLevel int
24+
hostname string
25+
username string
26+
processName string
27+
pid int
1328
)
1429

15-
var currentLogLevel = LOGLEVEL_INFO
30+
func InitLogger(level int) {
31+
currentLogLevel = level
32+
hostname, _ = os.Hostname()
33+
username = os.Getenv("USERNAME")
34+
pid = os.Getpid()
35+
processName = filepath.Base(os.Args[0])
36+
}
37+
38+
func SetLogToFile(filePath string) {
39+
40+
if logFile != nil {
41+
logFile.Close()
42+
}
43+
44+
var err error
45+
logFile, err = os.OpenFile(filePath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
46+
if err != nil {
47+
fmt.Printf("Error opening log file: %v\n", err)
48+
logFile = nil
49+
}
50+
}
1651

17-
func SetLogLevel(logLevel int) {
18-
if logLevel >= LOGLEVEL_INFO && logLevel <= LOGLEVEL_DEBUG {
19-
currentLogLevel = logLevel
20-
} else {
21-
fmt.Println("Niveau de logging invalide. Utilisation du niveau INFO par défaut.")
22-
currentLogLevel = LOGLEVEL_INFO
52+
func CloseLogger() {
53+
if logFile != nil {
54+
logFile.Sync()
55+
logFile.Close()
56+
logFile = nil
2357
}
2458
}
2559

26-
func logMessage(logLevel int, message string) {
27-
if logLevel <= currentLogLevel {
28-
currentTime := time.Now().Format("2006-01-02 15:04:05")
29-
logLevels := []string{"ERROR", "INFO", "WARNING", "DEBUG"}
30-
logMessage := fmt.Sprintf("[%s] [%s] %s", currentTime, logLevels[logLevel], message)
31-
fmt.Print(logMessage)
60+
func CleanData(message string) string {
61+
cleanedData := strings.ReplaceAll(message, "\n", "\\n")
62+
cleanedData = strings.ReplaceAll(cleanedData, "\r", "\\r")
63+
64+
return cleanedData
65+
}
66+
67+
func logMessage(level int, message string) {
68+
if level < currentLogLevel {
69+
return
70+
}
71+
72+
logPrefix := ""
73+
switch level {
74+
case LOGLEVEL_DEBUG:
75+
logPrefix = "DEBUG"
76+
case LOGLEVEL_INFO:
77+
logPrefix = "INFO"
78+
case LOGLEVEL_WARNING:
79+
logPrefix = "WARNING"
80+
case LOGLEVEL_ERROR:
81+
logPrefix = "ERROR"
82+
case LOGLEVEL_FATAL:
83+
logPrefix = "FATAL"
84+
case LOGLEVEL_DEV_DEBUG_VERBOSE:
85+
logPrefix = "DEV_DEBUG_VERBOSE"
86+
}
87+
88+
logEntry := fmt.Sprintf("[%s] [%s] Hostname: %s - Username: %s - ProcessName: %s - PID: %d - Message: %s\n",
89+
time.Now().Format("2006-01-02 15:04:05.000000"),
90+
logPrefix,
91+
hostname,
92+
username,
93+
processName,
94+
pid,
95+
CleanData(message),
96+
)
97+
98+
fmt.Print(logEntry)
99+
100+
if logFile != nil {
101+
_, err := logFile.WriteString(logEntry)
102+
103+
if err != nil {
104+
fmt.Printf("Error writing to log file: %v\n", err)
105+
}
32106
}
33107
}

0 commit comments

Comments
 (0)