forked from chinponya/riichishitty
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrun_n_gun.c
More file actions
202 lines (192 loc) · 7.24 KB
/
run_n_gun.c
File metadata and controls
202 lines (192 loc) · 7.24 KB
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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
// Where it all started
#include <Windows.h>
#include <winternl.h>
#include <io.h>
#include <stdbool.h>
#include <stdio.h>
#define GFL_HAXX
bool exists(char *path)
{
if(_access_s(path, 0)) {
char buffer[256];
strerror_s(buffer, sizeof(buffer), errno);
printf("_access_s failure: %s. are you sure %s exists?\n", buffer, path);
return false;
}
return true;
}
void error(const char *function)
{
DWORD error = GetLastError();
char *buffer = "";
DWORD count = FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
buffer,
0,
NULL
);
if(count) {
printf("%s failed: 0x%08lx (%s)\n", function, error, buffer);
} else {
printf("%s failed: 0x%08lx (unknown error)\n", function, error);
}
}
#define CALL_WINAPI(api, args, post) \
if(!api args) { \
error(#api); \
post; \
}
#define CALL_THREAD_WINAPI(api, args) \
if(api args == (DWORD)-1) { \
error(#api); \
goto cleanup; \
}
#define CALL_WINAPI_CREATE(type, name, api, args) \
type name = api args; \
if(!name) { \
error(#api); \
goto cleanup; \
}
bool patch(HANDLE hProcess, void *address, size_t length, const void *new, void *old)
{
DWORD oldprotect;
CALL_WINAPI(VirtualProtectEx, (hProcess, address, length, PAGE_EXECUTE_READWRITE, &oldprotect), return false)
CALL_WINAPI(ReadProcessMemory, (hProcess, address, old, length, NULL), return false)
CALL_WINAPI(WriteProcessMemory, (hProcess, address, new, length, NULL), return false)
FlushInstructionCache(hProcess, address, length);
return true;
}
int main(int argc, char *argv[])
{
if(argc < 3) {
printf("Usage: %s <exe> <dll> [args...]\n", argv[0]);
printf("Extra arguments will be forwarded to the process\n");
return(-1);
}
if(!exists(argv[1])) { return(-1); }
if(!exists(argv[2])) { return(-1); }
// Parse arguments to create a new array to pass to the created process.
// Skip first 3 arguments since they're going to be command_name exe_name dll_name.
size_t length = 0;
char *args = NULL;
bool alloc = false;
if(argc > 3) {
for(int i = 3; i < argc; ++i) {
length += strlen(argv[i]) + 2;
}
args = malloc(length * sizeof(char));
if(!args) {
printf("malloc() failed, size %zu", length * sizeof(char));
return(-1);
}
alloc = true;
strcpy_s(args, length, "");
for(int i = 3; i < argc; ++i) {
int ret = 0;
ret = strcat_s(args, length, argv[i]);
if(ret) {
printf("strcat_s failure: %d\n", ret);
return(-1);
}
ret = strcat_s(args, length, " ");
if(ret) {
printf("strcat_s failure: %d\n", ret);
return(-1);
}
}
}
printf("invoking %s with arguments %s\n", argv[1], args);
STARTUPINFOA startupinfo = { 0 };
PROCESS_INFORMATION processinformation;
startupinfo.cb = sizeof(startupinfo);
CALL_WINAPI(CreateProcessA, (argv[1], args, NULL, NULL, FALSE, CREATE_NEW_CONSOLE | CREATE_SUSPENDED, NULL, NULL, &startupinfo, &processinformation), return(-1))
HANDLE hProcess = processinformation.hProcess;
HANDLE hThread = processinformation.hThread;
// XXX: wtf? Is there a better way of acquiring the PEB?
LONG(WINAPI *NtQueryInformationProcess)
(HANDLE ProcessHandle,
ULONG ProcessInformationClass, PVOID ProcessInformation,
ULONG ProcessInformationLength, PULONG ReturnLength) = NULL;
*(FARPROC *) &NtQueryInformationProcess = GetProcAddress(GetModuleHandleA("ntdll"), "NtQueryInformationProcess");
PROCESS_BASIC_INFORMATION basicinformation = {0};
DWORD dwReturnLength = 0;
NtQueryInformationProcess(hProcess, ProcessBasicInformation, &basicinformation, sizeof(PROCESS_BASIC_INFORMATION), &dwReturnLength);
PPEB peb = basicinformation.PebBaseAddress;
if(!peb) {
printf("failed to acquire PEB from NtQueryInformationProcess\n");
return(-1);
}
DWORD_PTR baseaddress = 0;
CALL_WINAPI(ReadProcessMemory, (hProcess, &peb->Reserved3[1], &baseaddress, sizeof(baseaddress), NULL), goto cleanup)
printf("base address @ 0x%08llx\n", baseaddress);
IMAGE_DOS_HEADER dosheader = {0};
CALL_WINAPI(ReadProcessMemory, (hProcess, (PVOID)baseaddress, &dosheader, sizeof(dosheader), NULL), goto cleanup)
if(dosheader.e_magic != IMAGE_DOS_SIGNATURE) {
printf("dos header signature mismatch (expected 0x%04X but got 0x%04X instead)\n", IMAGE_DOS_SIGNATURE, dosheader.e_magic);
goto cleanup;
}
IMAGE_NT_HEADERS64 ntheader64 = {0};
CALL_WINAPI(ReadProcessMemory, (hProcess, (char *)baseaddress + dosheader.e_lfanew, &ntheader64, sizeof(ntheader64), NULL), goto cleanup)
if(ntheader64.Signature != IMAGE_NT_SIGNATURE) {
printf("nt header signature mismatch (expected 0x%08X but got 0x%08lX instead)\n", IMAGE_NT_SIGNATURE, ntheader64.Signature);
goto cleanup;
}
if(ntheader64.OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
printf("nt optional header signature mismatch (expected 0x%04X but got 0x%04X instead)\n", IMAGE_NT_OPTIONAL_HDR64_MAGIC, ntheader64.OptionalHeader.Magic);
goto cleanup;
}
DWORD_PTR entrypoint = baseaddress + ntheader64.OptionalHeader.AddressOfEntryPoint;
printf("entrypoint @ 0x%08llx\n", entrypoint);
#ifndef GFL_HAXX
WORD old;
WORD new = 0xFEEB; // JMP -2
if(!patch(hProcess, (void *)entrypoint, sizeof(WORD), &new, &old)) {
printf("failed to write patch to entrypoint\n");
goto cleanup;
}
printf("patched entrypoint (old: %x | new: %x)\n", old, new);
// For whatever reason GF2_Exilium never hits the actual entrypoint?
while(1) {
CALL_THREAD_WINAPI(ResumeThread, (hThread))
Sleep(100);
CALL_THREAD_WINAPI(SuspendThread, (hThread))
CONTEXT context = {0};
context.ContextFlags = CONTEXT_FULL;
CALL_WINAPI(GetThreadContext, (hThread, &context), goto cleanup)
printf("ctx rip: 0x%08llx\n", context.Rip);
if(context.Rip == entrypoint) { break; }
}
#endif
CALL_WINAPI_CREATE(HMODULE, hKernel32, GetModuleHandleA, ("kernel32"))
CALL_WINAPI_CREATE(LPTHREAD_START_ROUTINE, loadlibrary, (LPTHREAD_START_ROUTINE)GetProcAddress, (hKernel32, "LoadLibraryA"))
char path[MAX_PATH] = {0};
CALL_WINAPI_CREATE(DWORD, pathlen, GetFullPathNameA, (argv[2], sizeof(path), path, NULL))
CALL_WINAPI_CREATE(void *, remotepath, VirtualAllocEx, (hProcess, NULL, pathlen + 1, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE))
CALL_WINAPI(WriteProcessMemory, (hProcess, remotepath, path, pathlen + 1, NULL), goto cleanup)
CALL_WINAPI_CREATE(HANDLE, loadlibrarythread, CreateRemoteThread, (hProcess, NULL, 0, loadlibrary, remotepath, 0, NULL))
WaitForSingleObject(loadlibrarythread, INFINITE);
if(loadlibrarythread) { CloseHandle(loadlibrarythread); }
if(remotepath) { VirtualFreeEx(hProcess, remotepath, 0, MEM_RELEASE); }
#ifndef GFL_HAXX
if(!patch(hProcess, (void *)entrypoint, sizeof(WORD), &old, &new)) {
printf("failed to erase patch to entrypoint\n");
goto cleanup;
}
#endif
CALL_THREAD_WINAPI(ResumeThread, (hThread))
if(hProcess) { CloseHandle(hProcess); }
if(hThread) { CloseHandle(hThread); }
if(alloc) { free(args); }
return(0);
cleanup:
if(hProcess) {
TerminateProcess(hProcess, -1);
CloseHandle(hProcess);
}
if(hThread) { CloseHandle(hThread); }
if(alloc) { free(args); }
return(-1);
}