移远模块adb key生成算法

移远5G模块,开启adb, 需要输入一个key来开启

import crypt

#sn = '18700338'
#sn = '40901409'
sn = '12741851'


def generateUnlockKey(sn):
    """
    @param sn: the serial number to generate an unlock key for
    """
    salt = "$1${0}$".format(sn)
    c = crypt.crypt("SH_adb_quectel", salt)
    print("Salt: {0}\nCrypt: {1}\nCode: {2}\n".format(salt, c, c[12:27]))
    return c[12:27]
    
    
xx = generateUnlockKey(sn)    

print(xx)


def old_key(salt):
    code = crypt.crypt("SH_adb_quectel", "$1$" + salt)
    #code = crypt.crypt("SH_adb_quectel", "$1$" + salt + '$')
    code = code[12:27]
    
    return code
       
       
yy = old_key(sn)    

print('jiandan=', yy)     

全网通EC20使用电信的4G物联网卡

对于电信2020年后发行的普通SIM卡和物联网卡,是没有CDMA所需要的CSIM文件的。早期的EC20为了适配当时的电信UIM卡,是做了特殊处理的,启动后会搜寻SIM卡中的CSIM文件,没有这些文件就不会注册到网络。

解决方法:
(1) 读取nv 配置

发送AT命令给EC20模块

AT+QNVFR="/nv/item_files/modem/mmode/operator_name"

读出来的结果应该是 01
(2) 将该配置改为 00

AT+QNVFW="/nv/item_files/modem/mmode/operator_name",00

(3) 插入 电信4G物联网卡,断电重启EC20

说明:
operator_name = 00 表示 OPERATE_NULL, 选网时采用默认设计,无特定运营商
operator_name = 01 表示 OPERATE_CT, 中国电信,选网时是考虑CDMA兼容,SRLTE(CDMA+LTE双在网)等需求

在一款 2017年出厂的EC20上实测成功, 版本为 EC20CEFAGR06A05M4G

WiFi-Calling

Phone connects to Edge Packet Data Gateway (EPDG)
over WiFi
• Voice calls over WiFi
• Phone connects on low/no signal
• Also connects in Airplane mode + WiFi

Connection to EPDG uses IPsec
• Authenticates using Internet Key Exchange Protocol (IKEv2)

Internet Protocol Security
• Confidentiality, data integrity, access control, and data source
authentication
• Recovery from transmission errors: packet loss, packet replay, and
packet forgery
• Authentication
• Authentication Header (AH) – RFC 4302

• Confidentiality
• Encapsulating Security Payload (ESP) – RFC 4303
• Key management
• Internet Key Exchange v2 (IKEv2) – RFC7296
• Two modes
• Tunnel – used for connection to Gateway (EPDG)
• Transport

Internet Key Exchange (IKEv2)
• Initiates connection in two phases
• IKE_SA_INIT
• Negotiate cryptographic algorithms, exchange nonces, and do
a Diffie-Hellman exchange
• IKE_AUTH
• Authenticate the previous messages, exchange identities (e.g.
IMSI), and certificates, and establish the child Security
Association(s) (SA)
• IKE_AUTH uses EAP-AKA
• IMSI exchange not protected by a certificate
• Open to MitM attacks on identity (IMSI)

IPsec ESP keys are not compromised
• Call content still safe

xiaomi cdn

小米firmware下载的cdn 限速了。
据说是因为一帮搞 pcdn的人,为了让自己的上行流量占比 小一点, 故意刷下行流量。 其中小米firmware的下载地址是很好获取的,所以被狂刷了很多流量。
其实没什么用,现在运营商不是看占比, 而是上行流量超过多少G,就停宽带。
这帮人做一些损人不利己的缺德事:小米付出了不应该的流量费用,普通用户获得了糟糕的下载体验; 他们的宽带还是被运营商停了。

默认的地址是 bigota.d.miui.com, 改成

cdn-ota.azureedge.net
cdnorg.d.miui.com
bn.d.miui.com
bkt-sgp-miui-ota-update-alisgp.oss-ap-southeast-1.aliyuncs.com

