4

Guide: Reverse-engineering Xiaomi OTA Updates to Find Unreleased Versions

 1 year ago
source link: https://forum.xda-developers.com/t/guide-reverse-engineering-xiaomi-ota-updates-to-find-unreleased-versions.3691612/page-4#post-87584233
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Guide: Reverse-engineering Xiaomi OTA Updates to Find Unreleased Versions

palexis06

Senior Member
Mar 23, 2011 Nice
<?php
define('AES_128_CBC', 'aes-128-cbc');

$q = 'RMnOGd%2Be0NNG2DwH7PkO1Wsudgf7Ss0CgFCRv5iTrpWO46ODkEI%2FQ9%2B9udjXENxgdcpwRKYiiGJW6Ov39q2eOUZtP%2BhwvQ4daM2Jd0wxBkWSuNYVfRIsZZMJyaPAtxnWP6whLNUi1DE%2F3zm%2BNX947TAAwJ%2BwisR031Am8nJDsHNv%2F22dtzK3XRJNCF9j2zhdriYDs5lIfV2R1CLKN6mlBKZ8%2Br8nROK5oXd1ji%2FW%2BdsY%2BsxSoaMyR221oMQYwg%2Flxw8nUX1ZQqyBd1Qtipr7L9QKPJYnwEnyVZqw3qG6nVI%3D';
$q_urldecode = urldecode($q);
$miui_key = 'miuiotavalided11';
$miui_iv = '0102030405060708';

$device_data = openssl_decrypt(base64_decode($q_urldecode), AES_128_CBC, $miui_key, $options=OPENSSL_RAW_DATA, $miui_iv);

print_r ("device_data = $device_data\n\n");
?>

Result
==============================================
device_data = {
"b" : "F",
"c" : "7.1.2",
"d" : "vince_global",
"f" : "1",
"id" : "",
"isR" : 0,
"l" : "fr-FR",
"n" : "",
"r" : "FR",
"sid" : "2",
"sn" : "0xc67d1d89",
"v" : "V9.5.11.0.NEGMIFA"
}
Great work thank you very mutch
But It's not what I expected :/

---------- Post added at 06:08 PM ---------- Previous post was at 06:07 PM ----------
Anyone got it to work with miui x alpha updates ?
unfortunately not for the moment :/

louwii_fr

Member
Jun 13, 2018
<?php
define('AES_128_CBC', 'aes-128-cbc');

$q = 'RMnOGd%2Be0NNG2DwH7PkO1Wsudgf7Ss0CgFCRv5iTrpWO46ODkEI%2FQ9%2B9udjXENxgdcpwRKYiiGJW6Ov39q2eOUZtP%2BhwvQ4daM2Jd0wxBkWSuNYVfRIsZZMJyaPAtxnWP6whLNUi1DE%2F3zm%2BNX947TAAwJ%2BwisR031Am8nJDsHNv%2F22dtzK3XRJNCF9j2zhdriYDs5lIfV2R1CLKN6mlBKZ8%2Br8nROK5oXd1ji%2FW%2BdsY%2BsxSoaMyR221oMQYwg%2Flxw8nUX1ZQqyBd1Qtipr7L9QKPJYnwEnyVZqw3qG6nVI%3D';
$q_urldecode = urldecode($q);
$miui_key = 'miuiotavalided11';
$miui_iv = '0102030405060708';

$device_data = openssl_decrypt(base64_decode($q_urldecode), AES_128_CBC, $miui_key, $options=OPENSSL_RAW_DATA, $miui_iv);

print_r ("device_data = $device_data\n\n");
?>

Result
==============================================
device_data = {
"b" : "F",
"c" : "7.1.2",
"d" : "vince_global",
"f" : "1",
"id" : "",
"isR" : 0,
"l" : "fr-FR",
"n" : "",
"r" : "FR",
"sid" : "2",
"sn" : "0xc67d1d89",
"v" : "V9.5.11.0.NEGMIFA"
}
How were you able to find that out?

geminids14

Member
Jan 16, 2018 Bangkok
I don't know why the pythod code is not working in my environment (can't decrypt the result correctly), so I write the code using php to do this.
Code:
<?php

$cipher = 'rijndael-128';
$mode = 'cbc';
$miui_key = 'miuiotavalided11';
$miui_iv = '0102030405060708';

function miui_decrypt($s)
{
    global $cipher, $mode, $miui_key, $miui_iv;

    $td = mcrypt_module_open($cipher, '', $mode, '');
    mcrypt_generic_init($td, $miui_key, $miui_iv);
    $decrypted = mdecrypt_generic($td, base64_decode($s));
    mcrypt_generic_deinit($td);
    mcrypt_module_close($td);
    $pos = strrpos($decrypted, '}');
    if ($pos !== false)
        return substr($decrypted, 0, $pos + 1);
    return $decrypted;
}

