Skip to content

Commit d2fa7be

Browse files
committed
Added Rebuilding system
Update Updater class
1 parent 459180f commit d2fa7be

File tree

8 files changed

+445
-42
lines changed

8 files changed

+445
-42
lines changed

ErScripts/ErScripts.vcxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@
173173
<ClCompile Include="KnifeSwitch.cpp" />
174174
<ClCompile Include="Logger.cpp" />
175175
<ClCompile Include="Menu.cpp" />
176+
<ClCompile Include="Rebuild.cpp" />
176177
<ClCompile Include="RoundStartAlert.cpp" />
177178
<ClCompile Include="Overlay.cpp" />
178179
<ClCompile Include="OverlayHelper.cpp" />
@@ -205,6 +206,7 @@
205206
<ClInclude Include="imgui\imstb_truetype.h" />
206207
<ClInclude Include="Logger.h" />
207208
<ClInclude Include="Overlay.h" />
209+
<ClInclude Include="Rebuild.h" />
208210
<ClInclude Include="resource.h" />
209211
<ClInclude Include="SimpleSound.h" />
210212
<ClInclude Include="SteamTools.h" />

ErScripts/ErScripts.vcxproj.filters

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@
5454
<Filter Include="Functions\Updater">
5555
<UniqueIdentifier>{1ff65aba-bfb7-4875-8138-ecfe24c3d9d6}</UniqueIdentifier>
5656
</Filter>
57+
<Filter Include="Rebuild">
58+
<UniqueIdentifier>{8e37d140-a614-43b2-a3a4-89e025f3878f}</UniqueIdentifier>
59+
</Filter>
5760
</ItemGroup>
5861
<ItemGroup>
5962
<ClCompile Include="Main.cpp">
@@ -170,6 +173,9 @@
170173
<ClCompile Include="ChatSpammer.cpp">
171174
<Filter>Functions\Functions</Filter>
172175
</ClCompile>
176+
<ClCompile Include="Rebuild.cpp">
177+
<Filter>Rebuild</Filter>
178+
</ClCompile>
173179
</ItemGroup>
174180
<ItemGroup>
175181
<ClInclude Include="Logger.h">
@@ -236,6 +242,9 @@
236242
<ClInclude Include="Updater.h">
237243
<Filter>Functions\Updater</Filter>
238244
</ClInclude>
245+
<ClInclude Include="Rebuild.h">
246+
<Filter>Rebuild</Filter>
247+
</ClInclude>
239248
</ItemGroup>
240249
<ItemGroup>
241250
<ResourceCompile Include="ErScripts.rc">

