U+E000 私用領域

しがない緑茶好きのメモ的なの。

SoftBank Air 3のカーネルいじった時のメモ

工事がいらないのCMのあれ。

いつもの

この記事の内容を参考に行うあらゆる行為はすべて自己責任で行ってください

まえがき

あまり良い評価を聴かないSoftBank Air 3くんですが、はるろいど氏のブログを見てもらえばわかる通り、いじれば使える子になるようです。

old.haruroid.com

old.haruroid.com

それで、私のミスでメルカリの売上金が全部ポイントになる惨事が起こったので、この際買っちゃうかって事で家にお迎えする事になりました。
友達から貰った奴はAir3+(B610s-79a)で全くいじれなかったので...

https://cdn.discordapp.com/attachments/530608865256013840/750636398884683806/image0.jpg

(誰も得をしない大きさ比較画像)
はるろいど氏のブログに書いてありますが、実はこいつの中身はHuaweiのB618s-22dとさほど変わりなく、しかもandroidで動いています。びっくり。
なので、もう少し自由になろうとカーネルをいじってみました。そのメモ。

カーネル解析

純正ファームじゃadbもtelnetも使えず解析するのに少し不便なので、はるろいど氏のブログを参考に海外ファーム焼いた前提でやっていきます。
とりあえず、どこにbootが生えてるのか調べます。大体の泥端末なら/dev/block/platform以下とかにby-nameとかがあってそこからどのパテが何なのかが得られますが、Air3はMTDドライバーを使っているのでby-nameがないです。

kohshi.blogspot.com

しかし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のソースコードがそのまま使える予感がしたのでやってみます。

.config_B610s-77a · GitHub

(77aの.configの下にB618sとのdiffの出力結果を貼ってます)
B618sからUSB関連とサウンド関連(?)が削られた感じですね。 USBメモリとかが読めないのはこれで削られていたからなんですね...
B618sのソースは以下から落としてください。

https://consumer.huawei.com/en/opensource/detail/?siteCode=worldwide&keywords=b618s&fileType=openSourceSoftware&pageSize=10&curPage=1

[追記]ビルドが普通にできるやつをGitHubに上げたので、そっち使ってください。

github.com

README通りにやればext4とUSBストレージが使えてSELinuxがDisabledなカーネルができるはずです。

落として中身を見てもらえばわかりますが、gcc 4.7を使う必要があるみたいです。
そこそこ古いですね...
最新のディストリとかだとレポジトリから拾えないし面倒なので、今回はQuaStationの時にお世話になったBanana Piのカーネルビルド用Dockerを使いました。

hub.docker.com

ここを参考に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を使う事にしました。

forum.xda-developers.com

これを使って引っ張り出した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とかはしばらく座学して、学業落ち着いたら実践やります...