有时候可以提高下载速率

https://bn.d.miui.com/V12.5.15.0.RGGEUXM/begonia_eea_global_images_V12.5.15.0.RGGEUXM_20220826.0000.00_11.0_eea_b8c6b15c15.tgz

https://cdn-ota.azureedge.net/V12.5.15.0.RGGEUXM/begonia_eea_global_images_V12.5.15.0.RGGEUXM_20220826.0000.00_11.0_eea_b8c6b15c15.tgz

https://cdn-ota.azureedge.net/V13.0.8.0.SJHCNXM/atom_images_V13.0.8.0.SJHCNXM_20230630.0000.00_12.0_cn_acca549dfc.tgz

wget -c      --referer="https://miui.com/"    https://hugeota.d.miui.com/V12.5.6.0.RGGCNXM/begonia_images_V12.5.6.0.RGGCNXM_20220602.0000.00_11.0_cn_fbed701a77.tgz

MTK之NVRAM实现数据的备份与恢复

2017年的时候有做过这样的一个定制化需求:写入一个文件数据,恢复出厂设置后该文件数据也要恢复。

第一步:nvram lib id定义
vendor/mediatek/proprietary/custom/project/cgen/inc/Custom_NvRam_LID.h

typedef enum
{
    AP_CFG_RDCL_FILE_AUDIO_LID=AP_CFG_CUSTOM_BEGIN_LID, //AP_CFG_CUSTOM_BEGIN_LID: this lid must not be changed, it is reserved for system.
    AP_CFG_RDCL_FILE_AUDIO_MAGI_CONFERENCE_LID,
    AP_CFG_RDCL_FILE_AUDIO_HAC_PARAM_LID,
    AP_CFG_CUSTOM_TEST_CUSTOM1_LID, //zrx add 定义lib id
    AP_CFG_CUSTOM_FILE_MAX_LID,
} CUSTOM_CFG_FILE_LID;

//zrx add 添加LID版本信息
#define AP_CFG_CUSTOM_TEST_CUSTOM1_LID_VERNO        "000"

第二步:nvram lib id的数据结构和版本号声明
vendor/mediatek/proprietary/custom/project/cgen/inc/Custom_NvRam_data_item.h

//zrx add
LID_BIT VER_LID(AP_CFG_CUSTOM_TEST_CUSTOM1_LID)
Test_Custom1_Struct *CFG_TEST_CUSTOM1_REC_TOTAL
{

};

第三步:nvram lib数据结构定义
vendor/mediatek/proprietary/custom/project/cgen/cfgfileinc/CFG_Custom1_File.h

//zrx add start
typedef struct
{
    unsigned char Array[1024];
}Test_Custom1_Struct;
//zrx add end

//zrx add start
#define CFG_TEST_CUSTOM1_REC_SIZE    sizeof(Test_Custom1_Struct)
#define CFG_TEST_CUSTOM1_REC_TOTAL   1
//zrx add end

第四步:nvram lib 默认值定义
vendor/mediatek/proprietary/custom/project/cgen/cfgdefault/CFG_Custom1_Default.h

Test_Custom1_Struct stCustom2Default =
{

    0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
    
};

第五步:nvram lib内容加入nvram数组中
vendor/mediatek/proprietary/custom/m107/cgen/inc/CFG_file_info_custom.h

#include "../cfgfileinc/CFG_Custom1_File.h"
#include "../cfgdefault/CFG_Custom1_Default.h"

 const TCFG_FILE g_akCFG_File_Custom[]=
    {

    { "/data/nvram/APCFG/APRDCL/Test_Custom1",   VER(AP_CFG_CUSTOM_TEST_CUSTOM1_LID), CFG_TEST_CUSTOM1_REC_SIZE,
            CFG_TEST_CUSTOM1_REC_TOTAL, SIGNLE_DEFUALT_REC  ,    (char *)&stCustom2Default, DataReset , NULL
        },
    };

