Skip to content

Commit 5df0ab5

Browse files
committed
Split into multiple functions to try and reduce AV detection
1 parent 84fa2cb commit 5df0ab5

3 files changed

Lines changed: 169 additions & 49 deletions

File tree

injector/injector.c

Lines changed: 162 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,95 @@
1+
#define _CRT_SECURE_NO_WARNINGS
2+
13
#include <Windows.h>
24

5+
#include <stdbool.h>
36
#include <stdio.h>
47
#include <string.h>
58
#include <time.h>
69

7-
void Log(const char* fmt, ...) {
8-
va_list va;
9-
va_start(va, fmt);
10+
struct IsaacOptions {
11+
// Repentogon options
12+
int updates;
13+
int console;
14+
15+
// Game options
16+
int lua_debug;
17+
int level_stage;
18+
int stage_type;
19+
const char* lua_heap_size;
20+
};
1021

11-
FILE* f = fopen("injector.log", "a");
12-
if (!f) {
13-
f = stderr;
22+
/* Perform the early setup for the injection: create the Isaac process,
23+
* allocate memory for the remote thread function etc.
24+
*
25+
* No extra thread is created in the process. ImGui should be initialized
26+
* afterwards to setup the injector, and then the remote thread can be
27+
* created.
28+
*
29+
* Return true of the initialization was sucessful, false otherwise.
30+
*/
31+
static int FirstStageInit(struct IsaacOptions const* options, HANDLE* process, void** page, size_t* functionOffset, PROCESS_INFORMATION* processInfo);
32+
33+
static void Log(const char* fmt, ...);
34+
35+
static void GenerateCLI(const struct IsaacOptions* options, char cli[256]);
36+
37+
void GenerateCLI(const struct IsaacOptions* options, char cli[256]) {
38+
memset(cli, 0, sizeof(cli));
39+
if (options->console) {
40+
strcat(cli, "--console ");
1441
}
1542

16-
char buffer[4096];
17-
time_t now = time(NULL);
18-
struct tm* tm = localtime(&now);
19-
strftime(buffer, 4095, "%Y-%m-%d %H:%M:%S", tm);
20-
fprintf(f, "[%s] ", buffer);
21-
vfprintf(f, fmt, va);
22-
va_end(va);
23-
}
43+
if (!options->updates) {
44+
strcat(cli, "--skipupdates ");
45+
}
2446

25-
int main() {
26-
{
27-
FILE* f = fopen("injector.log", "w");
28-
if (f) {
29-
fclose(f);
30-
}
47+
if (options->lua_debug) {
48+
strcat(cli, "--luadebug ");
3149
}
3250

33-
Log("Starting injector\n");
51+
if (options->level_stage) {
52+
strcat(cli, "--set-stage=");
53+
char buffer[13]; // 11 chars for a max int (including sign) + 1 char for space + 1 char for '\0'
54+
sprintf(buffer, "%d ", options->level_stage);
55+
strcat(cli, buffer);
56+
}
57+
58+
if (options->stage_type) {
59+
strcat(cli, "--set-stage-type=");
60+
char buffer[13]; // 11 chars for a max int (including sign) + 1 char for space + 1 char for '\0'
61+
sprintf(buffer, "%d ", options->stage_type);
62+
strcat(cli, buffer);
63+
}
64+
65+
if (options->lua_heap_size) {
66+
strcat(cli, "--luaheapsize=");
67+
strcat(cli, options->lua_heap_size);
68+
}
69+
}
3470

71+
DWORD CreateIsaac(struct IsaacOptions const* options, PROCESS_INFORMATION* processInfo) {
3572
STARTUPINFOA startupInfo;
3673
memset(&startupInfo, 0, sizeof(startupInfo));
3774

38-
PROCESS_INFORMATION processInfo;
39-
memset(&processInfo, 0, sizeof(processInfo));
75+
memset(processInfo, 0, sizeof(*processInfo));
76+
77+
char cli[256];
78+
GenerateCLI(options, cli);
4079

41-
DWORD result = CreateProcess("isaac-ng.exe", NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startupInfo, &processInfo);
80+
DWORD result = CreateProcess("isaac-ng.exe", cli, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startupInfo, processInfo);
4281
if (result == 0) {
4382
Log("Failed to create process: %d\n", GetLastError());
4483
return -1;
4584
}
4685
else {
47-
Log("Started isaac-ng.exe in suspended state, processID = %d\n", processInfo.dwProcessId);
86+
Log("Started isaac-ng.exe in suspended state, processID = %d\n", processInfo->dwProcessId);
4887
}
4988

50-
HANDLE process = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
51-
FALSE, processInfo.dwProcessId);
52-
if (!process) {
53-
Log("Failed to open process: %d\n", GetLastError());
54-
return -1;
55-
}
56-
else {
57-
Log("Acquired handle to isaac-ng.exe, process ID = %d\n", processInfo.dwProcessId);
58-
}
89+
return result;
90+
}
5991

92+
int UpdateMemory(HANDLE process, PROCESS_INFORMATION const* processInfo, void** page, size_t* functionOffset) {
6093
void* remotePage = VirtualAllocEx(process, NULL, 4096, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
6194
if (!remotePage) {
6295
Log("Failed to allocate memory in isaac-ng.exe to load the dsound DLL: %d\n", GetLastError());
@@ -66,7 +99,7 @@ int main() {
6699
Log("Allocated memory for remote thread at %p\n", remotePage);
67100
}
68101

69-
size_t bytesWritten = 0;
102+
SIZE_T bytesWritten = 0;
70103
char zeroBuffer[4096];
71104
memset(zeroBuffer, 0, sizeof(zeroBuffer));
72105
WriteProcessMemory(process, remotePage, zeroBuffer, 4096, &bytesWritten);
@@ -110,15 +143,17 @@ int main() {
110143
// 0x16 (0x15 is a '\0')
111144
WriteProcessMemory(process, (char*)remotePage + offset, functionName, strlen(functionName), &bytesWritten);
112145
offset += (bytesWritten + 1);
113-
size_t functionOffset = offset;
146+
147+
*functionOffset = offset;
148+
114149
/* 0x21 (0x20 is a '\0')
115150
* Call LoadLibraryA in the remote thread.
116151
* The thread will push the name of the DLL from its stack.
117152
* It will then call LoadLibraryA.
118-
*
153+
*
119154
* This function is a THREAD_START_ROUTINE, with the following signature :
120155
* DWORD WINAPI(LPVOID);
121-
*
156+
*
122157
* WINAPI is __stdcall: arguments are pushed in reverse order on the stack and callee cleans the stack.
123158
*/
124159
char hook[128] = {
@@ -148,7 +183,42 @@ int main() {
148183
};
149184
WriteProcessMemory(process, (char*)remotePage + offset, hook, 128, &bytesWritten);
150185

151-
HANDLE remoteThread = CreateRemoteThread(process, NULL, 0, (char*)remotePage + functionOffset, remotePage, 0, NULL);
186+
*page = remotePage;
187+
return 0;
188+
}
189+
190+
int FirstStageInit(struct IsaacOptions const* options, HANDLE* outProcess, void** page, size_t* functionOffset, PROCESS_INFORMATION* processInfo) {
191+
{
192+
FILE* f = fopen("injector.log", "w");
193+
if (f) {
194+
fclose(f);
195+
}
196+
}
197+
198+
Log("Starting injector\n");
199+
DWORD processId = CreateIsaac(options, processInfo);
200+
201+
HANDLE process = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
202+
FALSE, processInfo->dwProcessId);
203+
if (!process) {
204+
Log("Failed to open process: %d\n", GetLastError());
205+
return -1;
206+
}
207+
else {
208+
Log("Acquired handle to isaac-ng.exe, process ID = %d\n", processInfo->dwProcessId);
209+
}
210+
211+
if (UpdateMemory(process, processInfo, page, functionOffset)) {
212+
return -1;
213+
}
214+
215+
*outProcess = process;
216+
217+
return 0;
218+
}
219+
220+
int CreateAndWait(HANDLE process, void* remotePage, size_t functionOffset) {
221+
HANDLE remoteThread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)((char*)remotePage + functionOffset), remotePage, 0, NULL);
152222
if (!remoteThread) {
153223
Log("Error while creating remote thread: %d\n", GetLastError());
154224
return -1;
@@ -158,26 +228,69 @@ int main() {
158228
}
159229

160230
Log("Waiting for remote thread to complete\n");
161-
result = WaitForSingleObject(remoteThread, 60 * 1000);
231+
DWORD result = WaitForSingleObject(remoteThread, 60 * 1000);
162232
switch (result) {
163233
case WAIT_OBJECT_0:
164234
Log("RemoteThread completed\n");
165235
break;
166236

167237
case WAIT_ABANDONED:
168238
Log("This shouldn't happened: RemoteThread returned WAIT_ABANDONNED\n");
169-
break;
239+
return -1;
170240

171241
case WAIT_TIMEOUT:
172242
Log("RemoteThread timed out\n");
173-
break;
243+
return -1;
174244

175245
case WAIT_FAILED:
176246
Log("WaitForSingleObject on RemoteThread failed: %d\n", GetLastError());
177-
break;
247+
return -1;
178248
}
179249

180-
result = ResumeThread(processInfo.hThread);
250+
return 0;
251+
}
252+
253+
void Log(const char* fmt, ...) {
254+
va_list va;
255+
va_start(va, fmt);
256+
257+
FILE* f = fopen("injector.log", "a");
258+
if (!f) {
259+
f = stderr;
260+
}
261+
262+
char buffer[4096];
263+
time_t now = time(NULL);
264+
struct tm* tm = localtime(&now);
265+
strftime(buffer, 4095, "%Y-%m-%d %H:%M:%S", tm);
266+
fprintf(f, "[%s] ", buffer);
267+
vfprintf(f, fmt, va);
268+
va_end(va);
269+
}
270+
271+
int __declspec(dllexport) InjectIsaac(int updates, int console, int lua_debug, int level_stage, int stage_type, const char* lua_heap_size) {
272+
HANDLE process;
273+
void* remotePage;
274+
size_t functionOffset;
275+
PROCESS_INFORMATION processInfo;
276+
277+
struct IsaacOptions options;
278+
options.updates = updates;
279+
options.console = console;
280+
options.lua_debug = lua_debug;
281+
options.level_stage = level_stage;
282+
options.stage_type = stage_type;
283+
options.lua_heap_size = lua_heap_size;
284+
285+
if (FirstStageInit(&options, &process, &remotePage, &functionOffset, &processInfo)) {
286+
return -1;
287+
}
288+
289+
if (CreateAndWait(process, remotePage, functionOffset)) {
290+
return -1;
291+
}
292+
293+
DWORD result = ResumeThread(processInfo.hThread);
181294
if (result == -1) {
182295
Log("Failed to resume isaac-ng.exe main thread: %d\n", GetLastError());
183296
return -1;
@@ -193,5 +306,10 @@ int main() {
193306
CloseHandle(processInfo.hProcess);
194307
CloseHandle(processInfo.hThread);
195308

309+
return 0;
310+
}
311+
312+
int main(int argc, char** argv) {
313+
InjectIsaac(1, 1, 0, 0, 0, NULL);
196314
return 0;
197315
}

launcher/dllmain.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,6 @@ extern "C" {
161161

162162
if (!HasCommandLineArgument("-skipupdates")) {
163163
sLogger->Info("dsound: Checking for updates\n");
164-
165-
if (HasCommandLineArgument("-console"))
166-
ConsoleWindow::Init();
167-
168-
if (!HasCommandLineArgument("-skipupdates"))
169164
CheckForUpdates();
170165
sLogger->Info("dsound: Update checking done\n");
171166
}

libzhl/SigScan.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include "Log.h"
12
#include "SigScan.h"
23
#include <string>
34
#include <Windows.h>
@@ -197,6 +198,12 @@ bool SigScan::Scan(Callback callback)
197198
}
198199

199200
s_pLastAddress = s_pBase;
201+
ZHL::Logger logger;
202+
logger.Log("[ERROR] Unable to find signature ");
203+
FILE* f = logger.GetFile();
204+
for (size_t i = 0; i < m_iLength; ++i)
205+
fprintf(f, "%hhx", m_sig[i]);
206+
fprintf(f, "\n");
200207
return false;
201208
}
202209

0 commit comments

Comments
 (0)