Seregon/Hermes

Hermes/Dyforge is a program written in c++ allows you to inject a dll that can analyze all processes in a program, can be used for mod and reverse engeneering

C/3.8 KB/No license
DyHexInject/DyHexInject.c
Hermes / DyHexInject / DyHexInject.c
1#define DYHEXINJECT_EXPORTS
2#include "DyHexInject.h"
3#include "include/DyHexInjectTypes.h"
4#include <windows.h>
5#include <tlhelp32.h>
6#include <psapi.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10 
11// Debug logging
12static bool g_debugLogging = false;
13static FILE* g_logFile = NULL;
14 
15// Shared memory layout
16typedef struct {
17 char command[1024];
18 char response[1024];
19 bool commandReady;
20 bool responseReady;
21 HANDLE commandEvent;
22 HANDLE responseEvent;
23} SharedMemoryLayout;
24 
25// Helper functions
26static void LogDebug(const char* format, ...) {
27 if (!g_debugLogging) return;
28
29 va_list args;
30 va_start(args, format);
31 vfprintf(g_logFile, format, args);
32 va_end(args);
33 fflush(g_logFile);
34}
35 
36static bool IsProcess64Bit(HANDLE processHandle) {
37 BOOL isWow64 = FALSE;
38 IsWow64Process(processHandle, &isWow64);
39 return !isWow64;
40}
41 
42// Core functions
43DYHEXINJECT_API DyHexInjectError DyHexInject_Initialize(void) {
44 if (g_debugLogging) {
45 g_logFile = fopen("DyHexInject.log", "a");
46 if (!g_logFile) {
47 return DYHEXINJECT_ERROR_INVALID_PARAMETERS;
48 }
49 }
50 return DYHEXINJECT_SUCCESS;
51}
52 
53DYHEXINJECT_API void DyHexInject_Cleanup(void) {
54 if (g_logFile) {
55 fclose(g_logFile);
56 g_logFile = NULL;
57 }
58}
59 
60// Process management
61DYHEXINJECT_API DyHexInjectError DyHexInject_OpenProcess(DWORD processId, DyHexInjectProcessInfo* processInfo) {
62 if (!processInfo) {
63 return DYHEXINJECT_ERROR_INVALID_PARAMETERS;
64 }
65 
66 // Open process with required access rights
67 HANDLE processHandle = OpenProcess(
68 PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION |
69 PROCESS_VM_WRITE | PROCESS_VM_READ,
70 FALSE,
71 processId
72 );
73 
74 if (!processHandle) {
75 LogDebug("Failed to open process %d: %d\n", processId, GetLastError());
76 return DYHEXINJECT_ERROR_PROCESS_NOT_FOUND;
77 }
78 
79 // Get process information
80 processInfo->processId = processId;
81 processInfo->processHandle = processHandle;
82 processInfo->is64Bit = IsProcess64Bit(processHandle);
83 
84 // Get process name and path
85 if (!GetModuleFileNameExW(processHandle, NULL, processInfo->processPath, MAX_PATH)) {
86 LogDebug("Failed to get process path: %d\n", GetLastError());
87 CloseHandle(processHandle);
88 return DYHEXINJECT_ERROR_PROCESS_NOT_FOUND;
89 }
90 
91 wchar_t* lastSlash = wcsrchr(processInfo->processPath, L'\\');
92 if (lastSlash) {
93 wcscpy_s(processInfo->processName, MAX_PATH, lastSlash + 1);
94 } else {
95 wcscpy_s(processInfo->processName, MAX_PATH, processInfo->processPath);
96 }
97 
98 return DYHEXINJECT_SUCCESS;
99}
100 
101DYHEXINJECT_API void DyHexInject_CloseProcess(DyHexInjectProcessInfo* processInfo) {
102 if (processInfo && processInfo->processHandle) {
103 CloseHandle(processInfo->processHandle);
104 processInfo->processHandle = NULL;
105 }
106}
107 
108// Injection functions
109DYHEXINJECT_API DyHexInjectError DyHexInject_InjectDll(DyHexInjectProcessInfo* processInfo, const DyHexInjectConfig* config) {
110 if (!processInfo || !config) {
111 return DYHEXINJECT_ERROR_INVALID_PARAMETERS;
112 }
113 
114 LogDebug("Injecting DLL: %ls\n", config->dllPath);
115 
116 // Allocate memory for DLL path
117 size_t pathSize = (wcslen(config->dllPath) + 1) * sizeof(wchar_t);
118 LPVOID remotePath = VirtualAllocEx(
119 processInfo->processHandle,
120 NULL,
121 pathSize,
122 MEM_COMMIT | MEM_RESERVE,
123 PAGE_READWRITE
124 );
125 
126 if (!remotePath) {
127 LogDebug("Failed to allocate memory: %d\n", GetLastError());
128 return DYHEXINJECT_ERROR_INJECTION_FAILED;
129 }
130 
131 // Write DLL path to remote memory
132 if (!WriteProcessMemory(
133 processInfo->processHandle,
134 remotePath,
135 config->dllPath,
136 pathSize,
137 NULL
138 )) {
139 LogDebug("Failed to write memory: %d\n", GetLastError());
140 VirtualFreeEx(processInfo->processHandle, remotePath, 0, MEM_RELEASE);
141 return DYHEXINJECT_ERROR_INJECTION_FAILED;
142 }
143 
144 // Get LoadLibraryW address
145 HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
146 if (!kernel32) {
147 LogDebug("Failed to get kernel32 handle: %d\n", GetLastError());
148 VirtualFreeEx(processInfo->processHandle, remotePath, 0, MEM_RELEASE);
149 return DYHEXINJECT_ERROR_INJECTION_FAILED;
150 }
151 
152 LPTHREAD_START_ROUTINE loadLibraryAddr = (LPTHREAD_START_ROUTINE)GetProcAddress(
153 kernel32,
154 "LoadLibraryW"
155 );
156 
157 if (!loadLibraryAddr) {
158 LogDebug("Failed to get LoadLibraryW address: %d\n", GetLastError());
159 VirtualFreeEx(processInfo->processHandle, remotePath, 0, MEM_RELEASE);
160 return DYHEXINJECT_ERROR_INJECTION_FAILED;
161 }
162 
163 // Create remote thread to load DLL
164 HANDLE remoteThread = CreateRemoteThread(
165 processInfo->processHandle,
166 NULL,
167 0,
168 loadLibraryAddr,
169 remotePath,
170 0,
171 NULL
172 );
173 
174 if (!remoteThread) {
175 LogDebug("Failed to create remote thread: %d\n", GetLastError());
176 VirtualFreeEx(processInfo->processHandle, remotePath, 0, MEM_RELEASE);
177 return DYHEXINJECT_ERROR_INJECTION_FAILED;
178 }
179 
180 // Wait for injection if requested
181 if (config->waitForInjection) {
182 WaitForSingleObject(remoteThread, INFINITE);
183 }
184 
185 // Cleanup
186 CloseHandle(remoteThread);
187 VirtualFreeEx(processInfo->processHandle, remotePath, 0, MEM_RELEASE);
188 
189 return DYHEXINJECT_SUCCESS;
190}
191 
192DYHEXINJECT_API DyHexInjectError DyHexInject_EjectDll(DyHexInjectProcessInfo* processInfo, const wchar_t* dllPath) {
193 if (!processInfo || !dllPath) {
194 return DYHEXINJECT_ERROR_INVALID_PARAMETERS;
195 }
196 
197 LogDebug("Ejecting DLL: %ls\n", dllPath);
198 
199 // Get module handle
200 HMODULE moduleHandle = NULL;
201 if (!GetModuleHandleExW(
202 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
203 dllPath,
204 &moduleHandle
205 )) {
206 LogDebug("Failed to get module handle: %d\n", GetLastError());
207 return DYHEXINJECT_ERROR_EJECTION_FAILED;
208 }
209 
210 // Get FreeLibrary address
211 HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
212 if (!kernel32) {
213 LogDebug("Failed to get kernel32 handle: %d\n", GetLastError());
214 return DYHEXINJECT_ERROR_EJECTION_FAILED;
215 }
216 
217 LPTHREAD_START_ROUTINE freeLibraryAddr = (LPTHREAD_START_ROUTINE)GetProcAddress(
218 kernel32,
219 "FreeLibrary"
220 );
221 
222 if (!freeLibraryAddr) {
223 LogDebug("Failed to get FreeLibrary address: %d\n", GetLastError());
224 return DYHEXINJECT_ERROR_EJECTION_FAILED;
225 }
226 
227 // Create remote thread to unload DLL
228 HANDLE remoteThread = CreateRemoteThread(
229 processInfo->processHandle,
230 NULL,
231 0,
232 freeLibraryAddr,
233 (LPVOID)moduleHandle,
234 0,
235 NULL
236 );
237 
238 if (!remoteThread) {
239 LogDebug("Failed to create remote thread: %d\n", GetLastError());
240 return DYHEXINJECT_ERROR_EJECTION_FAILED;
241 }
242 
243 // Wait for ejection
244 WaitForSingleObject(remoteThread, INFINITE);
245 CloseHandle(remoteThread);
246 
247 return DYHEXINJECT_SUCCESS;
248}
249 
250// Communication functions
251DYHEXINJECT_API DyHexInjectError DyHexInject_StartCommunication(DyHexInjectProcessInfo* processInfo, DyHexInjectCommunication* communication) {
252 if (!processInfo || !communication) {
253 return DYHEXINJECT_ERROR_INVALID_PARAMETERS;
254 }
255 
256 // Create shared memory
257 char sharedMemoryName[32];
258 sprintf_s(sharedMemoryName, sizeof(sharedMemoryName), "DyHexInject_%d", processInfo->processId);
259 
260 communication->sharedMemoryHandle = CreateFileMappingA(
261 INVALID_HANDLE_VALUE,
262 NULL,
263 PAGE_READWRITE,
264 0,
265 sizeof(SharedMemoryLayout),
266 sharedMemoryName
267 );
268 
269 if (!communication->sharedMemoryHandle) {
270 LogDebug("Failed to create shared memory: %d\n", GetLastError());
271 return DYHEXINJECT_ERROR_SHARED_MEMORY_FAILED;
272 }
273 
274 // Map shared memory
275 communication->sharedMemoryPtr = MapViewOfFile(
276 communication->sharedMemoryHandle,
277 FILE_MAP_ALL_ACCESS,
278 0,
279 0,
280 sizeof(SharedMemoryLayout)
281 );
282 
283 if (!communication->sharedMemoryPtr) {
284 LogDebug("Failed to map shared memory: %d\n", GetLastError());
285 CloseHandle(communication->sharedMemoryHandle);
286 return DYHEXINJECT_ERROR_SHARED_MEMORY_FAILED;
287 }
288 
289 // Initialize shared memory
290 SharedMemoryLayout* layout = (SharedMemoryLayout*)communication->sharedMemoryPtr;
291 layout->commandReady = false;
292 layout->responseReady = false;
293 layout->commandEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
294 layout->responseEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
295 
296 if (!layout->commandEvent || !layout->responseEvent) {
297 LogDebug("Failed to create events: %d\n", GetLastError());
298 UnmapViewOfFile(communication->sharedMemoryPtr);
299 CloseHandle(communication->sharedMemoryHandle);
300 return DYHEXINJECT_ERROR_SHARED_MEMORY_FAILED;
301 }
302 
303 communication->isConnected = true;
304 return DYHEXINJECT_SUCCESS;
305}
306 
307DYHEXINJECT_API void DyHexInject_StopCommunication(DyHexInjectCommunication* communication) {
308 if (!communication || !communication->isConnected) {
309 return;
310 }
311 
312 SharedMemoryLayout* layout = (SharedMemoryLayout*)communication->sharedMemoryPtr;
313 if (layout) {
314 if (layout->commandEvent) CloseHandle(layout->commandEvent);
315 if (layout->responseEvent) CloseHandle(layout->responseEvent);
316 }
317 
318 if (communication->sharedMemoryPtr) {
319 UnmapViewOfFile(communication->sharedMemoryPtr);
320 }
321 
322 if (communication->sharedMemoryHandle) {
323 CloseHandle(communication->sharedMemoryHandle);
324 }
325 
326 communication->isConnected = false;
327}
328 
329DYHEXINJECT_API DyHexInjectError DyHexInject_SendCommand(DyHexInjectCommunication* communication, const char* command, size_t length) {
330 if (!communication || !communication->isConnected || !command) {
331 return DYHEXINJECT_ERROR_INVALID_PARAMETERS;
332 }
333 
334 SharedMemoryLayout* layout = (SharedMemoryLayout*)communication->sharedMemoryPtr;
335 if (!layout) {
336 return DYHEXINJECT_ERROR_COMMUNICATION_FAILED;
337 }
338 
339 // Copy command to shared memory
340 strncpy_s(layout->command, sizeof(layout->command), command, length);
341 layout->commandReady = true;
342 SetEvent(layout->commandEvent);
343 
344 return DYHEXINJECT_SUCCESS;
345}
346 
347DYHEXINJECT_API DyHexInjectError DyHexInject_ReceiveResponse(DyHexInjectCommunication* communication, char* buffer, size_t bufferSize, size_t* bytesReceived) {
348 if (!communication || !communication->isConnected || !buffer || !bytesReceived) {
349 return DYHEXINJECT_ERROR_INVALID_PARAMETERS;
350 }
351 
352 SharedMemoryLayout* layout = (SharedMemoryLayout*)communication->sharedMemoryPtr;
353 if (!layout) {
354 return DYHEXINJECT_ERROR_COMMUNICATION_FAILED;
355 }
356 
357 // Wait for response
358 if (WaitForSingleObject(layout->responseEvent, INFINITE) != WAIT_OBJECT_0) {
359 return DYHEXINJECT_ERROR_COMMUNICATION_FAILED;
360 }
361 
362 // Copy response from shared memory
363 strncpy_s(buffer, bufferSize, layout->response, sizeof(layout->response));
364 *bytesReceived = strlen(buffer);
365 layout->responseReady = false;
366 
367 return DYHEXINJECT_SUCCESS;
368}
369 
370// Utility functions
371DYHEXINJECT_API const char* DyHexInject_GetErrorString(DyHexInjectError error) {
372 switch (error) {
373 case DYHEXINJECT_SUCCESS:
374 return "Success";
375 case DYHEXINJECT_ERROR_PROCESS_NOT_FOUND:
376 return "Process not found";
377 case DYHEXINJECT_ERROR_ACCESS_DENIED:
378 return "Access denied";
379 case DYHEXINJECT_ERROR_INJECTION_FAILED:
380 return "Injection failed";
381 case DYHEXINJECT_ERROR_COMMUNICATION_FAILED:
382 return "Communication failed";
383 case DYHEXINJECT_ERROR_INVALID_PARAMETERS:
384 return "Invalid parameters";
385 case DYHEXINJECT_ERROR_EJECTION_FAILED:
386 return "Ejection failed";
387 case DYHEXINJECT_ERROR_DLL_NOT_FOUND:
388 return "DLL not found";
389 case DYHEXINJECT_ERROR_SHARED_MEMORY_FAILED:
390 return "Shared memory failed";
391 default:
392 return "Unknown error";
393 }
394}
395 
396void DyHexInject_EnableDebugLogging(bool enable) {
397 g_debugLogging = enable;
398}
399 
400bool DyHexInject_IsDllLoaded(const DyHexInjectProcessInfo* processInfo, const wchar_t* dllPath) {
401 if (!processInfo || !dllPath) {
402 return false;
403 }
404 
405 HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, processInfo->processId);
406 if (snapshot == INVALID_HANDLE_VALUE) {
407 return false;
408 }
409 
410 MODULEENTRY32W moduleEntry;
411 moduleEntry.dwSize = sizeof(moduleEntry);
412 
413 if (!Module32FirstW(snapshot, &moduleEntry)) {
414 CloseHandle(snapshot);
415 return false;
416 }
417 
418 bool found = false;
419 do {
420 if (_wcsicmp(moduleEntry.szModule, dllPath) == 0) {
421 found = true;
422 break;
423 }
424 } while (Module32NextW(snapshot, &moduleEntry));
425 
426 CloseHandle(snapshot);
427 return found;
428}
429 
430/*
431 * API pubbliche per l'integrazione semplificata
432 */
433 
434DYHEXINJECT_API int InjectDll(const char* processName, const char* dllPath) {
435 if (!processName || !dllPath) {
436 printf("Parametri non validi\n");
437 return DYHEXINJECT_ERROR_INVALID_PARAMETERS;
438 }
439 
440 // Trova il processo tramite il nome
441 DWORD processId = 0;
442 HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
443 if (snapshot == INVALID_HANDLE_VALUE) {
444 printf("Impossibile creare snapshot dei processi\n");
445 return DYHEXINJECT_ERROR_PROCESS_NOT_FOUND;
446 }
447 
448 PROCESSENTRY32 processEntry;
449 processEntry.dwSize = sizeof(PROCESSENTRY32);
450 
451 if (Process32First(snapshot, &processEntry)) {
452 do {
453 if (_stricmp(processEntry.szExeFile, processName) == 0) {
454 processId = processEntry.th32ProcessID;
455 break;
456 }
457 } while (Process32Next(snapshot, &processEntry));
458 }
459 
460 CloseHandle(snapshot);
461 
462 if (processId == 0) {
463 printf("Processo '%s' non trovato\n", processName);
464 return DYHEXINJECT_ERROR_PROCESS_NOT_FOUND;
465 }
466 
467 return InjectDllByPID(processId, dllPath);
468}
469 
470DYHEXINJECT_API int InjectDllByPID(int processId, const char* dllPath) {
471 if (processId <= 0 || !dllPath) {
472 printf("Parametri non validi\n");
473 return DYHEXINJECT_ERROR_INVALID_PARAMETERS;
474 }
475 
476 // Ottieni l'handle del processo
477 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId);
478 if (!hProcess) {
479 printf("Impossibile aprire il processo (PID: %d)\n", processId);
480 return DYHEXINJECT_ERROR_PROCESS_NOT_FOUND;
481 }
482 
483 // Calcola la dimensione del percorso DLL (in byte)
484 SIZE_T dllPathSize = (strlen(dllPath) + 1) * sizeof(char);
485 
486 // Alloca memoria nel processo target per il percorso DLL
487 LPVOID remoteDllPath = VirtualAllocEx(
488 hProcess,
489 NULL,
490 dllPathSize,
491 MEM_COMMIT | MEM_RESERVE,
492 PAGE_READWRITE
493 );
494 
495 if (!remoteDllPath) {
496 printf("Impossibile allocare memoria nel processo target\n");
497 CloseHandle(hProcess);
498 return DYHEXINJECT_ERROR_INJECTION_FAILED;
499 }
500 
501 // Scrivi il percorso DLL nella memoria del processo target
502 if (!WriteProcessMemory(hProcess, remoteDllPath, dllPath, dllPathSize, NULL)) {
503 printf("Impossibile scrivere nella memoria del processo target\n");
504 VirtualFreeEx(hProcess, remoteDllPath, 0, MEM_RELEASE);
505 CloseHandle(hProcess);
506 return DYHEXINJECT_ERROR_INJECTION_FAILED;
507 }
508 
509 // Ottieni l'indirizzo della funzione LoadLibraryA
510 HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
511 if (!hKernel32) {
512 printf("Impossibile ottenere l'handle di kernel32.dll\n");
513 VirtualFreeEx(hProcess, remoteDllPath, 0, MEM_RELEASE);
514 CloseHandle(hProcess);
515 return DYHEXINJECT_ERROR_INJECTION_FAILED;
516 }
517 
518 FARPROC pLoadLibraryA = GetProcAddress(hKernel32, "LoadLibraryA");
519 if (!pLoadLibraryA) {
520 printf("Impossibile ottenere l'indirizzo di LoadLibraryA\n");
521 VirtualFreeEx(hProcess, remoteDllPath, 0, MEM_RELEASE);
522 CloseHandle(hProcess);
523 return DYHEXINJECT_ERROR_INJECTION_FAILED;
524 }
525 
526 // Crea un thread remoto che carica la DLL
527 HANDLE hThread = CreateRemoteThread(
528 hProcess,
529 NULL,
530 0,
531 (LPTHREAD_START_ROUTINE)pLoadLibraryA,
532 remoteDllPath,
533 0,
534 NULL
535 );
536 
537 if (!hThread) {
538 printf("Impossibile creare thread remoto\n");
539 VirtualFreeEx(hProcess, remoteDllPath, 0, MEM_RELEASE);
540 CloseHandle(hProcess);
541 return DYHEXINJECT_ERROR_INJECTION_FAILED;
542 }
543 
544 // Attendi che il thread termini
545 WaitForSingleObject(hThread, INFINITE);
546 
547 // Controlla il risultato dell'iniezione
548 DWORD exitCode = 0;
549 GetExitCodeThread(hThread, &exitCode);
550 
551 // Pulisci le risorse
552 VirtualFreeEx(hProcess, remoteDllPath, 0, MEM_RELEASE);
553 CloseHandle(hThread);
554 CloseHandle(hProcess);
555 
556 // Se exitCode è 0, l'iniezione è fallita
557 if (exitCode == 0) {
558 printf("Iniezione fallita\n");
559 return DYHEXINJECT_ERROR_INJECTION_FAILED;
560 }
561 
562 printf("DLL iniettata con successo\n");
563 return DYHEXINJECT_SUCCESS;
564}