2017年8月27日日曜日

完全文鎮と化したFireタブレットのリカバリ その2



続きです。

先の記事で説明した通り、adbコマンドもfastbootコマンドもリカバリも使えないFireでも、preloaderからイメージファイルを焼き直せば復活が可能です。本記事ではその手順をご紹介します。


おおまかな手順は以下の通り。


1. preloader用のドライバを導入してDownload Modeに入る
2. 端末の全てのパーティションアドレスを読み込む
3. バイナリエディタを使ってuboot領域、recovery領域、tee1領域のアドレスを識別する
4. 識別したアドレスに正しいイメージファイルを書き込む
5. TWRPを起動して正しいOSを焼く

では詳しい説明に入ります。


必要なもの一覧

aftv2-toolsのダウンロード
正しいブートイメージのダウンロード
(下の方にある453_padded_img.zipってヤツ)
Pythonのインストール
Hex editorのインストール


1. preloader用のドライバを導入してDownload Modeに入る


まずはこちらのサイトからaftv2-toolsというFire TV用のToolkitをダウンロードして下さい。もともとFire TVのroot化に使うToolkitですが、OS依存のToolkitなのでFireでも問題なく転用できました。ダウンロードしたら好きなところに展開しておきましょう。


その中にwin-driversというフォルダがあります。そこに入っているのがpreloader用のドライバです。ここからは、これをインストールする手順を説明します。
ただし、このドライバは無署名のドライバなので、通常はセキュリティブロックがかかってインストールすることが出来ません。そのため、無署名でもインストールできるモードでPCをリブートする必要があります。ここらへんは割愛するので各自調べてください。


まずはFireをPCに接続しましょう。ブートループして切断・接続を繰り返すと思いますが、デバイスマネージャで監視すると、接続されている数秒間はpreloaderが認識されていると思います。それを右クリックし、ドライバの更新を行ってください。ドライバのファイルにはinfファイルが3つ入っていると思いますが、私はmdmcpq.infで上手くいきました。



これでドライバの導入は終了です。


ただし、ドライバを導入しただけでは、ただFireを接続しても依然ブートループします。どうやらDownload Modeに入るためには、PCからpreloaderに「PCと接続してDownload modeに入れ」と指令することが必要なようです。
ここからは、Download Modeへの入り方を簡単に説明します。


Download Modeに入るためには、aftv2-toolsに同梱されている「handshake.py」を使うのですが、拡張子から見てもわかるように、こちらのプログラムはPythonというプログラミング言語で書かれていますので、Pythonをインストールする必要があります。公式サイトからダウンロードし、インストールを行ってください。


Pythonをインストールしたら、これからの操作に必要なモジュールをPythonにインストールします。コマンドプロンプトに以下の2つを入力して実行しましょう。

python -m pip install pyserial
python -m pip install py2exe

プログレスバーのようなものが出てインストールが完了するはずです。もしエラーが出れば、コマンドの「Python」の部分を「Python3」に変えれば上手くいくかもしれません。


ここまでの操作が終わったら、先述のhandshake.pyをFireを接続する前に起動させておきます。コマンド画面にwaiting for preloader...と表示されたらFireを接続して下さい。Download Modeに入ることが出来ます。






2.端末の全てのパーティションアドレスを読み込む


いわゆるHard Brick(完全文鎮)状態のFireでは、ブートローダーが死んでいるか、ブートローダーが生きていても起動させるモノが存在しません。よって、復活させるためにはひとまず正しいリカバリとブートローダーを上書きしてやる必要があります。


TWRPなどのカスタムリカバリがあれば、書き込むべきパーティションを自動で判別して適切な場所にイメージを書き込んでくれるので楽なのですが、この状態の文鎮になるとそういう便利な機能なんて生きてるはずもありません。パーティションのアドレスを全て読み込み、リカバリ領域とブート領域がどれか識別し、そこに正しいイメージを焼く…という手順を踏まなければなりません。


幸いなことに、aftv2-toolsの中にパーティションの読み込みをするプログラムは準備されています。それを実行すれば読み込みはすぐに終わります。まあ、あとの識別が大変なんですけどね…


aftv2-toolsを開いたら、そこでコマンドプロンプトを開いてください。

開いたら次のコマンドを実行。ターミナル画面がすごい速度で進むのが分かると思います。