function miui_encrypt($s)
{
    global $cipher, $mode, $miui_key, $miui_iv;

    $td = mcrypt_module_open($cipher, '', $mode, '');
    mcrypt_generic_init($td, $miui_key, $miui_iv);
    $bs = mcrypt_get_block_size($cipher, $mode);
    $n = $bs - (strlen($s) % $bs);
    while ($bs - (strlen($s) % $bs) != $bs)
        $s .= chr($n);
    $encrypted = base64_encode(mcrypt_generic($td, $s));
    mcrypt_generic_deinit($td);
    mcrypt_module_close($td);
    return $encrypted;
}

$checkurl = 'http://update.miui.com/updates/miotaV3.php';

$device_data = array(
    "a" => "0", # Don't know what this is.
    "c" => "7.0", # Same as 'c' above, it's the Android version.
    "b" => "F", # Same as above, 'X' for weekly build.
    "d" => "mido_global", # The device name, same as above, chiron for Chinese, chiron_global for global.
    "g" => "00000000000000000000000000000000", # This seems to be the android_id of the device. Maybe encoded somehow.
    "cts" => "0", # I don't know what this is.
    "i" => "0000000000000000000000000000000000000000000000000000000000000000", # This seems to be the imei of the device, obviously encoded somehow.
    "isR" => "0", # I don't know what this is.
    "f" => "1", # I don't know what this is.
    "l" => "en_US", # The locale.
    "n" => "",  # I don't know what this parameter is
    "sys" => "0", # I don't know what this is.
    "p" => "msm8953", # The chipset
    "unlock" => "1",  # 1 means bootloader is unlocked. 0 means locked.
    "r" => "CN", # I don't know what this is, maybe region of device?
    "sn" => "0x00000000", # Probably the serial number of the device, maybe encoded somehow.
    "v" => "MIUI-V9.0.5.0.NCFMIEI", # The version of MIUI installed.
    "bv" => "9", # I don't know what this is.
    "id" => "", # I don't' know what this is.
);

$js = json_encode($device_data);

$postdata = "q=".urlencode(miui_encrypt($js))."&t=&s=1";

$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $checkurl);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($curl, CURLOPT_HEADER, 0);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $postdata);
$data = curl_exec($curl);
if ($data === false) {
    echo "*** curl_exec() failed: ".curl_errno($curl)." => ".curl_error($curl)."\n";
    curl_close($curl);
    exit;
}

$r = miui_decrypt($data);
$result = json_decode($r);
print_r($result);

exit;
the above code is for Redmi Note 4X, get the current stable nightly version V9.0.5.0.NCFMIEI => miui_HMNote4XGlobal_V9.0.5.0.NCFMIEI_d6176de291_7.0.zip
How were you able to find that out?
Just implement php above quot and the result is inconsiderable:crying:

Reactions: louwii_fr

Mr.frich

New member
Jun 27, 2019
<?php
define('AES_128_CBC', 'aes-128-cbc');

$q = 'RMnOGd%2Be0NNG2DwH7PkO1Wsudgf7Ss0CgFCRv5iTrpWO46ODkEI%2FQ9%2B9udjXENxgdcpwRKYiiGJW6Ov39q2eOUZtP%2BhwvQ4daM2Jd0wxBkWSuNYVfRIsZZMJyaPAtxnWP6whLNUi1DE%2F3zm%2BNX947TAAwJ%2BwisR031Am8nJDsHNv%2F22dtzK3XRJNCF9j2zhdriYDs5lIfV2R1CLKN6mlBKZ8%2Br8nROK5oXd1ji%2FW%2BdsY%2BsxSoaMyR221oMQYwg%2Flxw8nUX1ZQqyBd1Qtipr7L9QKPJYnwEnyVZqw3qG6nVI%3D';
$q_urldecode = urldecode($q);
$miui_key = 'miuiotavalided11';
$miui_iv = '0102030405060708';

$device_data = openssl_decrypt(base64_decode($q_urldecode), AES_128_CBC, $miui_key, $options=OPENSSL_RAW_DATA, $miui_iv);

print_r ("device_data = $device_data\n\n");
?>

Result
==============================================
device_data = {
"b" : "F",
"c" : "7.1.2",
"d" : "vince_global",
"f" : "1",
"id" : "",
"isR" : 0,
"l" : "fr-FR",
"n" : "",
"r" : "FR",
"sid" : "2",
"sn" : "0xc67d1d89",
"v" : "V9.5.11.0.NEGMIFA"
}
I believed this key is out of date now.

CoinsClassic

