-
Notifications
You must be signed in to change notification settings - Fork 0
/
Injector.cs
174 lines (131 loc) · 7.27 KB
/
Injector.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
namespace chihuahua {
/*
* Shamelessly stolen from UEVR frontend: https://github.com/praydog/uevr-frontend/blob/main/UEVR/Injector.cs
*
* All credit goes to Praydog and UEVR Project.
*
* Main UEVR project page: https://github.com/praydog/UEVR
* Patreon: https://www.patreon.com/praydog
*
*/
internal class Injector {
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out int lpNumberOfBytesWritten);
[DllImport("kernel32.dll")]
public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);
// Inject the DLL into the target process
// dllPath is local filename, relative to EXE.
public static bool InjectDll(int processId, string dllPath, out IntPtr dllBase) {
string originalPath = dllPath;
try {
var exeDirectory = AppContext.BaseDirectory;
if (exeDirectory != null) {
var newPath = Path.Combine(exeDirectory, dllPath);
if (File.Exists(newPath)) {
dllPath = Path.Combine(exeDirectory, dllPath);
}
}
} catch (Exception) {
}
if (!File.Exists(dllPath)) {
Logger.Error($"{originalPath} does not appear to exist! Check if any anti-virus software has deleted the file. Reinstall UEVR if necessary.");
}
dllBase = IntPtr.Zero;
string fullPath = Path.GetFullPath(dllPath);
// Open the target process with the necessary access
IntPtr processHandle = OpenProcess(0x1F0FFF, false, processId);
if (processHandle == IntPtr.Zero) {
Logger.Error("Could not open a handle to the target process.\nYou may need to start this program as an administrator, or the process may be protected.");
return false;
}
// Get the address of the LoadLibrary function
IntPtr loadLibraryAddress = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryW");
if (loadLibraryAddress == IntPtr.Zero) {
Logger.Error("Could not obtain LoadLibraryW address in the target process.");
return false;
}
// Allocate memory in the target process for the DLL path
IntPtr dllPathAddress = VirtualAllocEx(processHandle, IntPtr.Zero, (uint)fullPath.Length, 0x1000, 0x40);
if (dllPathAddress == IntPtr.Zero) {
Logger.Error("Failed to allocate memory in the target process.");
return false;
}
// Write the DLL path in UTF-16
int bytesWritten = 0;
var bytes = Encoding.Unicode.GetBytes(fullPath);
WriteProcessMemory(processHandle, dllPathAddress, bytes, (uint)(fullPath.Length * 2), out bytesWritten);
// Create a remote thread in the target process that calls LoadLibrary with the DLL path
IntPtr threadHandle = CreateRemoteThread(processHandle, IntPtr.Zero, 0, loadLibraryAddress, dllPathAddress, 0, IntPtr.Zero);
if (threadHandle == IntPtr.Zero) {
Logger.Error("Failed to create remote thread in the target processs.");
return false;
}
WaitForSingleObject(threadHandle, 1000);
Process p = Process.GetProcessById(processId);
// Get base of DLL that was just injected
if (p != null) try {
foreach (ProcessModule module in p.Modules) {
if (module.FileName != null && module.FileName == fullPath) {
dllBase = module.BaseAddress;
break;
}
}
} catch (Exception ex) {
Logger.Error($"Exception: {ex.Message}");
}
return true;
}
public static bool InjectDll(int processId, string dllPath) {
IntPtr dummy;
return InjectDll(processId, dllPath, out dummy);
}
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr LoadLibrary(string lpFileName);
// FreeLibrary
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool FreeLibrary(IntPtr hModule);
public static bool CallFunctionNoArgs(int processId, string dllPath, IntPtr dllBase, string functionName, bool wait = false) {
IntPtr processHandle = OpenProcess(0x1F0FFF, false, processId);
if (processHandle == IntPtr.Zero) {
Logger.Error("Could not open a handle to the target process. You may need to start this program as an administrator, or the process may be protected.");
return false;
}
// We need to load the DLL into our own process temporarily as a workaround for GetProcAddress not working with remote DLLs
IntPtr localDllHandle = LoadLibrary(dllPath);
if (localDllHandle == IntPtr.Zero) {
Logger.Error("Could not load the target DLL into our own process.");
return false;
}
IntPtr localVa = GetProcAddress(localDllHandle, functionName);
if (localVa == IntPtr.Zero) {
Logger.Error("Could not obtain " + functionName + " address in our own process.");
return false;
}
IntPtr rva = (IntPtr)(localVa.ToInt64() - localDllHandle.ToInt64());
IntPtr functionAddress = (IntPtr)(dllBase.ToInt64() + rva.ToInt64());
// Create a remote thread in the target process that calls the function
IntPtr threadHandle = CreateRemoteThread(processHandle, IntPtr.Zero, 0, functionAddress, IntPtr.Zero, 0, IntPtr.Zero);
if (threadHandle == IntPtr.Zero) {
Logger.Error("Failed to create remote thread in the target processs.");
return false;
}
if (wait) {
WaitForSingleObject(threadHandle, 2000);
}
return true;
}
}
}