第六步:nvram lib id需要备份到BinRegion
vendor/mediatek/proprietary/external/nvram/libcustom_nvram/CFG_file_info.c

FileName aBackupToBinRegion[]=
{
  {"CUSTOM_TEST",AP_CFG_CUSTOM_TEST_CUSTOM1_LID},
}

pfConvertFunc aNvRamConvertFuncTable[]=
{
  NULL,//AP_CFG_CUSTOM_TEST_CUSTOM1_LID
}

const TABLE_FOR_SPECIAL_LID g_new_nvram_lid[] =
{
    { AP_CFG_CUSTOM_TEST_CUSTOM1_LID, 1024 * 1024, 1024 * 1024},
};

第七步:上层读写nvram数据接口
NvRAMAgent.java

package com.example.nvram_test;

import android.os.IBinder;

public interface NvRAMAgent extends android.os.IInterface
{
    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements NvRAMAgent
    {
        private static final java.lang.String DESCRIPTOR = "NvRAMAgent";
        /** Construct the stub at attach it to the interface. */
        public Stub()
        {
            this.attachInterface(this, DESCRIPTOR);
        }
        /**
         * Cast an IBinder object into an NvRAMAgent interface,
         * generating a proxy if needed.
         */
        public static NvRAMAgent asInterface(android.os.IBinder obj)
        {
            if ((obj == null)) {
                return null;
            }

            android.os.IInterface iin = (android.os.IInterface) obj.queryLocalInterface(DESCRIPTOR);

            if (((iin != null) && (iin instanceof NvRAMAgent))) {
                return ((NvRAMAgent) iin);
            }

            return new NvRAMAgent.Stub.Proxy(obj);
        }
        public android.os.IBinder asBinder()
        {
            return this;
        }
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
        {
            switch (code)
            {
            case INTERFACE_TRANSACTION:
            {
                reply.writeString(DESCRIPTOR);
                return true;
            }
            case TRANSACTION_READFILE:
            {
                data.enforceInterface(DESCRIPTOR);
                int _arg0;
                _arg0 = data.readInt();
                byte[] _result = this.readFile(_arg0);
                reply.writeNoException();
                reply.writeByteArray(_result);
                return true;
            }
            case TRANSACTION_WRITEFILE:
            {
                data.enforceInterface(DESCRIPTOR);
                int _arg0;
                _arg0 = data.readInt();
                byte[] _arg1;
                _arg1 = data.createByteArray();
                int _result = this.writeFile(_arg0, _arg1);
                reply.writeNoException();
                reply.writeInt(_result);
                return true;
            }
            default:
            {
                break;
            }
            }

            return super.onTransact(code, data, reply, flags);
        }
        private static class Proxy implements NvRAMAgent
        {
            private android.os.IBinder mRemote;
            Proxy(android.os.IBinder remote)
            {
                mRemote = remote;
            }
            public android.os.IBinder asBinder()
            {
                return mRemote;
            }
            public java.lang.String getInterfaceDescriptor()
            {
                return DESCRIPTOR;
            }
            public byte[] readFile(int file_lid) throws android.os.RemoteException
            {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                byte[] _result;

                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeInt(file_lid);
                    mRemote.transact(Stub.TRANSACTION_READFILE, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.createByteArray();
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }

                return _result;
            }
            public int writeFile(int file_lid, byte[] buff) throws android.os.RemoteException
            {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                int _result;

                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeInt(file_lid);
                    _data.writeByteArray(buff);
                    mRemote.transact(Stub.TRANSACTION_WRITEFILE, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }

                return _result;
            }

            public byte[] readFileByName(String filename) throws android.os.RemoteException
            {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                byte[] _result;

                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeString(filename);
                    mRemote.transact(Stub.TRANSACTION_READFILEBYNAME, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.createByteArray();
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }

                return _result;
            }

            public int writeFileByName(String filename, byte[] buff) throws android.os.RemoteException
            {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                int _result;

                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeString(filename);
                    _data.writeByteArray(buff);
                    mRemote.transact(Stub.TRANSACTION_WRITEFILEBYNAME, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }

                return _result;
            }
        }
        static final int TRANSACTION_READFILE = (IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_WRITEFILE = (IBinder.FIRST_CALL_TRANSACTION + 1);
        static final int TRANSACTION_READFILEBYNAME = (IBinder.FIRST_CALL_TRANSACTION + 2);
        static final int TRANSACTION_WRITEFILEBYNAME = (IBinder.FIRST_CALL_TRANSACTION + 3);
    }
    public byte[] readFile(int file_lid) throws android.os.RemoteException;
    public int writeFile(int file_lid, byte[] buff) throws android.os.RemoteException;
    public byte[] readFileByName(String filepath) throws android.os.RemoteException;
    public int writeFileByName(String filepath, byte[] buff) throws android.os.RemoteException;
}

第八步:读写数据帮助类
Utils.java

ackage com.example.nvram_test;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.ArrayList;

import android.content.Context;
import android.os.IBinder;
import android.os.ServiceManager;
import android.util.Log;
import android.widget.Toast;

public class Utils {
    final String TAG = "Utis";
    byte[] buff;
    Context mContext;
    public Utils(Context mContext){
        this.mContext=mContext;
    }   

