forked from truckersmp-cli/truckersmp-cli
-
Notifications
You must be signed in to change notification settings - Fork 0
/
truckersmp-cli.c
169 lines (134 loc) · 4.27 KB
/
truckersmp-cli.c
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
/* See LICENSE file for copyright and license details.
* Inspired by mewrev "inject" tool
* https://github.com/mewrev/inject
*
* This barebone truckersMP launcher only provides the most basic launching
* capability: it perform the dll injection needed to start the mod and
* nothing else.
*
* Author : lhark
*/
#include <stdio.h>
#include <windows.h>
#include <unistd.h>
#define BUF_SIZE 1024
#define STEAMID_ETS2 "227300"
#define STEAMID_ATS "270880"
static void inject(char *cmd, char *dll);
static void die(const char *fmt, ...);
static void dieonerror(const char* function, const char* cmd);
static int upprivileges();
int
main(int argc, char **argv)
{
int i, len;
const char opts[] = "-nointro -64bit";
char cmd[BUF_SIZE];
char dll[BUF_SIZE];
char *exepath, *dllpath, *steamid;
if (argc < 3)
die("Usage: truckersmp-cli GAMEDIR MODDIR\n");
for (i = 1; i < 3; i++) { /* '\' and '/' can be mixed in windows type pathes */
len = strlen(argv[i]);
if (argv[i][len - 1] == '\\' || argv[i][len - 1] == '/')
argv[i][len - 1] = '\0';
}
snprintf(cmd, sizeof(cmd), "%s%s", argv[1], "\\bin\\win_x64\\eurotrucks2.exe");
if (access (cmd, F_OK) != -1) {
exepath = "\\bin\\win_x64\\eurotrucks2.exe";
dllpath = "\\core_ets2mp.dll";
steamid = STEAMID_ETS2;
} else {
snprintf(cmd, sizeof(cmd), "%s%s", argv[1], "\\bin\\win_x64\\amtrucks.exe");
if (access (cmd, F_OK) != -1) {
exepath = "\\bin\\win_x64\\amtrucks.exe";
dllpath = "\\core_atsmp.dll";
steamid = STEAMID_ATS;
} else {
die ("Unable to find ETS2 or ATS in this GAMEDIR.");
}
}
snprintf(cmd, sizeof(cmd), "%s%s %s", argv[1], exepath, opts);
snprintf(dll, sizeof(dll), "%s%s", argv[2], dllpath);
SetEnvironmentVariable("SteamGameId", steamid);
SetEnvironmentVariable("SteamAppID", steamid);
upprivileges();
inject(cmd, dll);
return 0;
}
static void
inject(char *cmd, char *dll)
{
int len;
void *page;
HANDLE hThread;
STARTUPINFO si = {0};
PROCESS_INFORMATION pi = {0};
si.cb = sizeof(STARTUPINFO);
if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi))
dieonerror("CreateProcess()", cmd);
// Allocate a page in memory for the arguments of LoadLibrary.
page = VirtualAllocEx(pi.hProcess, NULL, MAX_PATH, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
if (page == NULL)
dieonerror("VirtualAllocEx()", "[]");
/* Inject the core dll into the process address space */
len = strlen(dll) + 1;
if (len > MAX_PATH)
die("path length (%d) exceeds MAX_PATH (%d).\n", len, MAX_PATH);
if (GetFileAttributes(dll) == INVALID_FILE_ATTRIBUTES)
die("unable to locate library (%s).\n", dll);
/* Write library path to the page used for LoadLibrary arguments. */
if (!WriteProcessMemory(pi.hProcess, page, dll, len, NULL))
dieonerror("WriteProcessMemory", "[]");
/* Inject the library */
hThread = CreateRemoteThread(pi.hProcess, NULL, 0, (LPTHREAD_START_ROUTINE) LoadLibraryA, page, 0, NULL);
if (!hThread)
dieonerror("CreateRemoteThread", "[]");
if (WaitForSingleObject(hThread, INFINITE) == WAIT_FAILED)
dieonerror("WaitForSingleObject", "[]");
CloseHandle(hThread);
if (ResumeThread(pi.hThread) == -1)
dieonerror("ResumeThread", "[]");
CloseHandle(pi.hProcess);
VirtualFreeEx(pi.hProcess, page, MAX_PATH, MEM_RELEASE);
}
static int
upprivileges()
{
HANDLE Token;
TOKEN_PRIVILEGES tp;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &Token)) {
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(Token, 0, &tp, sizeof(tp), NULL, NULL);
}
}
static void
die(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
fputc(' ', stderr);
perror(NULL);
} else {
fputc('\n', stderr);
}
exit(1);
}
static void
dieonerror(const char* function, const char* cmd)
{
LPVOID buf;
DWORD err = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &buf, 0, NULL );
fprintf(stderr, "%s with argument \"%s\" failed with error %d: %s\n", function, cmd, err, buf);
LocalFree(buf);
ExitProcess(err);
}