read_mmc.py  0x0000000  0x1000  0x0000000.part
read_mmc.py  0x0080000  0x1000  0x0080000.part
read_mmc.py  0x0100000  0x1000  0x0100000.part
read_mmc.py  0x0180000  0x1000  0x0180000.part
read_mmc.py  0x0200000  0x1000  0x0200000.part
read_mmc.py  0x0280000  0x1000  0x0280000.part
read_mmc.py  0x0300000  0x1000  0x0300000.part
read_mmc.py  0x0380000  0x1000  0x0380000.part
read_mmc.py  0x0400000  0x1000  0x0400000.part
read_mmc.py  0x0480000  0x1000  0x0480000.part
read_mmc.py  0x0500000  0x1000  0x0500000.part
read_mmc.py  0x0580000  0x1000  0x0580000.part
read_mmc.py  0x0600000  0x1000  0x0600000.part
read_mmc.py  0x0680000  0x1000  0x0680000.part
read_mmc.py  0x0700000  0x1000  0x0700000.part
read_mmc.py  0x0780000  0x1000  0x0780000.part
read_mmc.py  0x0800000  0x1000  0x0800000.part
read_mmc.py  0x0880000  0x1000  0x0880000.part
read_mmc.py  0x0900000  0x1000  0x0900000.part
read_mmc.py  0x0980000  0x1000  0x0980000.part
read_mmc.py  0x0a00000  0x1000  0x0a00000.part
read_mmc.py  0x0a80000  0x1000  0x0a80000.part
read_mmc.py  0x0b00000  0x1000  0x0b00000.part
read_mmc.py  0x0b80000  0x1000  0x0b80000.part
read_mmc.py  0x0c00000  0x1000  0x0c00000.part
read_mmc.py  0x0c80000  0x1000  0x0c80000.part
read_mmc.py  0x0d00000  0x1000  0x0d00000.part
read_mmc.py  0x0d80000  0x1000  0x0d80000.part
read_mmc.py  0x0e00000  0x1000  0x0e00000.part
read_mmc.py  0x0e80000  0x1000  0x0e80000.part
read_mmc.py  0x0f00000  0x1000  0x0f00000.part
read_mmc.py  0x0f80000  0x1000  0x0f80000.part
read_mmc.py  0x1000000  0x1000  0x1000000.part
read_mmc.py  0x1080000  0x1000  0x1080000.part
read_mmc.py  0x1100000  0x1000  0x1100000.part
read_mmc.py  0x1180000  0x1000  0x1180000.part
read_mmc.py  0x1200000  0x1000  0x1200000.part
read_mmc.py  0x1280000  0x1000  0x1280000.part
read_mmc.py  0x1300000  0x1000  0x1300000.part
read_mmc.py  0x1380000  0x1000  0x1380000.part
read_mmc.py  0x1400000  0x1000  0x1400000.part
read_mmc.py  0x1480000  0x1000  0x1480000.part
read_mmc.py  0x1500000  0x1000  0x1500000.part
read_mmc.py  0x1580000  0x1000  0x1580000.part
read_mmc.py  0x1600000  0x1000  0x1600000.part
read_mmc.py  0x1680000  0x1000  0x1680000.part
read_mmc.py  0x1700000  0x1000  0x1700000.part
read_mmc.py  0x1780000  0x1000  0x1780000.part
read_mmc.py  0x1800000  0x1000  0x1800000.part
read_mmc.py  0x1880000  0x1000  0x1880000.part
read_mmc.py  0x1900000  0x1000  0x1900000.part
read_mmc.py  0x1980000  0x1000  0x1980000.part
read_mmc.py  0x1a00000  0x1000  0x1a00000.part
read_mmc.py  0x1a80000  0x1000  0x1a80000.part
read_mmc.py  0x1b00000  0x1000  0x1b00000.part
read_mmc.py  0x1b80000  0x1000  0x1b80000.part
read_mmc.py  0x1c00000  0x1000  0x1c00000.part
read_mmc.py  0x1c80000  0x1000  0x1c80000.part
read_mmc.py  0x1d00000  0x1000  0x1d00000.part
read_mmc.py  0x1d80000  0x1000  0x1d80000.part
read_mmc.py  0x1e00000  0x1000  0x1e00000.part
read_mmc.py  0x1e80000  0x1000  0x1e80000.part
read_mmc.py  0x1f00000  0x1000  0x1f00000.part
read_mmc.py  0x1f80000  0x1000  0x1f80000.part
read_mmc.py  0x2000000  0x1000  0x2000000.part
read_mmc.py  0x2080000  0x1000  0x2080000.part
read_mmc.py  0x2100000  0x1000  0x2100000.part
read_mmc.py  0x2180000  0x1000  0x2180000.part
read_mmc.py  0x2200000  0x1000  0x2200000.part
read_mmc.py  0x2280000  0x1000  0x2280000.part
read_mmc.py  0x2300000  0x1000  0x2300000.part
read_mmc.py  0x2380000  0x1000  0x2380000.part
read_mmc.py  0x2400000  0x1000  0x2400000.part
read_mmc.py  0x2480000  0x1000  0x2480000.part
read_mmc.py  0x2500000  0x1000  0x2500000.part
read_mmc.py  0x2580000  0x1000  0x2580000.part
read_mmc.py  0x2600000  0x1000  0x2600000.part
read_mmc.py  0x2680000  0x1000  0x2680000.part
read_mmc.py  0x2700000  0x1000  0x2700000.part
read_mmc.py  0x2780000  0x1000  0x2780000.part
read_mmc.py  0x2800000  0x1000  0x2800000.part
read_mmc.py  0x2880000  0x1000  0x2880000.part
read_mmc.py  0x2900000  0x1000  0x2900000.part
read_mmc.py  0x2980000  0x1000  0x2980000.part
read_mmc.py  0x2a00000  0x1000  0x2a00000.part
read_mmc.py  0x2a80000  0x1000  0x2a80000.part
read_mmc.py  0x2b00000  0x1000  0x2b00000.part
read_mmc.py  0x2b80000  0x1000  0x2b80000.part
read_mmc.py  0x2c00000  0x1000  0x2c00000.part
read_mmc.py  0x2c80000  0x1000  0x2c80000.part
read_mmc.py  0x0400000  0x4000              0x00a.part
read_mmc.py  0x0408000  0x4000        0xPRO_INFOa.part
read_mmc.py  0x0500000  0x4000             0xPMTa.part
read_mmc.py  0x0900000  0x1000            0xTEE1a.part
read_mmc.py  0x1300000  0x1000           0xUBOOTa.part
read_mmc.py  0x0780000  0x4000              0x00b.part
read_mmc.py  0x0788000  0x4000        0xPRO_INFOb.part
read_mmc.py  0x0880000  0x4000             0xPMTb.part
read_mmc.py  0x0c80000  0x1000            0xTEE1b.part
read_mmc.py  0x1680000  0x1000           0xUBOOTb.part
read_mmc.py  0x0a00000  0x4000              0x00c.part
read_mmc.py  0x0a08000  0x4000        0xPRO_INFOc.part
read_mmc.py  0x0b00000  0x4000             0xPMTc.part
read_mmc.py  0x0f00000  0x1000            0xTEE1c.part
read_mmc.py  0x1900000  0x1000           0xUBOOTc.part


コマンドが一通り終わると、拡張子が.partのファイルが大量に生成されます。それがあなたの端末のパーティション・アドレスの一覧です。


3. バイナリエディタを使ってuboot領域、recovery領域、tee1領域のアドレスを識別する


最難関です。


生成したpartファイルは通常のテキストエディタでは閲覧できないので、対応するエディタをインストールしてそこから閲覧します。エディタはこちらのサイトからどうぞ。


おそらく、ほとんどすべてのファイルは意味不明な文字列で埋め尽くされているか、あるいは全て空白かのどちらかだと思います。しかしたまに有意な英単語の文字列が入っているアドレスがあります。そこが特定のパーティションのアドレスなので、そこを指定して正しいイメージファイルを焼き焼きしてあげればいいワケです。今回だと、UBOOT領域(ブートローダー)、recovery領域(リカバリ)、Tee1領域(セキュリティ)の3つに上書きします。


しかし厄介なのが、このアドレスは機種によって微妙に(というか結構)異なります。私と同一機種で同一OS、つまりFireOS5.1.2を積んだFire HD7(第4世代)なら下と同じアドレスだと思いますが、機種が異なったり、OSがメジャーアップデート前/後のものだとアドレスが異なってくる可能性が高いです。
さらに厄介なことに、間違ったアドレスにイメージを焼くと、イメージが競合したりして今度こそ修復不可能な文鎮になってしまう恐れがあります。よって、ここから先は私のアドレスを受け売りして実行するのではなく、自分の端末に合ったアドレスに脳内変換してから操作を実行してください。



これがUBOOT領域です。LKと表示されているのがわかりますが、このLKとはLittle Kernelの略で、Fireが採用しているブートローダーの一種です。Fireの場合、ダウングレードによる文鎮化はここのコードの不整合によって起こることがほとんどです。
私の場合、アドレス0x1300000にありました。




これがrecovery領域です。Androidと書いてあるのが分かると思いますが、文鎮化前にカスタムリカバリを導入していた場合は、AndroidではなくCertISWなどと表示されているかもしれません。
私の場合、アドレス0x1b80000にありました。




これがboot領域です。UBOOT領域と何が違うのかよくわからないのですが、おそらくブートローダーの次に起動するkernelのようなものだと思います。今回はここに何かを上書きする必要はないのですが、ややこしいのは、ここもrecovery領域と同じく、文字列「Android」から始まるということ。
ただ、このboot領域はrecovery領域よりも先に読み込まれるものであるため、基本的にrecovery領域よりも前のアドレスに存在します。すなわち、どちらが先のアドレスにあるかでrecovery領域とboot領域を識別することが出来ます。私の場合はアドレス0x1380000にありました。




これがTee1領域です。Tee1はDRMキーなどの端末固有の情報が格納されている領域で、簡単に改竄されないようにOSとは別の領域に実装されています。つまり端末の最も最下層にあるセキュリティ・システムのようなものでしょうか。理由はよくわからないのですが、Fireの文鎮修理の際にはここも焼き直さないとダメみたい。
私の場合はアドレス0x0900000にありました。



以上が識別すべきパーティションのアドレスです。


4. 識別したアドレスに正しいイメージファイルを書き込む


ここは割と楽です。
aftv2-toolsのファイルにダウンロードしたイメージファイルを移動します。全て展開してファイルから取り出しておくこと。


次に、先と同じようにaftv2-toolsでコマンドプロンプトを開き、下のアドレスを入力してエンター。(xは自分のtee1のアドレス、yはUBOOTのアドレス、zはrecoveryのアドレスで置き換えてください。)



write_mmc.py xxxxxxxxx 453p_tee1.img
write_mmc.py yyyyyyyyy 453p_uboot.img
write_mmc.py zzzzzzzzz 453p_twrp.img


私は1時間ほどで終わりましたが、PCの処理性能によっては数時間かかるかもしれません。とにかくかなり時間はかかりますので、間違ってもPCやFireの電源を落とすことのないよう。


5. TWRPを起動して正しいOSを焼く

ここまでの操作が全て正しく行われていれば、TWRPが起動します。一旦電源を押し続けて完全に電源を落としてから、電源+ボリュームアップを長押しでTWRP起動。ボリュームダウンだったかも。起動すれば見事文鎮復活です。そこから先は煮るなり焼くなりお好きにどうぞ。


正直この記事はここで終わりでもいいのですが、まあ付録+備忘録としてRootの取り方も書いておきます。


なお、TWRPの使い方は他のサイトで紹介されているので詳しくは書きません。


まずは念のためCacheとDalvik Cacheを消去。

ここからは、まず少し古いFireOS4.5.3を焼きます。(古いOSの方がRootが取りやすいからというのもありますが、先ほど焼いたブートローダーがそもそも4.5.3用のものなので他のOSを焼いても起動しないと思います。あとあと5.3.1に戻すのでご心配なく。)


まずは、XDAのここのサイトから4.5.3のROMを入手してください(ついでに、後で使う5.3.1のROMもダウンロードしておきましょう)。ROMは拡張子がbinになっていると思いますので、TWRPが認識できるようzipにリネーム。

そうすればいつものようにTWRPに送ってインストールすればFire OS4.5.3なFireが起動します。
なお、ネットに繋いだまま放っておくと勝手にOTAアップデートが始まってしまいますので、Rootが必要ならWi-Fiは切っておきましょう。初めのユーザー情報も入力しなくていいです。Rootが要らない場合はそのままOTAでアップデートしちゃってください。


次はKingRootでrootを取ります。セキュリティが不安という方もいらっしゃるかもしれませんが、どうせここからまたROMを焼き直すワケですから、初回の起動で個人情報を入力していなければ問題ないと思います。
kingrootはいろんなサイトで出回っていますので、ウイルスのなさそうなサイトから落としてきてインストール。そこからはアプリの指示に従えばRootがすぐに取れるはずです。


Rootが取れたら、Root権限を維持したまま最新版のROMを焼くため、再びTWRPをインストールします。これは、Fireは、仕様上ROMを焼くたびにリカバリがデフォルトのものに焼き替えられてしまうためです。
こちらのサイトからTWRPをインストールするバッチファイルを入手し、展開してから1_FIRE_HD_4TH_GEN_TWRP.batを実行しましょう。端末側でスーパーユーザーリクエストが出ると思いますので、Allowを選択。これでTWRPがインストールされます。


TWRPを起動したら、最新版のROMを焼きます。
まずは必要なファイルを端末に転送してしまいましょう。必要なものは以下の通りです。

先ほどダウンロードした5.3.1なROM
5.3.1用のブートローダー
SuperSU(apkではなくzip)

転送したら上から順番にインストールしていきましょう。Gappsもこの時入れられればラクなんですが、私はエラーが出てインストール出来ませんでした。Playストアはあとでもインストール出来るので妥協。


これでRoot権限取得済みのFireOS5.3.1なFireの完成です。