Skip to content

Instantly share code, notes, and snippets.

@matejsemancik
Last active October 25, 2025 12:15
Show Gist options
  • Select an option

  • Save matejsemancik/aa8a98fa580d61d7815403e1e01baee3 to your computer and use it in GitHub Desktop.

Select an option

Save matejsemancik/aa8a98fa580d61d7815403e1e01baee3 to your computer and use it in GitHub Desktop.
Mi Fitness app hacking to flash Global firmware for Xiaomi Smart Band 8
Java.perform(function () {
const versionName = 'firmware.bin';
const changelog = 'Force upgrade to global firmware.';
const firmwareUrl = 'https://files.catbox.moe/...';
const md5 = 'md5HashOfFirmwareFile';
let CheckUpdateUtil = Java.use("com.mi.fitness.checkupdate.util.CheckUpdateUtil");
CheckUpdateUtil["compareFirmwareVersion2"].implementation = function (latestVersion, currentVersion) {
console.log(`CheckUpdateUtil.compareFirmwareVersion2 is called: latestVersion=${latestVersion}, currentVersion=${currentVersion}`);
return 1;
};
let LatestVersion = Java.use("com.mi.fitness.checkupdate.model.LatestVersion");
LatestVersion["getVersion"].implementation = function () {
console.log(`LatestVersion.getVersion is called`);
return versionName;
};
LatestVersion["getChangeLog"].implementation = function () {
console.log(`LatestVersion.getChangeLog is called`);
return changelog;
};
LatestVersion["getUrl"].implementation = function () {
console.log(`LatestVersion.getUrl is called`);
return firmwareUrl;
};
LatestVersion["getMD5"].implementation = function () {
console.log(`LatestVersion.getMD5 is called`);
return md5;
};
LatestVersion["getMd5"].implementation = function () {
console.log(`LatestVersion.getMd5 is called`);
return md5;
};
LatestVersion["getFullPackageMD5"].implementation = function () {
console.log(`LatestVersion.getMd5 is called`);
return md5;
};
let AnonymousClass2 = Java.use("com.mi.fitness.checkupdate.ui.bluetooth.BluetoothUpgradeViewModel$downLoadFirmWareAndUpdate$1$1$2");
AnonymousClass2["invoke"].overload('java.lang.String').implementation = function (it) {
console.log(`AnonymousClass2.invoke2 is called: it=${it}`);
this["invoke"](it);
};
})

Xiaomi Smart Band Global Firmware OTA

(even if you are on latest firmware version)

This document outlines the steps I took to convert my Xiaomi Smart Band 8 from Chinese firmware to Global firmware by hooking into the Mi Fitness mobile app, making it think there is an FW update available and forcing it to download a custom firmware binary to be flashed onto the wearable device using OTA update.

This method builds upon an existing Reddit post Global firmware for chinese model (Flashing guide) , however, it does not require a rooted Android device & allows you to perform OTA even if the wearable device is on the latest firmware version.

I did this out of curiosity, because my dumbass brain decided to update the firmware on my CN version of the Xiaomi Smart Band to the latest version a day before I found out about the method linked in the Reddit post / video. I did not want to wait for the next firmware update by Xiaomi.

The method described here was tested with Xiaomi Smart Band 8, however there is a chance it could be applied to other types of Xiaomi wearables compatible with the Mi Fitness app, considering you are able to source a valid firmware binary to be flashed onto the device.

Proceed at your own risk. You can always brick your device if you don't know what you're doing.

Method description

There were two possible methods I considered:

  • To use a proxy, such as Charles to sniff on HTTP communication between the mobile app and backend. When the app fetches latest firmware info from the backend, then we theoretically could modify the response to trick the app into thinking there is a new FW available and throw in a URL with a custom firmware binary.
  • To repack the existing APK using objection and hook custom code using Frida during runtime. By doing this, we can modify a few key method calls during runtime to allow us to do an OTA update with a custom firmware binary.