    /**
     * 多个字节数组合并为一个字节数组
     * @param a 字节数组
     * @param b 字节数组
     * @return byte[]
     */
    public byte[] combineBytes(byte[] a, byte[] b) {
        byte[] bytes = new byte[a.length + b.length];
        System.arraycopy(a, 0, bytes, 0, a.length);
        System.arraycopy(b, 0, bytes, a.length, b.length);
        return bytes;
    }   

    /**
     * 写文件到app下
     */
    public void writeOwnFile(String fileName,String message){
        try {
            FileOutputStream fout = mContext.openFileOutput(fileName,
                    mContext.MODE_PRIVATE);
            byte[] bytes = message.getBytes();
            fout.write(bytes);
            fout.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 从app下读文件
     * @param fileName
     * @return
     */
    public String readOwnFile(String fileName){
        try {
            FileInputStream fis=mContext.openFileInput(fileName);
            ByteArrayOutputStream bos=new ByteArrayOutputStream();
            byte[] buffer=new byte[1024];
            int len=0;
            while((len=fis.read(buffer))!=-1){
                bos.write(buff, 0, len);
            }
            byte[] content_byte = bos.toByteArray();  
            String content = new String(content_byte);  
            return content;
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 写文件
     * @param fileName 文件名
     * @param bytes 字节数组
     */
    public void writeFile(String fileName,byte[] bytes){
         try {              
                FileOutputStream fout = new FileOutputStream(fileName);            
                fout.write(bytes);
                fout.close();               
            } catch (Exception e) {
                e.printStackTrace();
            }
    }

    /**
     * 读文件
     * @param fileName 文件名
     * @return byte[]
     */
    public byte[] readFile(String fileName){
        try {
            FileInputStream fin = new FileInputStream(fileName);
            int length = fin.available();
            byte [] buffer = new byte[length];
            fin.read(buffer); 
            fin.close();
            return buffer;
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        return buff;
    }

    /**
     * 写值到NvRam
     * @param file_name NvRam路径
     * @param bytes 字节数组
     */
    public void writeData(String file_name, byte[] bytes) {
        byte[] buff=new byte[1024];
        if(bytes.length 0) {
                Toast.makeText(mContext, "write Success", Toast.LENGTH_SHORT).show();
            //  Log.d(TAG, "zrx----write Success");
            } else {
                Toast.makeText(mContext, "write Failure", Toast.LENGTH_SHORT).show();
                Log.d(TAG, "zrx---- write Failure");
            }
        }
    }

    /**
     * 从NvRam读值
     * @param file_name NvRam路径
     * @param offset  开始位置
     * @param byteCount 字节数
     * @return
     */
    public byte[] readData(String file_name,int offset,int byteCount) {
        byte[] data=new byte[byteCount];
        IBinder binder = ServiceManager.getService("NvRAMAgent");
        NvRAMAgent agent = NvRAMAgent.Stub.asInterface(binder);
        if (agent != null) {
            try {
                buff = agent.readFileByName(file_name);
            } catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();
            }
        }
        if (buff != null) {
            try {
                for(int i=0;i

第九步:验证
MainActivity.java

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

import com.example.nvram_test.R;

public class MainActivity extends Activity{
    String TAG="MainActivity";

    /**
     * 文件名在vendor/mediatek/proprietary/custom/m107/cgen/inc/CFG_file_info_custom.h中有定义
     */
    private static final String TEST_FILENAME = "/data/nvram/APCFG/APRDCL/Test_Custom1";
    Button btn1;
    Button btn2;
    Button btn3;
    Button btn4;
    Utils utils;
    /**
     * 测试备份SecretKey文件的路径
     */
    private static final String secret_filename="/storage/emulated/0/SecretKey";

    /**
     * 测试备份goc_database文件的路径
     */
    private static final String goc_database="/storage/emulated/0/goc_database";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        utils=new Utils(this);
        btn1=(Button)findViewById(R.id.btn1);
        btn2=(Button)findViewById(R.id.btn2);

        btn3=(Button)findViewById(R.id.btn3);
        btn4=(Button)findViewById(R.id.btn4);

        /**
         * 测试把SecretKey文件的字节备份到NvRam下
         */
        btn1.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                byte[] a=utils.readFile(secret_filename); //读SecretKey文件
                utils.writeData(TEST_FILENAME, a); //把SecretKey文件的字节备份到NvRam下

                //byte[] b=utils.readData(TEST_FILENAME, 0, a.length);
            /*    if(!Arrays.equals(a, b)){
                    utils.writeData(TEST_FILENAME, a);
                }else{
                    Toast.makeText(MainActivity.this, "SecretKey Data has existed, no need to backup!", Toast.LENGTH_SHORT).show();
                }*/
            }
        });

        /**
         * 测试从NvRAM读SecretKey文件的字节
         */
        btn2.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                byte[] bytes=utils.readData(TEST_FILENAME,0,27);//测试从NvRAM读SecretKey文件的字节
                Toast.makeText(getApplicationContext(), "data = "+new String(bytes), Toast.LENGTH_LONG).show();
            }
        });

        /**
         * 测试写goc_database文件的字节到NvRAM
         */
        btn3.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                byte[] bytes=utils.readFile(goc_database); //goc_database文件的字节
                byte[] a=utils.readData(TEST_FILENAME,0,27); //读NvRAM下SecretKey文件的字节
                utils.writeData(TEST_FILENAME, utils.combineBytes(a, bytes));           
            }
        });

