-
Notifications
You must be signed in to change notification settings - Fork 25
Expand file tree
/
Copy pathGSpots.cpp
More file actions
155 lines (139 loc) · 6.69 KB
/
GSpots.cpp
File metadata and controls
155 lines (139 loc) · 6.69 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
#include "GOffsets/GOffsets.h"
#include "UEVersionScanner/UEVersionScanner.h"
#include "EncryptionDetection/EncryptionDetection.h"
#include <iostream>
#include <string>
#include <vector>
#include <windows.h>
#include <TlHelp32.h>
#include <Psapi.h>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <cctype>
#pragma comment(lib, "Version.lib")
int main(int argc, char* argv[]) {
if (argc < 2) {
std::cout << "Close this window then drag and drop the Unreal Engine game onto this exe... OR\n";
std::cout << "Usage: " << argv[0] << " <game file path>\n";
std::cout << "Press Enter to exit...";
std::cin.get();
return 1;
}
std::string gameFilePath = argv[1];
size_t lastSlash = gameFilePath.find_last_of("\\/");
std::string exeName = (lastSlash != std::string::npos) ? gameFilePath.substr(lastSlash + 1) : gameFilePath;
std::vector<Byte> data = readBinaryFile(gameFilePath);
if (data.empty()) {
std::cout << "Error: Could not open file.\n\nPress Enter to exit...";
std::cin.get();
return 1;
}
// Header output.
std::cout << "----- GSpots : v1.5 -----\n\n";
std::string ueVersion = GetUnrealEngineVersion(gameFilePath, exeName);
if (ueVersion.rfind("1.", 0) == 0 || ueVersion.rfind("2.", 0) == 0) {
ueVersion = "Undefined..";
}
std::cout << "\nUnreal Engine Version: " << ueVersion << "\n\n";
// Check if the file is encrypted.
bool fileEncrypted = IsFileEncrypted(data);
// Scan file only if it's not encrypted.
uint64_t fileGWorld = 0, fileGNames = 0, fileGObjects = 0;
std::vector<Signature> signatures = getSignatures();
if (!fileEncrypted) {
for (const auto& sig : signatures) {
size_t foundOffset = findPatternMask(data, sig.pattern, sig.mask);
if (foundOffset != std::string::npos && foundOffset + 7 <= data.size()) {
if (sig.name.find("GWorld") != std::string::npos && fileGWorld == 0)
foundOffset = adjustFoundOffsetForGroup(data, foundOffset, "GWorld");
else if (sig.name.find("GNames") != std::string::npos && fileGNames == 0)
foundOffset = adjustFoundOffsetForGroup(data, foundOffset, "GNames");
else if (sig.name.find("GObjects") != std::string::npos && fileGObjects == 0)
foundOffset = adjustFoundOffsetForGroup(data, foundOffset, "GObjects");
int32_t disp = *reinterpret_cast<const int32_t*>(&data[foundOffset + 3]);
size_t nextInstr = foundOffset + 7;
size_t rawAddress = nextInstr + disp;
uint32_t sectionDelta = getSectionDelta(data, foundOffset);
uint64_t computedAddress = rawAddress + sectionDelta;
if (sig.name.find("GWorld") != std::string::npos && fileGWorld == 0)
fileGWorld = computedAddress;
else if (sig.name.find("GNames") != std::string::npos && fileGNames == 0)
fileGNames = computedAddress;
else if (sig.name.find("GObjects") != std::string::npos && fileGObjects == 0)
fileGObjects = computedAddress;
}
}
}
// If the file is encrypted and the process is not running.
else {
DWORD dummyPID;
if (!IsProcessRunning(exeName, dummyPID)) {
std::cout << "It looks like this exe is encrypted but I might be able to find them in memory...";
}
}
// Memory scanning: only if file scan failed and if process is running.
DWORD processID = 0;
bool processRunning = IsProcessRunning(exeName, processID);
uint64_t memGWorld = 0, memGNames = 0, memGObjects = 0;
if (processRunning) {
HANDLE hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, processID);
if (hProcess) {
for (const auto& sig : signatures) {
if (sig.name.find("GWorld") != std::string::npos && fileGWorld == 0 && memGWorld == 0)
memGWorld = findOffsetInProcessMemory(hProcess, sig.pattern, sig.mask, "GWorld");
else if (sig.name.find("GNames") != std::string::npos && fileGNames == 0 && memGNames == 0)
memGNames = findOffsetInProcessMemory(hProcess, sig.pattern, sig.mask, "GNames");
else if (sig.name.find("GObjects") != std::string::npos && fileGObjects == 0 && memGObjects == 0)
memGObjects = findOffsetInProcessMemory(hProcess, sig.pattern, sig.mask, "GObjects");
}
CloseHandle(hProcess);
}
}
// Print offsets if found.
if (fileGWorld != 0)
std::cout << "GWorld Offset: 0x" << std::hex << std::uppercase << fileGWorld << "\n";
else if (memGWorld != 0)
std::cout << "GWorld Offset: 0x" << std::hex << std::uppercase << memGWorld << "\n";
if (fileGNames != 0)
std::cout << "GNames Offset: 0x" << std::hex << std::uppercase << fileGNames << "\n";
else if (memGNames != 0)
std::cout << "GNames Offset: 0x" << std::hex << std::uppercase << memGNames << "\n";
if (fileGObjects != 0)
std::cout << "GObjects Offset: 0x" << std::hex << std::uppercase << fileGObjects << "\n";
else if (memGObjects != 0)
std::cout << "GObjects Offset: 0x" << std::hex << std::uppercase << memGObjects << "\n";
// If the file is encrypted and the process is running.
if (fileEncrypted && processRunning && memGWorld && memGNames && memGObjects) {
std::cout << "\nIt looks like the exe is encrypted..\nThere may be obfuscation happening that may render these offsets invalid.\n";
}
// Notify if any signature is missing.
bool missing = false;
if ((fileGWorld == 0 && memGWorld == 0) ||
(fileGNames == 0 && memGNames == 0) ||
(fileGObjects == 0 && memGObjects == 0))
{
missing = true;
}
if (!fileEncrypted) {
if (missing) {
if (fileGWorld == 0 && memGWorld == 0)
std::cout << "GWorld signature not found...\n";
if (fileGNames == 0 && memGNames == 0)
std::cout << "GNames signature not found...\n";
if (fileGObjects == 0 && memGObjects == 0)
std::cout << "GObjects signature not found...\n";
if (processRunning)
std::cout << "\nSubmit a compatibility request on GSpots official GitHub!\n\n";
else
std::cout << "\nTry running the game in the background and try again!\n\n";
}
}
else {
if (!processRunning)
std::cout << "\nTry running the game in the background and try again!\n\n";
}
std::cout << "\nPress Enter to exit...";
std::cin.get();
return 0;
}