pull/116/merge
longzheng268 4 days ago committed by GitHub
commit 6d84f0cb4c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -1,4 +1,4 @@
@echo off
chcp 866 >NUL
chcp 65001 >NUL
SET PYTHONUNBUFFERED=TRUE
start cmd /k python\python.exe menu.py
start cmd /c "cd /d "%~dp0" && python\python.exe menu.py && pause"

3
.gitattributes vendored

@ -0,0 +1,3 @@
name=.gitattributes
# ensure shell scripts use LF
*.sh text eol=lf

1
.gitignore vendored

@ -5,4 +5,5 @@ data/
tmp/
outdir/
config.txt
config.json
full_info.txt

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

@ -1,23 +1,733 @@
[![Download latest](https://img.shields.io/badge/🡇-Download_latest-green)](https://github.com/openwrt-xiaomi/xmir-patcher/archive/refs/heads/main.zip)
[![ViewCount](https://views.whatilearened.today/views/github/openwrt-xiaomi/xmir-patcher.svg)](https://github.com/openwrt-xiaomi/xmir-patcher/archive/refs/heads/main.zip)
[![Hits](https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2Fopenwrt-xiaomi%2Fxmir-patcher&count_bg=%2379C83D&title_bg=%23555555&icon=&icon_color=%23E7E7E7&title=hits&edge_flat=false)](https://github.com/openwrt-xiaomi/xmir-patcher/archive/refs/heads/main.zip)
[![Donations Page](https://github.com/andry81-cache/gh-content-static-cache/raw/master/common/badges/donate/donate.svg)](https://github.com/remittor/donate)
# 小米路由器破解工具 (XMiR-Patcher)
[![Download latest](https://img.shields.io/badge/🡇-下载最新版本-green)](https://github.com/longzheng268/Xiaomi-Router-patcher/archive/refs/heads/main.zip)
![ViewCount](https://views.whatilearened.today/views/github/longzheng268/Xiaomi-Router-patcher.svg)
[![官方老固件下载](https://img.shields.io/badge/📦-官方老固件下载-blue)](https://mirom.ezbox.idv.tw/en/miwifi)
一个功能强大的小米路由器固件破解工具支持多种小米路由器型号的漏洞利用、SSH启用、语言包安装、固件刷写等功能。
## 📋 目录
- [支持的设备](#支持的设备)
- [功能特性](#功能特性)
- [安装教程](#安装教程)
- [使用指南](#使用指南)
- [详细功能说明](#详细功能说明)
- [故障排除](#故障排除)
- [安全提示](#安全提示)
- [开发说明](#开发说明)
- [贡献指南](#贡献指南)
## 🔧 支持的设备
### 完全支持的型号
本工具支持以下小米路由器型号按型号ID排序
#### 第一代系列
- **R1CM** (miwifi-mini) - 小米路由器 Mini
- **R1CL** (miwifi-nano) - 小米路由器 Nano
- **R2D** - 小米路由器 2
- **R2CM** - 小米路由器 2
#### 第三代系列
- **R3** - 小米路由器 3
- **R3D** (r3d) - 小米路由器 3D
- **R3L** (miwifi-3c) - 小米路由器 3C
- **R3P** (mi-router-3-pro) - 小米路由器 3 Pro
- **R3A** - 小米路由器 3A
- **R3G** (mi-router-3g) - 小米路由器 3G
- **R3GV2** (mi-router-3g-v2) - 小米路由器 3G V2
#### 第四代系列
- **R4** (mi-router-4) - 小米路由器 4
- **R4C** (mi-router-4q) - 小米路由器 4Q
- **R4A** (mi-router-4a-gigabit) - 小米路由器 4A 千兆版
- **R4CM** (mi-router-4c) - 小米路由器 4C
- **R4AC** (mi-router-4a-100m) - 小米路由器 4A 百兆版
#### AC系列
- **R2100** (mi-router-ac2100) - 小米路由器 AC2100
- **RM2100** (redmi-router-ac2100) - 红米路由器 AC2100
- **R2200** - 小米路由器 AC2200
- **R2350** (aiot-ac2350) - 小米 AIoT 路由器 AC2350
- **R2600** - 小米路由器 AC2600
#### AX系列 (Wi-Fi 6)
- **R3600** (ax3600) - 小米路由器 AX3600
- **R1350** - 小米路由器 AX1350
- **RA67** - 红米路由器 AX1800C
- **RA69** (ax6) - 小米路由器 AX6
- **RA70** (ax9000) - 小米路由器 AX9000
- **RA71** - 红米路由器 AX1800
- **RA72** - 小米路由器 AX6000
- **RA75** (mi-ra75) - 小米路由器 RA75
- **RA80/RA82** - 小米路由器 AX3000
#### 企业级系列
- **CR6006** (mi-router-cr6606) - 小米企业路由器 CR6606
- **CR6008** (mi-router-cr6608) - 小米企业路由器 CR6608
- **CR6009** (mi-router-cr6609) - 小米企业路由器 CR6609
#### TR系列
- **TR608** - 小米路由器 TR608
- **TR609** - 小米路由器 TR609
#### 其他型号
- **P01** - 小米随身路由器
- **D01** - 小米路由器 HD
- **IR1200G** - 小米路由器 1200G
- **RM1800** - 红米路由器 1800
- **R2100D** - 小米路由器 AC2100D
- **RA50** - 小米路由器 RA50
> **注意**: 不同型号支持的功能可能有差异,建议在操作前仔细阅读相关说明。
## ✨ 功能特性
### 核心功能
- 🔓 **漏洞利用**: 自动检测并利用小米路由器的已知漏洞
- 🔑 **SSH启用**: 永久启用SSH访问方便高级用户管理
- 🌐 **多语言支持**: 安装英文/俄文/中文语言包,支持中文菜单界面
- 💾 **完整备份**: 创建路由器固件的完整备份
- 🔄 **固件刷写**: 支持自定义固件的安装
- ⚡ **Bootloader替换**: 支持安装Breed等第三方Bootloader
### 高级功能
- 📊 **设备信息读取**: 获取详细的硬件和系统信息
- 🔐 **密码修改**: 修改路由器root密码
- 📋 **日志读取**: 读取系统日志和内核信息
- ⚙️ **分区备份**: 创建指定分区的备份
- 🚀 **引导设置**: 设置内核引导地址
- 🔧 **功能解锁**: 解锁隐藏的路由器功能
## 🚀 安装教程
### Windows 用户
1. **下载工具包**
```
下载并解压项目文件到任意目录
```
2. **运行工具**
```
双击运行 run.bat 文件
```
3. **自动环境配置**
- 工具会自动使用内置的 Python 环境
- 无需手动安装 Python 或依赖包
### Linux / macOS 用户
1. **系统要求**
```bash
# 确保已安装 Python 3.8+ 和 OpenSSL
python3 --version # 应显示 3.8 或更高版本
openssl version # 确认 OpenSSL 已安装
```
2. **安装依赖**
```bash
# Ubuntu/Debian
sudo apt update
sudo apt install python3 python3-pip python3-venv openssl
# CentOS/RHEL
sudo yum install python3 python3-pip openssl
# macOS (使用 Homebrew)
brew install python3 openssl
```
3. **下载并运行**
```bash
# 下载项目
git clone https://github.com/longzheng268/Xiaomi-Router-patcher.git
cd Xiaomi-Router-patcher
# 运行工具
chmod +x run.sh
./run.sh
```
### Docker 用户
```bash
# 构建 Docker 镜像
docker build -t xmir-patcher .
# 运行容器
docker run -it --network host xmir-patcher
```
## 📖 使用指南
### 第一步:连接准备
1. **网络连接**
- 确保电脑和小米路由器在同一网络中
- 记录路由器的IP地址通常是 192.168.31.1
- 确保能正常访问路由器管理界面
2. **启动工具**
- Windows: 双击 `run.bat`
- Linux/macOS: 执行 `./run.sh`
### 第二步:基本配置
运行工具后会看到主菜单:
```
==========================================================
Xiaomi MiR Patcher
1 - Set IP-address (current value: 192.168.31.1)
2 - Connect to device (install exploit)
3 - Read full device info
4 - Create full backup
5 - Install EN/RU languages
6 - Install permanent SSH
7 - Install firmware (from directory "firmware")
8 - {{{ Other functions }}}
9 - [[ Reboot device ]]
0 - Exit
Select:
```
### 第三步:执行操作
#### 必要的前置步骤
1. **设置IP地址 (选项1)**
```
选择 1 → 输入路由器IP地址 → 按回车确认
```
2. **连接设备并安装漏洞利用 (选项2)**
```
选择 2 → 工具会自动检测设备型号并安装相应的漏洞利用程序
```
> ⚠️ **重要**: 这是所有后续操作的前提,必须先成功执行此步骤!
#### 常用操作流程
1. **完整备份 (推荐首先执行)**
```
选择 4 → 工具会创建完整的固件备份,保存在 backup 目录中
```
2. **启用SSH访问**
```
选择 6 → 工具会永久启用SSH访问默认用户名/密码: root/root
```
3. **安装语言包**
```
选择 5 → 安装英文/俄文/中文语言包,让路由器界面支持更多语言
```
#### 语言界面设置
首次启动工具时,会显示语言选择菜单:
```
Language / 语言 / Язык
1 - English
2 - 中文 (Chinese)
3 - Русский (Russian)
Select language [1-English, 2-中文, 3-Русский]:
```
选择对应数字即可切换到相应语言的菜单界面。语言设置会保存在 `config.json` 文件中。
**中文界面预览**:
```
==========================================================
小米路由器破解工具
1 - 设置IP地址 (当前值: 192.168.31.1)
2 - 连接设备 (安装漏洞利用)
3 - 读取完整设备信息
4 - 创建完整备份
5 - 安装 英文/俄文/中文 语言包
6 - 安装永久SSH
7 - 安装固件 (从 "firmware" 目录)
8 - {{{ 其他功能 }}}
9 - [[ 重启设备 ]]
0 - 退出
请选择:
```
## 🔍 详细功能说明
### 主菜单功能
#### 1. 设置IP地址
- **用途**: 设置目标路由器的IP地址
- **默认值**: 192.168.31.1
- **使用场景**: 当路由器IP不是默认值时需要修改
#### 2. 连接设备(安装漏洞利用)
- **用途**: 检测设备型号并安装对应的漏洞利用程序
- **支持的漏洞**:
- `c_upload/netspeed` - 适用于较老型号
- `get_icon` - 适用于较新型号
- **执行过程**:
1. 自动检测路由器型号
2. 选择合适的漏洞利用方法
3. 上传并执行漏洞利用代码
4. 启用SSH和Telnet访问
#### 3. 读取完整设备信息
- **获取信息包括**:
- 硬件型号和版本
- 固件版本信息
- 分区表结构
- 内存和存储信息
- 网络配置
- **输出位置**: `outdir/` 目录
#### 4. 创建完整备份
- **备份内容**:
- 所有分区的原始数据
- Bootloader
- 内核镜像
- 根文件系统
- 配置数据
- **备份格式**: 二进制镜像文件
- **存储位置**: `backup/` 目录
#### #### 5. 安装多语言包
**语言包功能详解**
**支持的语言**:
- **英文 (English)**: 完整的英文界面和语言包
- **中文 (Chinese)**: 完整的中文界面和语言包
- **俄文 (Russian)**: 完整的俄文界面和语言包
**功能特点**:
- 🌐 **智能语言选择**: 首次运行自动显示语言选择菜单
- 💾 **持久化配置**: 语言选择保存在 `config.json` 中,下次启动自动应用
- 🔄 **实时切换**: 可通过重新运行程序切换语言
- 📱 **完整本地化**: 包括菜单、提示信息、错误消息等全面本地化
- 🎯 **路由器语言包**: 支持为路由器安装对应的语言包文件
**安装方式**:
1. 上传语言文件到路由器
2. 修改系统配置
3. 重启相关服务
4. **卸载**: 通过扩展菜单选项5可以卸载
**技术实现**:
- 使用 UTF-8 编码支持多语言字符显示
- Windows 批处理文件使用 `chcp 65001` 支持中文显示
- 模块化翻译系统,易于扩展新语言
- 基于 `.po` 格式的标准化语言包管理
#### 6. 安装永久SSH
- **功能**: 启用持久化的SSH访问
- **默认凭据**:
- 用户名: `root`
- 密码: `root`
- **端口**: 22
- **特点**: 重启后仍然有效
#### 7. 安装固件
- **支持格式**:
- 标准的小米固件格式
- OpenWrt固件需兼容
- **固件位置**: 将固件放在 `firmware/` 目录
- **安装过程**: 自动化刷写流程
#### 8. 其他功能(扩展菜单)
进入扩展功能菜单,包含更多高级选项。
#### 9. 重启设备
安全重启路由器设备。
### 扩展菜单功能
# XMiR-Patcher
Firmware patcher for Xiaomi routers
#### 1. 设置IP地址
与主菜单功能1相同。
#### 2. 修改root密码
- **用途**: 修改路由器的root用户密码
- **安全性**: 提高系统安全性
## Usage
#### 3. 读取dmesg和syslog
- **获取内容**:
- 内核日志 (dmesg)
- 系统日志 (syslog)
- **用途**: 故障诊断和系统分析
### Windows
#### 4. 创建指定分区备份
- **灵活性**: 可选择备份特定分区
- **常用分区**:
- `bootloader` - 引导加载器
- `kernel` - 内核
- `rootfs` - 根文件系统
- `overlay` - 配置数据
* Run `run.bat`
#### 5. 卸载英文/俄文语言包
还原到原始的中文界面。
### Linux / Mac OS
#### 6. 设置内核引导地址
- **用途**: 修改内核的加载地址
- **应用场景**: 安装自定义固件时使用
* Install python 3.8+ and openssl
* Run `run.sh`
#### 7. 安装Breed引导加载器
- **Breed特点**:
- 功能强大的第三方Bootloader
- 支持Web界面固件刷写
- 不怕刷坏(变砖保护)
- **支持型号**:
- R3G, R3P, RM2100, RA71: `breed_r3g_eng.bin`
- CR6606, CR6608, CR6609, TR608, TR609: `pb-boot-cr660x.img`
- **安装命令**: `python3 install_bl.py breed`
## Donations
#### 7a. 安装原厂U-Boot引导加载器
- **U-Boot特点**:
- 设备原厂Bootloader
- 设备特定的引导程序
- 用于恢复原厂引导环境
- **支持型号**:
- R3G: `uboot_r3g.bin`
- R3P: `uboot_r3p.bin`
- RM2100: `uboot_rm2100.bin`
- **安装命令**: `python3 install_bl.py uboot`
#### 8. 测试功能
开发和调试用途的测试功能。
#### 9. 重启设备
与主菜单功能9相同。
## 🛠️ 故障排除
### 常见问题
#### 1. 连接失败
**问题**: 无法连接到路由器
**解决方案**:
```bash
# 检查网络连接
ping 192.168.31.1
# 检查路由器管理界面
curl -I http://192.168.31.1
# 确认IP地址正确
# 某些路由器可能使用 192.168.1.1
```
#### 2. 漏洞利用失败
**问题**: "Exploit not working" 错误
**可能原因**:
- 固件版本太新,已修复漏洞
- 路由器型号不支持
- 网络连接不稳定
**解决方案**:
```bash
# 检查设备型号支持情况
# 尝试降级固件(如果可能)
# 检查网络连接稳定性
```
#### 3. SSH连接问题
**问题**: SSH连接被拒绝
**解决方案**:
```bash
# 检查SSH服务状态
ssh root@192.168.31.1
# 如果连接被拒绝重新执行选项6
# 检查防火墙设置
```
#### 4. 固件刷写失败
**问题**: 固件安装过程中出错
**解决方案**:
- 确保固件与设备型号匹配
- 检查固件文件完整性
- 确保有足够的存储空间
- 检查电源稳定性
#### 5. Python依赖问题
**问题**: ModuleNotFoundError
**解决方案**:
```bash
# 重新安装依赖
pip install -r requirements.txt
# 或者使用虚拟环境
python3 -m venv venv
source venv/bin/activate # Linux/macOS
# venv\Scripts\activate # Windows
pip install -r requirements.txt
```
### 恢复模式
如果路由器变砖,可以尝试以下恢复方法:
#### 1. 使用Breed恢复如已安装
1. 路由器断电
2. 按住reset键不放
3. 插入电源等待10秒
4. 浏览器访问 `192.168.1.1`
5. 通过Web界面刷写固件
#### 2. 使用备份恢复
1. 通过SSH连接到路由器
2. 使用dd命令恢复分区
```bash
# 恢复完整固件(谨慎操作!)
dd if=/tmp/backup.bin of=/dev/mtdblock0
# 恢复特定分区
dd if=/tmp/kernel_backup.bin of=/dev/mtdblock2
```
#### 3. TFTP恢复模式
某些型号支持TFTP恢复
1. 设置电脑IP为 192.168.1.2
2. 运行TFTP服务器
3. 按住reset键启动路由器
4. 传输固件文件
## ⚠️ 安全提示
### 风险声明
- **⚠️ 刷机有风险,操作需谨慎!**
- **⚠️ 任何固件修改都可能导致设备变砖!**
- **⚠️ 修改固件可能失去官方保修!**
- **⚠️ 请在操作前做好完整备份!**
### 安全建议
#### 操作前准备
1. **完整备份**: 务必先执行选项4创建完整备份
2. **稳定电源**: 确保操作过程中电源稳定
3. **网络稳定**: 确保网络连接稳定
4. **充足时间**: 不要在时间紧迫时进行操作
#### 密码安全
1. **修改默认密码**: SSH启用后立即修改默认密码
```bash
passwd root
```
2. **禁用不必要的服务**:
```bash
# 如不需要Telnet建议禁用
/etc/init.d/telnet disable
```
3. **配置防火墙**:
```bash
# 限制SSH访问的IP范围
iptables -A INPUT -p tcp --dport 22 -s 192.168.31.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j DROP
```
#### 固件安全
1. **验证固件来源**: 只使用可信来源的固件
2. **校验文件完整性**: 使用MD5或SHA256校验
3. **渐进式升级**: 避免跨越太多版本升级
## 🔧 开发说明
### 项目结构
```
Xiaomi-Router-patcher/
├── menu.py # 主菜单界面
├── gateway.py # 网关通信模块
├── connect*.py # 各种漏洞利用脚本
├── xqmodel.py # 设备型号定义
├── read_info.py # 设备信息读取
├── create_backup.py # 备份功能
├── install_*.py # 各种安装功能
├── unlock_features.py # 功能解锁
├── xmir_base/ # 核心库
│ ├── ubireader/ # UBI文件系统读取
│ ├── fdt/ # 设备树处理
│ └── telnetlib/ # Telnet库
├── data/ # 数据文件
│ ├── payload/ # 漏洞利用载荷
│ ├── payload_ssh/ # SSH相关脚本
│ └── *.po # 语言包文件
├── bootloader/ # 引导加载器文件
├── firmware/ # 固件存放目录
└── python/ # Windows内置Python
```
### 核心模块说明
#### Gateway类 (gateway.py)
负责与路由器的通信,包括:
- HTTP/HTTPS请求
- SSH连接
- Telnet连接
- FTP传输
- 设备检测
#### 漏洞利用模块 (connect*.py)
- `connect1.py`: c_upload/netspeed漏洞
- `connect7.py`: get_icon漏洞
- 支持多种小米路由器型号
#### 设备模型 (xqmodel.py)
定义了所有支持的设备型号和属性。
### 添加新设备支持
1. **在xqmodel.py中添加设备定义**:
```python
mi(42, "NEW_MODEL", "", "device-alt-name")
```
2. **在connect.py中添加检测逻辑**:
```python
if gw.model_id == get_modelid_by_name('NEW_MODEL'):
# 使用适当的漏洞利用方法
```
3. **测试新设备**:
```python
# 创建测试脚本验证功能
```
### 自定义漏洞利用
参考现有的connect脚本主要步骤
1. **检测设备**:
```python
gw.detect_device()
```
2. **安装载荷**:
```python
install_exploit(api='API/endpoint')
```
3. **执行功能**:
```python
run_exploit('function_name', timeout=10)
```
## 🤝 贡献指南
### 如何贡献
1. **Fork 项目**
2. **创建功能分支**:
```bash
git checkout -b feature/new-feature
```
3. **提交更改**:
```bash
git commit -am 'Add new feature'
```
4. **推送分支**:
```bash
git push origin feature/new-feature
```
5. **创建 Pull Request**
### 贡献方向
- 支持新的路由器型号
- 修复现有漏洞利用
- 改进用户界面
- 增加新功能
- 完善文档
- 修复bug
### 代码规范
- 使用Python 3.8+语法
- 遵循PEP 8代码风格
- 添加适当的注释
- 编写测试用例
### 报告问题
请在GitHub Issues中报告bug或提出功能请求
- 详细描述问题
- 提供复现步骤
- 包含系统环境信息
- 附上相关日志
## 📄 许可证
本项目采用 GPL-3.0 许可证。详见 [LICENSE](LICENSE) 文件。
## 💝 捐赠支持
如果这个项目对您有帮助,欢迎支持开发:
[![Donations Page](https://github.com/andry81-cache/gh-content-static-cache/raw/master/common/badges/donate/donate.svg)](https://github.com/remittor/donate)
## 📞 联系方式
- **GitHub Issues**: [提交问题](https://github.com/longzheng268/Xiaomi-Router-patcher/issues)
- **讨论区**: [GitHub Discussions](https://github.com/longzheng268/Xiaomi-Router-patcher/discussions)
## 🙏 致谢
- 感谢原始项目的所有贡献者
- 感谢小米路由器破解社区
- 感谢OpenWrt项目
- 感谢所有测试用户的反馈
---
**⚠️ 免责声明**: 本工具仅供学习和研究使用。使用本工具进行的任何操作,风险由用户自行承担。开发者不对因使用本工具而造成的任何损失负责。
## 🖼️ 界面展示 / Interface Preview
![成功执行界面](image/display-successful.png)
*工具成功执行后的界面展示 / Interface after successful execution*
![成功连接ssh界面](image/display-ssh.png)
*ssh成功执行后的界面展示 / Interface after ssh connetct successful execution*
![成功持久化ssh界面](image/display-permanent-ssh.png)
*ssh成功执行后的界面展示 / Interface after ssh permanent execution*
---
## English Summary
**XMiR-Patcher** is a comprehensive firmware patcher for Xiaomi routers that supports:
- **50+ Xiaomi router models** from R1CM to latest AX series
- **Exploit installation** for gaining root access
- **Permanent SSH access** with customizable credentials
- **Full firmware backup** and selective partition backup
- **Custom firmware installation** including OpenWrt support
- **Bootloader replacement** (Breed support for R3G/R3P/RM2100/RA71/CR660x/TR60x series, U-Boot support for R3G/R3P/RM2100)
- **Multi-language support** (EN/RU/ZH language packs with Chinese menu interface)
- **Advanced features** like password change, log reading, feature unlocking
### Quick Start
**Windows**: Run `run.bat` | **Linux/macOS**: Run `./run.sh`
### Basic Usage Flow
1. Set router IP address (default: 192.168.31.1)
2. Connect and install exploit (essential first step)
3. Create full backup (highly recommended)
4. Enable permanent SSH access
5. Install custom firmware or additional features
**⚠️ Warning**: Firmware modification carries risks. Always backup before proceeding!

Binary file not shown.

@ -7,6 +7,8 @@ import time
import xmir_base
from gateway import *
import i18n
import lang_config
gw = Gateway(detect_device = False, detect_ssh = False)
@ -48,6 +50,12 @@ if gw.model_id > 0 and gw.model_id < gw.get_modelid_by_name('R2100'):
# import connect4
# sys.exit(0)
# Route BE3600 variants (RD15, RD16, RN06) to connect6
if dn in ['RD15', 'RD16', 'RN06']:
inited_gw = create_gateway(timeout = 4, die_if_sshOk = True, die_if_ftpOk = True, web_login = True, try_telnet = True)
import connect6
sys.exit(0)
if True:
# init gw and check ssh
gw = create_gateway(timeout = 4, die_if_sshOk = True, die_if_ftpOk = True, web_login = True, try_telnet = True)
@ -61,15 +69,36 @@ if True:
'connect5', # smartcontroller
'connect7', # get_icon
]
exploit_worked = False
exploit_warnings = []
for mod_name in exp_modules:
try:
import_module(mod_name, gw)
exploit_worked = True
break # Ok
except ExploitFixed as e:
print('WARN:', str(e))
exploit_warnings.append(str(e))
continue # try next module
except ExploitNotWorked as e:
print('WARN:', str(e))
exploit_warnings.append(str(e))
continue # try next module
except Exception:
raise
# Show general exploit failure message if all exploits failed
if not exploit_worked:
current_lang = lang_config.get_language() or 'en'
print()
print("=" * 60)
print(i18n.get_translation(current_lang, 'messages', 'exploit_failed_title'))
print()
print(i18n.get_translation(current_lang, 'messages', 'exploit_failed_message'))
print()
print(i18n.get_translation(current_lang, 'messages', 'exploit_failed_suggestion'))
print("=" * 60)
print()

@ -8,6 +8,8 @@ import requests
import xmir_base
from gateway import *
import i18n
import lang_config
web_password = True
if len(sys.argv) > 1 and sys.argv[0].endswith('connect6.py'):
@ -81,6 +83,61 @@ for idx, exp_func in enumerate(exp_list):
gw.set_diag_iperf_test_thr(20)
if not exec_cmd:
current_lang = lang_config.get_language() or 'en'
# Show device-specific firmware downgrade suggestions
if gw.device_name in ['RD15', 'RN06']: # BE3600 2.5G variants
print()
print("=" * 60)
print(i18n.get_translation(current_lang, 'messages', 'firmware_downgrade_title'))
print()
print(i18n.get_translation(current_lang, 'messages', 'firmware_downgrade_rd15'))
print()
if gw.rom_version:
if current_lang == 'zh':
print(f"当前固件版本: {gw.rom_version}")
print("建议降级到: v1.0.65 或更旧版本")
elif current_lang == 'ru':
print(f"Текущая версия прошивки: {gw.rom_version}")
print("Рекомендуемое понижение до: v1.0.65 или старше")
else:
print(f"Current firmware version: {gw.rom_version}")
print("Recommended downgrade to: v1.0.65 or older")
print()
print(i18n.get_translation(current_lang, 'messages', 'firmware_downgrade_tutorial'))
print()
print(i18n.get_translation(current_lang, 'messages', 'firmware_downgrade_tool'))
print("=" * 60)
print()
elif gw.device_name == 'RD16': # BE3600 1G variant
print()
print("=" * 60)
print(i18n.get_translation(current_lang, 'messages', 'firmware_downgrade_title'))
print()
print(i18n.get_translation(current_lang, 'messages', 'firmware_downgrade_rd16'))
print()
if gw.rom_version:
if current_lang == 'zh':
print(f"当前固件版本: {gw.rom_version}")
print("建议降级到: v1.0.34 或更旧版本")
elif current_lang == 'ru':
print(f"Текущая версия прошивки: {gw.rom_version}")
print("Рекомендуемое понижение до: v1.0.34 или старше")
else:
print(f"Current firmware version: {gw.rom_version}")
print("Recommended downgrade to: v1.0.34 or older")
print()
print(i18n.get_translation(current_lang, 'messages', 'firmware_downgrade_tutorial'))
print()
print(i18n.get_translation(current_lang, 'messages', 'firmware_downgrade_tool'))
print("=" * 60)
print()
raise ExploitNotWorked('Exploits "arn_switch/start_binding/set_mac_filter" not working!!!')
if exec_cmd == exploit_1:

File diff suppressed because it is too large Load Diff

@ -11,23 +11,50 @@ fi
mv -f /tmp/ssh_patch.sh $DIR_PATCH/
chmod +x $DIR_PATCH/ssh_patch.sh
# Set nvram settings
nvram set ssh_en=1
nvram commit
INSTALL_METHOD=2
# Method 1: UCI firewall hook (primary method)
uci set firewall.auto_ssh_patch=include
uci set firewall.auto_ssh_patch.type='script'
uci set firewall.auto_ssh_patch.path="$DIR_PATCH/ssh_patch.sh"
uci set firewall.auto_ssh_patch.enabled='1'
uci commit firewall
if [ $INSTALL_METHOD = 1 ]; then
FILE_FOR_EDIT=/etc/crontabs/root
grep -v "/ssh_patch.sh" $FILE_FOR_EDIT > $FILE_FOR_EDIT.new
echo "*/1 * * * * /etc/crontabs/patches/ssh_patch.sh >/dev/null 2>&1" >> $FILE_FOR_EDIT.new
mv $FILE_FOR_EDIT.new $FILE_FOR_EDIT
# Method 2: Cron job as backup (runs every 5 minutes)
FILE_CRON=/etc/crontabs/root
if [ -f "$FILE_CRON" ]; then
# Remove any existing ssh_patch entries
grep -v "/ssh_patch.sh" $FILE_CRON > $FILE_CRON.new || echo "" > $FILE_CRON.new
# Add new entry that runs every 5 minutes
echo "*/5 * * * * $DIR_PATCH/ssh_patch.sh >/dev/null 2>&1" >> $FILE_CRON.new
mv $FILE_CRON.new $FILE_CRON
/etc/init.d/cron restart
fi
if [ $INSTALL_METHOD = 2 ]; then
uci set firewall.auto_ssh_patch=include
uci set firewall.auto_ssh_patch.type='script'
uci set firewall.auto_ssh_patch.path="$DIR_PATCH/ssh_patch.sh"
uci set firewall.auto_ssh_patch.enabled='1'
uci commit firewall
fi
# Method 3: Create an additional init script as backup
INIT_SCRIPT=/etc/init.d/ssh_persistent
cat > $INIT_SCRIPT << 'EOF'
#!/bin/sh /etc/rc.common
START=19
STOP=89
start() {
DIR_PATCH=/etc/crontabs/patches
if [ -x "$DIR_PATCH/ssh_patch.sh" ]; then
$DIR_PATCH/ssh_patch.sh &
fi
}
stop() {
return 0
}
EOF
chmod +x $INIT_SCRIPT
$INIT_SCRIPT enable
# Run the patch immediately
$DIR_PATCH/ssh_patch.sh

@ -1,18 +1,45 @@
#!/bin/sh
[ -e "/tmp/ssh_patch.log" ] && return 0
# Check if SSH is already working properly
if [ -f "/tmp/ssh_patch.log" ]; then
# Verify SSH is still enabled and running
SSH_EN=`nvram get ssh_en`
if [ "$SSH_EN" = "1" ] && pgrep dropbear >/dev/null 2>&1; then
return 0
fi
# If verification fails, continue with patching
rm -f /tmp/ssh_patch.log
fi
# Ensure nvram SSH setting is enabled
SSH_EN=`nvram get ssh_en`
if [ "$SSH_EN" != "1" ]; then
nvram set ssh_en=1
nvram commit
fi
# Patch dropbear init script to bypass release channel check
if grep -q '= "release"' /etc/init.d/dropbear ; then
sed -i 's/= "release"/= "XXXXXX"/g' /etc/init.d/dropbear
fi
# Additional hardening: ensure dropbear service is enabled and configured
/etc/init.d/dropbear enable
/etc/init.d/dropbear restart
echo "ssh enabled" > /tmp/ssh_patch.log
# Ensure dropbear is running - restart if necessary
if ! pgrep dropbear >/dev/null 2>&1; then
/etc/init.d/dropbear start
else
/etc/init.d/dropbear restart
fi
# Wait a moment for service to start
sleep 2
# Verify SSH is actually working
if pgrep dropbear >/dev/null 2>&1; then
echo "ssh enabled - $(date)" > /tmp/ssh_patch.log
else
echo "ssh patch failed - $(date)" > /tmp/ssh_patch.log
exit 1
fi

@ -2,15 +2,29 @@
DIR_PATCH=/etc/crontabs/patches
# Method 1: Remove cron job entries
if grep -q '/ssh_patch.sh' /etc/crontabs/root ; then
# remove older version of patch
grep -v "/ssh_patch.sh" /etc/crontabs/root > /etc/crontabs/root.new
mv /etc/crontabs/root.new /etc/crontabs/root
/etc/init.d/cron restart
fi
uci delete firewall.auto_ssh_patch
uci commit firewall
# Method 2: Remove UCI firewall hook
if uci -q get firewall.auto_ssh_patch ; then
uci delete firewall.auto_ssh_patch
uci commit firewall
fi
# Method 3: Remove init script
INIT_SCRIPT=/etc/init.d/ssh_persistent
if [ -f "$INIT_SCRIPT" ]; then
$INIT_SCRIPT disable
$INIT_SCRIPT stop
rm -f $INIT_SCRIPT
fi
# Clean up files
rm -f $DIR_PATCH/ssh_patch.sh
rm -f /tmp/ssh_patch.log

@ -1 +1,37 @@
English:
In this folder, you should put the firmware for flashing.
IMPORTANT: If you encounter exploit warnings like:
- "Exploits arn_switch/start_binding/set_mac_filter not working!!!"
- "Exploits Smartcontroller are not usable (hackCheck:3)"
- "Exploit get_icon not working!!! (API not founded)"
For Xiaomi BE3600 (RD15) routers, please downgrade to firmware version 1.0.68 or older.
You can use the Xiaomi Router Repair Tool for firmware downgrade.
Firmware downgrade tutorial: https://mirom.ezbox.idv.tw/en/miwifi/
中文:
此文件夹中应放置用于刷写的固件。
重要提示:如果您遇到漏洞利用警告,如:
- "漏洞利用 arn_switch/start_binding/set_mac_filter 不工作!!!"
- "漏洞利用 Smartcontroller 不可用 (hackCheck:3)"
- "漏洞利用 get_icon 不工作!!! (API未找到)"
对于小米BE3600 (RD15)路由器请降级到固件版本1.0.68或更旧版本。
您可以使用小米路由器修复工具进行固件降级。
固件降级教程https://mirom.ezbox.idv.tw/en/miwifi/
Русский:
В эту папку следует помещать прошивки для прошивки.
ВАЖНО: Если вы столкнулись с предупреждениями об эксплойтах:
- "Эксплойты arn_switch/start_binding/set_mac_filter не работают!!!"
- "Эксплойты Smartcontroller недоступны (hackCheck:3)"
- "Эксплойт get_icon не работает!!! (API не найден)"
Для роутеров Xiaomi BE3600 (RD15), пожалуйста, понизьте версию прошивки до 1.0.68 или старше.
Вы можете использовать инструмент восстановления роутера Xiaomi для понижения версии прошивки.
Руководство по понижению версии прошивки: https://mirom.ezbox.idv.tw/en/miwifi/

@ -1253,7 +1253,7 @@ class Gateway():
return 0
if telnet_en:
self.install_dropbearmulti(force = False, die_on_error = True)
self.install_dropbearmulti(force = True, die_on_error = True)
return 0
return -1

@ -0,0 +1,203 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Language translations for menu system
# Supported languages: en (English), zh (Chinese), ru (Russian)
TRANSLATIONS = {
'en': {
'title': 'Xiaomi MiR Patcher',
'main_menu': [
'Set IP-address (current value: {})',
'Connect to device (install exploit)',
'Read full device info',
'Create full backup',
'Install EN/RU/ZH languages',
'Install permanent SSH',
'Install firmware (from directory "firmware")',
'{{{ Other functions }}}',
'Change language',
'[[ Reboot device ]]',
'Exit'
],
'extended_menu': [
'Set IP-address (current value: {})',
'Change root password',
'Read dmesg and syslog',
'Create a backup of the specified partition',
'Uninstall EN/RU/ZH languages',
'Set kernel boot address',
'Install bootloader (Breed/U-Boot)',
'__test__',
'[[ Reboot device ]]',
'Return to main menu'
],
'prompts': {
'select': 'Select: ',
'choice': 'Choice: ',
'enter_ip': 'Enter device IP-address: ',
'extended_functions': '(extended functions)',
'language_menu': 'Language / 语言 / Язык',
'language_prompt': 'Select language [1-English, 2-中文, 3-Русский]: ',
'bootloader_choice': 'Select bootloader [1-Breed, 2-U-Boot]: '
},
'messages': {
'firmware_downgrade_title': 'FIRMWARE DOWNGRADE SUGGESTION:',
'firmware_downgrade_be3600': 'If exploits are not working on your BE3600 router, please\ndowngrade to firmware version 1.0.68 or older.',
'firmware_downgrade_rd15': 'RD15 (BE3600 2.5G) latest firmware v1.0.68 has fixed the vulnerability.\nPlease downgrade to v1.0.65 or older.',
'firmware_downgrade_rd16': 'RD16 (BE3600 1G) latest firmware v1.0.40 has fixed the vulnerability.\nPlease downgrade to v1.0.34 or older.',
'firmware_downgrade_tutorial': 'Firmware downgrade tutorial:\nhttps://github.com/uyez/lyq/releases/tag/be3600',
'firmware_downgrade_tool': 'You can use the Xiaomi Router Repair Tool for downgrade.',
'exploit_failed_title': 'EXPLOIT FAILED:',
'exploit_failed_message': 'All available exploits failed to work on this device.\nThis may be due to newer firmware versions that have\npatched the vulnerabilities.',
'exploit_failed_suggestion': 'Consider checking for alternative firmware versions\nor contact the community for device-specific solutions.'
}
},
'zh': {
'title': '小米路由器破解工具',
'main_menu': [
'设置IP地址 (当前值: {})',
'连接设备 (安装漏洞利用)',
'读取完整设备信息',
'创建完整备份',
'安装 英文/俄文/中文 语言包',
'安装永久SSH',
'安装固件 (从 "firmware" 目录)',
'{{{ 其他功能 }}}',
'更改语言',
'[[ 重启设备 ]]',
'退出'
],
'extended_menu': [
'设置IP地址 (当前值: {})',
'修改root密码',
'读取dmesg和系统日志',
'创建指定分区备份',
'卸载 英文/俄文/中文 语言包',
'设置内核启动地址',
'安装引导程序 (Breed/U-Boot)',
'__测试__',
'[[ 重启设备 ]]',
'返回主菜单'
],
'prompts': {
'select': '请选择: ',
'choice': '请选择: ',
'enter_ip': '请输入设备IP地址: ',
'extended_functions': '(扩展功能)',
'language_menu': 'Language / 语言 / Язык',
'language_prompt': '选择语言 [1-English, 2-中文, 3-Русский]: ',
'bootloader_choice': '选择引导程序 [1-Breed, 2-U-Boot]: '
},
'messages': {
'firmware_downgrade_title': '固件降级建议:',
'firmware_downgrade_be3600': '如果漏洞利用在您的BE3600路由器上不工作\n降级到固件版本1.0.68或更旧版本。',
'firmware_downgrade_rd15': 'RD15BE3600 2.5G版本最新固件v1.0.68已修复漏洞。\n请降级到v1.0.65或更旧版本。',
'firmware_downgrade_rd16': 'RD16BE3600 1G版本最新固件v1.0.40已修复漏洞。\n请降级到v1.0.34或更旧版本。',
'firmware_downgrade_tutorial': '固件降级教程:\nhttps://github.com/uyez/lyq/releases/tag/be3600',
'firmware_downgrade_tool': '您可以使用小米路由器修复工具进行降级。',
'exploit_failed_title': '漏洞利用失败:',
'exploit_failed_message': '所有可用的漏洞利用都无法在此设备上工作。\n这可能是由于较新的固件版本已修补了\n这些漏洞。',
'exploit_failed_suggestion': '请考虑检查替代固件版本\n或联系社区获取设备特定解决方案。'
}
},
'ru': {
'title': 'Xiaomi MiR Patcher',
'main_menu': [
'Установить IP-адрес (текущее значение: {})',
'Подключиться к устройству (установить эксплойт)',
'Читать полную информацию об устройстве',
'Создать полную резервную копию',
'Установить языки EN/RU/ZH',
'Установить постоянный SSH',
'Установить прошивку (из папки "firmware")',
'{{{ Другие функции }}}',
'Изменить язык',
'[[ Перезагрузить устройство ]]',
'Выход'
],
'extended_menu': [
'Установить IP-адрес (текущее значение: {})',
'Изменить пароль root',
'Прочитать dmesg и syslog',
'Создать резервную копию указанного раздела',
'Удалить языки EN/RU/ZH',
'Установить адрес загрузки ядра',
'Установить загрузчик (Breed/U-Boot)',
'__тест__',
'[[ Перезагрузить устройство ]]',
'Вернуться в главное меню'
],
'prompts': {
'select': 'Выбрать: ',
'choice': 'Выбор: ',
'enter_ip': 'Введите IP-адрес устройства: ',
'extended_functions': '(расширенные функции)',
'language_menu': 'Language / 语言 / Язык',
'language_prompt': 'Выберите язык [1-English, 2-中文, 3-Русский]: ',
'bootloader_choice': 'Выберите загрузчик [1-Breed, 2-U-Boot]: '
},
'messages': {
'firmware_downgrade_title': 'ПРЕДЛОЖЕНИЕ ПОНИЖЕНИЯ ВЕРСИИ ПРОШИВКИ:',
'firmware_downgrade_be3600': 'Если эксплойты не работают на вашем роутере BE3600, пожалуйста\nпонизьте версию прошивки до 1.0.68 или старше.',
'firmware_downgrade_rd15': 'RD15 (BE3600 2.5G) последняя прошивка v1.0.68 исправила уязвимость.\nПожалуйста, понизьте до v1.0.65 или старше.',
'firmware_downgrade_rd16': 'RD16 (BE3600 1G) последняя прошивка v1.0.40 исправила уязвимость.\nПожалуйста, понизьте до v1.0.34 или старше.',
'firmware_downgrade_tutorial': 'Руководство по понижению версии прошивки:\nhttps://github.com/uyez/lyq/releases/tag/be3600',
'firmware_downgrade_tool': 'Вы можете использовать инструмент восстановления роутера Xiaomi для понижения версии.',
'exploit_failed_title': 'ЭКСПЛОЙТ НЕ СРАБОТАЛ:',
'exploit_failed_message': 'Все доступные эксплойты не смогли работать на этом устройстве.\nЭто может быть связано с более новыми версиями прошивки,\nкоторые исправили уязвимости.',
'exploit_failed_suggestion': 'Рассмотрите возможность проверки альтернативных версий прошивки\nили обратитесь к сообществу за решениями для конкретного устройства.'
}
}
}
def get_translation(lang, key, subkey=None, *args):
"""Get translated text for given language and key"""
if lang not in TRANSLATIONS:
lang = 'en' # fallback to English
trans = TRANSLATIONS[lang]
# Handle nested dictionary lookup
if subkey:
if key in trans and isinstance(trans[key], dict) and subkey in trans[key]:
text = trans[key][subkey]
if args:
return text.format(*args)
return text
# fallback to English
elif lang != 'en' and key in TRANSLATIONS['en'] and isinstance(TRANSLATIONS['en'][key], dict) and subkey in TRANSLATIONS['en'][key]:
text = TRANSLATIONS['en'][key][subkey]
if args:
return text.format(*args)
return text
else:
return f"{key}.{subkey}" # fallback key
# Handle normal key lookup
if key in trans:
if isinstance(trans[key], list):
return trans[key]
elif args:
return trans[key].format(*args)
else:
return trans[key]
elif key in trans.get('prompts', {}):
text = trans['prompts'][key]
if args:
return text.format(*args)
return text
else:
# fallback to English only if we're not already using English
if lang != 'en':
return get_translation('en', key, subkey, *args)
else:
# If key not found even in English, return a default message
if subkey:
return f"[Missing translation: {key}.{subkey}]"
else:
return f"[Missing translation: {key}]"
def get_supported_languages():
"""Get list of supported language codes"""
return list(TRANSLATIONS.keys())

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

@ -26,12 +26,20 @@ fn_remote = '/tmp/bootloader.bin'
fn_local = None
if bl_name == 'breed':
if dn != 'R3G' and dn != 'R3P' and dn != 'RM2100':
supported_devices = ['R3G', 'R3P', 'RM2100', 'RA71', 'CR6606', 'CR6608', 'CR6609', 'TR609', 'TR608']
if dn not in supported_devices:
die("Breed bootloader cannot be installed on this device!")
fn_local = fn_dir + 'breed_r3g_eng.bin'
if dn in ['CR6606', 'CR6608', 'CR6609', 'TR609', 'TR608']:
fn_local = fn_dir + 'pb-boot-cr660x.img'
else:
fn_local = fn_dir + 'breed_r3g_eng.bin'
if bl_name == 'uboot':
fn_local = fn_dir + 'uboot_{}.bin'.format(gw.device_name)
# Check if device has a specific uboot file available
supported_uboot_devices = ['R3G', 'R3P', 'RM2100']
if dn not in supported_uboot_devices:
die("U-Boot bootloader is not available for this device! Supported devices: {}".format(', '.join(supported_uboot_devices)))
fn_local = fn_dir + 'uboot_{}.bin'.format(dn.lower())
if not fn_local:
die('Incorrect bootloader name!')
@ -51,6 +59,10 @@ if dev.bl.spi_rom:
die("Not support SPI Flash ROM! (now supported only NAND)")
addr = None
name = None
size = None
# Find bootloader partition (typically at address 0, but skip large "ALL" partitions)
for p, part in enumerate(dev.partlist):
if part['addr'] == 0 and part['size'] > 0x00800000: # 8MiB
continue # skip "ALL" part
@ -59,12 +71,29 @@ for p, part in enumerate(dev.partlist):
fname = ''.join(e for e in name if e.isalnum())
addr = part['addr']
size = part['size']
break # Take the first valid partition found
if addr is None:
die("No matching partition found!")
gw.upload(fn_local, fn_remote)
print ('Writing data to partition "{}" (addr: {}) ...'.format(name, "0x%08X" % addr))
gw.run_cmd('mtd write {bin} "{name}"'.format(bin=fn_remote, name=name))
# Validate that we have a proper partition name before proceeding
if not name:
die("Invalid partition name found!")
print('Selected partition: "{}" at address 0x{:08X} (size: 0x{:08X})'.format(name, addr, size))
# Upload bootloader file to device
try:
gw.upload(fn_local, fn_remote)
except Exception as e:
die('Failed to upload bootloader file: {}'.format(str(e)))
print('Writing data to partition "{}" (addr: {}) ...'.format(name, "0x%08X" % addr))
# Write bootloader to partition with error handling
try:
gw.run_cmd('mtd write {bin} "{name}"'.format(bin=fn_remote, name=name))
except Exception as e:
die('Failed to write bootloader to partition: {}'.format(str(e)))
print('Ready! Bootloader "{}" installation is complete.'.format(bl_name))

@ -23,22 +23,50 @@ fn_uninstall = '/tmp/ssh_uninstall.sh'
os.makedirs('tmp', exist_ok = True)
ssh_patch = '''#!/bin/sh
[ -e "/tmp/ssh_patch.log" ] && return 0
# Check if SSH is already working properly
if [ -f "/tmp/ssh_patch.log" ]; then
# Verify SSH is still enabled and running
SSH_EN=`nvram get ssh_en`
if [ "$SSH_EN" = "1" ] && pgrep dropbear >/dev/null 2>&1; then
return 0
fi
# If verification fails, continue with patching
rm -f /tmp/ssh_patch.log
fi
# Ensure nvram SSH setting is enabled
SSH_EN=`nvram get ssh_en`
if [ "$SSH_EN" != "1" ]; then
nvram set ssh_en=1
nvram commit
nvram set ssh_en=1
nvram commit
fi
# Patch dropbear init script to bypass release channel check
if grep -q '= "release"' /etc/init.d/dropbear ; then
sed -i 's/= "release"/= "XXXXXX"/g' /etc/init.d/dropbear
sed -i 's/= "release"/= "XXXXXX"/g' /etc/init.d/dropbear
fi
# Additional hardening: ensure dropbear service is enabled and configured
/etc/init.d/dropbear enable
/etc/init.d/dropbear restart
echo "ssh enabled" > /tmp/ssh_patch.log
# Ensure dropbear is running - restart if necessary
if ! pgrep dropbear >/dev/null 2>&1; then
/etc/init.d/dropbear start
else
/etc/init.d/dropbear restart
fi
# Wait a moment for service to start
sleep 2
# Verify SSH is actually working
if pgrep dropbear >/dev/null 2>&1; then
echo "ssh enabled - $(date)" > /tmp/ssh_patch.log
else
echo "ssh patch failed - $(date)" > /tmp/ssh_patch.log
exit 1
fi
'''
with open(FN_patch, 'w', newline = '\n') as file:
file.write(ssh_patch)
@ -55,16 +83,52 @@ fi
mv -f /tmp/ssh_patch.sh $DIR_PATCH/
chmod +x $DIR_PATCH/ssh_patch.sh
# Set nvram settings
nvram set ssh_en=1
nvram commit
# Method 1: UCI firewall hook (primary method)
uci set firewall.auto_ssh_patch=include
uci set firewall.auto_ssh_patch.type='script'
uci set firewall.auto_ssh_patch.path="$DIR_PATCH/ssh_patch.sh"
uci set firewall.auto_ssh_patch.enabled='1'
uci commit firewall
rm -f /tmp/ssh_patch.log
# Method 2: Cron job as backup (runs every 5 minutes)
FILE_CRON=/etc/crontabs/root
if [ -f "$FILE_CRON" ]; then
# Remove any existing ssh_patch entries
grep -v "/ssh_patch.sh" $FILE_CRON > $FILE_CRON.new || echo "" > $FILE_CRON.new
# Add new entry that runs every 5 minutes
echo "*/5 * * * * $DIR_PATCH/ssh_patch.sh >/dev/null 2>&1" >> $FILE_CRON.new
mv $FILE_CRON.new $FILE_CRON
/etc/init.d/cron restart
fi
# Method 3: Create an additional init script as backup
INIT_SCRIPT=/etc/init.d/ssh_persistent
cat > $INIT_SCRIPT << 'EOF'
#!/bin/sh /etc/rc.common
START=19
STOP=89
start() {
DIR_PATCH=/etc/crontabs/patches
if [ -x "$DIR_PATCH/ssh_patch.sh" ]; then
$DIR_PATCH/ssh_patch.sh &
fi
}
stop() {
return 0
}
EOF
chmod +x $INIT_SCRIPT
$INIT_SCRIPT enable
# Run the patch immediately
$DIR_PATCH/ssh_patch.sh
### bdata_patch ###
@ -73,50 +137,104 @@ with open(FN_install, 'w', newline = '\n') as file:
file.write(ssh_install)
bdata_patch = '''
# Enhanced bdata persistence patch
rm -f /tmp/bdata_patch.log
TELNET_EN=`bdata get telnet_en`
SSH_EN=`bdata get ssh_en`
UART_EN=`bdata get uart_en`
if [ "$TELNET_EN" != "1" -o "$SSH_EN" != "1" -o "$UART_EN" != "1" ]; then
KMOD_FN=/tmp/xmir_patcher.ko
if [ -f $KMOD_FN ]; then
insmod $KMOD_FN
if lsmod | grep -q xmir_patcher ; then
echo 'set_mtd_rw|bdata' > /sys/module/xmir_patcher/parameters/cmd
echo "Starting bdata patch..." > /tmp/bdata_patch.debug
# Check current bdata settings
TELNET_EN=`bdata get telnet_en 2>/dev/null || echo ""`
SSH_EN=`bdata get ssh_en 2>/dev/null || echo ""`
UART_EN=`bdata get uart_en 2>/dev/null || echo ""`
echo "Current bdata: telnet_en=$TELNET_EN ssh_en=$SSH_EN uart_en=$UART_EN" >> /tmp/bdata_patch.debug
# Always attempt to patch bdata for maximum persistence - don't skip if already set
KMOD_FN=/tmp/xmir_patcher.ko
if [ -f $KMOD_FN ]; then
echo "Loading xmir_patcher module..." >> /tmp/bdata_patch.debug
insmod $KMOD_FN
sleep 1
if lsmod | grep -q xmir_patcher ; then
echo "Module loaded successfully" >> /tmp/bdata_patch.debug
# Try bdata partition name (lowercase)
echo 'set_mtd_rw|bdata' > /sys/module/xmir_patcher/parameters/cmd
RESP=`cat /sys/module/xmir_patcher/parameters/cmd`
echo "bdata partition response: $RESP" >> /tmp/bdata_patch.debug
# If lowercase fails, try Bdata (uppercase)
if [ "${RESP::2}" != "0|" ]; then
echo 'set_mtd_rw|Bdata' > /sys/module/xmir_patcher/parameters/cmd
RESP=`cat /sys/module/xmir_patcher/parameters/cmd`
if [ "${RESP::2}" != "0|" ]; then
echo 'set_mtd_rw|Bdata' > /sys/module/xmir_patcher/parameters/cmd
RESP=`cat /sys/module/xmir_patcher/parameters/cmd`
fi
if [ "${RESP::2}" = "0|" ]; then
bdata set telnet_en=1
bdata set ssh_en=1
bdata set uart_en=1
bdata commit
echo OK > /tmp/bdata_patch.log
echo "Bdata partition response: $RESP" >> /tmp/bdata_patch.debug
fi
if [ "${RESP::2}" = "0|" ]; then
echo "Partition writable, setting bdata values..." >> /tmp/bdata_patch.debug
# Set all required values
bdata set telnet_en=1 2>&1 >> /tmp/bdata_patch.debug
bdata set ssh_en=1 2>&1 >> /tmp/bdata_patch.debug
bdata set uart_en=1 2>&1 >> /tmp/bdata_patch.debug
# Commit changes
if bdata commit 2>&1 >> /tmp/bdata_patch.debug ; then
echo "OK" > /tmp/bdata_patch.log
echo "bdata commit successful" >> /tmp/bdata_patch.debug
else
echo "error_commit" > /tmp/bdata_patch.log
echo "bdata commit failed" >> /tmp/bdata_patch.debug
fi
[ ! -f /tmp/bdata_patch.log ] && echo error_3 > /tmp/bdata_patch.log
else
echo "error_partition_not_writable" > /tmp/bdata_patch.log
echo "Failed to make partition writable" >> /tmp/bdata_patch.debug
fi
[ ! -f /tmp/bdata_patch.log ] && echo error_2 > /tmp/bdata_patch.log
# Clean up module
rmmod xmir_patcher 2>/dev/null
else
echo "error_module_load" > /tmp/bdata_patch.log
echo "Failed to load xmir_patcher module" >> /tmp/bdata_patch.debug
fi
[ ! -f /tmp/bdata_patch.log ] && echo error_1 > /tmp/bdata_patch.log
else
echo "error_module_missing" > /tmp/bdata_patch.log
echo "xmir_patcher module file not found" >> /tmp/bdata_patch.debug
fi
# Verify final state
TELNET_EN_FINAL=`bdata get telnet_en 2>/dev/null || echo ""`
SSH_EN_FINAL=`bdata get ssh_en 2>/dev/null || echo ""`
UART_EN_FINAL=`bdata get uart_en 2>/dev/null || echo ""`
echo "Final bdata: telnet_en=$TELNET_EN_FINAL ssh_en=$SSH_EN_FINAL uart_en=$UART_EN_FINAL" >> /tmp/bdata_patch.debug
'''
ssh_uninstall = '''#!/bin/sh
DIR_PATCH=/etc/crontabs/patches
# Method 1: Remove cron job entries
if grep -q '/ssh_patch.sh' /etc/crontabs/root ; then
# remove older version of patch
grep -v "/ssh_patch.sh" /etc/crontabs/root > /etc/crontabs/root.new
mv /etc/crontabs/root.new /etc/crontabs/root
/etc/init.d/cron restart
fi
# Method 2: Remove UCI firewall hook
if uci -q get firewall.auto_ssh_patch ; then
uci delete firewall.auto_ssh_patch
uci commit firewall
fi
# Method 3: Remove init script
INIT_SCRIPT=/etc/init.d/ssh_persistent
if [ -f "$INIT_SCRIPT" ]; then
$INIT_SCRIPT disable
$INIT_SCRIPT stop
rm -f $INIT_SCRIPT
fi
# Clean up files
rm -f $DIR_PATCH/ssh_patch.sh
rm -f /tmp/ssh_patch.log
'''
@ -134,48 +252,56 @@ if bdata and bdata.var:
ssh_en = bdata.var["ssh_en"] if 'ssh_en' in bdata.var else None
uart_en = bdata.var["uart_en"] if 'uart_en' in bdata.var else None
print(f'bdata: telnet_en = {telnet_en}, ssh_en = {ssh_en}, uart_en = {uart_en}')
if telnet_en != '1' or ssh_en != '1' or uart_en != '1':
print(f'CPU arch: {dev.info.cpu_arch}')
print(f'Kernel: {dev.info.linux_stamp}')
krn_version = dev.info.linux_ver.strip()
krn_ver = krn_version.split('.')
kver = krn_ver[0] + '.' + krn_ver[1]
arch = dev.info.cpu_arch
if kver in [ '4.4', '5.4' ] and arch in [ 'armv7', 'arm64' ]:
print(f'Insert patch for bdata partition!')
preempt = '-preempt' if 'PREEMPT' in dev.info.linux_stamp else ''
FN_kmod = FN_kmod.format(kver = kver, arch = arch, preempt = preempt)
if not os.path.exists(FN_kmod):
die(f'File "{FN_kmod}" not found!')
with open(FN_kmod, 'rb') as file:
kmod = file.read()
modmagic_pos = kmod.find(b'\x00vermagic=' + kver.encode())
if modmagic_pos <= 0:
die(f'Cannot found vermagic into file "{FN_kmod}"')
modmagic_pos = kmod.find(kver.encode(), modmagic_pos)
modmagic_end = kmod.find(b'\x00', modmagic_pos)
if modmagic_end <= 0 or modmagic_end - modmagic_pos > 200:
die(f'File "{FN_kmod}" contain incorrect vermagic (1)')
modmagic = kmod[modmagic_pos:modmagic_end]
fsp = modmagic.find(b' ')
if fsp <= 0:
die(f'File "{FN_kmod}" contain incorrect vermagic (2)')
modmagic_ver = modmagic[0:fsp]
modmagic_opt = modmagic[fsp:]
if b'-XMiR-Patcher' not in modmagic_ver:
die(f'File "{FN_kmod}" contain incorrect vermagic (3)')
new_modmagic = krn_version.encode('latin1') + modmagic_opt
xx = len(modmagic) - len(new_modmagic)
new_modmagic += b'\x00' * xx
kmod = kmod.replace(modmagic, new_modmagic)
FN_kmod = 'tmp/xmir_patcher.ko'
with open(FN_kmod, 'wb') as file:
file.write(kmod)
ssh_install = ssh_install.replace('### bdata_patch ###', bdata_patch)
with open(FN_install, 'w', newline = '\n') as file:
file.write(ssh_install)
FN_bdata_log = f'tmp/bdata_patch.log'
fn_bdata_log = '/tmp/bdata_patch.log'
# Check if we have the capability to apply bdata patch
print(f'CPU arch: {dev.info.cpu_arch}')
print(f'Kernel: {dev.info.linux_stamp}')
krn_version = dev.info.linux_ver.strip()
krn_ver = krn_version.split('.')
kver = krn_ver[0] + '.' + krn_ver[1]
arch = dev.info.cpu_arch
if kver in [ '4.4', '5.4' ] and arch in [ 'armv7', 'arm64' ]:
# Always try to apply bdata patch for maximum persistence
# Even if values appear correct, they might not persist across firmware updates
print(f'Applying bdata partition patch for enhanced persistence!')
preempt = '-preempt' if 'PREEMPT' in dev.info.linux_stamp else ''
FN_kmod = FN_kmod.format(kver = kver, arch = arch, preempt = preempt)
if not os.path.exists(FN_kmod):
die(f'File "{FN_kmod}" not found!')
with open(FN_kmod, 'rb') as file:
kmod = file.read()
modmagic_pos = kmod.find(b'\x00vermagic=' + kver.encode())
if modmagic_pos <= 0:
die(f'Cannot found vermagic into file "{FN_kmod}"')
modmagic_pos = kmod.find(kver.encode(), modmagic_pos)
modmagic_end = kmod.find(b'\x00', modmagic_pos)
if modmagic_end <= 0 or modmagic_end - modmagic_pos > 200:
die(f'File "{FN_kmod}" contain incorrect vermagic (1)')
modmagic = kmod[modmagic_pos:modmagic_end]
fsp = modmagic.find(b' ')
if fsp <= 0:
die(f'File "{FN_kmod}" contain incorrect vermagic (2)')
modmagic_ver = modmagic[0:fsp]
modmagic_opt = modmagic[fsp:]
if b'-XMiR-Patcher' not in modmagic_ver:
die(f'File "{FN_kmod}" contain incorrect vermagic (3)')
new_modmagic = krn_version.encode('latin1') + modmagic_opt
xx = len(modmagic) - len(new_modmagic)
new_modmagic += b'\x00' * xx
kmod = kmod.replace(modmagic, new_modmagic)
FN_kmod = 'tmp/xmir_patcher.ko'
with open(FN_kmod, 'wb') as file:
file.write(kmod)
ssh_install = ssh_install.replace('### bdata_patch ###', bdata_patch)
with open(FN_install, 'w', newline = '\n') as file:
file.write(ssh_install)
FN_bdata_log = f'tmp/bdata_patch.log'
fn_bdata_log = '/tmp/bdata_patch.log'
else:
print(f'bdata patch not supported for kernel {kver} / arch {arch}')
else:
print('No bdata information available - skipping bdata patch')
# ---------------------------------------------------------------------------
@ -206,10 +332,33 @@ gw.run_cmd(f"rm -f {fn_patch} ; rm -f {fn_install} ; rm -f {fn_uninstall}")
print("Ready! The Permanent SSH patch installed.")
if FN_bdata_log:
fn_bdata_debug = '/tmp/bdata_patch.debug'
FN_bdata_debug = 'tmp/bdata_patch.debug'
# Download both log and debug files
gw.download(fn_bdata_log, FN_bdata_log, verbose = 0)
gw.download(fn_bdata_debug, FN_bdata_debug, verbose = 0)
if not os.path.exists(FN_bdata_log):
print(f'WARN: Patch for bdata partition not executed!')
else:
with open(FN_bdata_log, 'r') as file:
res = file.read()
res = file.read().strip()
print(f'Patch for bdata result: {res}')
if res == 'OK':
print('SUCCESS: bdata partition patched successfully - SSH should persist across reboots')
else:
print(f'WARNING: bdata patch failed with result: {res}')
if os.path.exists(FN_bdata_debug):
print('Debug information:')
with open(FN_bdata_debug, 'r') as file:
debug_info = file.read()
print(debug_info)
print('SSH may still work but persistence across firmware updates is not guaranteed')
print("SSH persistence mechanisms installed:")
print("1. UCI firewall hook (primary)")
print("2. Cron job backup (every 5 minutes)")
print("3. Init script backup (on boot)")
print("Multiple redundant mechanisms ensure maximum persistence!")

@ -0,0 +1,67 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import json
CONFIG_FILE = 'config.json'
def load_config():
"""Load configuration from file"""
if os.path.exists(CONFIG_FILE):
try:
with open(CONFIG_FILE, 'r', encoding='utf-8') as f:
return json.load(f)
except (json.JSONDecodeError, IOError):
pass
return {}
def save_config(config):
"""Save configuration to file"""
try:
with open(CONFIG_FILE, 'w', encoding='utf-8') as f:
json.dump(config, f, ensure_ascii=False, indent=2)
return True
except IOError:
return False
def get_language():
"""Get current language setting"""
config = load_config()
# Return None if no config file exists or no language is set
# This will trigger the language selection menu
if not os.path.exists(CONFIG_FILE) or 'language' not in config:
return None
return config.get('language', 'en')
def set_language(lang):
"""Set language preference"""
config = load_config()
config['language'] = lang
return save_config(config)
def show_language_menu():
"""Show language selection menu"""
print()
print("=" * 58)
print()
print("Language / 语言 / Язык")
print()
print(" 1 - English")
print(" 2 - 中文 (Chinese)")
print(" 3 - Русский (Russian)")
print()
while True:
choice = input("Select language [1-English, 2-中文, 3-Русский]: ").strip()
if choice == '1':
set_language('en')
return 'en'
elif choice == '2':
set_language('zh')
return 'zh'
elif choice == '3':
set_language('ru')
return 'ru'
else:
print("Invalid choice. Please enter 1, 2, or 3.")

@ -8,34 +8,39 @@ import subprocess
import xmir_base
import gateway
from gateway import die
import i18n
import lang_config
gw = gateway.Gateway(detect_device = False, detect_ssh = False)
# Check for language preference or show language menu
current_lang = lang_config.get_language()
if current_lang is None or current_lang not in i18n.get_supported_languages():
current_lang = lang_config.show_language_menu()
def get_header(delim, suffix = ''):
header = delim*58 + '\n'
header += '\n'
header += 'Xiaomi MiR Patcher {} \n'.format(suffix)
title = i18n.get_translation(current_lang, 'title')
header += '{} {} \n'.format(title, suffix)
header += '\n'
return header
def menu1_show():
gw.load_config()
print(get_header('='))
print(' 1 - Set IP-address (current value: {})'.format(gw.ip_addr))
print(' 2 - Connect to device (install exploit)')
print(' 3 - Read full device info')
print(' 4 - Create full backup')
print(' 5 - Install EN/RU languages')
print(' 6 - Install permanent SSH')
print(' 7 - Install firmware (from directory "firmware")')
print(' 8 - {{{ Other functions }}}')
print(' 9 - [[ Reboot device ]]')
print(' 0 - Exit')
menu_items = i18n.get_translation(current_lang, 'main_menu')
for i, item in enumerate(menu_items, 1):
if i == 1: # IP address item needs formatting
print(' {} - {}'.format(i, item.format(gw.ip_addr)))
else:
print(' {} - {}'.format(i if i <= 10 else 0, item))
def menu1_process(id):
if id == 1:
ip_addr = input("Enter device IP-address: ")
ip_prompt = i18n.get_translation(current_lang, 'enter_ip')
ip_addr = input(ip_prompt)
return [ "gateway.py", ip_addr ]
if id == 2: return "connect.py"
if id == 3: return "read_info.py"
@ -44,33 +49,41 @@ def menu1_process(id):
if id == 6: return "install_ssh.py"
if id == 7: return "install_fw.py"
if id == 8: return "__menu2"
if id == 9: return "reboot.py"
if id == 9: return "__change_language"
if id == 10: return "reboot.py"
if id == 0: sys.exit(0)
return None
def menu2_show():
print(get_header('-', '(extended functions)'))
print(' 1 - Set IP-address (current value: {})'.format(gw.ip_addr))
print(' 2 - Change root password')
print(' 3 - Read dmesg and syslog')
print(' 4 - Create a backup of the specified partition')
print(' 5 - Uninstall EN/RU languages')
print(' 6 - Set kernel boot address')
print(' 7 - Install Breed bootloader')
print(' 8 - __test__')
print(' 9 - [[ Reboot device ]]')
print(' 0 - Return to main menu')
extended_suffix = i18n.get_translation(current_lang, 'extended_functions')
print(get_header('-', extended_suffix))
menu_items = i18n.get_translation(current_lang, 'extended_menu')
for i, item in enumerate(menu_items, 1):
if i == 1: # IP address item needs formatting
print(' {} - {}'.format(i, item.format(gw.ip_addr)))
else:
print(' {} - {}'.format(i if i <= 9 else 0, item))
def menu2_process(id):
if id == 1:
ip_addr = input("Enter device IP-address: ")
ip_prompt = i18n.get_translation(current_lang, 'enter_ip')
ip_addr = input(ip_prompt)
return [ "gateway.py", ip_addr ]
if id == 2: return "passw.py"
if id == 3: return "read_dmesg.py"
if id == 4: return [ "create_backup.py", "part" ]
if id == 5: return [ "install_lang.py", "uninstall" ]
if id == 6: return "activate_boot.py"
if id == 7: return [ "install_bl.py", "breed" ]
if id == 7:
# Bootloader selection submenu
bootloader_prompt = i18n.get_translation(current_lang, 'bootloader_choice')
bootloader_choice = input(bootloader_prompt)
if bootloader_choice == '1':
return [ "install_bl.py", "breed" ]
elif bootloader_choice == '2':
return [ "install_bl.py", "uboot" ]
else:
return None
if id == 8: return "test.py"
if id == 9: return "reboot.py"
if id == 0: return "__menu1"
@ -79,10 +92,10 @@ def menu2_process(id):
def menu_show(level):
if level == 1:
menu1_show()
return 'Select: '
return i18n.get_translation(current_lang, 'select')
else:
menu2_show()
return 'Choice: '
return i18n.get_translation(current_lang, 'choice')
def menu_process(level, id):
if level == 1:
@ -115,6 +128,12 @@ def menu():
if cmd == '__menu2':
level = 2
continue
if cmd == '__change_language':
# Show language menu and restart with new language
global current_lang
current_lang = lang_config.show_language_menu()
level = 1
continue
#print("cmd2 =", cmd)
if isinstance(cmd, str):
result = subprocess.run([sys.executable, cmd])

@ -1,5 +1,5 @@
@echo off
chcp 866 >NUL
chcp 65001 >NUL
SET PYTHONUNBUFFERED=TRUE
if "%~1"=="" goto menu

@ -1,5 +1,6 @@
#!/usr/bin/env bash
set -e
if [ ! -f "./xmir_base/xmir_init.py" ]; then

Loading…
Cancel
Save