Member
Nov 17, 2017
I believed this key is out of date now.

Still works like a charm for renoir

Zibri

Senior Member
Dec 10, 2010

Top Liked Posts

  • This is something I've been looking into in order to find newer, older, and unreleased updates for the Mi Mix 2.
    Ideally, I'd like to figure out a way to get Xiaomi's nightly builds, which go out to only beta testers. I think I'm close, but any help I can get would be awesome.

    I currently have two methods. One of them is rather difficult, the other is rather easy. Let's start with the easy one.

    Method 1: Example 1
    http://update.miui.com/updates/mi-updateV6.php?v=MIUI-7.9.21&c=7.1&d=chiron_global&b=X
    This is a URL which asks for an update to the unreleased MIUI 9 7.9.21 global edition.


    If you visit this URL, you get the following response:
    Code:
    {"UserLevel":9,"LatestVersion":{"type":"rom","device":"chiron_global","name":"XM-MIMIX2-GLOBAL 7.9.21","description":"MIUI\u5347\u7ea7","descriptionUrl":"http:\/\/update.miui.com\/updates\/updateinfo\/7.9.21\/chiron_global_0_7.9.21_4494ccfcc506caca9904efb74b489e0a.html","md5":"7f94ca393fae77c6171e6c7a551bea2e","filename":"miui_MIMIX2Global_7.9.21_7f94ca393f_7.1.zip","filesize":"1.6G","codebase":"7.1","version":"7.9.21","branch":"X"},"UpdateList":[{"type":"rom","device":"chiron_global","name":"XM-MIMIX2-GLOBAL 7.9.21","description":"","descriptionUrl":"http:\/\/update.miui.com\/updates\/updateinfo\/7.9.21\/chiron_global_0_7.9.21_4494ccfcc506caca9904efb74b489e0a.html","md5":"7f94ca393fae77c6171e6c7a551bea2e","filename":"miui_MIMIX2Global_7.9.21_7f94ca393f_7.1.zip","filesize":"1.6G","codebase":"7.1","version":"7.9.21","branch":"X"}],"IncrementalUpdateList":[],"MirrorList":["http:\/\/bigota.d.miui.com"],"Signup":{"version":"","total":"","rank":""},"AuthResult":0,"ForceUpdate":0
    We can piece together looking at this that the update file can be downloaded at:
    http://bigota.d.miui.com/7.9.21/miui_MIMIX2Global_7.9.21_7f94ca393f_7.1.zip

    Method 1 Example 2
    It was announced today that there was a new Chinese stable release pushed only to some phones called 8.5.7.0.NDECNEF. We can modify the parameters in the URL to get this:

    http://update.miui.com/updates/mi-updateV6.php?v=MIUI-V8.5.7.0.NDECNEF&c=7.1&d=chiron&b=S

    This returns the following:
    Code:
    {"UserLevel":9,"LatestVersion":[],"UpdateList":[{"type":"rom","device":"chiron","name":"XM-MIMIX2 V8.5.7.0.NDECNEF","description":"","descriptionUrl":"http:\/\/update.miui.com\/updates\/updateinfo\/V8.5.7.0.NDECNEF\/chiron_0_V8.5.7.0.NDECNEF_a9374e7e6aa4f38a22fd58aae29337ce.html","md5":"487f34ee14e84d0eb9ed280a059bcc65","filename":"miui_MIMIX2_V8.5.7.0.NDECNEF_487f34ee14_7.1.zip","filesize":"1.4G","codebase":"7.1","version":"V8.5.7.0.NDECNEF","branch":"F"}],"IncrementalUpdateList":[],"MirrorList":["http:\/\/bigota.d.miui.com"],"Signup":{"version":"","total":"","rank":""},"AuthResult":0,"ForceUpdate":0}
    And that lets us know that the update can be found at:
    http://bigota.d.miui.com/V8.5.7.0.NDECNEF/miui_MIMIX2_V8.5.7.0.NDECNEF_487f34ee14_7.1.zip

    So now that we see that we have a way to query for downloads, let's look into some of the parameters.

    At a minimum we need the following:

    v=MIUI-V8.5.7.0.NDECNEF - This is the version with which you are querying.
    c=7.1 - This is the build of Andoid. It's Android 7.1 so we put 7.1
    d=chiron - This is the device. For Chinese Mix 2 firmwares it's chiron. For global it's chiron_global

    You might also notice this:
    b=S - S means stable. X means weekly. Actually, there is a whole list as follows, but not sure how accurate it is:
    Code:
    «S» — monthly build
    «X» — weekly build
    «D» — daily build
    «E» — emegency build
    «F» — stable build
    «A» — experimental build
    «I» — internal build
    «T» — top secret build
    «U» — unstable build
    On top of this, there are more possible parameters. I will get around to these when talking about Method 2.

    Right now, I can't access anything but weekly and stable builds, so there are not really any undiscovered/unannounced/internal builds that I've been able to find. But I think we are on the right track to being able to find them. I'm hoping that other people can continue looking using this information, and we'll see if we can find anything. Stay tuned while I update this post with Method 2, which is much more complex and much more likely to yield results.

    If you want to keep my stomach full while I keep this research going, give the Donate button a click!
    Apparently Xiaomi has disable method 1.
    Method 2 will still work (and probably can't be disabled without a lot of trouble from Xiaomi).
    I was able to find the first MIUI 9 Stable (non-developer) global build for Mix 2.
    http://bigota.d.miui.com/V9.1.1.0.NDEMIEI/miui_MIMIX2Global_V9.1.1.0.NDEMIEI_232bee13eb_7.1.zip

    Caveat is, I think it's actually older than the most recent developer build.
    I don't know why the pythod code is not working in my environment (can't decrypt the result correctly), so I write the code using php to do this.
    Code:
    <?php
    
    $cipher = 'rijndael-128';
    $mode = 'cbc';
    $miui_key = 'miuiotavalided11';
    $miui_iv = '0102030405060708';
    
    function miui_decrypt($s)
    {
        global $cipher, $mode, $miui_key, $miui_iv;
    
        $td = mcrypt_module_open($cipher, '', $mode, '');
        mcrypt_generic_init($td, $miui_key, $miui_iv);
        $decrypted = mdecrypt_generic($td, base64_decode($s));
        mcrypt_generic_deinit($td);
        mcrypt_module_close($td);
        $pos = strrpos($decrypted, '}');
        if ($pos !== false)
            return substr($decrypted, 0, $pos + 1);
        return $decrypted;
    }
    
    function miui_encrypt($s)
    {
        global $cipher, $mode, $miui_key, $miui_iv;
    
        $td = mcrypt_module_open($cipher, '', $mode, '');
        mcrypt_generic_init($td, $miui_key, $miui_iv);
        $bs = mcrypt_get_block_size($cipher, $mode);
        $n = $bs - (strlen($s) % $bs);
        while ($bs - (strlen($s) % $bs) != $bs)
            $s .= chr($n);
        $encrypted = base64_encode(mcrypt_generic($td, $s));
        mcrypt_generic_deinit($td);
        mcrypt_module_close($td);
        return $encrypted;
    }
    
    $checkurl = 'http://update.miui.com/updates/miotaV3.php';
    
    $device_data = array(
        "a" => "0", # Don't know what this is.
        "c" => "7.0", # Same as 'c' above, it's the Android version.
        "b" => "F", # Same as above, 'X' for weekly build.
        "d" => "mido_global", # The device name, same as above, chiron for Chinese, chiron_global for global.
        "g" => "00000000000000000000000000000000", # This seems to be the android_id of the device. Maybe encoded somehow.
        "cts" => "0", # I don't know what this is.
        "i" => "0000000000000000000000000000000000000000000000000000000000000000", # This seems to be the imei of the device, obviously encoded somehow.
        "isR" => "0", # I don't know what this is.
        "f" => "1", # I don't know what this is.
        "l" => "en_US", # The locale.
        "n" => "",  # I don't know what this parameter is
        "sys" => "0", # I don't know what this is.
        "p" => "msm8953", # The chipset
        "unlock" => "1",  # 1 means bootloader is unlocked. 0 means locked.
        "r" => "CN", # I don't know what this is, maybe region of device?
        "sn" => "0x00000000", # Probably the serial number of the device, maybe encoded somehow.
        "v" => "MIUI-V9.0.5.0.NCFMIEI", # The version of MIUI installed.
        "bv" => "9", # I don't know what this is.
        "id" => "", # I don't' know what this is.
    );
    
    $js = json_encode($device_data);
    
    $postdata = "q=".urlencode(miui_encrypt($js))."&t=&s=1";
    
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $checkurl);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
    curl_setopt($curl, CURLOPT_HEADER, 0);
    curl_setopt($curl, CURLOPT_POST, 1);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $postdata);
    $data = curl_exec($curl);
    if ($data === false) {
        echo "*** curl_exec() failed: ".curl_errno($curl)." => ".curl_error($curl)."\n";
        curl_close($curl);
        exit;
    }
    
    $r = miui_decrypt($data);
    $result = json_decode($r);
    print_r($result);
    
    exit;
    the above code is for Redmi Note 4X, get the current stable nightly version V9.0.5.0.NCFMIEI => miui_HMNote4XGlobal_V9.0.5.0.NCFMIEI_d6176de291_7.0.zip

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK