SoftBank Air 3のカーネルいじった時のメモ
工事がいらないのCMのあれ。
いつもの
この記事の内容を参考に行うあらゆる行為はすべて自己責任で行ってください
まえがき
あまり良い評価を聴かないSoftBank Air 3くんですが、はるろいど氏のブログを見てもらえばわかる通り、いじれば使える子になるようです。
それで、私のミスでメルカリの売上金が全部ポイントになる惨事が起こったので、この際買っちゃうかって事で家にお迎えする事になりました。
友達から貰った奴はAir3+(B610s-79a)で全くいじれなかったので...
(誰も得をしない大きさ比較画像)
はるろいど氏のブログに書いてありますが、実はこいつの中身はHuaweiのB618s-22dとさほど変わりなく、しかもandroidで動いています。びっくり。
なので、もう少し自由になろうとカーネルをいじってみました。そのメモ。
カーネル解析
純正ファームじゃadbもtelnetも使えず解析するのに少し不便なので、はるろいど氏のブログを参考に海外ファーム焼いた前提でやっていきます。
とりあえず、どこにbootが生えてるのか調べます。大体の泥端末なら/dev/block/platform以下とかにby-nameとかがあってそこからどのパテが何なのかが得られますが、Air3はMTDドライバーを使っているのでby-nameがないです。
しかしMTDドライバーの場合は/proc/mtdに各ブロックデバイスの役目が書いてあるようなので、とりあえずこれを見てみます。
# cat /proc/mtd dev: size erasesize name mtd0: 00080000 00040000 "m3boot" mtd1: 00080000 00040000 "fastboot" mtd2: 00300000 00040000 "nvbacklte" mtd3: 00300000 00040000 "nvdefault" mtd4: 00f00000 00040000 "nvimg" mtd5: 00500000 00040000 "nvdload" mtd6: 00300000 00040000 "oeminfo" mtd7: 00c00000 00040000 "kernel" mtd8: 00c00000 00040000 "kernelbk" mtd9: 00200000 00040000 "dts" mtd10: 00140000 00040000 "m3image" mtd11: 00800000 00040000 "dsp" mtd12: 00500000 00040000 "hifi" mtd13: 01000000 00040000 "vxworks" mtd14: 00200000 00040000 "wbdata" mtd15: 006c0000 00040000 "reserve2" mtd16: 00500000 00040000 "reserve3" mtd17: 00c00000 00040000 "om" mtd18: 01e00000 00040000 "app" mtd19: 03c00000 00040000 "webui" mtd20: 03200000 00040000 "system" mtd21: 01400000 00040000 "userdata" mtd22: 0e600000 00040000 "online" mtd23: 00a00000 00040000 "coredump" mtd24: 00000000 00040000 "nullMTD" mtd25: 00000000 00040000 "nullMTD" mtd26: 00000000 00040000 "nullMTD" mtd27: 00000000 00040000 "nullMTD" mtd28: 00000000 00040000 "nullMTD" mtd29: 00000000 00040000 "nullMTD" mtd30: 00000000 00040000 "nullMTD" mtd31: 00000000 00040000 "nullMTD" mtd32: 00000000 00040000 "nullMTD" mtd33: 00000000 00040000 "nullMTD" mtd34: 00000000 00040000 "nullMTD"
あまり聞かないブートローダとお目当てのカーネル、あとandroidっぽい奴らと謎のnull層がありますね...
適当にスクリプト書いて全部ダンプしてみたんですが、nullMTDの中身は0xFFで埋められていました...謎。
それからkernelbkはバックアップ用っぽい感じかな(kernelとハッシュが一致した)
どのタイミングで使われるのか不明ですが...
[追記]mtdblock7が改変された場合にkernelbkで起動するようです。
多分、kernelとkernelbkを比較して異なった場合はkernelbkを起動させる仕組みだと思います。
後記しますが、書き換える場合はこっちも書き換える必要があります。
とまあ、カーネルがどこに生えてるのかわかったので、早速カーネルをひっぱり出して解析してみます。
# dd if=/dev/block/mtdblock7 of=/data/local/tmp/boot.img 17650+0 records in 17649+0 records out 9036288 bytes transferred in 1.963 secs (4603305 bytes/sec)
いつも通りadb pullしてbinwalkでカーネル部分だけ取り出します。
$ binwalk -e boot.img DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 128 0x80 Android bootimg, kernel size: 5618264 bytes, kernel addr: 0x46E10000, ramdisk size: 542800 bytes, ramdisk addr: 0x48008000, product name: "" 4224 0x1080 Linux kernel ARM boot executable zImage (little-endian) 22460 0x57BC gzip compressed data, maximum compression, from Unix, last modified: 1970-01-01 00:00:00 (null date) 5623936 0x55D080 gzip compressed data, from Unix, last modified: 1970-01-01 00:00:00 (null date) 6168704 0x5E2080 gzip compressed data, maximum compression, from Unix, last modified: 2017-02-25 08:45:55 $ file ./_boot.img.extracted/* ./_boot.img.extracted/5E2080: ASCII cpio archive (SVR4 with no CRC) ./_boot.img.extracted/55D080: ASCII cpio archive (SVR4 with no CRC) ./_boot.img.extracted/57BC : data
出てきた57BCがカーネル本体です。
ここでbinwalkの出力結果に少し注目して欲しいのですが、androidのbootの前に0x80の大きさを持つ謎の空間が存在しています。
出力結果を元に取り出してみると...
$ dd if=boot.img bs=1 count=128 of=head.img 128+0 レコード入力 128+0 レコード出力 128 bytes copied, 0.00376952 s, 34.0 kB/s $ strings head.img KERNEL $ hexdump head.img 0000000 454b 4e52 4c45 0000 0000 0000 0000 0000 0000010 0000 0000 0000 0000 0000 0000 0000 0000 * 0000030 0000 0000 d000 006f 8000 46e0 0000 0000 0000040 0000 0000 0000 0000 0000 0000 0000 0000 * 0000080
何かしらの目印っぽいですね。
ブートローダが判別するのに使うのかなーとか思っています(ブートローダ調べるのはまた今度で...)
つまるところ、Air3のboot.imgはこの謎ヘッダーと一般的なandroidのboot.imgで構成されているようです。
なので、作ったカーネルにこれをひっつけないとうまく動いてくれません...
次にカーネルをビルドする上で必要な.conifgを取り出します。
これは普通に/proc/config.gzにあるのでadb pullで取り出して展開すれば出てきます。
しかし私はこの時ちょうどAir3をいじりすぎて半文鎮状態にしてしまっていたので、boot.imgから取り出しました。
(文鎮からの復旧が結構面倒だったので...)
今後役に立つかもなので一応書いておきます。
binwalk -e 57BC DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 384 0x180 device tree image (dtb) 1978049 0x1E2EC1 Certificate in DER format (x509 v3), header length: 4, sequence length: 5376 7241832 0x6E8068 Linux kernel version 3.10.5 7254728 0x6EB2C8 gzip compressed data, maximum compression, from Unix, last modified: 1970-01-01 00:00:00 (null date) 8255658 0x7DF8AA MPEG transport stream data 8256418 0x7DFBA2 MPEG transport stream data 8256450 0x7DFBC2 MPEG transport stream data 9459332 0x905684 Unix path: /dev/mtd/mtd%d 9515912 0x913388 Unix path: /lib/firmware/updates/3.10.59 9574676 0x921914 Unix path: /dev/block/mtdblock 9575792 0x921D70 Unix path: /dev/block/mtdblock%d 9634160 0x930170 Unix path: /sys/devices/platform/balong_led/leds/Balong_dr%d/%s 9763492 0x94FAA4 Unix path: /sys/kernel/debug/modem_diag/diag 9949236 0x97D034 Unix path: /sys/power/autosleep 10014929 0x98D0D1 PARity archive data - file number 20548 10133024 0x9A9E20 Unix path: /dev/block/mmcblk%dp1 10133108 0x9A9E74 Unix path: /dev/block/mmcblk%d 10136288 0x9AAAE0 Unix path: /dev/block/mmcblk0 10154683 0x9AF2BB Copyright string: "Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>" 10312232 0x9D5A28 Neighborly text, "NeighborSolicits6InDatagrams" 10312252 0x9D5A3C Neighborly text, "NeighborAdvertisementsorts" 10323946 0x9D87EA Neighborly text, "neighbor %.2x%.2x.%pM lost timer expired" 11048856 0xA89798 ASCII cpio archive (SVR4 with no CRC), file name: "dev", file name length: "0x00000004", file size: "0x00000000" 11048972 0xA8980C ASCII cpio archive (SVR4 with no CRC), file name: "dev/console", file name length: "0x0000000C", file size: "0x00000000" 11049096 0xA89888 ASCII cpio archive (SVR4 with no CRC), file name: "root", file name length: "0x00000005", file size: "0x00000000" 11049212 0xA898FC ASCII cpio archive (SVR4 with no CRC), file name: "TRAILER!!!", file name length: "0x0000000B", file size: "0x00000000" 11059200 0xA8C000 CRC32 polynomial table, little endian 11191515 0xAAC4DB LZMA compressed data, properties: 0xC0, dictionary size: 0 bytes, uncompressed size: 32 bytes 11428268 0xAE61AC Unix path: /sys/class/leds/power_led:green/brightness $ file _57BC.extracted/* _57BC.extracted/6EB2C8: Linux make config build file, ASCII text _57BC.extracted/A89798.cpio: ASCII cpio archive (SVR4 with no CRC) _57BC.extracted/AAC4DB: data _57BC.extracted/AAC4DB.7z: dBase III DBT, version number 0, next free block index 192 _57BC.extracted/cpio-root: directory $ head _57BC.extracted/6EB2C8 # # Automatically generated file; DO NOT EDIT. # Linux/arm 3.10.59 Kernel Configuration # CONFIG_ARM=y CONFIG_MIGHT_HAVE_PCI=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y CONFIG_HAVE_PROC_CPU=y CONFIG_STACKTRACE_SUPPORT=y CONFIG_HAVE_LATENCYTOP_SUPPORT=y
どうやらカーネル本体のすぐ下にあるgzipがconfig.gzにあたる部分のようで、binwalkがこれを取り出して展開したものを6EB2C8として出力してくれているみたいです。
カーネルビルド
カーネルコンフィグが手に入ったので早速ビルドしてみます。
SoftBank Air 3はソースコードが公開されてないようですが、上に書いた通り中身はB618sとさほど変わらないようですし、B618sのファームウェアから取り出した.configと比較したところ中心部の設定はあんまり変わらない事からB618sのソースコードがそのまま使える予感がしたのでやってみます。
(77aの.configの下にB618sとのdiffの出力結果を貼ってます)
B618sからUSB関連とサウンド関連(?)が削られた感じですね。
USBメモリとかが読めないのはこれで削られていたからなんですね...
B618sのソースは以下から落としてください。
[追記]ビルドが普通にできるやつをGitHubに上げたので、そっち使ってください。
README通りにやればext4とUSBストレージが使えてSELinuxがDisabledなカーネルができるはずです。
落として中身を見てもらえばわかりますが、gcc 4.7を使う必要があるみたいです。
そこそこ古いですね...
最新のディストリとかだとレポジトリから拾えないし面倒なので、今回はQuaStationの時にお世話になったBanana Piのカーネルビルド用Dockerを使いました。
ここを参考にpullして走らせます。
そしたらARM用gcc 4.7をインストールしていきます。
# apt-get install gcc-4.7-arm-linux-gnueabi
そのままだとクロスコンパイル時の指定が面倒なので名前を変更
# mv /usr/bin/arm-linux-gnuebi-gcc-4.7 /usr/bin/arm-linux-gnuebi-gcc
ソースrar中のandroid-4.4.1.tar.gzを適当に展開したら77aの.configを置いてmake menuconfig。
ここでUSBを使えるようにしたり、ext4対応させたり、SELinuxをDisabledにしたりできます。
終わったらEsc二回押しで保存。
あとは保存したのをコンフィグ用ディレクトリに放り込んでREADMEに従ってmakeするだけです。
# mv .config arch/arm/configs/B610_defconfig # chmod 777 arch/arm/configs/B610_defconfig # mkdir ../out # make ARCH=arm O=../out B610_defconfig (出力略) # make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- O=../out -j8 (出力略)
うまくいけば、カレントディレクトリの一個手前のoutフォルダに色々入っています。
なんかもっと綺麗に出力する方法があった気がしますが...
今回必要になるのはzImageなので、これを母艦に移動させます。
上のboot.imgをbinwalkでバラした時の出力にあるようにzImageが使われているので、これを入れ替えようっていう魂胆です。
# cd ../out # cp arch/arm/boot/zImage $HOME
(母艦のターミナル) $ sudo docker cp <コンテナID>:/root/zImage .
コンテナIDはdocker psとかで調べてください。
boot.img改変
zImageをboot.imgに組み込んでヘッダをつけます。
最初はbinwalkとddでやろうかと思ってたんですが、今後もいじる事を考えると面倒だなって事でAndroid Image Kitchenを使う事にしました。
これを使って引っ張り出したboot.imgをバラします。
謎ヘッダ付きでもバラしてくれるので脳死で投げればOKです。
$ cd AIK-Linux $ cp /path/to/boot.img . (名前がboot.imgじゃないとダメそうなので注意) $ ./unpack.sh Android Image Kitchen - UnpackImg Script by osm0sis @ xda-developers Supplied image: boot.img Setting up work folders... Image type: AOSP Splitting image to "split_img/"... Android magic found at: 128 BOARD_KERNEL_CMDLINE BOARD_KERNEL_BASE 46e08000 BOARD_NAME BOARD_PAGE_SIZE 4096 BOARD_HASH_TYPE sha1 BOARD_KERNEL_OFFSET 00008000 BOARD_RAMDISK_OFFSET 01200000 BOARD_SECOND_OFFSET 00f00000 BOARD_TAGS_OFFSET 00000100 BOARD_HEADER_VERSION 0 Unpacking ramdisk (as root) to "ramdisk/"... Compression used: gzip 1922 ブロック Done!
バラしたらdocker cpしてきたzImageと入れ替えます。
$ ls split_img/ | grep zImage boot.img-zImage $ cp -f /path/to/zImage split_img/boot.img-zImage
あとは再構築して謎ヘッダを添えれば完成です。
$ ./repack.sh Android Image Kitchen - RepackImg Script by osm0sis @ xda-developers Packing ramdisk (as root)... Using compression: gzip Getting build information... kernel = boot.img-zImage second = boot.img-second cmdline = board = base = 46e08000 pagesize = 4096 kernel_offset = 00008000 ramdisk_offset = 01200000 second_offset = 00f00000 tags_offset = 00000100 header_version = 0 hash = sha1 Building image... Using format: AOSP Done! $ ls authors.txt* boot.img head.img ramdisk/ repackimg.sh* unpackimg.sh* bin/ cleanup.sh* image-new.img ramdisk-new.cpio.gz split_img/ $ cat head.img image-new.img > own_kernel.img
あとは実機にて直接書き込むだけです。
$ adb push own_kernel.img /data/local/tmp $ adb shell # dd if=/data/local/tmp/own_kernel.img of=/dev/block/mtdblock7 [追記]バックアップ用ブロックにも書き込んでください。 # dd if=/data/local/tmp/own_kernel.img of=/dev/block/mtdblock8
再起動した後にuname -aを実行してカーネルのビルド日時がやたら新しくなっていたら成功です。
こんな感じでカーネルいじれる事がわかったので、学業やりながらボチボチと色々やっていこうと思います。
OpenWrt移植とかやってみたいんですけど、いかんせんブートローダが完全にandroid用なので色々工夫する必要がありそうです。
まあ、それが楽しいんですけどね。
CTFとかはしばらく座学して、学業落ち着いたら実践やります...