        /**
         * 测试写到NvRAM下的goc_database文件字节是否与原文件goc_database是否一样。
         */
        btn4.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub              
                byte[] bytes=utils.readFile(goc_database); //读goc_database文件
                byte[] b=utils.readData(TEST_FILENAME, 27, bytes.length); //读NvRAM下的goc_database字节
                utils.writeFile("/storage/emulated/0/goc_database2", b);    //把NvRAM下的goc_database字节写到goc_database2文件,  goc_database2文件与原文件goc_database比对,发现是相同的。                   
            }
        });
    }


}

JDRead1

硬件

CPU:  Onyx i.MX 6SoloLite
[ro.hardware]: [freescale]
ro.product.manufacturer]: [Onyx]
[ro.build.fingerprint]: [Onyx/JDRead/JDRead:4.4.2/2018-06-29_16-28_r3_a9ff2db/371:user/dev-keys]

开启USB调试
(0)联网
开启JDRead1,连接WiFi

(1)设置密码为0423
设置-设备名称-密码设置:密码输入0423,手机号输入自己的手机号。
为什么设置密码为 0423, 请看 https://www.senventise.com/posts/jdread1-exploit/

(2)开启开发者权限
设置-设备名称-设备信息:连续点击系统版本,直到显示“已开启开发者权限”。

https://www.cnblogs.com/arbo/p/14619813.html