ErScripts/Rebuild.cpp

Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
#include "Rebuild.h"
2+
#include "Logger.h"
3+
#include <filesystem>
4+
#include <fstream>
5+
#include <random>
6+
#include <thread>
7+
#include <windows.h>
8+
#include <shlwapi.h>
9+
10+
#pragma comment(lib, "shlwapi.lib")
11+
12+
std::string Rebuild::random_suffix_; // Initialize static member
13+
14+
Rebuild::Rebuild() {
15+
// Generate suffix once per run
16+
if (random_suffix_.empty()) {
17+
random_suffix_ = generateRandomString(8);
18+
}
19+
}
20+
21+
std::string Rebuild::generateRandomString(size_t length) {
22+
static const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
23+
std::random_device rd;
24+
std::mt19937 gen(rd());
25+
std::uniform_int_distribution<> dis(0, sizeof(charset) - 2);
26+
std::string result;
27+
result.reserve(length);
28+
for (size_t i = 0; i < length; ++i) {
29+
result += charset[dis(gen)];
30+
}
31+
return result;
32+
}
33+
34+
bool Rebuild::isValidExecutable(const std::string& filePath) {
35+
std::ifstream file(filePath, std::ios::binary);
36+
if (!file) {
37+
Logger::logWarning(std::format("Cannot open file for validation: {}", filePath));
38+
return false;
39+
}
40+
41+
char header[2];
42+
file.read(header, 2);
43+
file.close();
44+
bool isValid = (header[0] == 'M' && header[1] == 'Z');
45+
if (!isValid) {
46+
Logger::logWarning(std::format("File is not a valid PE executable: {}", filePath));
47+
}
48+
return isValid;
49+
}
50+
51+
std::string Rebuild::getCurrentExeName() {
52+
char exePath[MAX_PATH];
53+
DWORD pathLength = GetModuleFileNameA(NULL, exePath, MAX_PATH);
54+
if (pathLength == 0) {
55+
Logger::logWarning(std::format("Failed to get module filename: {}", GetLastError()));
56+
return "ErScripts.exe";
57+
}
58+
59+
std::string fullPath(exePath, pathLength);
60+
size_t lastSlash = fullPath.find_last_of("\\/");
61+
if (lastSlash != std::string::npos) {
62+
return fullPath.substr(lastSlash + 1);
63+
}
64+
return fullPath;
65+
}
66+
67+
std::string Rebuild::getCurrentExePath() {
68+
char exePath[MAX_PATH];
69+
DWORD pathLength = GetModuleFileNameA(NULL, exePath, MAX_PATH);
70+
if (pathLength == 0) {
71+
Logger::logWarning(std::format("Failed to get module path: {}", GetLastError()));
72+
return "ErScripts.exe";
73+
}
74+
return std::string(exePath, pathLength);
75+
}
76+
77+
bool Rebuild::unpackIfNeeded() {
78+
std::string current_exe = getCurrentExePath();
79+
80+
// Read binary
81+
std::ifstream in_file(current_exe, std::ios::binary);
82+
if (!in_file) {
83+
Logger::logWarning(std::format("Failed to read binary for unpacking: {}", current_exe));
84+
return false;
85+
}
86+
std::vector<char> binary_data((std::istreambuf_iterator<char>(in_file)), std::istreambuf_iterator<char>());
87+
in_file.close();
88+
89+
// Check for marker (2 bytes: random byte + 0xFF)
90+
if (binary_data.size() < 2 || binary_data[binary_data.size() - 1] != 0xFF) {
91+
return true; // Not packed
92+
}
93+
94+
// Remove random byte and marker
95+
binary_data.pop_back(); // Marker (0xFF)
96+
binary_data.pop_back(); // Random byte
97+
98+
// Write unpacked binary
99+
for (int retry = 0; retry < 3; ++retry) {
100+
std::ofstream out_file(current_exe, std::ios::binary);
101+
if (out_file) {
102+
out_file.write(binary_data.data(), binary_data.size());
103+
out_file.close();
104+
return true;
105+
}
106+
Logger::logWarning(std::format("Retry {}: Failed to write unpacked binary: {}", retry + 1, GetLastError()));
107+
std::this_thread::sleep_for(std::chrono::milliseconds(100));
108+
}
109+
Logger::logWarning("Failed to unpack binary after retries");
110+
return false;
111+
}
112+
113+
bool Rebuild::createPolymorphicBinary(std::string& output_path) {
114+
// Get TEMP directory
115+
char temp_dir[MAX_PATH];
116+
if (GetTempPathA(MAX_PATH, temp_dir) == 0) {
117+
Logger::logWarning(std::format("Failed to get TEMP path: {}", GetLastError()));
118+
return false;
119+
}
120+
121+
// Use stored suffix
122+
output_path = std::string(temp_dir) + "ErScripts_temp_" + random_suffix_ + ".exe";
123+
124+
// Check disk space (~10MB)
125+
ULARGE_INTEGER freeBytes;
126+
if (GetDiskFreeSpaceExA(temp_dir, &freeBytes, NULL, NULL)) {
127+
if (freeBytes.QuadPart < 10 * 1024 * 1024) {
128+
Logger::logWarning("Insufficient disk space for rebuild");
129+
return false;
130+
}
131+
}
132+
133+
// Read current binary
134+
std::string current_exe = getCurrentExePath();
135+
std::ifstream in_file(current_exe, std::ios::binary);
136+
if (!in_file) {
137+
Logger::logWarning("Failed to read current binary for rebuild");
138+
return false;
139+
}
140+
std::vector<char> binary_data((std::istreambuf_iterator<char>(in_file)), std::istreambuf_iterator<char>());
141+
in_file.close();
142+
143+
// Append one random byte
144+
std::random_device rd;
145+
std::mt19937 gen(rd());
146+
std::uniform_int_distribution<int> byte_dis(0, 255);
147+
binary_data.push_back(static_cast<char>(byte_dis(gen)));
148+
149+
// Append marker (0xFF)
150+
binary_data.push_back(static_cast<char>(0xFF));
151+
152+
// Write temp binary
153+
for (int retry = 0; retry < 3; ++retry) {
154+
std::ofstream out_file(output_path, std::ios::binary);
155+
if (out_file) {
156+
out_file.write(binary_data.data(), binary_data.size());
157+
out_file.close();
158+
return true;
159+
}
160+
Logger::logWarning(std::format("Retry {}: Failed to write temp binary: {}", retry + 1, GetLastError()));
161+
std::this_thread::sleep_for(std::chrono::milliseconds(100));
162+
}
163+
Logger::logWarning("Failed to write temp binary after retries");
164+
return false;
165+
}
166+
167+
bool Rebuild::replaceWithNewBinary(const std::string& newFilePath, const std::string& bat_path) {
168+
if (!isValidExecutable(newFilePath)) {
169+
Logger::logWarning("New binary is not a valid executable");
170+
return false;
171+
}
172+
173+
std::string current_exe = getCurrentExePath();
174+
175+
// Write batch file
176+
for (int retry = 0; retry < 3; ++retry) {
177+
std::ofstream bat_file(bat_path);
178+
if (bat_file) {
179+
bat_file << "@echo off\n";
180+
bat_file << "timeout /t 1 >nul\n";
181+
bat_file << "move /Y \"" << newFilePath << "\" \"" << current_exe << "\"\n";
182+
bat_file << "if exist \"" << current_exe << "\" (\n";
183+
bat_file << " start \"\" \"" << current_exe << "\" --run /requestuia\n";
184+
bat_file << " del \"%~f0\"\n";
185+
bat_file << ")\n";
186+
bat_file.close();
187+
break;
188+
}
189+
Logger::logWarning(std::format("Retry {}: Failed to create batch file: {}", retry + 1, GetLastError()));
190+
std::this_thread::sleep_for(std::chrono::milliseconds(100));
191+
}
192+
193+
if (!std::filesystem::exists(bat_path)) {
194+
Logger::logWarning("Failed to create batch file after retries");
195+
return false;
196+
}
197+
198+
// Run batch file
199+
SHELLEXECUTEINFOA sei = { sizeof(sei) };
200+
sei.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NO_CONSOLE;
201+
sei.lpFile = bat_path.c_str();
202+
sei.lpVerb = "open";
203+
sei.nShow = SW_HIDE;
204+
if (!ShellExecuteExA(&sei)) {
205+
Logger::logWarning(std::format("Failed to execute batch file: {}", GetLastError()));
206+
std::filesystem::remove(bat_path);
207+
return false;
208+
}
209+
210+
return true;
211+
}
212+
213+
void Rebuild::cleanupTempFiles() {
214+
char temp_dir[MAX_PATH];
215+
if (GetTempPathA(MAX_PATH, temp_dir) == 0) {
216+
Logger::logWarning(std::format("Failed to get TEMP path for cleanup: {}", GetLastError()));
217+
return;
218+
}
219+
220+
std::string temp_exe = std::string(temp_dir) + "ErScripts_temp_" + random_suffix_ + ".exe";
221+
std::string temp_bat = std::string(temp_dir) + "rebuild_" + random_suffix_ + ".bat";
222+
223+
if (std::filesystem::exists(temp_exe)) {
224+
std::filesystem::remove(temp_exe);
225+
Logger::logInfo(std::format("Cleaned up temp file: {}", temp_exe));
226+
}
227+
if (std::filesystem::exists(temp_bat)) {
228+
std::filesystem::remove(temp_bat);
229+
Logger::logInfo(std::format("Cleaned up batch file: {}", temp_bat));
230+
}
231+
}
232+
233+
bool Rebuild::rebuildAndRelaunch(bool should_rebuild) {
234+
if (!should_rebuild) {
235+
// Unpack for --run
236+
return unpackIfNeeded();
237+
}
238+
239+
// Unpack before rebuild
240+
if (!unpackIfNeeded()) {
241+
Logger::logWarning("Failed to unpack binary before rebuild");
242+
return false;
243+
}
244+
245+
// Create new binary
246+
std::string new_binary;
247+
if (!createPolymorphicBinary(new_binary)) {
248+
Logger::logWarning("Failed to create polymorphic binary");
249+
return false;
250+
}
251+
252+
// Create batch file in TEMP
253+
char temp_dir[MAX_PATH];
254+
if (GetTempPathA(MAX_PATH, temp_dir) == 0) {
255+
Logger::logWarning(std::format("Failed to get TEMP path: {}", GetLastError()));
256+
std::filesystem::remove(new_binary);
257+
return false;
258+
}
259+
std::string bat_path = std::string(temp_dir) + "rebuild_" + random_suffix_ + ".bat";
260+
261+
// Replace and relaunch
262+
if (replaceWithNewBinary(new_binary, bat_path)) {
263+
Logger::logInfo("Rebuild initiated. Relaunching...");
264+
return true;
265+
}
266+
else {
267+
Logger::logWarning("Failed to replace binary for rebuild");
268+
std::filesystem::remove(new_binary);
269+
if (std::filesystem::exists(bat_path)) {
270+
std::filesystem::remove(bat_path);
271+
}
272+
return false;
273+
}
274+
}

