From 69fac67b4930b7e93b4b4a938f44e5bb951f5400 Mon Sep 17 00:00:00 2001 From: Jaida Wu Date: Thu, 23 Nov 2023 01:27:56 +0800 Subject: [PATCH] Initial PoC release --- README.md | 105 +++++++++++- bypass.php | 378 ++++++++++++++++++++++++++++++++++++++++++ libraries/placeholder | 1 + 3 files changed, 480 insertions(+), 4 deletions(-) create mode 100644 bypass.php create mode 100644 libraries/placeholder diff --git a/README.md b/README.md index 0e3754f..02bea7b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,101 @@ -# Xiaomi-BootLoader-Bypass -Bypass Xiaomi HyperOS community restrictions of BootLodaer unlock account bind. - -WIP +# Xiaomi BootLoader Bypass + +![Version: 1.0](https://img.shields.io/badge/Version-1.0-brightgreen?style=for-the-badge) ![中文文档](https://img.shields.io/badge/中文文档-brightgreen?style=for-the-badge) + +A PoC that exploits a vulnerability to bypass the Xiaomi HyperOS community restrictions of BootLoader unlocked account bindings. + +Feel free pull request if you want :) + +## php-adb + +The project proudly uses the [php-adb](https://github.com/MlgmXyysd/php-adb) library. + +## Buy me a Coffee + +✨ If you like my projects, you can buy me a coffee at: + + - [爱发电](https://afdian.net/@MlgmXyysd) + - [PayPal](https://paypal.me/MlgmXyysd) + - [Patreon](https://www.patreon.com/MlgmXyysd) + +## Warning + +After unlocking the BootLoader, you may encounter the following situations: + +- Software or hardware not working properly or even damaged. +- Loss of data stored in the device. +- Credit card theft, or other financial loss. + +If you're experiencing any of the above, you should take all the responsibility yourself as this is the risk you may encounter when unlocking BootLoader. This obviously does not cover all risks. You've been warned. + +- Warranty lost. Not only the base warranty, but some of the extra extended warranties (such as Mi Care or broken-screen warranty) that you have purchased may also be lost according to the exclusions provided by Xiaomi. +- Hardware level self-destruct like Samsung Knox. TEE-related features will be permanently damaged. There is no way to restore other than by replacing the motherboard. +- Functional anomalies after flashing a third-party system due to closed-source kernel source code. +- Device or account banned by unlocking BootLoader. + +If you're experiencing any of the above, consider yourself damned. Ever since Xiaomi restricted unlocking BootLoader, it has been against Xiaomi's 'geek' spirit and even the GPL. Xiaomi's restrictions on BootLoader unlocking are endless, and there's nothing we as developers can do about it. + +## Unlocking requirements + +- An valid device: + - A unbanned\* Xiaomi, Redmi or POCO device. + - Device is running the official version of HyperOS. + - (Update 2023/11/23) Device is not forced to verify account qualification by Xiaomi. +- An valid SIM card: + - Except for tablets that cannot use SIM cards. + - SIM card must not be out of service. + - SIM card needs to be able to access the internet. + - Only 2 devices per valid SIM card are allowed to be unlock to a valid SIM card within a three-month period. +- An valid Xiaomi account: + - Each account can only unlock 1 phone in a month and 3 phones in a year period. + - Account not banned\*. +- You have read and understood the Warning above. + +- \* According to the unlocking instructions provided by Xiaomi, it will prohibit some accounts and devices from using the unlocking tool, which is called "risk control". + +## How to use + +1. Download and install PHP 8.0+ for your system from the [official website](https://www.php.net/downloads). +2. Enable OpenSSL extension in `php.ini`. +3. Place `adb.php` in [php-adb](https://github.com/MlgmXyysd/php-adb) to the directory. +4. Download [platform-tools](https://developer.android.com/studio/releases/platform-tools) and place them in `libraries`. *Note: Mac OS needs to rename `adb` to `adb-darwin`.* +5. Open a terminal and use PHP interpreter to execute the [script](bypass.php). + +- p.s. Releases has packaged the required files and click-to-run scripts. + +6. Tap repeatedly on the `Settings - About Phone - MIUI Version` to enable `Development Options`. +7. Enable `OEM Unlocking`, `USB Debugging` and `USB Debugging (Security Settings)` in `Settings - Additional Settings - Development Options`. +8. Log in an _valid_\* Xiaomi account. +9. Connect phone to PC via wired interface. +10. Check `Always allow from this computer` and click `OK`. + +- \* See "Unlocking Requirements" below. + +11. Wait and follow the prompts of script. +12. After successful binding, you can use the [official unlock tool](https://en.miui.com/unlock/index.html) to check the time you need to wait. + +## Workaround + +- [52 Pojie]() +- [My Blog]() +- [My Blog (English)]() + +## FAQ + +- Q: Why does the unlock tool still remind me to wait 168/360 (or more) hours? +- A: By principle, this PoC only bypasses the restrictions added for HyperOS. You still need to comply with the restrictions for MIUI. + +- Q: Binding failed with error code 401. +- A: Your Xiaomi account credentials have expired, you need to log out and log in again in your device. + +- Q: Binding failed with error code 20086. +- A: Your device credentials have expired, you need to reboot your device. + +- Q: Binding failed with error code 20090 & 20091. +- A: Device's Security Device Credential Manager function failure, contact after-sales. + +- Q: Binding failed with error code 30001. +- A: Your device has been forced to verify the account qualification by Xiaomi. Xiaomi lost its 'geek' spirit a long time ago, and there's nothing we can do about it. + +## License +No license, you are only allowed to use this project. All copyright (and link, etc.) in this software is not allowed to be deleted or changed without permission. All rights are reserved by [MeowCat Studio](https://github.com/MeowCat-Studio), [Meow Mobile](https://github.com/Meow-Mobile) and [NekoYuzu](https://github.com/MlgmXyysd). diff --git a/bypass.php b/bypass.php new file mode 100644 index 0000000..6a95f74 --- /dev/null +++ b/bypass.php @@ -0,0 +1,378 @@ + refreshDeviceList(); + $t = array(); + foreach ($s as $d) { + if ($d["status"] === $a::CONNECT_TYPE_DEVICE) { + $t[] = array($d["serial"], $d["transport"]); + } + } + return $t; +} + +/** + * Formatted Log + * @param $m string optional Message + * @param $c string optional Color + * @param $p string optional Indicator + * @param $t string optional Type (Level) + * @author NekoYuzu (MlgmXyysd) + * @date 2022/03/24 14:50:01 + */ + +function logf(string $m = "", string $c = "", string $p = "-", string $t = "I"): void +{ + switch (strtoupper($c)) { + case "G": + $c = "\033[32m"; + break; + case "R": + $c = "\033[31m"; + break; + case "Y": + $c = "\033[33m"; + break; + default: + $c = ""; + } + switch (strtoupper($t)) { + case "W": + $t = "WARN"; + break; + case "E": + $t = "ERROR"; + break; + case "I": + default: + $t = "INFO"; + } + print(date("[Y-m-d] [H:i:s]") . " [" . $t . "] " . $p . " " . $c . $m . "\033[0m" . PHP_EOL); +} + +/** + * Curl HTTP wrapper function + * @param $url string required Target url + * @param $method string required Request method + * @param $fields array optional Request body + * @param $header array optional Request header + * @param $useForm bool optional Treat request body as urlencoded form + * @return array Curl response + * @author NekoYuzu (MlgmXyysd) + * @date 2023/11/20 23:50:39 + */ + +function http(string $url, string $method, array $fields = array(), array $header = array(), bool $useForm = false): array +{ + if ($useForm) { + $fields = http_build_query($fields); + } + $curl = curl_init(); + curl_setopt_array($curl, array( + CURLOPT_URL => $url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_ENCODING => "", + CURLOPT_SSL_VERIFYPEER => false, + CURLOPT_SSL_VERIFYHOST => false, + CURLOPT_MAXREDIRS => 10, + CURLOPT_CONNECTTIMEOUT => 2, + CURLOPT_TIMEOUT => 6, + CURLOPT_CUSTOMREQUEST => $method, + CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, + CURLOPT_POST => $method == "POST", + CURLOPT_POSTFIELDS => $fields, + CURLOPT_HTTPHEADER => $header + )); + + $response = curl_exec($curl); + $info = curl_getinfo($curl); + $info["errno"] = curl_errno($curl); + $info["error"] = curl_error($curl); + $info["request"] = json_encode($fields); + $info["response"] = $response; + curl_close($curl); + return $info; +} + +/** + * HTTP POST wrapper + * @param $_api string required Target endpoint + * @param $data array optional Request body + * @param $header array optional Request header + * @param $useForm bool optional Treat request body as urlencoded form + * @return array Curl response + * @return false Response code is not HTTP 200 OK + * @author NekoYuzu (MlgmXyysd) + * @date 2023/11/20 23:55:41 + */ + +function postApi(string $_api, array $data = array(), array $header = array(), bool $useForm = false): array|false +{ + $response = http($GLOBALS["api"] . $_api, "POST", $data, $header, $useForm); + if ($response["http_code"] != 200) { + return false; + } + return json_decode($response["response"], true); +} + +/** + * Sign data using HMAC SHA-1 + * @param $data string required Data to sign + * @return string Signed hash + * @author NekoYuzu (MlgmXyysd) + * @date 2023/11/21 00:20:56 + */ + +function signData(string $data): string +{ + return strtolower(bin2hex(hash_hmac("sha1", "POST\n/v1/unlock/applyBind\ndata=" . $data . "&sid=miui_sec_android", $GLOBALS["sign_key"], true))); +} + +/** + * Decrypt data using AES/CBC/PKCS5Padding + * @param $data string required Data to decrypt + * @return string Decrypted data + * @return false Failed to decrypt + * @author NekoYuzu (MlgmXyysd) + * @date 2023/11/21 00:15:30 + */ + +function decryptData(string $data): string|false +{ + return openssl_decrypt(base64_decode($data), "AES-128-CBC", $GLOBALS["data_pass"], OPENSSL_RAW_DATA, $GLOBALS["data_iv"]); +} + +/*********************** + * Functions End * + ***********************/ + +/********************** + * Banner Start * + **********************/ + +logf("************************************", "g"); +logf("* Xiaomi HyperOS BootLoader Bypass *", "g"); +logf("* By NekoYuzu Version " . $version . " *", "g"); +logf("************************************", "g"); +logf("GitHub: https://github.com/MlgmXyysd"); +logf("XDA: https://xdaforums.com/m/mlgmxyysd.8430637"); +logf("X (Twitter): https://x.com/realMlgmXyysd"); +logf("PayPal: https://paypal.me/MlgmXyysd"); +logf("My Blog: https://www.neko.ink/"); +logf("************************************", "g"); + +/******************** + * Banner End * + ********************/ + +/******************** + * Main Logic * + ********************/ + +logf("Starting ADB server..."); + +$adb = new ADB(__DIR__ . DIRECTORY_SEPARATOR . "libraries"); + +$devices = parseDeviceList($adb); +$devices_count = count($devices); + +while ($devices_count != 1) { + if ($devices_count == 0) { + logf("Waiting for device connection..."); + } else { + logf("Only one device is allowed to connect, disconnect others to continue. Current number of devices: " . $devices_count); + } + sleep(1); + $devices = parseDeviceList($adb); + $devices_count = count($devices); +} + +$device = $devices[0]; +$id = $adb -> getDeviceId($device[1], true); +logf("Processing device " . $device[0] . "(" . $device[1] . ")..."); + +$adb -> clearLogcat($id); +$adb -> runAdb($id . "shell svc data enable"); + +logf("Finding BootLoader unlock bind request..."); + +$focus = $adb -> getCurrentActivity(); +if ($focus[0] != "com.android.settings") { + if ($focus[0] != "NotificationShade") { + $adb -> runAdb($id . "shell am start -a android.settings.APPLICATION_DEVELOPMENT_SETTINGS"); + } +} else { + if ($focus[1] != "com.android.settings.bootloader.BootloaderStatusActivity") { + $adb -> runAdb($id . "shell am start -a android.settings.APPLICATION_DEVELOPMENT_SETTINGS"); + } +} +logf("Now you can bind account in the developer options.", "y", "*"); + +$args = $headers = null; + +$process = proc_open($adb -> bin . " " . $id . "logcat *:S CloudDeviceStatus:V", array( + 1 => ["pipe", "w"] +), $pipes); + +if (is_resource($process)) { + while (!feof($pipes[1])) { + $output = fgets($pipes[1]); + + if (str_contains($output, "CloudDeviceStatus: args:")) { + if (preg_match("/args:(.*)/", $output, $matches)) { + $args = trim($matches[1]); + } + $adb -> runAdb($id . "shell svc data disable"); + } + + if (str_contains($output, "CloudDeviceStatus: headers:")) { + if (preg_match("/headers:(.*)/", $output, $matches)) { + $headers = trim($matches[1]); + } + logf("Account bind request found! Let's block it."); + break; + } + } + + fclose($pipes[1]); +} + +logf("Refactoring parameters..."); + +$data = json_decode(decryptData($args), true); + +$data["rom_version"] = str_replace("V816", "V14", $data["rom_version"]); + +$data = json_encode($data); +$sign = signData($data); + +$headers = decryptData($headers); +$cookies = null; +if (preg_match("/Cookie=\[(.*)\]/", $headers, $matches)) { + $cookies = trim($matches[1]); +} + +logf("Sending POST request..."); +$res = postApi("unlock/applyBind", array( + "data" => $data, + "sid" => "miui_sec_android", + "sign" => $sign +), array( + "Cookie: " . $cookies, + "Content-Type: application/x-www-form-urlencoded" +), true); + +$adb -> runAdb($id . "shell svc data enable"); + +if (!$res) { + logf("Fail to send request, check your internet connection.", "r", "!"); + exit(); +} + +switch ($res["code"]) { + case 0: + logf("Target account: " . $res["data"]["userId"], "g"); + logf("Account bound successfully, wait time can be viewed in the unlock tool.", "g"); + break; + case 401: + logf("Account credentials have expired, re-login to your account in your phone. (401)", "y"); + break; + case 20086: + logf("Device credentials expired. (20086)", "y"); + break; + case 30001: + logf("Binding failed, this device has been forced to verify the account qualification by Xiaomi. (30001)", "y"); + break; + case 86015: + logf("Fail to bind account, invalid device signature. (86015)", "y"); + break; + default: + logf($res["descEN"] . " (" . $res["code"] . ")", "y"); +} diff --git a/libraries/placeholder b/libraries/placeholder new file mode 100644 index 0000000..73e76e8 --- /dev/null +++ b/libraries/placeholder @@ -0,0 +1 @@ +# Do NOT remove this folder \ No newline at end of file