Skip to content

Commit

Permalink
refactor: Patch logic refactored using C++20
Browse files Browse the repository at this point in the history
fix: Resolve issue with non-functional pause functionality
fix: Throw error when .bak file already exists
fix: Backup when file patched

Signed-off-by: Mai Ooizumi <[email protected]>
  • Loading branch information
Mai-Ooizumi committed Apr 16, 2024
1 parent 9788592 commit 8d26a62
Showing 1 changed file with 91 additions and 107 deletions.
198 changes: 91 additions & 107 deletions VScriptAutoPatcher/VScriptAutoPatcher.cpp
Original file line number Diff line number Diff line change
@@ -1,40 +1,83 @@
#include <iostream>
#include <Windows.h>
#include <vector>
#include <cstdint>
#include <filesystem>
#include <fstream>

#ifdef _WIN32
#include <Windows.h>
#include <conio.h>

bool readFile(const std::string& filename, std::vector<uint8_t>& buffer)
static std::string SelectPEFile()
{
HANDLE fileHandle = CreateFileA(
filename.c_str(),
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);

if (fileHandle == INVALID_HANDLE_VALUE)
TCHAR szBuffer[MAX_PATH] = { 0 };
OPENFILENAME file = { 0 };

ZeroMemory(&file, sizeof(file));

file.hwndOwner = NULL;
file.lStructSize = sizeof(file);
file.lpstrFilter = L"vscript.dll(vscript.dll)\0vscript.dll\0所有文件(*.*)\0*.*\0\0";
file.lpstrInitialDir = L"";
file.lpstrFile = szBuffer;
file.nMaxFile = sizeof(szBuffer) / sizeof(*szBuffer);
file.nFilterIndex = 0;
file.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

if (GetOpenFileName(&file))
{
std::cerr << "[ERROR] " << "Failed to create handle to: " << filename << std::endl;
//std::cout << "[REMINDER] " << "Make sure the executable is in same folder with: " << filename << std::endl;
return false;
int size = WideCharToMultiByte(CP_ACP, 0, file.lpstrFile, -1, NULL, 0, NULL, NULL);
if (size == 0)
{
return std::string();
}
std::string result(size - 1, 0);
WideCharToMultiByte(CP_ACP, 0, file.lpstrFile, -1, &result[0], size, NULL, NULL);
return result;
}
else
{
return std::string();
}
}

static void Pause()
{
std::cout << "Press any key to continue..." << std::flush;
(void)_getch();
}

DWORD fileSize = GetFileSize(fileHandle, NULL);
buffer.resize(fileSize);
#else

DWORD bytesRead = 0;
ReadFile(fileHandle, buffer.data(), fileSize, &bytesRead, NULL);
static void Pause()
{

CloseHandle(fileHandle);
}

#endif // _WIN32

static bool readFile(const std::string & fileName, std::vector<uint8_t> & buffer)
{
std::ifstream file(fileName, std::ios::binary);

if (!file.is_open())
{
std::cerr << "[ERROR] " << "Failed to open file: " << fileName << std::endl;
return false;
}

file.seekg(0, std::ios::end);
std::streamsize fileSize = file.tellg();
file.seekg(0, std::ios::beg);

buffer.resize(static_cast<size_t>(fileSize));
file.read(reinterpret_cast<char *>(buffer.data()), fileSize);

file.close();
return true;
}

std::vector<size_t> findHexArray(std::vector<uint8_t>& buffer, const std::vector<uint8_t>& hexArray)
static std::vector<size_t> findHexArray(const std::vector<uint8_t> & buffer, const std::vector<uint8_t> & hexArray)
{
std::vector<size_t> positions;

Expand All @@ -43,16 +86,11 @@ std::vector<size_t> findHexArray(std::vector<uint8_t>& buffer, const std::vector

for (size_t i = 0; i <= bufferSize - arraySize; ++i)
{
bool found = true;

for (size_t j = 0; j < arraySize; ++j) {
if (buffer[i + j] != hexArray[j] && hexArray[j] != 0x2A) {
found = false;
break;
}
}

if (found)
if (std::ranges::equal(buffer.begin() + i, buffer.begin() + i + arraySize, hexArray.begin(), hexArray.end(),
[](uint8_t a, uint8_t b)
{
return a == b || b == 0x2A;
}))
{
std::cout << "[INFO] " << "Found position at buffer index: " << i << std::endl;
positions.push_back(i);
Expand All @@ -62,37 +100,27 @@ std::vector<size_t> findHexArray(std::vector<uint8_t>& buffer, const std::vector
return positions;
}

bool writeFile(const std::string& filename, const std::vector<uint8_t>& buffer)
static bool writeFile(const std::string & fileName, const std::vector<uint8_t> & buffer)
{
HANDLE fileHandle = CreateFileA(
filename.c_str(),
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);

if (fileHandle == INVALID_HANDLE_VALUE)
{
std::cerr << "[ERROR] " << "Failed to create handle to: " << filename << std::endl;
//std::cout << "[REMINDER] " << "Make sure the executable is in same folder with: " << filename << std::endl;
std::ofstream file(fileName, std::ios::binary);

if (!file.is_open())
{
std::cerr << "[ERROR] " << "Failed to open file: " << fileName << std::endl;
return false;
}

DWORD bytesWritten = 0;
WriteFile(fileHandle, buffer.data(), buffer.size(), &bytesWritten, NULL);
file.write(reinterpret_cast<const char *>(buffer.data()), buffer.size());

CloseHandle(fileHandle);
file.close();

return (bytesWritten == buffer.size());
return true;
}

void PatchFile(std::string fileName, std::vector<uint8_t> originalArray, std::vector<uint8_t> replacedArray)
static void patchFile(const std::string & fileName, const std::vector<uint8_t> & originalArray, const std::vector<uint8_t> & replacedArray)
{
std::vector<uint8_t> buffer;

if (!readFile(fileName, buffer))
{
return;
Expand All @@ -102,19 +130,19 @@ void PatchFile(std::string fileName, std::vector<uint8_t> originalArray, std::ve

if (positions.empty())
{
std::cout << "[ERROR] " << fileName << " is already patched" << std::endl;
std::cerr << "[ERROR] " << fileName << " is already patched" << std::endl;
return;
}

if (std::filesystem::exists(fileName + ".bak"))
{
std::filesystem::remove(fileName + ".bak");
}
std::filesystem::copy(fileName, fileName + ".bak");

for (size_t pos : positions)
{
for (size_t i = 0; i < replacedArray.size(); ++i)
{
if (replacedArray[i] != 0x2A)
{
buffer[pos + i] = replacedArray[i];
}
}
std::ranges::copy(replacedArray.begin(), replacedArray.end(), buffer.begin() + pos);
}

if (!writeFile(fileName, buffer))
Expand All @@ -125,48 +153,6 @@ void PatchFile(std::string fileName, std::vector<uint8_t> originalArray, std::ve
std::cout << "[SUCCESS] " << fileName << " has been patched." << std::endl;
}

static std::string SelectPEFile()
{
TCHAR szBuffer[MAX_PATH] = { 0 };
OPENFILENAME file = { 0 };

ZeroMemory(&file, sizeof(file));

file.hwndOwner = NULL;
file.lStructSize = sizeof(file);
file.lpstrFilter = L"vscript.dll(vscript.dll)\0vscript.dll\0所有文件(*.*)\0*.*\0\0";
file.lpstrInitialDir = L"";
file.lpstrFile = szBuffer;
file.nMaxFile = sizeof(szBuffer) / sizeof(*szBuffer);
file.nFilterIndex = 0;
file.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

if (GetOpenFileName(&file))
{
int size = WideCharToMultiByte(CP_ACP, 0, file.lpstrFile, -1, NULL, 0, NULL, NULL);
if (size == 0)
{
return std::string();
}
std::string result(size - 1, 0);
WideCharToMultiByte(CP_ACP, 0, file.lpstrFile, -1, &result[0], size, NULL, NULL);
return result;
}
else
{
return std::string();
}
}

static void Pause()
{
std::cout << "Press any key to continue..." << std::flush;
HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
FlushConsoleInputBuffer(h);
WaitForSingleObject(h, INFINITE);
FlushConsoleInputBuffer(h);
}

int main(int argc, const char * const * argv)
{
std::string filePath;
Expand Down Expand Up @@ -198,23 +184,21 @@ int main(int argc, const char * const * argv)
{
filePath = "./bin/win64/vscript.dll";
}

#ifdef _WIN32
if (!std::filesystem::exists(filePath))
{
filePath = SelectPEFile();
}
#endif // _WIN32
if (std::filesystem::exists(filePath))
{
std::filesystem::copy(filePath, filePath + ".bak");

PatchFile(filePath, { 0xBE, 0x01, 0x2A, 0x2A, 0x2A, 0x2B, 0xD6, 0x74, 0x2A, 0x3B, 0xD6 }, { 0xBE, 0x02 });
patchFile(filePath, { 0xBE, 0x01, 0x2A, 0x2A, 0x2A, 0x2B, 0xD6, 0x74, 0x2A, 0x3B, 0xD6 }, { 0xBE, 0x02 });
}
else
{
std::cerr << "File doesn't exist" << std::endl;
return 2;
}

}
catch (const std::exception & e)
{
Expand Down

0 comments on commit 8d26a62

Please sign in to comment.