用kingroot进行root
jdread1小白教程及软件v2.2.zip

提醒: 不要替换 services.jar

Kindle Paperwhite 3

型号: DP75SDI
属于 Kindel的 第七代 产品

2015 年 6 月 17 日,亚马逊上架了全新 Kindle Paperwhite(KPW3)电子书阅读器。像素 300 ppi, RAM增大了一倍,也就是说运行速度也会有较大提升,但Storage依然是 4GB。 这款新机在亚马逊中国上的预订价格为 958 元,2015 年 6 月 30 日正式发货。

Jailbreak
参考资料:
https://www.mobileread.com/forums/showthread.php?t=225030
https://bookfere.com/post/892.html
https://bookfere.com/post/311.html
https://bookfere.com/post/59.html

设备信息
序列号 G090 G1
固件版本 5.8.11
硬件 Hardware : Freescale i.MX 6SoloLite based Wario Board

步骤:
1. 通过序列号 确定型号
(G090G1 Kindle PaperWhite 3 (2015) WiFi PW3 型号)
可以root / jailbreak

2. 充满电

3. 关掉密码 , 关掉家长控制

4. 开启 飞行模式,关闭3G/WiFi


更新到 5.12.3 固件 https://s3.amazonaws.com/firmwaredownloads/update_kindle_all_new_paperwhite_5.12.3.bin

固件文件名:update_kindle_all_new_paperwhite_5.12.3.bin
MD5 校验码:e4d7ff60132c58448b0c1b31d5961b12
SHA1 校验码:ff8cf3a93ce37f6adf7c12b5166f73dc0ba929fe

6. 下载 kindle-jb-kindlebreak-1.0-r18327.tar.xz

下载 jb-kindlebreak.zip 并解压,得到下列四个文件,把它们全部拷贝到 Kindle 根目录(所谓根目录,就是那个目录下有一个叫documents的子目录)

kindlebreak.jxr
kindlebreak.html
jb.sh
jb

接着点击 Kindle 右上角的菜单按钮,进入“体验版网页浏览器(Experimental Browser)”。

请务必确保“浏览器设置”中的图片设置处于启用状态,也就是显示“禁用图片(Disable Images)”字样。如显示的是“启用图片(Enable Images)”字样,你需要点击启用,以确保浏览器能够正常解析图片。

最后输入如下所示的文件地址(注意 file:/// 是一个冒号三个斜杠):

file:///mnt/us/kindlebreak.html

如果一切正常,Kindle 会在数秒至数分钟后自动重启(时长取决于不同设备)。重启完毕越狱便告成功。之前放进去的文件会被自动清理,你会在 Kindle 根目录看到一个日志文件 kindlebreak_log.txt。

7. 安装热修复补丁 JailBreak-1.16.N-FW-5.x-hotfix.zip

Jailbreak Hotfix 的具体安装步骤如下:

(1)用 USB 数据线把 Kindle 连接到电脑,直到出现 Kindle 盘符;
(2)解压缩下载到的 ZIP 压缩包 JailBreak-x.xx.N-FW-5.x-hotfix.zip,得到一个名为 Update_jailbreak_hotfix_x.xx.N_install.bin 的文件;
(3)将此 bin 文件拷贝到 Kindle 磁盘根目录,然后从电脑弹出 Kindle;
(4) 依次在 Kindle 中点击【菜单 → 设置 → 菜单 → 更新您的 Kindle】,等待重启;

8. 安装 MobileRead Package Installer (MRPI)

(1)用 USB 数据线将 Kindle 连接到电脑上,直到出现 Kindle 磁盘;
(2) 解压缩下载到的 kual-mrinstaller-1.7.N-xxx.tar.xz 得到一个文件夹;
(3)把文件夹内的 extensions 和 mrpackages 拷贝到 Kindle 的根目录。
(4)从电脑上断开 Kindle磁盘,重启Kindel

注意,如果根目录已有 extensions 这个文件夹,可以只把解压得到的 extensions 文件夹中的内容拷贝到 Kindle 根目录原有的 extensions 文件夹内,以避免原文件夹内的其它文件被删除。

9. 安装 KUAL ( Kindle Unified Application Launcher)
(1) 用 USB 数据线将 Kindle 连接到电脑上,直到出现 Kindle 磁盘;
(2) 如果没有安装MRPI, 先按照第8步的方法安装 MobileRead Package Installer (MRPI);
(3) 然后解压缩下载到的 KUAL-v2.x.xx-xxxxxxxx-20xxxxxx.tar.xz 得到一个文件夹;
在文件夹中找到 Update_KUALBooklet_v2.x.xx_install.bin 文件,拷贝到 Kindle 根目录下的 mrpackages 文件夹,然后在 Kindle 搜索框中输入 ;log mrpi 点击回车;
这时会调用 mrpi 安装 KUAL,安装完成并等待 Kindle 重启完毕后即可使用 KUAL。

10. 安装 Koreader

首先确保安装了 MRPI 和 KUAL;
用 USB 数据线将 Kindle 连接到电脑上,直到出现 Kindle 磁盘;
解压缩下载到的 Koreader 压缩包,可得到 extensions 和 koreader 两个文件夹;
先把文件夹 extensions 中的内容拷贝到 Kindle 根目录下的 extensions 文件夹中;
然后把文件夹内的 koreader 文件夹拷贝到 kindle 根目录下;
通过 KUAL 菜单中启动 Koreader 并用它的文件浏览器打开并阅读电子书。

11. 安装 USBNetwork

(1)首先确保安装了 MRPI 和 KUAL;
(2)用 USB 数据线将 Kindle 连接到电脑上,直到出现 Kindle 磁盘;
(3) 解压缩下载到的 kindle-usbnet-0.xx.N-rxxxxx.tar.xz 压缩包,得到一个文件夹;
(4) 把文件夹内的 Update_usbnet_0.xx.N_install_pw2_and_up.bin 拷贝到 Kindle 里 mrpackages 文件夹中;
(5)弹出 Kindle 磁盘,进入 Kindle 界面,打开 KUAL,依次点击菜单【Helper → Install MR Packages】(或在搜索栏输入 ;log mrpi 并回车);
耐心等待 USBNetwork 安装,直到安装完成后 Kindle 重启完毕;

配置 USBNetwork
修改配置文件

重启完成后,可以在 Kindle 根目录可以看到 usbnet 文件夹。首先将此文件夹中的文件 DISABLED_auto 重命名为 auto。然后在此文件夹里的 etc 文件夹中找到配置文件 config,并用代码编辑器(如 Sublime Text)将其打开。找到 USE_WIFI 和 USE_WIFI_SSHD_ONLY 两个配置项,将两者的值从默认的 false 修改为 true(注意,两者都要改成 true),保存并关闭。

USE_WIFI="true"
USE_WIFI_SSHD_ONLY="true"

如果不将USE_WIFI_SSHD_ONLY 改为true, 会导致 将kindel通过usb插入电脑时, 不识别 Kindle 磁盘

创建密钥

ssh-keygen -t rsa -f ~/Desktop/KindleKey

会在你的桌面上会出现 KindleKey 和 KindleKey.pub 两个文件,把其中的 KindleKey.pub 重命名为 authorized_keys,并拷贝到 usbnet 插件目录中的 etc 文件夹中。

ssh登陆到kindle

ssh -i KindleKey root@192.168.xxx.xxx

在 Kindle 搜索框中输入 ;711 可以看到 Kindel分配到IP地址

红米Note 10 Pro启动modem分析

Redmi Note 10 Pro
天玑1100
CPU型号为 MT6891Z/CZA
( MT6885,天玑1000L, 联发科的首款5G芯片)

sysfs

/sys/kernel/ccci
/sys/class/ccci_node/ccci_ccb_meta
/sys/class/ccci_node/ccci_ccb_md_monitor
/sys/class/ccci_node/ccci_raw_mdm
/sys/class/ccci_node/ccci_mdl_monitor

/sys/class/ccci_md_sta/ccci_md1_sta
/sys/firmware/devicetree/base/mddriver/ccci,modem_info_v2

代码

drivers/misc/mediatek/ccci_util/ccci_util_lib_load_img.c

drivers/misc/mediatek/ccci_util/ccci_util_lib_sys.c


drivers/misc/mediatek/eccci/ccci_core.c
    ccci_init(void)



drivers/misc/mediatek/eccci/mt6885/ccci_platform.c
     ccci_plat_common_init


配置地址

drivers/misc/mediatek/eccci/ccci_modem.c
void ccci_md_config(struct ccci_modem *md)
{
	phys_addr_t md_resv_mem_addr = 0,
		md_resv_smem_addr = 0, md1_md3_smem_phy = 0;
	unsigned int md_resv_mem_size = 0,
		md_resv_smem_size = 0, md1_md3_smem_size = 0;
	int amms_pos_size = 0;
	phys_addr_t bank4_phy_addr;
......
......
	/* Get memory info */
	get_md_resv_mem_info(md->index, &md_resv_mem_addr,
		&md_resv_mem_size, &md_resv_smem_addr, &md_resv_smem_size);
	get_md1_md3_resv_smem_info(md->index, &md1_md3_smem_phy,
		&md1_md3_smem_size);
	/* setup memory layout */
	/* MD image */
	md->mem_layout.md_bank0.base_ap_view_phy = md_resv_mem_addr;
	md->mem_layout.md_bank0.size = md_resv_mem_size;
	/* do not remap whole region, consume too much vmalloc space */
	md->mem_layout.md_bank0.base_ap_view_vir =
		ccci_map_phy_addr(
			md->mem_layout.md_bank0.base_ap_view_phy,
			MD_IMG_DUMP_SIZE);
	/* Share memory */
	/*
	 * MD bank4 is remap to nearest 32M aligned address
	 * assume share memoy layout is:
	 * |---AP/MD1--| <--MD1 bank4 0x0 (non-cacheable)
	 * |--MD1/MD3--| <--MD3 bank4 0x0 (non-cacheable)
	 * |---AP/MD3--|
	 * |--non-used_-|
	 * |--cacheable--| <-- MD1 bank4 0x8000000 (for 6292)
	 * this should align with LK's remap setting
	 */



eccci/modem_sys1.c
    ccci_set_mem_access_protection_1st_stage(md);


eccci/fsm/ccci_fsm.c

    ccci_set_mem_access_protection_second_stage








modem firmware的结构
代码位于 drivers/misc/mediatek/ccci_util/ccci_util_lib_load_img.c



#define IMG_MAGIC		0x58881688
#define EXT_MAGIC		0x58891689

#define IMG_NAME_SIZE		32
#define IMG_HDR_SIZE		512
union prt_img_hdr {
	struct {
		/* always IMG_MAGIC */
		unsigned int magic;
		/* image size, image header and padding are not included */
		unsigned int dsize;
		char name[IMG_NAME_SIZE];
		/* image load address in RAM */
		unsigned int maddr;
		/* maddr is counted from the beginning or end of RAM */
		unsigned int mode;
		/* extension */
		/* always EXT_MAGIC */
		unsigned int ext_magic;
		/* header size is 512 bytes currently,
		 * but may extend in the future
		 */
		unsigned int hdr_size;
		/* see HDR_VERSION */
		unsigned int hdr_version;
		/* please refer to #define beginning with SEC_IMG_TYPE_ */
		unsigned int img_type;
		/* end of image list?
		 * 0: this image is followed by another image
		 * 1: end
		 */
		unsigned int img_list_end;
		/* image size alignment setting in bytes,
		 * 16 by default for AES encryption
		 */
		unsigned int align_size;
		/* high word of image size for 64 bit address support */
		unsigned int dsize_extend;
		/* high word of image load address in RAM
		 * for 64 bit address support
		 */
		unsigned int maddr_extend;
	} info;
	unsigned char data[IMG_HDR_SIZE];
};