├── patches-R3600 ├── enable-iot-radio.patch └── hostapd_options.patch ├── patches-RA72 ├── enable-iot-radio.patch └── hostapd_options.patch ├── xqflash ├── ubinize.sh ├── repack-squashfs.sh └── README.md /patches-R3600/enable-iot-radio.patch: -------------------------------------------------------------------------------- 1 | patch to stop disabling the IoT interface, thanks to Mel: 2 | https://forum.openwrt.org/t/xiaomi-ax3600-int-wifi/74276/523 3 | 4 | ----- 5 | --- a/lib/wifi/qcawificfg80211.sh 2021-07-08 06:48:54.000000000 +0000 6 | +++ b/lib/wifi/qcawificfg80211.sh 2022-07-10 17:08:27.153316389 +0000 7 | @@ -3039,10 +3039,6 @@ 8 | disable_qrfs 9 | fi 10 | 11 | - if [ $ifname = "wl2" ]; then 12 | - ifconfig $ifname down 13 | - fi 14 | - 15 | #need to check router bind or not 16 | if [ $ifname == "wl13" ] && [ $bindstatus == 0 -o $userswitch == 0 ];then 17 | hostapd_cli -i wl13 -p /var/run/hostapd-wifi1 disable 18 | -------------------------------------------------------------------------------- /patches-RA72/enable-iot-radio.patch: -------------------------------------------------------------------------------- 1 | patch to stop disabling the IoT interface, thanks to Mel: 2 | https://forum.openwrt.org/t/xiaomi-ax3600-int-wifi/74276/523 3 | 4 | ----- 5 | --- a/lib/wifi/qcawificfg80211.sh 2021-03-22 07:59:08.000000000 +0100 6 | +++ b/lib/wifi/qcawificfg80211.sh 2022-12-15 19:52:58.024247590 +0100 7 | @@ -4355,9 +4355,7 @@ 8 | 9 | config_get CSwOpts "$device" CSwOpts 10 | [ -n "$CSwOpts" ] && "$device_if" "$phy" CSwOpts "${CSwOpts}" 11 | - if [ $ifname = "wl2" ]; then 12 | - ifconfig $ifname down 13 | - fi 14 | + 15 | 16 | local netmode=$(uci -q get xiaoqiang.common.NETMODE) 17 | if [ -n "$netmode" ] && [ "$netmode" = "whc_re" ]; then 18 | -------------------------------------------------------------------------------- /patches-R3600/hostapd_options.patch: -------------------------------------------------------------------------------- 1 | --- a/lib/wifi/hostapd.sh 2021-07-08 06:48:54.000000000 +0000 2 | +++ b/lib/wifi/hostapd.sh 2022-07-11 07:56:12.751197169 +0000 3 | @@ -104,6 +104,8 @@ 4 | config_add_string country 5 | config_add_boolean country_ie doth 6 | config_add_int beacon_int 7 | + 8 | + config_add_array hostapd_options 9 | } 10 | 11 | 12 | @@ -137,6 +139,10 @@ 13 | [ -n "$brlist" ] && append base_cfg "basic_rates=$brlist" "$N" 14 | [ -n "$beacon_int" ] && append base_cfg "beacon_int=$beacon_int" "$N" 15 | 16 | + local opts 17 | + json_get_values opts hostapd_options 18 | + for hopt in $opts; do append base_cfg "$hopt" "$N"; done 19 | + 20 | cat > "$config" < "$config" <"; exit 1; } 14 | 15 | [ -f "$IMAGE" ] || { echo "image file not found"; exit 2; } 16 | 17 | img_type=$(identify $IMAGE) 18 | [ "$img_type" = "ubi" ] || { echo "image file needs to be of type UBI, not \"$img_type\""; exit 2; } 19 | 20 | # determine partition 21 | r0_mtd=$(grep '"rootfs"' /proc/mtd | awk -F: '{print substr($1,4)}') 22 | r1_mtd=$(grep '"rootfs_1"' /proc/mtd | awk -F: '{print substr($1,4)}') 23 | os_idx=$(nvram get flag_boot_rootfs) 24 | mtd_cur=$(($r0_mtd+${os_idx:-0})) 25 | mtd_nxt=$(($r0_mtd+$r1_mtd-$mtd_cur)) 26 | 27 | MTD_DEV=/dev/mtd$mtd_nxt 28 | [ -c "$MTD_DEV" ] || { echo "unable to determine MTD partition to flash to: $MTD_DEV"; exit 2; } 29 | 30 | # abort if any command fails 31 | set -e 32 | 33 | echo "flashing $IMAGE onto $MTD_DEV..." 34 | ubiformat $MTD_DEV -f $IMAGE -s 2048 -O 2048 35 | 36 | echo "setting nvram variables..." 37 | nvram set flag_ota_reboot=1 38 | nvram commit 39 | 40 | echo "Done. You may reboot now." 41 | 42 | -------------------------------------------------------------------------------- /ubinize.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # repacks the kernel & rootfs image into a UBI image 4 | # 5 | # 2020.07.20 darell tan 6 | # 7 | 8 | set -e 9 | 10 | KERNEL=$1 11 | ROOTFS=$2 12 | ROOTFS_DATA=$3 13 | OUTPUT=r3600-raw-img.bin 14 | 15 | # check for ubinize 16 | ubinize -V >/dev/null || { echo "need ubinize, from mtd-utils maybe?"; exit 1; } 17 | 18 | [ -f "$KERNEL" ] || { echo "kernel img doesnt exist."; exit 1; } 19 | [ -f "$ROOTFS" ] || { echo "rootfs doesnt exist."; exit 1; } 20 | [ -z "$ROOTFS_DATA" -o "$ROOTFS_DATA" = "--data" ] || { echo "invalid data argument."; exit 1; } 21 | 22 | # verify files 23 | ROOTFS_SIG=`hexdump -n 4 -e '"%_p"' "$ROOTFS"` 24 | [ "$ROOTFS_SIG" = "hsqs" ] || { echo "rootfs is not squashfs."; exit 1; } 25 | 26 | KERNEL_SIG=`hexdump -n 4 -e '1/1 "%02x"' "$KERNEL"` 27 | [ "$KERNEL_SIG" = "d00dfeed" ] || { echo "invalid kernel img"; exit 1; } 28 | 29 | UBICFG=`mktemp /tmp/r3600-ubicfg.XXXXX` 30 | trap "rm -f $UBICFG" EXIT 31 | 32 | cat < $UBICFG 33 | [kernel] 34 | mode=ubi 35 | image=$KERNEL 36 | vol_id=0 37 | vol_type=dynamic 38 | vol_name=kernel 39 | 40 | [rootfs] 41 | mode=ubi 42 | image=$ROOTFS 43 | vol_id=1 44 | vol_type=dynamic 45 | vol_name=ubi_rootfs 46 | CFGEND 47 | 48 | # generate an empty rootfs_data volume if requested 49 | [ -n "$ROOTFS_DATA" ] && cat <> $UBICFG 50 | [data] 51 | mode=ubi 52 | vol_size=1 53 | vol_id=2 54 | vol_type=dynamic 55 | vol_name=rootfs_data 56 | vol_flags=autoresize 57 | CFGEND2 58 | 59 | ubinize -m 2048 -p 128KiB -o "$OUTPUT" "$UBICFG" 60 | 61 | echo "done." 62 | 63 | -------------------------------------------------------------------------------- /repack-squashfs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # unpack, modify and re-pack the Xiaomi R3600 firmware 4 | # removes checks for release channel before starting dropbear 5 | # 6 | # 2020.07.20 darell tan 7 | # 8 | 9 | set -e 10 | 11 | IMG=$1 12 | ROOTPW='$1$qtLLI4cm$c0v3yxzYPI46s28rbAYG//' # "password" 13 | 14 | [ -e "$IMG" ] || { echo "rootfs img not found $IMG"; exit 1; } 15 | 16 | # verify programs exist 17 | command -v unsquashfs &>/dev/null || { echo "install unsquashfs"; exit 1; } 18 | mksquashfs -version >/dev/null || { echo "install mksquashfs"; exit 1; } 19 | 20 | FSDIR=`mktemp -d /tmp/resquash-rootfs.XXXXX` 21 | trap "rm -rf $FSDIR" EXIT 22 | 23 | # test mknod privileges 24 | mknod "$FSDIR/foo" c 0 0 2>/dev/null || { echo "need to be run with fakeroot"; exit 1; } 25 | rm -f "$FSDIR/foo" 26 | 27 | >&2 echo "unpacking squashfs..." 28 | unsquashfs -f -d "$FSDIR" "$IMG" 29 | 30 | >&2 echo "patching squashfs..." 31 | 32 | # modify dropbear init 33 | sed -i 's/channel=.*/channel=release2/' "$FSDIR/etc/init.d/dropbear" 34 | sed -i 's/flg_ssh=.*/flg_ssh=1/' "$FSDIR/etc/init.d/dropbear" 35 | 36 | # mark web footer so that users can confirm the right version has been flashed 37 | sed -i 's/romVersion%>/& xqrepack/;' "$FSDIR/usr/lib/lua/luci/view/web/inc/footer.htm" 38 | 39 | # stop resetting root password 40 | sed -i '/set_user(/a return 0' "$FSDIR/etc/init.d/system" 41 | sed -i 's/flg_init_pwd=.*/flg_init_pwd=0/' "$FSDIR/etc/init.d/boot_check" 42 | 43 | # make sure our backdoors are always enabled by default 44 | sed -i '/ssh_en/d;' "$FSDIR/usr/share/xiaoqiang/xiaoqiang-reserved.txt" 45 | sed -i '/ssh_en=/d; /uart_en=/d; /boot_wait=/d;' "$FSDIR/usr/share/xiaoqiang/xiaoqiang-defaults.txt" 46 | cat <> "$FSDIR/usr/share/xiaoqiang/xiaoqiang-defaults.txt" 47 | uart_en=1 48 | ssh_en=1 49 | boot_wait=on 50 | XQDEF 51 | 52 | # always reset our access nvram variables 53 | grep -q -w enable_dev_access "$FSDIR/lib/preinit/31_restore_nvram" || \ 54 | cat <> "$FSDIR/lib/preinit/31_restore_nvram" 55 | enable_dev_access() { 56 | nvram set uart_en=1 57 | nvram set ssh_en=1 58 | nvram set boot_wait=on 59 | nvram commit 60 | } 61 | 62 | boot_hook_add preinit_main enable_dev_access 63 | NVRAM 64 | 65 | # modify root password 66 | sed -i "s@root:[^:]*@root:${ROOTPW}@" "$FSDIR/etc/shadow" 67 | 68 | # stop phone-home in web UI 69 | cat <> "$FSDIR/www/js/miwifi-monitor.js" 70 | (function(){ if (typeof window.MIWIFI_MONITOR !== "undefined") window.MIWIFI_MONITOR.log = function(a,b) {}; })(); 71 | JS 72 | 73 | # add xqflash tool into firmware for easy upgrades 74 | cp xqflash "$FSDIR/sbin" 75 | chmod 0755 "$FSDIR/sbin/xqflash" 76 | chown root:root "$FSDIR/sbin/xqflash" 77 | 78 | # dont start crap services 79 | for SVC in stat_points statisticsservice \ 80 | datacenter \ 81 | smartcontroller \ 82 | plugincenter plugin_start_script.sh cp_preinstall_plugins.sh; do 83 | rm -f $FSDIR/etc/rc.d/[SK]*$SVC 84 | done 85 | 86 | # prevent stats phone home & auto-update 87 | for f in StatPoints mtd_crash_log logupload.lua otapredownload wanip_check.sh; do > $FSDIR/usr/sbin/$f; done 88 | 89 | rm -f $FSDIR/etc/hotplug.d/iface/*wanip_check 90 | 91 | for f in wan_check messagingagent.sh; do 92 | sed -i '/start_service(/a return 0' $FSDIR/etc/init.d/$f 93 | done 94 | 95 | # cron jobs are mostly non-OpenWRT stuff 96 | for f in $FSDIR/etc/crontabs/*; do 97 | sed -i 's/^/#/' $f 98 | done 99 | 100 | # as a last-ditch effort, change the *.miwifi.com hostnames to localhost 101 | sed -i 's@\w\+.miwifi.com@localhost@g' $FSDIR/etc/config/miwifi 102 | 103 | # get hardware name 104 | HWNAME=`sed -n "/option\s\+HARDWARE/ s/.*'\(.*\)'/\1/g p" $FSDIR/usr/share/xiaoqiang/xiaoqiang_version` 105 | [ -n "$HWNAME" ] && echo "detected hw $HWNAME" || echo "[WARN] cant find hw name in firmware" 106 | 107 | # apply hw-specific patches 108 | PATCHES= 109 | [ -n "$HWNAME" ] && [ -d "patches-$HWNAME" ] && PATCHES=patches-$HWNAME/*.patch 110 | 111 | # generic patches 112 | [ -d patches ] && PATCHES="$PATCHES patches/*.patch" 113 | 114 | # apply patches 115 | for p in $PATCHES; do 116 | >&2 echo "applying patch $p..." 117 | patch -d "$FSDIR" -s -p1 < $p 118 | 119 | [ $? -ne 0 ] && { echo "patch $p didnt apply cleanly - aborting."; exit 1; } 120 | done 121 | 122 | >&2 echo "repacking squashfs..." 123 | rm -f "$IMG.new" 124 | mksquashfs "$FSDIR" "$IMG.new" -comp xz -b 256K -no-xattrs 125 | 126 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | xqrepack 2 | ========= 3 | 4 | These scripts allow you to modify the *Xiaomi AX3600 (R3600)* and *Xiaomi AX1800 (RM1800)* firmware image to make sure SSH and UART access is always enabled. 5 | 6 | The default root password is `password`. Please remember to login to the router and change that after the upgrade. Your router settings like IP address and SSIDs are stored in the nvram and should stay the same. 7 | 8 | ⚠ The script also tries its best to remove or disable phone-home binaries, and also the smart controller (AIoT) parts, leaving you with a (close to) OpenWRT router that you can configure via UCI or `/etc/config`. 9 | Between preserving stock functionality and privacy concerns, I would err on the side of caution and rather that some functionality be sacrificed for a router that I have more confidence to connect to the Internet. 10 | 11 | Note that in order to get SSH access to the router initially, you need to [downgrade the AX3600 to version 1.0.17 and exploit it first](https://forum.openwrt.org/t/adding-openwrt-support-for-ax3600/55049/123) / [downgrade the AX1800 to version 1.0.378 (or below) and exploit it first](https://forum.openwrt.org/t/adding-openwrt-support-for-ax3600/55049/123). 12 | Once you have SSH, you can use this repacking method to maintain SSH access for newer versions. 13 | 14 | Requirements 15 | ============== 16 | 17 | You will need to install the following tools: 18 | 19 | - [ubi_reader](https://github.com/jrspruitt/ubi_reader) 20 | - ubinize 21 | - unsquashfs / mksquashfs 22 | - fakeroot 23 | 24 | Usage 25 | ======= 26 | 27 | 1. Download the firmware from miwifi.com. 28 | It should be something like `miwifi_r3600_firmware_xxxx_y.y.yyy.bin` or `miwifi_rm1800_firmware_xxxx_y.y.yyy.bin`. 29 | 30 | 2. Use the `ubireader_extract_images` utility from ubi_reader to unpack the UBI image from the firmware. 31 | Technically there's junk at the front, but the script will ignore it: 32 | 33 | ubireader_extract_images -w miwifi_r3600_firmware_xxx_yyy.bin 34 | 35 | The unpacked files will be in the `ubifs-root/miwifi_r3600_firmware...` directory. 36 | 37 | 3. Patch the rootfs using the `repack-squashfs.sh` script: 38 | 39 | fakeroot -- ./repack-squashfs.sh ubifs-root/miwifi_r3600_firmware.../img-264..._vol-ubi_rootfs.ubifs 40 | 41 | The script will create a new squashfs image with the `.new` suffix. 42 | You will need `fakeroot` in order to create files and devices as `root`. You _could_ also run this script as `root`, but please don't. 43 | 44 | 4. Recombine the kernel and patched rootfs with `ubinize.sh`: 45 | 46 | for R3600: 47 | 48 | ./ubinize.sh ubifs-root/miwifi_r3600_firmware.../...kernel.ubifs \ 49 | ubifs-root/miwifi_r3600_firmware.../...ubi_rootfs.ubifs.new 50 | 51 | for RM1800: 52 | 53 | ./ubinize.sh ubifs-root/miwifi_rm1800_firmware.../...kernel.ubifs \ 54 | ubifs-root/miwifi_rm1800_firmware.../...ubi_rootfs.ubifs.new \ 55 | --data 56 | 57 | Note the use of the `.ubifs.new` file. 58 | The combined output file will be `r3600-raw-img.bin`, even if you are using a rm1800 image! 59 | 60 | 5. Flash this file directly into the router using SSH. 61 | You cannot use the web UI because this is a raw image, and more importantly has no signature. 62 | 63 | If you are using a recently xqrepack'ed firmware, you can use the `xqflash` utility on the router to flash an update image: 64 | 65 | xqflash /tmp/r3600-raw-img.bin 66 | 67 | After it completes successfully, you should be able to `reboot`. 68 | 69 | If the `xqflash` utility is not available, you can manually flash the update image described in the following section. 70 | 71 | 72 | Manual Flashing 73 | ================ 74 | 75 | The R3600 firmware uses an A/B partition system, called `rootfs` and `rootfs_1`. This corresponds to `mtd12` and `mtd13`. Find the partition that is not the one in use and use `ubiformat` to write the raw image onto the partition: 76 | 77 | ubiformat /dev/mtd12 -f /tmp/r3600-raw-img.bin -s 2048 -O 2048 78 | 79 | Set the nvram variable to re-initialize `/etc` (and I think to switch partitions also): 80 | 81 | nvram set flag_ota_reboot=1 82 | nvram commit 83 | reboot 84 | 85 | 86 | A/B Partitions 87 | =============== 88 | 89 | You can check the MTD partitions from `/proc/mtd`: 90 | 91 | ``` 92 | root@XiaoQiang:~# grep rootfs /proc/mtd 93 | mtd12: 023c0000 00020000 "rootfs" 94 | mtd13: 023c0000 00020000 "rootfs_1" 95 | mtd17: 015cc000 0001f000 "ubi_rootfs" 96 | 97 | root@XiaoQiang:~# nvram get flag_boot_rootfs 98 | 1 99 | ``` 100 | 101 | The `flag_boot_rootfs` nvram variable indicates which partition is booted, `0` or `1`. 102 | You should pick the partition that is **not in use**, otherwise `ubiformat` will complain: 103 | 104 | ubiformat: error!: please, first detach mtd13 (/dev/mtd13) from ubi0 105 | 106 | 107 | License 108 | ========= 109 | 110 | **xqrepack** is licensed under **the 3-clause ("modified") BSD License**. 111 | 112 | Copyright (C) 2020-2021 Darell Tan 113 | 114 | Redistribution and use in source and binary forms, with or without 115 | modification, are permitted provided that the following conditions 116 | are met: 117 | 118 | 1. Redistributions of source code must retain the above copyright 119 | notice, this list of conditions and the following disclaimer. 120 | 2. Redistributions in binary form must reproduce the above copyright 121 | notice, this list of conditions and the following disclaimer in the 122 | documentation and/or other materials provided with the distribution. 123 | 3. The name of the author may not be used to endorse or promote products 124 | derived from this software without specific prior written permission. 125 | 126 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR 127 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 128 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 129 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 130 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 131 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 132 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 133 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 134 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 135 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 136 | 137 | --------------------------------------------------------------------------------