iPhone 5sをiOS 10.3.3へダウングレード

iOS 12.4.5状態だったiPhone 5sをiOS 10.3.3へ落としたときのメモ．
<font color="Crimson">当然の事ながらオフィシャルにはできない事を脆弱性を突いて行なう脱獄系なので，**自己責任**です．</font>

※220214 最後に[追記](#追記)

# 最終的にやったこと

Mac (Sierra)にて

https://ipsw.me/

IPSW Downloadsから
iPhone→iPhone 5s (GSM)→iOS 10.3.3 (14G60)
でiPhone_4.0_64bit_10.3.3_14G60_Restore.ipswを落とし，DFUモードでiPhoneを繋いでVieuxを走らせた．

https://github.com/MatthewPierson/Vieux

# 経緯
ホンダのカオパネという32bitアプリが更新されず，64bitしか動かないiOS 11以降では動作しなくなっている．
とうの昔にサポート終了してるので仕方ないが，（とは言えサポート終了はiOS 11リリース後なので対応してほしかった所）
I-O DATAのNVSPH-1経由でインターナビを使っている身としてはとても困る．
Android版に至ってはもうGoogle Playから消滅してた気がする．

仕方がないので手持ちのiPad mini 4 (MK782J/A)を10.3.3から上げずにキープしているのだが，iOSは頻繁に「アプデあるよ！」と迫ってくるので間違って更新してしまいそうで非常に怖い．
（切ることはできないので，かつデータを消してもまたWiFi接続中に入手していらっしゃるので，わざとストレージをギリギリまで音楽で埋めておくなどしてイメージが落ちてこないようにしたり…）

そこで保険も兼ね，余っているiPhone 5s（既にiOS 12.x）も使えるようにしておくことにした．

[App Store カオパネ](https://apps.apple.com/jp/app/%E3%82%AB%E3%82%AA%E3%83%91%E3%83%8D/id633810422)

https://apps.apple.com/jp/app/%E3%82%AB%E3%82%AA%E3%83%91%E3%83%8D/id633810422

[2018/02/05 スマートフォンアプリ「カオパネ」サポート終了のご案内](https://www.honda.co.jp/internavi/caution_1802/)

https://www.honda.co.jp/internavi/caution_1802/

[スマートフォン インターナビアダプター NVSPH-1](https://www.iodata.jp/product/tsushin/caradp/nvsph-1/)

https://www.iodata.jp/product/tsushin/caradp/nvsph-1/


# 試したこと（失敗）

色々試したものの，ことごとく失敗していった

## iPwnder32 + futurerestore （build済みバイナリ）

https://reras-factory.com/a7-1033downgrade/

↑コチラの記事を見て「イケるのでは？」と諸々を開始．
Releasesのビルド済みバイナリ群で試す限り，iPwnder32で

```sh
$ ./iPwnder32 -p -f
** iPwnder32 - RELEASE v3.2.0 [3C152] by @dora2ios
Waiting for device in DFU mode...
DFU device infomation iPhone 5s (GSM) [iPhone6,1]
CPID:0x0000 CPRV:0x00 BDID:0x00 ECID:0x0000000FFFFFFFFF CPFM:0x00 SCEP:0x00 IBFL:0x00
SRTG:[iBoot-1704.10] PWND:[checkm8]
exploiting with checkm8
This device is already in pwned DFU mode!
```
大体こんな感じでpwnedDFUには入れるっぽいが，

```sh
$ ./futurerestore -t ticket.shsh2 -b Mav7Mav8-7.60.00.Release.bbfw -s sep-firmware.n51.RELEASE.im4p -p BuildManifest_iPhone6,1_1033_OTA.plist -m BuildManifest_iPhone6,1_1033_OTA.plist --use-pwndfu iPhone_4.0_64bit_10.3.3_14G60_Restore.ipsw
Version: 38b168002bca318c91068fc194abd36e2d54f155 - 180
Libipatcher Version: 18cf8be6788f7e7ad96dac805724b8db7afcb9b0 - 69
Odysseus for 32-bit support: yes
Odysseus for 64-bit support: yes
[INFO] 64-bit device detected
futurerestore init done
reading signing ticket ticket.shsh2 is done
.
.
.
Sending iBSS (164896 bytes)...
[==================================================] 100.0%
Sending iBEC (648224 bytes)...
[==================================================] 100.0%
waiting for device to reconnect...
Cleaning up...
[exception]:
what=Device did not reconnect. Possibly invalid iBEC. Reset device and try again
code=34471953
line=526
file=futurerestore.cpp
commit count=29:
commit sha =2994651a10d8176a298b31e7706b4b6af97975d1:
Done: restoring failed!
```
こんな感じでfuturerestoreで失敗してしまう．

## iPwnder32 + futurerestore （自前build）

Sierraなのも悪影響したかも知れないため，futurerestoreの自前buildを試みた．

https://github.com/tihmstar/futurerestore

brewで入らない（失敗するor転がっていない）Dependenciesを全て自前buildし始めた．
…のだが，よくあるOpenSSLのリンク問題にぶち当たって

```sh
export PATH=/usr/local/Cellar/openssl\@1.1/1.1.1k/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/Cellar/openssl\@1.1/1.1.1k/lib:$LD_LIBRARY_PATH
export CPATH=/usr/local/Cellar/openssl\@1.1/1.1.1k/include:$CPATH
export LDFLAGS=-L/usr/local/Cellar/openssl\@1.1/1.1.1k/lib
export CPPFLAGS=-I/usr/local/Cellar/openssl\@1.1/1.1.1k/include
export PKG_CONFIG_PATH=/usr/local/Cellar/openssl\@1.1/1.1.1k/pkgconfig:$PKG_CONFIG_PATH
```
してみたり，libgeneralのbuild結果のバージョンがどうしても1.0.0になってしまって参照時のバージョン依存関係で弾かれてしまい，理由を探していると

```sh:libgeneral.pc.in
Version: @VERSION_COMMIT_COUNT@
```
「あ，`git clone`じゃないと駄目なのね」ってことに気付いたり，libinsnのmake時には

```sh
../include/libinsn/INSNexception.hpp:17:11: note: candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 5 were provided
insn_decode.cpp:818:13: error: no matching constructor for initialization of 'tihmstar::INSNexception'
            reterror("failed to get rt2");
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/include/libgeneral/macros.h:88:43: note: expanded from macro 'reterror'
#   define reterror(errstr ...) do{ throw tihmstar::EXPECTIONNAME(VERSION_COMMIT_COUNT, VERSION_COMMIT_SHA, __LINE__, __FILE__, errstr); } while(0)
                                          ^                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../include/libinsn/INSNexception.hpp:19:9: note: candidate constructor not viable: no known conversion from 'const char [1]' to 'int' for 1st argument
        INSNexception(int code, const char *filename, const char *err ...) : tihmstar::exception(code,filename,err){}
        ^
../include/libinsn/INSNexception.hpp:17:11: note: candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 5 were provided
    class INSNexception : public tihmstar::exception{
          ^
../include/libinsn/INSNexception.hpp:17:11: note: candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 5 were provided
fatal error: too many errors emitted, stopping now [-ferror-limit=]
4 warnings and 20 errors generated.
make[2]: *** [libinsn_la-insn_decode.lo] Error 1
make[1]: *** [all-recursive] Error 1
make: *** [all] Error 2
```
こんな大量のエラーに出くわしたり，liboffsetfinder64のmake時には

```sh
clang: error: unable to execute command: Segmentation fault: 11
clang: error: clang frontend command failed due to signal (use -v to see invocation)
Apple LLVM version 9.0.0 (clang-900.0.39.2)
Target: x86_64-apple-darwin16.7.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
clang: note: diagnostic msg: PLEASE submit a bug report to http://developer.apple.com/bugreporter/ and include the crash backtrace, preprocessed source, and associated run script.
clang: note: diagnostic msg:
```
となってしまったり（コレは多分Sierraな影響でXcodeが古いせい），
futurerestore.cpp内の`%"PRIu64"`がうまく解釈されず暫定で書き換えたり，その他諸々何やかんや大変だった上に**結局無理だった**．


## 1033-OTA-Downgrader

自前buildが面倒になってきつつ色々調べてる間に

https://twitter.com/moski_dev/status/1182636614113058817?s=20

こんなTweetを見付けたので，

https://github.com/MatthewPierson/1033-OTA-Downgrader/

を試してみることにした．
（しっかり"NO LONGER MAINTAINED, USE VIEUX INSTEAD!"と書いてあるんだけど，ココまでの流れでmacOSの古さが影響している気がしていたため，そのまま古いものを試した．）

…が，結局

```sh
./restore.sh /xxx/iPhone_4.0_64bit_10.3.3_14G60_Restore.ipsw
```
で実行しているのは，各ツールを`git clone`して`./autogen.sh`して`make`と`make install`という流れなわけで，iPwnder32がipwndfu_publicな点以外は基本的に[自前build時](#ipwnder32--futurerestore-自前build)と同じであり，同様の問題にぶつかっただけであった．

ちなみに遭遇したのは
<details><summary>こんな出力</summary><div>

```terminal
ERROR: Device is in an invalid state
[INFO] 32-bit device detected
futurerestore: failed with exception:
[exception]:
what=can't init, no device found

code=13697032
line=209
file=main.cpp
commit count=29:
commit sha  =2994651a10d8176a298b31e7706b4b6af97975d1:
Cleaning up :D
If you see this, we're done! Shoutout to the devs and Matty for making this possible! - Merculous
P.S. You know, this could look even better and be even easier if we port it to Python :D
```
</div></details>とか
<details><summary>こんなの</summary><div>

```terminal
Supported Device
iPhone6,1
Supported device found.
Done prepping files! Time to downgrade!!!
****RESTORING!****
Waiting for device to reconnect...
Version: 38b168002bca318c91068fc194abd36e2d54f155 - 180
Libipatcher Version: 18cf8be6788f7e7ad96dac805724b8db7afcb9b0 - 69
Odysseus for 32-bit support: yes
Odysseus for 64-bit support: yes
[INFO] 64-bit device detected
futurerestore init done
reading signing ticket shsh/apnonce.shsh2 is done
[TSSC] opening manifests/BuildManifest_iPhone6,1_1033_OTA.plist
[TSSR] User specified doesn't to request a baseband ticket.
Request URL set to https://gs.apple.com/TSS/controller?action=2
Sending TSS request attempt 1... response successfully received
Did set SEP+baseband path and firmware
ERROR: Unable to connect to device?!
ERROR: Unable to get FirmwarePreflightInfo
[WARNING] failed to read BasebandGoldCertID from device! Is it already in recovery?
[WARNING] using tsschecker's fallback to get BasebandGoldCertID. This might result in invalid baseband signing status information
[TSSC] opening manifests/BuildManifest_iPhone6,1_1033_OTA.plist
[TSSR] User specified to request only a Baseband ticket.
Request URL set to https://gs.apple.com/TSS/controller?action=2
Sending TSS request attempt 1... response successfully received
Found device in DFU mode
futurerestore: failed with exception:
[exception]:
what=unsupported device mode, please put device in recovery or normal mode

code=9895953
line=151
file=futurerestore.cpp
commit count=29:
commit sha  =2994651a10d8176a298b31e7706b4b6af97975d1:
Cleaning up :D
If you see this, we're done! Shoutout to the devs and Matty for making this possible! - Merculous
P.S. You know, this could look even better and be even easier if we port it to Python :D
```
</div></details>とかで，"we're done!"とか言ってるけどできてないです．


# 試したこと（成功）

[冒頭](#最終的にやったこと)の通りであるが，[1033-OTA-Downgrader](#1033-ota-downgrader)で駄目だったのでVieuxを試してみることにした．

https://github.com/MatthewPierson/Vieux

README.mdにある通りだが，基本的には，落としてきて

```sh
pip3 install -r requirements.txt
```
でPython3関連の依存ライブラリを入れ，

```sh
./vieux -i /xxx/iPhone_4.0_64bit_10.3.3_14G60_Restore.ipsw
```
という感じで用意したファームウェアを指定するだけでフルオートにスクリプトでやり切ってくれる．
ちなみにvieuxってのはバイナリではなく，.pyが無いけど普通のPythonコードなので，うまく行かなかったら`python3 vieux xxx`という感じで普通にPythonを走らせれば良いと書いてある．（自分の環境では頭に付けなくともちゃんとPythonが立ち上がっていた）

なお，必要なバイナリは全て同梱されているので，`make`などは不要．
（結果的にはこれで成功したわけなので，手順にいくつか足りない部分があっただけで，ちゃんとやれば[Releasesのビルド済みバイナリ群](#ipwnder32--futurerestore-build済みバイナリ)の段階で成功させられたのでしょう．）

手打ちしていく場合はipswからMav7Mav8-7.60.00.Release.bbfwやsep-firmware.n51.RELEASE.im4pを引っ張り出したりBuildManifest_iPhone6,1_1033_OTA.plistを落としてきたりしなければならないし，ECIDを調べて

```sh
./tsschecker -d iPhone6,1 -e 対象ECID -i 10.3.3 -o -s
```
でOTA SHSH blobsを用意したりもあったが，その辺りも全てフルオート．
ECIDを調べる所すら勝手にやってくれている模様．（device.pyの処理を見る限り，ipwndfuのdfu.pyから引っ張ってきているが，さらにその元になっているのはpyusbとの事．USBデバイスとして認識した際に読み取れるserial_number内に入っているってことかな．）

## 一部躓いた所

最初の実行時，

```sh
AttributeError: 'array.array' object has no attribute 'fromstring'
Segmentation fault: 11
```
という

https://github.com/MatthewPierson/Vieux/issues/203

まんまこのIssueにあるエラーが出た．
回答に[「3.8だとどう？」](https://github.com/MatthewPierson/Vieux/issues/203#issuecomment-735800695)だとか[「3.8に完全置換ダウングレードしたら解決した」](https://github.com/MatthewPierson/Vieux/issues/203#issuecomment-816846985)とあるので，素直に3.8で実行することにした．
ただし元の状態を壊す気はないので，3.9を消して完全に置き換えるなんてのは却下．
とりあえずpyenvで切り替えることにした．

確認すると

```sh
$ python -V
Python 2.7.10
$ python3 -V
Python 3.9.5
```
確かに3.9.xだったので，pyenvを入れ，

```sh
$ pyenv init
```
して`~/.bash_profile`の設定も指示通りに行ない，どれを入れようかと

```sh
$ pyenv install --list
```
を見ると，3.8と言っても3.8.0～3.8.9まで選べてどれが良いのかわからない．
とりあえず3.9で駄目なのだから一番遠いもの，ということで3.8.0をインストール．

```sh
$ pyenv install 3.8.0
```
入ったことの確認と切り替えを行ない，

```sh
$ pyenv versions
* system (set by /Users/xxx/.pyenv/version)
  3.8.0
$ pyenv global 3.8.0
$ pyenv versions
  system
* 3.8.0 (set by /Users/xxx/.pyenv/version)
```
パスが通っているかも確認し，

```sh
$ python -V
Python 3.8.0
```
この3.8.0環境でrequirementsのインストールとvieuxの実行を行なうと，[正常にダウングレードできた](##最終出力)．


## 最終出力

DFUモード（リカバリモードではない．画面が真っ暗な方）でiPhone5sを繋ぎ，vieuxをipswへのパスを指定して実行．

```sh
$ ./vieux -i /xxx/iPhone_4.0_64bit_10.3.3_14G60_Restore.ipsw
                                                                       
                                                                                                             
                                               /(//* /                         
                                            /(%@&/*((//*/                      
                                         (((((* %(&@@(*,///                    
                                       ((,((((((((/%%/,/(///                   
                                     ((((((((/*.((((////////**                 
                                    (((((((((((((((((///////**.                
                                    ((((((((((((((((//////*** .                
                                    ((((((((((((((//*//(%#(/*..               
                                    (((((((((((////** /%%#(* .                 
                                     (////////////**..##(/* ..                
                                    *(/*******,,,,...,* ,...***.               
                                   *(((&@@*.......*/***/////(//*////           
                               *** /((#@@@@@@@@@@@@@@@(///(((/**/*///          
                             #&(***/((%@@@@@@@@@@@@@@@(/((((// *****           
                            ((((%(*/((#@@@@@@@@@@@@@@@@((((//****              
                             (((((////(&@@@@@@@@@@@@@(((((//*,,,,           
                              ((((.//* %&&@@&&@@&((((////,.,,/((*          
                               (((/* **(%%&&&&&&&((((//**/** ((//            
                                (((((* ./##%%%%#((///**#&*******           
                                 /((*      */(((/****/(((((#(**             
                                                     *(((((((              
                                                      (((((((*               
                                                     *((((((*                 
                                                       (((((                  
                                                           
                                                           
Vieux - A tool for 32/64 Bit OTA downgrades

Current version is: 1.0.1
If you are using a 64 Bit device then connect it in DFU Mode
If you are using a 32 Bit device then just have it connected in NORMAL mode
Files cleaned.
/xxx/iPhone_4.0_64bit_10.3.3_14G60_Restore.ipsw is a zip archive!
Starting IPSW unzipping
Continuing...
IPSW found at given path...
Cleaning up old files...
Files cleaned.
Unzipping..
Found: CPID:0000 CPRV:00 CPFM:00 SCEP:00 BDID:00 ECID:0000000FFFFFFFFF IBFL:00 SRTG:[iBoot-1704.10]
Device is now in pwned DFU Mode.
(10.10 seconds)
Exploit worked!
*** SecureROM Signature check remover by Linus Henze ***
Applying patches...
Successfully applied patches

Starting iBSS/iBEC patching
Looks like you are downgrading an iPhone 5s to 10.3.3!
Patched iBSS/iBEC
About to re-build IPSW
Entering PWNREC mode...
Getting SHSH...
Restoring...
Note that errors about 'BbSkeyId', 'FDR Client', 'BasebandFirmware Node' and 'ERROR: zip_name_locate: Firmware/all_flash/manifest' are not important.
Just ignore them and only report errors that actually stop the restore.

Files cleaned.
Finished! Enjoy your downgraded device :)
```
最初の方でエラーばかり見てきたのもあるが，このスクリプトはprintがほぼコメントアウトされていたので非常に短い出力という印象だった．


# 結果画像

そんなこんなで，
![Original version from iTunes](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438132/38a23706-ff1d-a614-694f-e82b5b4c064e.jpeg "before from iTunes")
<img width="400" alt="Original version from iPhone" title="before from iPhone" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438132/488bebc1-b895-04f4-0312-6a858917a28e.jpeg"  style="display: block; margin: auto;">
このようにiOS 12.4.5なiPhone5s(GSM, iPhone6,1)を
<img width="400" alt="Downgraded version from iPhone" title="After from iPhone" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438132/09a66942-3d64-8884-8a6d-50e5011d62a5.png"  style="display: block; margin: auto;">
10.3.3にする事ができた．

そして2021年でも無事にカオパネが動作し，
![2021-05-23 17.16.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438132/43fb6ef7-41c1-0dcd-5a73-eaef3a09b592.png)
internaviの通信機能が使えた．
![2021-05-23 19.34.34.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438132/65fec097-961c-8006-6ee4-ebdc1eeb573e.jpeg)
![2021-05-23 19.33.12.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438132/e8afdae9-7908-4a91-dcbe-82dc9029ad7b.jpeg)
（疑似モデム通信な感じで非常に遅いので，当然お天気機能なんて要らないけど，例として）

これで32bitアプリ動作可能な端末が手元に2コあることになったのでちょっと安心．


#追記
スペルミスのご指摘を頂きましたが，[元プログラム](https://github.com/dora2-iOS/iPwnder32/blob/master/ipwnder32.c#L80)のprintfのミスであるため，実際の出力のままとさせて頂きますm(_ _)m