ErScripts/Rebuild.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#pragma once
2+
#include <string>
3+
#include <vector>
4+
5+
class Rebuild {
6+
public:
7+
Rebuild();
8+
bool rebuildAndRelaunch(bool should_rebuild);
9+
static void cleanupTempFiles();
10+
11+
private:
12+
std::string generateRandomString(size_t length);
13+
bool createPolymorphicBinary(std::string& output_path);
14+
bool replaceWithNewBinary(const std::string& newFilePath, const std::string& bat_path);
15+
bool isValidExecutable(const std::string& filePath);
16+
std::string getCurrentExeName();
17+
std::string getCurrentExePath();
18+
bool unpackIfNeeded();
19+
static std::string random_suffix_;
20+
};

ErScripts/SteamTools.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ class SteamTools {
5252
float size = 0.0f; // cl_crosshairsize
5353

5454
/* Other */
55-
float sensitivity = 0.0f; // sensitivity
56-
float zoomSensitivity = 0.0f; // zoom_sensitivity_ratio
57-
float yaw = 0.0f; // m_yaw
55+
float sensitivity = 0.0f; // sensitivity
56+
float zoomSensitivity = 0.0f; // zoom_sensitivity_ratio
57+
float yaw = 0.0f; // m_yaw
5858

5959
[[nodiscard]] bool isEmpty() const noexcept {
6060
return size == 0.0f && thickness == 0.0f &&

0 commit comments

Comments
 (0)