Skip to content

Commit

Permalink
case insensitive filename compare, clarify readme
Browse files Browse the repository at this point in the history
  • Loading branch information
ambiennt committed Aug 24, 2023
1 parent 46f8f4c commit efe7cd1
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 25 deletions.
4 changes: 3 additions & 1 deletion KeyPatcher/pch.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@
#include <string>
#include <string_view>
#include <optional>
#include <array>
#include <array>
#include <cwctype>
#include <algorithm>
54 changes: 36 additions & 18 deletions KeyPatcher/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,21 @@ namespace KeyData {

using lps_array_t = std::array<int32_t, KeyData::NEW_ROOT_PUBLIC_KEY.length()>;

inline constexpr std::array<std::wstring_view, 5> VALID_FILES{
L"Minecraft.Windows.exe", // windows client
L"bedrock_server.exe", // windows server
L"bedrock_server_mod.exe", // windows modded server
L"bedrock_server", // linux server
L"libminecraftpe.so", // android client
};

bool wstringCaseInsensitiveEquals(std::wstring_view lhs, std::wstring_view rhs) {
return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(),
[](std::wint_t lhs, std::wint_t rhs) -> bool {
return std::towlower(lhs) == std::towlower(rhs);
});
}

// create partial match table (longest proper prefix) for Knuth-Morris-Pratt algorithm
// https://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm
lps_array_t computeLPSArray(std::string_view pattern) {
Expand Down Expand Up @@ -141,7 +156,7 @@ std::optional<std::filesystem::path> getDefaultMinecraftFolder(const std::filesy
}
}
catch (std::filesystem::filesystem_error& ex) {
std::cerr << "Could not locate default Minecraft folder: " << ex.what() << '\n';
std::cerr << "Could not locate default Minecraft for Windows folder: " << ex.what() << '\n';
}
return std::nullopt;
Expand All @@ -160,36 +175,40 @@ std::optional<std::filesystem::path> getDefaultMinecraftPath() {
}
*/

std::array<std::wstring, 4> validFiles{
L"Minecraft.Windows.exe",
L"bedrock_server.exe",
L"bedrock_server_mod.exe",
L"libminecraftpe.so"
};

// if the user provided the folder path instead of the direct exe path
void sanitizeInputPathIfNeeded(std::filesystem::path& path) {
try {
if (!std::filesystem::is_directory(path)) {
return;
}
for (auto& it : std::filesystem::directory_iterator(path)) {
if (std::find(validFiles.begin(), validFiles.end(), it.path().filename().wstring()) != validFiles.end() && !it.is_directory()) {
path = it.path();
for (const auto& it : std::filesystem::directory_iterator(path)) {
if (!it.is_directory()) {
auto fileName = it.path().filename().wstring();
auto result = std::find_if(VALID_FILES.begin(), VALID_FILES.end(), [&](std::wstring_view validFile) -> bool { // select first match in the directory
return wstringCaseInsensitiveEquals(validFile, fileName); // windows files are case insensitive, lets give some leeway to the end user
});

if (result != VALID_FILES.end()) {
path = it.path();
}
}
}
}
catch (...) {}
}

bool isValidExePath(const std::filesystem::path& path) {
auto fn = path.filename().wstring();
if (std::find(validFiles.begin(), validFiles.end(), fn) == validFiles.end()) {

auto fileName = path.filename().wstring();
auto result = std::find_if(VALID_FILES.begin(), VALID_FILES.end(), [&](std::wstring_view validFile) -> bool {
return wstringCaseInsensitiveEquals(validFile, fileName);
});

if (result == VALID_FILES.end()) {
std::cerr << "File path did not resolve to a Minecraft executable!\n";
return false;
}


try {
if (!std::filesystem::exists(path)) {
std::cerr << "Specified executable path doesn't exist on disk!\n";
Expand All @@ -200,14 +219,12 @@ bool isValidExePath(const std::filesystem::path& path) {
std::cerr << "Specified path does not point to a file!\n";
return false;
}

return true;
}
catch (std::filesystem::filesystem_error& ex) {
std::cerr << "Failed to verify existence of Minecraft executable: " << ex.what() << '\n';
}

return false;
return true;
}

int main([[maybe_unused]] int argc, [[maybe_unused]] char** argv, [[maybe_unused]] char** envp) {
Expand All @@ -217,7 +234,7 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char** argv, [[maybe_unused

while (!patchedExe) {

std::cout << "Enter the full path for the Minecraft for Windows executable file OR its parent folder: ";
std::cout << "Enter the full path for the Minecraft executable file OR its parent folder: ";
std::getline(std::wcin, input);

std::filesystem::path path{ input };
Expand Down Expand Up @@ -248,6 +265,7 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char** argv, [[maybe_unused
}

if (hasValidPath) {
std::wcout << L"Attempting to patch " << path.wstring() << L"...\n";
patchedExe = patchFile(path);
}
}
Expand Down
19 changes: 13 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,18 @@

### A programmatic approach to fixing MCBE's broken Xbox Live authentication
- [Why is this needed?](https://blog.tobiasgrether.com/2023/08/23/how-microsoft-broke-minecraft.html)
- Patch any applicable Minecraft for Windows executable with an updated public Xbox Live authentication key (with one major caveat)
- Patch any applicable Minecraft executable with an updated public Xbox Live authentication key (with one caveat)
- Supported executables include:
- Minecraft for Windows (`Minecraft.Windows.exe`)
- Bedrock Dedicated Server for Windows (`bedrock_server.exe`)
- Bedrock Dedicated Server for Windows - modded (`bedrock_server_mod.exe`)
- Bedrock Dedicated Server for Linux (`bedrock_server`)
- Minecraft for Android (`libminecraftpe.so`)

### Limitations
### Limitations with patching appx files
- Appx is a file package format used by UWP apps, including Minecraft for Windows
- The default installation directory where the `Minecraft.Windows.exe` executable is stored is heavily (and obnoxiously) protected by Windows
- One problem lies within the inability of 3rd party programs to write anywhere inside the WindowsApps folder by default. This makes the patching process extremely inconvenient
- One problem lies within the inability of 3rd party programs to write anywhere inside the WindowsApps folder by default; this makes the patching process fairly inconvenient
- Additionally, even if write restrictions were bypassed, applying changes to the contents of an appx requires sideloading, or else the app will fail to run due to mismatching hashes
- By default, the contents of Minecraft appx files are installed in `%ProgramFiles%\WindowsApps\Microsoft.MinecraftUWP_*_8wekyb3d8bbwe`, where `*` will vary depending on your installed Minecraft version
- For example, if you have the 64 bit version of Minecraft v1.16.40 installed, the directory would be `%ProgramFiles%\WindowsApps\Microsoft.MinecraftUWP_1.16.4002.0_x64__8wekyb3d8bbwe`
Expand All @@ -20,9 +27,9 @@
- The location of the `Minecraft.Windows.exe` executable in this custom installation path is the same path you will specify when running the patcher

### How to use
- Make sure Minecraft for Windows is closed beforehand
- Make sure the Minecraft executable you wish to patch is closed beforehand
- Download the latest release of the patcher [here](https://github.com/ambiennt/KeyPatcher/releases/)
- Follow the steps described in the [Workarounds header](https://github.com/ambiennt/KeyPatcher#workarounds)
- If you are patching Minecraft for Windows, follow the steps described in the [Workarounds header](https://github.com/ambiennt/KeyPatcher#workarounds)
- You may need to run the patcher with administrator permissions
- Follow the prompts in the console as required

Expand All @@ -31,5 +38,5 @@
- However, you are not permitted to put this tool behind some sort of paywall, such as a 3rd party link shortener or other paid product

### Other remarks
- I am aware that the process to apply a seemingly simple patch is quite complex for the majority of users who do not use version managers, but this is largely due to Microsoft's restrictive UWP application ecosystem
- I am aware that the process to apply a seemingly simple patch to Minecraft for Windows is quite complex for the majority of users who do not use version managers, but this is largely due to Microsoft's restrictive UWP application ecosystem
- There may be better ways to streamline this entire process, so contributions are welcome and encouraged

0 comments on commit efe7cd1

Please sign in to comment.