I decompiled and analyzed the Mi Fitness APK using jadx. Since the mobile app uses certificate pinning (preventing us from communicating over a custom proxy), I ended up going the second route without the hassle of repackaging the app and getting rid of certificate pinning which would come with its own caveats.

By inspecting the decompiled APK, I identified several key classes and methods which contribute to the firmware update process:

public final class CheckUpdateUtil {
    public final int compareFirmwareVersion2(@Nullable String latestVersion, @Nullable String currentVersion);
}
  • Important: This allows us to trigger the update. If this method returns a positive integer, the Firmware update screen evaluates that there is a firmware update available.
public final class LatestVersion implements Serializable {
    public final String getVersion();
    public final String getChangeLog();
    public final String getUrl();
    public final String getMD5();
}
  • LatestVersion is a network model which describes the latest firmware version available for a particular wearable device (fetched from the backend)
  • getVersion() Optional: Returns a version name displayed on the FW update screen.
  • getChangelog() Optional: Returns a changelog displayed on the FW update screen.
  • getUrl() Important: Returns a URL of the firmware binary which will be downloaded when the user starts the firmware update.
  • getMD5() Important: Returns an MD5 hash of the binary. The app verifies this hash against the MD5 hash of the file hosted on the provided URL. If they don't match, the app will refuse to download the binary.

If we are able to modify the behavior of these methods, we will be able to trigger firmware OTA and provide a custom firmware binary no matter what firmware the device is currently running on.

Prerequisites

  • Android SDK tools
    • The easy way is to install Android Studio
    • Build tools must be on user path
    • export PATH=$PATH:$HOME/Library/Android/sdk/platform-tools/
      export PATH=$PATH:$HOME/Library/Android/sdk/build-tools/36.0.0/
      
  • objection
    • pip install objection
  • frida
    • pip install frida-tools
  • Mi Fitness APK
  • mobile-toolkit
    • Optional. I use it for installing APKs.
    • This document will use ainstall and auninstall commands from this toolkit.

Steps

  1. Obtain Xiaomi Smart Band 8 firmware binary from linked Reddit post. If you have another type of device, you have to find a compatible binary.
  2. Obtain MD5 hash of FW binary file md5 firmware.bin and save it for step 13.
  3. Upload FW binary to public hosting which can provide a direct HTTPS link to the file. I used https://catbox.moe/. Save the file URL for step 13.
  4. Enable developer options on your Android device
  5. Download the Mi Fitness APK and patch it using objection objection patchapk --source mihealth.apk
  6. Install the patched apk ainstall mihealth.objection.apk onto your Android device.
  7. Run the app. The patched APK will wait on the splash screen for attachment by frida
  8. Attach frida to the running process "Mi Fitness" frida -U 'Mi Fitness'.
  9. When the app starts, exit frida using the exit command.
  10. Log in using your Xiaomi account.
  11. Pair your wearable device with the app.
  12. When paired, visit the Device > More Settings page.
  13. Download the hook.js file which you can find below and update the firmwareUrl and md5 constants with values for your firmware binary.
  14. Re-attach Frida with custom JS hooks frida -U -l hook.js 'Mi Fitness'.
  15. Click Device > More Settings > Firmware update. The Frida CLI should log calls to modified methods and the app should present you with a firmware update.
  16. Start the firmware update process. If everything was set up correctly, the app will download the firmware binary from the URL you provided in hook.js and the device firmware update should be completed as usual. Do not kill the app during the process, just patiently wait for everything to complete.
  17. When the FW update is complete, unpair the smart band from the app, uninstall the app by running auninstall com.mi.health and install the latest version of the app from Google Play.
  18. Enjoy the global firmware.

Troubleshooting

I recommend monitoring the app process using logcat. Filter out logs or tags containing "download". When you start the firmware update, the app should log the URL of the file to be downloaded and any potential errors if the download fails (such as MD5 mismatch). By monitoring the app process, you can verify everything works correctly.

Happy hacking.

Reference

@HridoyHazard
Copy link

not everyone is genius as you! it's better if you just share the apk!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment