You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
381 lines
10 KiB
PHP
381 lines
10 KiB
PHP
<?php
|
|
/**
|
|
*
|
|
* Copyright (C) 2002-2024 NekoYuzu (MlgmXyysd) All Rights Reserved.
|
|
* Copyright (C) 2013-2024 MeowCat Studio All Rights Reserved.
|
|
* Copyright (C) 2020-2024 Meow Mobile All Rights Reserved.
|
|
*
|
|
*/
|
|
|
|
/**
|
|
*
|
|
* Xiaomi HyperOS BootLoader Bypass
|
|
*
|
|
* https://github.com/MlgmXyysd/Xiaomi-BootLoader-Bypass
|
|
*
|
|
* Bypass Xiaomi HyperOS community restrictions of BootLodaer unlock account bind.
|
|
*
|
|
* Environment requirement:
|
|
* - PHP 8.0+
|
|
* - OpenSSL Extension
|
|
* - Curl Extension
|
|
* - ADB
|
|
*
|
|
* @author MlgmXyysd
|
|
* @version 1.0
|
|
*
|
|
* All copyright in the software is not allowed to be deleted
|
|
* or changed without permission.
|
|
*
|
|
*/
|
|
|
|
/***********************
|
|
* Configs Start *
|
|
***********************/
|
|
|
|
// Global flag
|
|
// If you are running a Global ROM (Non-China Mainland), set it to true
|
|
$useGlobal = false;
|
|
|
|
/*********************
|
|
* Configs End *
|
|
*********************/
|
|
|
|
|
|
/***************************************
|
|
* WARNING *
|
|
* Do NOT modify the codes below *
|
|
* WARNING *
|
|
***************************************/
|
|
|
|
// Include php-adb library
|
|
// https://github.com/MlgmXyysd/php-adb
|
|
|
|
require_once __DIR__ . DIRECTORY_SEPARATOR . "adb.php";
|
|
|
|
use MeowMobile\ADB;
|
|
|
|
/*************************
|
|
* Constants Start *
|
|
*************************/
|
|
|
|
global $api;
|
|
global $sign_key;
|
|
global $data_pass;
|
|
global $data_iv;
|
|
|
|
$api = $useGlobal ? "https://unlock.update.intl.miui.com/v1/" : "https://unlock.update.miui.com/v1/";
|
|
$sign_key = "10f29ff413c89c8de02349cb3eb9a5f510f29ff413c89c8de02349cb3eb9a5f5";
|
|
$data_pass = "20nr1aobv2xi8ax4";
|
|
$data_iv = "0102030405060708";
|
|
|
|
$version = "1.0";
|
|
|
|
/***********************
|
|
* Constants End *
|
|
***********************/
|
|
|
|
/*************************
|
|
* Functions Start *
|
|
*************************/
|
|
|
|
/**
|
|
* Formatted Log
|
|
* @param $a ADB required ADB instance
|
|
* @return array List of connected adb devices
|
|
* @author NekoYuzu (MlgmXyysd)
|
|
* @date 2022/03/24 14:01:03
|
|
*/
|
|
|
|
function parseDeviceList(ADB $a): array
|
|
{
|
|
$s = $a -> 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);
|
|
|
|
// V816 is the special identity for HyperOS in MIUI version
|
|
$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");
|
|
}
|