U+E000 私用領域

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

android端末でchroot使ってディストリ動かしたときのメモ

root前提なので自己責任で。
Kali Linuxの開発元Offensive Securityがスマホ向けに出してるNetHunterを活用してLinuxディストリ動かそうというお話。

androidLinux

義務教育で習ったようにandroidLinuxカーネルで動いています。
なので各ディストリ用のファイルやらを用意してやれば、UbuntuなりArchなりが動いてくれます。
最近はUserLAndとかTermuxみたいにrootなくてもディストリを動かせるのが出てきて嬉しい限りですが、自由とは言いづらいし、個人的にroot振り回してchroot使ってディストリを動かしたほうが精神衛生上よろしいのでそうします(chrootも自由とは言えないだろっていうツッコミはなしで...)
というか、前回のURBANO V01君を売って手元にroot取得してない奴がないので自然とそうなるんですけどね。
今回はチャレンジパッド2ことTAB-A03-BSにArch Linuxを入れてみます。

ディストリの生成

ディストリのイメージがないと始まらないので、Linux Deployを使ってイメージを作ります。
チャレパ2はROM 16GBなので、アプリとかを考えるとディストリのイメージを入れるにはちと狭い...
そこでmicroSDにイメージを入れるのも考えましたがSDXC非対応でexFAT作れないので、FAT系の1ファイル2GB制限に引っかかって2GBのイメージしか作れないです...
なので、microSDext4パテを作ってそこにイメージを展開、mountのbindを使って本体とつなぐことにします。
Linux Deployの設定はこんな感じ。

https://cdn.discordapp.com/attachments/530608865256013840/699079037280059482/Screenshot_2020-04-13-11-09-02.png

アーキテクチャとかパーティションは機種によって違うので、CPU-Z使うなりdmesgでマウントログ見たりで対応してください。
間違ったパーティションに上書きして泣いても自己責任で。 microSDにはext4パーティションを作ってスロットに突っ込んでください。
あとは右上のボタンからInstallを選択すればmicroSDにディストリのイメージが書き込まれます。
今回はNetHunterのスクリプトで動かすので、作ったらLinux Deployは消しても大丈夫です。

スクリプト書き換え

今更ながらNetHunterでディストリを動かすメリットを紹介。

  • SSHとかをアプリから制御できて楽。自動起動も可。
  • コマンドから起動するので、adbとか他のターミナルアプリ上でも動かせる。
  • NetHunter用ターミナルアプリが使える。

要するに色々楽です。
自作するのがめんどい
アプリとかがKaliなデザインなのはあれですけど。
アプリは

http://store.nethunter.com/repo/com.offsec.nethunter_2019041400.apk

から落とせます。新しいのも出てますが、新しいのはスクリプトがガラッと変わっててまだ解析終わってないので...
Kaliなツールのアップデート多めみたいですし、chrootするためなら別に新しくなくてもいいと思います。(妥協)
あと、NetHunter用のターミナルも入れておかないと起動時に怒られるので使わなくても入れておきましょう。
apk書き換えたら良さそうだけど、めんどくさい...誰かやってくれないかなぁ...

http://store.nethunter.com/repo/com.offsec.nhterm_2020010200.apk

2つとも入れたらadbなり直接なりでインストールします。
インストールしたら早速スクリプトをいじります。
場所:/data/data/com.offsec.nethunter/files/scripts
色々スクリプトがありますが、今回いじるのはbootkali*系のスクリプトです。
スクリプトの役目は以下の通り

bootkali : 起動用スクリプト。引数をつけることでSSHVNCとかをコントロールできる。
bootkali_bash : 起動時のシェル準備。あとrootでのログインも定義されてる。
bootkali_env : 変数定義と画面クリア。
bootkali_init : 今回の主役。chrootのあれこれを構築したり定義したりする。
bootkali_log : logcatにログを吐く
bootkali_login : rootでのログインを定義。

通常の動作としては、/data/local/nhsystem/kali-armhfにchrootできる環境があったらchroot
なかったら/sdcard/kali-chroot.imgを/data/local/nhsystem/kali-armhfにマウントしてchroot
といった感じです。
今回はmicroSDパーティションにディストリがあるので、それをマウントできるように書き換えます。
とりあえずbootkali_initの123行目らへんを見ます

mount_kali_chroot() {
    $busybox mount -t ext4 /sdcard/kali-chroot.img $mnt

    mkdir -p $mnt/dev
    mkdir -p $mnt/dev/shm
    mkdir -p $mnt/proc
    mkdir -p $mnt/sys
    mkdir -p $mnt/system
    mkdir -p $mnt/sdcard

ここがイメージをマウントしてる部分です。
チャレパ2の場合、microSDは/dev/block/platform/soc.1/mmcblk1p1にext4microSDのパテが生えてるので、これを

mount_kali_chroot() {
    $busybox mount -t ext4 /dev/block/platform/soc.1/mmcblk1p1 $mnt

    mkdir -p $mnt/dev
    mkdir -p $mnt/dev/shm
    mkdir -p $mnt/proc
    mkdir -p $mnt/sys
    mkdir -p $mnt/system
    mkdir -p $mnt/sdcard

することでmicroSDchrootしてくれます。
その他にも155行目にDNSが定義されてるので、1.1.1.1大好きな人とかは変えるといいと思います。
あと、このままだとホストネームがkaliになってしまいます。
kaliじゃねーしArchだし! って感じですし、個人的にKaliあんま好かんので変えます。
232行目あたりから

# NETWORK SETTINGS #
    $busybox sysctl -w net.ipv4.ip_forward=1
    echo "127.0.0.1              localhost kali" > $mnt/etc/hosts
    echo "::1                            localhost ip6-localhost ip6-loopback" >> $mnt/etc/hosts
    echo "kali" > $mnt/proc/sys/kernel/hostname

といった感じで定義されてるので、ここのkaliの部分をお好きなホストネームに変えます。
あとは/data/data/com.offsec.nethunter/files/scripts/bootkali
でとりあえず起動できます。

https://cdn.discordapp.com/attachments/530608865256013840/699139660013895691/neofetch.png

終了するときはkillkaliスクリプトを実行すれば、マウントしてたディレクトリとかを一括でアンマウントしてくれます。
起動できることを確認したら、パスが通るとこにシンボリックリンクを貼っておきましょう。

# mount -o rw,remount /system
# ln -s /data/data/com.offsec.nethunter/files/scripts/bootkali /system/xbin/boot
# ln -s /data/data/com.offsec.nethunter/files/scripts/killkali /system/xbin/shutdown

これで楽に動かせます。
起動時にSSHとかを動かす場合はNetHunterアプリから設定すれば動きます(なげやり)

書きかけの記事がめっちゃ溜まってきたな...

boot.imgから任意のシンボルのアドレスを発掘する

去年暮れから書き始めた国産スマホ周りの延長的なやつです。
URBANO V01(KYV31)をrootできなかった言い訳も含んでます。
今回はboot.imgからカーネル本体を引っ張り出して、ほしいシンボルのアドレスを発掘する話です。
少しだけarmアセンブリ要素もあります。

なぜそんなことするの?

前回前々回の記事を読んでもらえばわかりますが、国産スマホでroot権限を奪取したりカーネルを書き換えるには、いくつかのシンボルのアドレスが必要になります。
しかし今回実際にアドレスを発掘するURBANO V01(KYV31)だと、get_essential_address(詳しくは過去記事を参照)が使えません。

$ ./get_essential_address                          


Device detected: KYV31 (103.0.2e00)

Try without fb_mem_exploit fist...

Try to find address in memory...
Attempt msm_cameraconfig exploit...
Detected kernel physical address at 0x00008000 from iomem

You need to manage to get remap_pfn_range address.

Try copying kernel memory... It will take a long time.
Attempt pingpong exploit...
Attempt futex exploit...
failed to exploit...
Attempt get_user exploit...
error in setsockopt().
Failed to get prepare_kernel_cred address.
Failed to get commit_creds address.
Failed to get remap_pfn_range address.
Failed to get vmalloc_exec address.
Failed to get ptmx_fops address.
connect(): failed
Attempt get_user exploit...
error in setsockopt().
Failed to get prepare_kernel_cred address.
Failed to get commit_creds address.
Failed to get remap_pfn_range address.
Failed to get vmalloc_exec address.
Failed to get ptmx_fops address.
KYV31 (103.0.2e00) is not supported.


Try again with fb_mem_exploit...

KYV31 (103.0.2e00) is not supported.


Try again with fb_mem_exploit...

Try to find address in memory...
Attempt msm_cameraconfig exploit...
Detected kernel physical address at 0x00008000 from iomem

Attempt fb_mem exploit...
Detected kernel physical address at 0x00008000 from iomem
Failed to open /dev/graphics/fb0 due to Permission denied
You need to manage to get remap_pfn_range address.

Try copying kernel memory... It will take a long time.
Attempt pingpong exploit...
Attempt futex exploit...
connect(): failed
Attempt get_user exploit...
error in setsockopt().
Failed to get prepare_kernel_cred address.
Failed to get commit_creds address.
Failed to get remap_pfn_range address.
Failed to get vmalloc_exec address.
Failed to get ptmx_fops address.
KYV31 (103.0.2e00) is not supported.
Failed to setup variables.
Try to find address in memory...
Attempt msm_cameraconfig exploit...
Detected kernel physical address at 0x00008000 from iomem

Attempt fb_mem exploit...
Detected kernel physical address at 0x00008000 from iomem
Failed to open /dev/graphics/fb0 due to Permission denied
You need to manage to get remap_pfn_range address.

Try copying kernel memory... It will take a long time.
Attempt pingpong exploit...
Attempt futex exploit...
connect(): failed
Attempt get_user exploit...
error in setsockopt().
Failed to get prepare_kernel_cred address.
Failed to get commit_creds address.
Failed to get remap_pfn_range address.
Failed to get vmalloc_exec address.
Failed to get ptmx_fops address.
KYV31 (103.0.2e00) is not supported.
Failed to setup variables.

アドレスを取る時に使用していた脆弱性郡が塞がれてしまっているからです。
なので、今回はboot.imgを取り出した後、母艦PCからアドレスを出して、脆弱性を使えるようにしようという考えです。
今回は試しにptmx_fopsのアドレスを発掘してみます。

ptmx_fopsとは

staticな変数の構造体です。
すごく簡単にいってしまうと、ここを抑えてしまえば任意の関数をカーネル権限で実行できてしまいます。
"なんかカーネル権限であれこれできちゃうやべーやつ"みたいな認識です。
この記事を読む分にはその程度で構いませんが、このやべーやつの正体をもっと深く知りたい方は、ももいろテクノロジー様が詳しく解説していますのでリンクを貼っておきます。

inaz2.hatenablog.com
非常に面白く、わかりやすい記事なのでぜひご一読を。

boot.imgを取ってくる

兎にも角にも、boot領域のイメージがないと始まりません。
方法としては、

  • メーカーのサイトからアップデート用データ落として取り出す
  • root権限奪取して、ddで取り出す

辺りがあると思いますが、KYV31はオンラインでのアップデートのみでアップデート用のデータとかが公開されてないので、今回はroot奪取する方法で行きたいと思います。
ちなみに今回使ってるKYV31ですが、ビルド番号は103.0.2e00です。
これ以前のやつは前回とかの方法でroot奪取、LSM解除まで簡単にいけます。
(とあるベトナムの方のKYV31、ビル番102で確認済み)
しかし103以降のものだと、run_root_shellとかでのroot奪取はできません。
なので、あの有名なDirtyCowくんを使ってrootを取ります。

rarのパスワードは"nox"だそうです。(XDAフォーラム参照)
解答して出てきたファイルをいつもの/data/local/tmpにpushして実行します。

$ ls
busybox  exploit.sh  libsupol.so  patch-init  readelf  run-as-dirtycow  run-as-dirtycow64  su.img  supolicy
$ adb push * /data/local/tmp
busybox: 1 file pushed. 2.6 MB/s (1815252 bytes in 0.654s)
exploit.sh: 1 file pushed. 0.6 MB/s (10397 bytes in 0.016s)
libsupol.so: 1 file pushed. 2.2 MB/s (203236 bytes in 0.090s)
patch-init: 1 file pushed. 1.2 MB/s (11584 bytes in 0.009s)
readelf: 1 file pushed. 2.5 MB/s (683324 bytes in 0.258s)
run-as-dirtycow: 1 file pushed. 2.7 MB/s (11448 bytes in 0.004s)
run-as-dirtycow64: 1 file pushed. 0.8 MB/s (10000 bytes in 0.011s)
su.img: 1 file pushed. 4.3 MB/s (5242880 bytes in 1.167s)
supolicy: 1 file pushed. 1.9 MB/s (38308 bytes in 0.019s)
9 files pushed. 3.4 MB/s (8026429 bytes in 2.234s)
shell@KYV31:/data/local/tmp $ chmod 755 *
shell@KYV31:/data/local/tmp $ ./exploit.sh                                     

              (      )
              ~(^^^^)~
               ) @@ \~_          |\
              /     | \        \~ /  CVE-2016-5195
             ( 0  0  ) \        | |   Lollipop (32bits)
              ---___/~  \       | |   SeLinux bye
               /'__/ |   ~-_____/ |
o          _   ~----~      ___---~
  O       //     |         |
         ((~\  _|         -|
   o  O //-_ \/ |        ~  |
        ^   \_ /         ~  |
               |          ~ |
               |     /     ~ |
               |     (       |
                \     \      /\
               / -_____-\   \ ~~-*
               |  /       \  \
               / /         / /
             /~  |       /~  |
             ~~~~        ~~~~

# Device:KYV31_jp_kdi

-Getting uid 0->Ok.
-Checking permissive run-as.->No
-Dump policy->Ok
-Dump init

Error searching shellcode addr, already patched?

なぜかうまくいきません。
カーネルのバージョン的にも有効なはずなんですが...
一応、解決策はありますが...非常に屈辱的です。
その方法というのがKingRootを使うというものです。ええ、あのKingRootです。
あの怪しくて何をしてるのかわからん上に余計なアプリぶち込んできたり、勝手にロック画面を乗っ取るあのKingRootです。
あのアプリを実行してもKYV31はroot化されません(KingRootはLSM解除非対応)
しかし、実行してしばらくすると何故かSELinuxが少しの間Permissiveになるんです。
そのすきにDirtyCow動かすとroot権限が奪い取れます。
他のDirtyCow使ってるexploitを使ってみても/data/local/tmpすら覗けないなんちゃってroot権限になりますし、こうするしかなかったんです...
DirtyCowはSELinuxがEnforcingでも動くのがウリなのに、何やってんだって感じですよ...
えー、本題はboot.imgからシンボルのアドレスを取ることなので、自虐的なナニカはこの辺にしてboot.imgを取っていきます。

shell@KYV31:/ $ cd /data/local/tmp
shell@KYV31:/data/local/tmp $ getenforce                                       
Permissive
shell@KYV31:/data/local/tmp $ ./exploit.sh                                     
              (      )
              ~(^^^^)~
               ) @@ \~_          |\
              /     | \        \~ /  CVE-2016-5195
             ( 0  0  ) \        | |   Lollipop (32bits)
              ---___/~  \       | |   SeLinux bye
               /'__/ |   ~-_____/ |
o          _   ~----~      ___---~
  O       //     |         |
         ((~\  _|         -|
   o  O //-_ \/ |        ~  |
        ^   \_ /         ~  |
               |          ~ |
               |     /     ~ |
               |     (       |
                \     \      /\
               / -_____-\   \ ~~-*
               |  /       \  \
               / /         / /
             /~  |       /~  |
             ~~~~        ~~~~

# Device:KYV31_jp_kdi

-Getting uid 0->Ok.
-Checking permissive run-as.->Ok
# turn off/on the bluetooth...
root@KYV31:/data/local/tmp # 
root@KYV31:/data/local/tmp # id
uid=0(root) gid=0(root) context=u:r:init:s0

KingRoot動かしたらgetenforceしまくって、謎Permissiveになったらexploit。
技術者の端くれとして非常に屈辱的です。
とりあえずrootは取れたので、bootのイメージをとります。

# ls -l /dev/block/platform/msm_sdcc.1/by-name | grep boot
lrwxrwxrwx root     root              1970-01-22 12:27 aboot -> /dev/block/mmcblk0p5
lrwxrwxrwx root     root              1970-01-22 12:27 abootbk -> /dev/block/mmcblk0p11
lrwxrwxrwx root     root              1970-01-22 12:27 boot -> /dev/block/mmcblk0p14
lrwxrwxrwx root     root              1970-01-22 12:27 bootwork -> /dev/block/mmcblk0p27
# dd if=/dev/block/mmcblk0p14 of=boot.img         
34816+0 records in
34816+0 records out
17825792 bytes transferred in 0.730 secs (24418893 bytes/sec)

無事にとれました。母艦に移します。

$ adb pull /data/local/tmp/boot.img
/data/local/tmp/boot.img: 1 file pu...3.9 MB/s (17825792 bytes in 4.409s)

なんか思ったより長くなりましたが、これで下準備完了です。

カーネル本体を取り出す

boot.imgは取れたわけですが、今回必要なのはboot領域すべてではなくkernelのみです。
ramdiskとかに用はないので、bootイメージからカーネル部のみを取り出します。
boot.imgの分解はsplit_bootとかmkbootimgとかでできるそうですが、入れるのが面倒そうなので、binwalkで取り出します。
binwalkっていうのは...まあ見たほうが早いです。

$ binwalk boot.img

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             Android bootimg, kernel size: 6426600 bytes, kernel addr: 0x8000, ramdisk size: 650124 bytes, ramdisk addr: 0x1000000, product name: ""
2048          0x800           Linux kernel ARM boot executable zImage (little-endian)
18255         0x474F          gzip compressed data, maximum compression, from Unix, last modified: 1970-01-01 00:00:00 (null date)
6428672       0x621800        gzip compressed data, from Unix, last modified: 1970-01-01 00:00:00 (null date)
7079936       0x6C0800        Qualcomm device tree container, version: 2, DTB entries: 105
7084032       0x6C1800        device tree image (dtb)
7280640       0x6F1800        device tree image (dtb)
7479296       0x722000        device tree image (dtb)
7677952       0x752800        device tree image (dtb)
7872512       0x782000        device tree image (dtb)
8069120       0x7B2000        device tree image (dtb)
8265728       0x7E2000        device tree image (dtb)
8460288       0x811800        device tree image (dtb)
8656896       0x841800        device tree image (dtb)
8853504       0x871800        device tree image (dtb)
9050112       0x8A1800        device tree image (dtb)
9246720       0x8D1800        device tree image (dtb)
9443328       0x901800        device tree image (dtb)
9629696       0x92F000        device tree image (dtb)
9816064       0x95C800        device tree image (dtb)
10012672      0x98C800        device tree image (dtb)
10209280      0x9BC800        device tree image (dtb)
10405888      0x9EC800        device tree image (dtb)
10602496      0xA1C800        device tree image (dtb)
10797056      0xA4C000        device tree image (dtb)
10991616      0xA7B800        device tree image (dtb)
11204608      0xAAF800        device tree image (dtb)
11417600      0xAE3800        device tree image (dtb)
11646976      0xB1B800        device tree image (dtb)
11859968      0xB4F800        device tree image (dtb)
11886592      0xB56000        device tree image (dtb)
12101632      0xB8A800        device tree image (dtb)
12312576      0xBBE000        device tree image (dtb)
12525568      0xBF2000        device tree image (dtb)
12738560      0xC26000        device tree image (dtb)

なんかdtbが多いですが出ました。
binwalkは、ファイル内に埋もれてるファイルを表示してくれます。

github.com

Ubuntuだったらapt install binwalkでいけます。
gzipが2つありますが、上がカーネル本体、下がramdiskです。
ちなみに、binwalkは-eオプションで検出したファイルを取り出してくれます。

$ binwalk -e boot.img 

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
(省略)
$ ls
_boot.img.extracted  boot.img  default.prop
$ cd _boot.img.extracted/ && ls
474F  621800
$ file *
474F:   data
621800: ASCII cpio archive (SVR4 with no CRC)

474Fがカーネル、621800がramdiskです。
カーネルをリネームしてわかりやすい場所においておきます。

アドレスを引っ張り出す

ようやっと本題です。
アドレスを引っ張りだす方法ですが、またしてもfi01氏制作のツールを使用させていただきます。

github.com

これをいつもどおりgit cloneします。

$ git clone https://github.com/fi01/kallsymsprint
Cloning into 'kallsymsprint'...
remote: Enumerating objects: 68, done.
remote: Total 68 (delta 0), reused 0 (delta 0), pack-reused 68
Unpacking objects: 100% (68/68), done.
$ cd kallsymsprint/
$ ls
Android.mk  Application.mk  README.md  kallsymsprint  kallsymsprint.arm64  kallsymsprint.x64  kallsymsprint.x86  libkallsyms  main.c

すでにコンパイル済みのものが置かれているので、ありがたく使用させていただきます。
使い方は、引数にカーネル本体へのパスを渡せばOKです。

$ ./kallsymsprint.x86 ../kernel.dump > kallsyms_kyv31.txt
[+]mmap
  mem=f6cf0000 length=0106fd04 offset=c9318000
[+]kallsyms_addresses=c0aac2b0
  count=00011316
[+]kallsyms_num_syms=00011316
[+]kallsyms_names=c0af0f20
[+]kallsyms_markers=c0bb9ac0
[+]kallsyms_token_table=c0bb9f10
[+]kallsyms_token_index=c0bba2b0
[+]kallsyms_lookup_name
$ head kallsyms_kyv31.txt
c0100000 asm_do_IRQ
c0100000 _stext
c0100000 __exception_text_start
c0100004 do_undefinstr
c010022c do_IPI
c0100230 do_DataAbort
c01003dc do_PrefetchAbort
c0100474 gic_handle_irq
c0100580 __do_fixup_smp_on_up
c0100580 __exception_text_end

とれましたね。
最初の方で述べた通り、今回必要なのはptmx_fopsのアドレスです。grepで探してみましょう。

$ cat kallsyms_kyv31.txt | grep ptmx_fops
$

ないです。
しかし隠してあるだけで実際には存在しています。
というわけで前回同様ディスアセンブルをして、ptmx_fopsを探していきます。

ptmx_fopsを探し出す

さて、どうやって見つけるんだって話ですが、ptmx_fopsを使用している関数から見つけます。
例えばカーネルの関数unix98_pty_initのソースは以下のようになっています。

unix98_pty_init()
  {
    (省略)
    /* Now create the /dev/ptmx special device */
    tty_default_fops(&ptmx_fops);
    ptmx_fops.open = ptmx_open;

    cdev_init(&ptmx_cdev, &ptmx_fops);
    (省略)
  }

なので、この関数をディスアセンブルすればptmx_fopsのアドレスがわかるはず...です。
ディスアセンブルには、前回からお世話になっているarm7-dasmを使用します。

github.com

これをgit clone、コンパイルして使用します。

$ git clone https://github.com/fi01/arm7-dasm
Cloning into 'arm7-dasm'...
remote: Enumerating objects: 71, done.
remote: Total 71 (delta 0), reused 0 (delta 0), pack-reused 71
Unpacking objects: 100% (71/71), done.
$ cd arm7-dasm/
$ ls
README.md  arm7-dasm.c  arm7core.h  arm7dasm.c  emu.h
$ gcc -o arm7-dasm arm7-dasm.c

ディスアセンブルの方法はREADMEに載ってます。

Disassemble with symbol table:  
$ ./arm7-dasm [kernel image filename] [image base address] [start address or symbol name] [symbol table file]  

早速ディスアセンブルしてみます。

$ ./arm7-dasm kernel.dump c0008000 pty_init kallsyms_kyv31.txt > pty_init.dasm
70271 symbols are loaded.
$ head pty_init.dasm 
Disassemble 0xc0e1e86c - 0xc0e1ebb0
c0e1e86c:             <pty_init>
c0e1e86c: e9 2d 4f f0     STMPW   [SP], { R4-R11, LR }
c0e1e870: e2 4d d0 14     SUB     SP, SP, #$14
c0e1e874: e5 9f 53 38     LDR     R5, =$c0fc0544 [$c0e1ebb4]
c0e1e878: e5 95 00 00     LDR     R0, [R5]
c0e1e87c: e3 50 00 00     CMPS    R0, #$0
c0e1e880: da 00 00 52     BLE     $c0e1e9d0
c0e1e884: e3 a0 10 00     MOV     R1, #$0
c0e1e888: eb d6 d9 94     BL      $c03d4ee0 <__alloc_tty_driver>

無事にディスアセンブルできたみたいです。
以下、ディスアセンブル結果

Disassemble 0xc0e1e86c - 0xc0e1ebb0
c0e1e86c:             <pty_init>
c0e1e86c: e9 2d 4f f0     STMPW   [SP], { R4-R11, LR }
c0e1e870: e2 4d d0 14     SUB     SP, SP, #$14
c0e1e874: e5 9f 53 38     LDR     R5, =$c0fc0544 [$c0e1ebb4]
c0e1e878: e5 95 00 00     LDR     R0, [R5]
c0e1e87c: e3 50 00 00     CMPS    R0, #$0
c0e1e880: da 00 00 52     BLE     $c0e1e9d0
c0e1e884: e3 a0 10 00     MOV     R1, #$0
c0e1e888: eb d6 d9 94     BL      $c03d4ee0 <__alloc_tty_driver>
c0e1e88c: e2 50 40 00     SUBS    R4, R0, #$0
c0e1e890: 05 9f 03 20     LDREQ   R0, =$c0c22160 [$c0e1ebb8]
c0e1e894: 0a 00 00 05     BEQ     $c0e1e8b0
c0e1e898: e5 95 00 00     LDR     R0, [R5]
c0e1e89c: e3 a0 10 00     MOV     R1, #$0
c0e1e8a0: eb d6 d9 8e     BL      $c03d4ee0 <__alloc_tty_driver>
c0e1e8a4: e2 50 60 00     SUBS    R6, R0, #$0
c0e1e8a8: 1a 00 00 01     BNE     $c0e1e8b4
c0e1e8ac: e5 9f 03 08     LDR     R0, =$c0c2217d [$c0e1ebbc]
c0e1e8b0:                                             ; from c0e1e894
c0e1e8b0:                                             ;      c0e1e9b8
c0e1e8b0:                                             ;      c0e1e9cc
c0e1e8b0:                                             ;      c0e1e9ec
c0e1e8b0:                                             ;      c0e1ea0c
c0e1e8b0:                                             ;      c0e1eb1c
c0e1e8b0:                                             ;      c0e1eb30
c0e1e8b0:                                             ;      c0e1eb6c
c0e1e8b0: eb ec 9d 77     BL      $c0945e94 <panic>
c0e1e8b4:                                             ; from c0e1e8a8
c0e1e8b4: e5 9f 33 04     LDR     R3, =$c0c221a0 [$c0e1ebc0]
c0e1e8b8: e3 a0 70 00     MOV     R7, #$0
c0e1e8bc: e3 a0 c0 04     MOV     R12, #$4
c0e1e8c0: e5 9f 52 fc     LDR     R5, =$c0fc0484 [$c0e1ebc4]
c0e1e8c4: e3 a0 b0 02     MOV     R11, #$2
c0e1e8c8: e2 84 e0 64     ADD     LR, R4, #$64
c0e1e8cc: e1 c4 c6 b0     STRH    R12, [R4,#$60]
c0e1e8d0: e3 a0 8c 96     MOV     R8, #$9600
c0e1e8d4: e3 a0 90 bf     MOV     R9, #$bf
c0e1e8d8: e5 84 b0 54     STR     R11, [R4, #$54]
c0e1e8dc: e3 a0 a0 06     MOV     R10, #$6
c0e1e8e0: e5 84 30 48     STR     R3, [R4, #$48]
c0e1e8e4: e5 9f 32 dc     LDR     R3, =$c0cb3542 [$c0e1ebc8]
c0e1e8e8: e5 84 70 58     STR     R7, [R4, #$58]
c0e1e8ec: e5 84 30 4c     STR     R3, [R4, #$4c]
c0e1e8f0: e3 a0 30 01     MOV     R3, #$1
c0e1e8f4: e1 c4 36 b2     STRH    R3, [R4,#$62]
c0e1e8f8: e8 b5 00 0f     LDMUW   [R5], { R0-R3 }
c0e1e8fc: e8 ae 00 0f     STMUW   [LR], { R0-R3 }
c0e1e900: e8 b5 00 0f     LDMUW   [R5], { R0-R3 }
c0e1e904: e8 ae 00 0f     STMUW   [LR], { R0-R3 }
c0e1e908: e8 95 00 07     LDMU    [R5], { R0-R2 }
c0e1e90c: e8 8e 00 07     STMU    [LR], { R0-R2 }
c0e1e910: e1 a0 00 04     MOV     R0, R4 
c0e1e914: e5 9f 12 b0     LDR     R1, =$c0a39a34 <master_pty_ops_bsd> [$c0e1ebcc]
c0e1e918: e5 84 70 64     STR     R7, [R4, #$64]
c0e1e91c: e5 84 70 68     STR     R7, [R4, #$68]
c0e1e920: e5 84 90 6c     STR     R9, [R4, #$6c]
c0e1e924: e5 84 70 70     STR     R7, [R4, #$70]
c0e1e928: e5 84 80 88     STR     R8, [R4, #$88]
c0e1e92c: e5 84 80 8c     STR     R8, [R4, #$8c]
c0e1e930: e5 84 a0 90     STR     R10, [R4, #$90]
c0e1e934: e5 84 60 98     STR     R6, [R4, #$98]
c0e1e938: e5 8d c0 0c     STR     R12, [SP, #$c]
c0e1e93c: eb d6 d8 77     BL      $c03d4b20 <tty_set_operations>
c0e1e940: e5 9f 32 88     LDR     R3, =$c0c221ab [$c0e1ebd0]
c0e1e944: e5 86 70 58     STR     R7, [R6, #$58]
c0e1e948: e2 45 e0 20     SUB     LR, R5, #$20
c0e1e94c: e5 86 30 48     STR     R3, [R6, #$48]
c0e1e950: e5 9f 32 7c     LDR     R3, =$c0c221b5 [$c0e1ebd4]
c0e1e954: e5 86 30 4c     STR     R3, [R6, #$4c]
c0e1e958: e3 a0 30 03     MOV     R3, #$3
c0e1e95c: e5 86 30 54     STR     R3, [R6, #$54]
c0e1e960: e5 9d c0 0c     LDR     R12, [SP, #$c]
c0e1e964: e1 c6 b6 b2     STRH    R11, [R6,#$62]
c0e1e968: e8 be 00 0f     LDMUW   [LR], { R0-R3 }
c0e1e96c: e1 c6 c6 b0     STRH    R12, [R6,#$60]
c0e1e970: e2 86 c0 64     ADD     R12, R6, #$64
c0e1e974: e8 ac 00 0f     STMUW   [R12], { R0-R3 }
c0e1e978: e8 be 00 0f     LDMUW   [LR], { R0-R3 }
c0e1e97c: e8 ac 00 0f     STMUW   [R12], { R0-R3 }
c0e1e980: e8 95 00 07     LDMU    [R5], { R0-R2 }
c0e1e984: e8 8c 00 07     STMU    [R12], { R0-R2 }
c0e1e988: e1 a0 00 06     MOV     R0, R6 
c0e1e98c: e5 9f 12 44     LDR     R1, =$c0a39ab0 <slave_pty_ops_bsd> [$c0e1ebd8]
c0e1e990: e5 86 90 6c     STR     R9, [R6, #$6c]
c0e1e994: e5 86 80 88     STR     R8, [R6, #$88]
c0e1e998: e5 86 80 8c     STR     R8, [R6, #$8c]
c0e1e99c: e5 86 a0 90     STR     R10, [R6, #$90]
c0e1e9a0: e5 86 40 98     STR     R4, [R6, #$98]
c0e1e9a4: eb d6 d8 5d     BL      $c03d4b20 <tty_set_operations>
c0e1e9a8: e1 a0 00 04     MOV     R0, R4 
c0e1e9ac: eb d6 d9 81     BL      $c03d4fb8 <tty_register_driver>
c0e1e9b0: e1 50 00 07     CMPS    R0, R7 
c0e1e9b4: 15 9f 02 20     LDRNE   R0, =$c0c221ba [$c0e1ebdc]
c0e1e9b8: 1a ff ff bc     BNE     $c0e1e8b0
c0e1e9bc: e1 a0 00 06     MOV     R0, R6 
c0e1e9c0: eb d6 d9 7c     BL      $c03d4fb8 <tty_register_driver>
c0e1e9c4: e3 50 00 00     CMPS    R0, #$0
c0e1e9c8: 15 9f 02 10     LDRNE   R0, =$c0c221d7 [$c0e1ebe0]
c0e1e9cc: 1a ff ff b7     BNE     $c0e1e8b0
c0e1e9d0:                                             ; from c0e1e880
c0e1e9d0: e3 a0 06 01     MOV     R0, #$100000
c0e1e9d4: e3 a0 10 00     MOV     R1, #$0
c0e1e9d8: e5 9f 52 04     LDR     R5, =$c1175a70 [$c0e1ebe4]
c0e1e9dc: eb d6 d9 3f     BL      $c03d4ee0 <__alloc_tty_driver>
c0e1e9e0: e3 50 00 00     CMPS    R0, #$0
c0e1e9e4: e5 85 00 00     STR     R0, [R5]
c0e1e9e8: 05 9f 01 f8     LDREQ   R0, =$c0c221fa [$c0e1ebe8]
c0e1e9ec: 0a ff ff af     BEQ     $c0e1e8b0
c0e1e9f0: e3 a0 06 01     MOV     R0, #$100000
c0e1e9f4: e3 a0 10 00     MOV     R1, #$0
c0e1e9f8: eb d6 d9 38     BL      $c03d4ee0 <__alloc_tty_driver>
c0e1e9fc: e3 50 00 00     CMPS    R0, #$0
c0e1ea00: e1 a0 e0 00     MOV     LR, R0 
c0e1ea04: e5 85 00 04     STR     R0, [R5, #$4]
c0e1ea08: 05 9f 01 dc     LDREQ   R0, =$c0c2221e [$c0e1ebec]
c0e1ea0c: 0a ff ff a7     BEQ     $c0e1e8b0
c0e1ea10: e5 95 c0 00     LDR     R12, [R5]
c0e1ea14: e3 a0 60 00     MOV     R6, #$0
c0e1ea18: e3 a0 b0 04     MOV     R11, #$4
c0e1ea1c: e5 9f 31 9c     LDR     R3, =$c0c221a0 [$c0e1ebc0]
c0e1ea20: e3 a0 80 01     MOV     R8, #$1
c0e1ea24: e3 a0 90 bf     MOV     R9, #$bf
c0e1ea28: e5 9f 41 94     LDR     R4, =$c0fc0484 [$c0e1ebc4]
c0e1ea2c: e3 a0 a0 1e     MOV     R10, #$1e
c0e1ea30: e2 8c 70 64     ADD     R7, R12, #$64
c0e1ea34: e5 8c 60 58     STR     R6, [R12, #$58]
c0e1ea38: e5 8c 30 48     STR     R3, [R12, #$48]
c0e1ea3c: e5 9f 31 ac     LDR     R3, =$c0c22242 [$c0e1ebf0]
c0e1ea40: e1 cc b6 b0     STRH    R11, [R12,#$60]
c0e1ea44: e1 cc 86 b2     STRH    R8, [R12,#$62]
c0e1ea48: e5 8c 30 4c     STR     R3, [R12, #$4c]
c0e1ea4c: e3 a0 30 80     MOV     R3, #$80
c0e1ea50: e5 8c 30 54     STR     R3, [R12, #$54]
c0e1ea54: e8 b4 00 0f     LDMUW   [R4], { R0-R3 }
c0e1ea58: e8 a7 00 0f     STMUW   [R7], { R0-R3 }
c0e1ea5c: e8 b4 00 0f     LDMUW   [R4], { R0-R3 }
c0e1ea60: e8 a7 00 0f     STMUW   [R7], { R0-R3 }
c0e1ea64: e8 94 00 07     LDMU    [R4], { R0-R2 }
c0e1ea68: e8 87 00 07     STMU    [R7], { R0-R2 }
c0e1ea6c: e3 a0 7c 96     MOV     R7, #$9600
c0e1ea70: e1 a0 00 0c     MOV     R0, R12 
c0e1ea74: e5 9f 11 78     LDR     R1, =$c0a39b2c <ptm_unix98_ops> [$c0e1ebf4]
c0e1ea78: e5 8c 60 64     STR     R6, [R12, #$64]
c0e1ea7c: e5 8c 60 68     STR     R6, [R12, #$68]
c0e1ea80: e5 8c 60 70     STR     R6, [R12, #$70]
c0e1ea84: e5 8c 90 6c     STR     R9, [R12, #$6c]
c0e1ea88: e5 8c 70 88     STR     R7, [R12, #$88]
c0e1ea8c: e5 8c e0 98     STR     LR, [R12, #$98]
c0e1ea90: e5 8c 70 8c     STR     R7, [R12, #$8c]
c0e1ea94: e5 8c a0 90     STR     R10, [R12, #$90]
c0e1ea98: eb d6 d8 20     BL      $c03d4b20 <tty_set_operations>
c0e1ea9c: e5 95 e0 04     LDR     LR, [R5, #$4]
c0e1eaa0: e5 9f 31 28     LDR     R3, =$c0c221ab [$c0e1ebd0]
c0e1eaa4: e5 8e 60 58     STR     R6, [LR, #$58]
c0e1eaa8: e2 44 60 20     SUB     R6, R4, #$20
c0e1eaac: e2 8e c0 64     ADD     R12, LR, #$64
c0e1eab0: e5 8e 30 48     STR     R3, [LR, #$48]
c0e1eab4: e5 9f 31 3c     LDR     R3, =$c0bea6c2 [$c0e1ebf8]
c0e1eab8: e1 ce b6 b0     STRH    R11, [LR,#$60]
c0e1eabc: e5 8e 30 4c     STR     R3, [LR, #$4c]
c0e1eac0: e3 a0 30 88     MOV     R3, #$88
c0e1eac4: e5 8e 30 54     STR     R3, [LR, #$54]
c0e1eac8: e3 a0 30 02     MOV     R3, #$2
c0e1eacc: e1 ce 36 b2     STRH    R3, [LR,#$62]
c0e1ead0: e8 b6 00 0f     LDMUW   [R6], { R0-R3 }
c0e1ead4: e8 ac 00 0f     STMUW   [R12], { R0-R3 }
c0e1ead8: e8 b6 00 0f     LDMUW   [R6], { R0-R3 }
c0e1eadc: e8 ac 00 0f     STMUW   [R12], { R0-R3 }
c0e1eae0: e8 94 00 07     LDMU    [R4], { R0-R2 }
c0e1eae4: e5 95 30 00     LDR     R3, [R5]
c0e1eae8: e8 8c 00 07     STMU    [R12], { R0-R2 }
c0e1eaec: e1 a0 00 0e     MOV     R0, LR 
c0e1eaf0: e5 9f 11 04     LDR     R1, =$c0a39ba8 <pty_unix98_ops> [$c0e1ebfc]
c0e1eaf4: e5 8e 90 6c     STR     R9, [LR, #$6c]
c0e1eaf8: e5 8e 70 88     STR     R7, [LR, #$88]
c0e1eafc: e5 8e 70 8c     STR     R7, [LR, #$8c]
c0e1eb00: e5 8e a0 90     STR     R10, [LR, #$90]
c0e1eb04: e5 8e 30 98     STR     R3, [LR, #$98]
c0e1eb08: eb d6 d8 04     BL      $c03d4b20 <tty_set_operations>
c0e1eb0c: e5 95 00 00     LDR     R0, [R5]
c0e1eb10: eb d6 d9 28     BL      $c03d4fb8 <tty_register_driver>
c0e1eb14: e3 50 00 00     CMPS    R0, #$0
c0e1eb18: 15 9f 00 e0     LDRNE   R0, =$c0c22246 [$c0e1ec00]
c0e1eb1c: 1a ff ff 63     BNE     $c0e1e8b0
c0e1eb20: e5 95 00 04     LDR     R0, [R5, #$4]
c0e1eb24: eb d6 d9 23     BL      $c03d4fb8 <tty_register_driver>
c0e1eb28: e3 50 00 00     CMPS    R0, #$0
c0e1eb2c: 15 9f 00 d0     LDRNE   R0, =$c0c2226a [$c0e1ec04]
c0e1eb30: 1a ff ff 5e     BNE     $c0e1e8b0
c0e1eb34: e2 85 00 08     ADD     R0, R5, #$8
c0e1eb38: eb d6 e5 85     BL      $c03d8154 <tty_default_fops>
c0e1eb3c: e5 9f 30 c4     LDR     R3, =$c03de998 <ptmx_open> [$c0e1ec08]
c0e1eb40: e2 85 00 70     ADD     R0, R5, #$70
c0e1eb44: e2 85 10 08     ADD     R1, R5, #$8
c0e1eb48: e5 85 30 34     STR     R3, [R5, #$34]
c0e1eb4c: eb d0 f4 3c     BL      $c025bc44 <cdev_init>
c0e1eb50: e2 85 00 70     ADD     R0, R5, #$70
c0e1eb54: e5 9f 10 b0     LDR     R1, =$500002 [$c0e1ec0c]
c0e1eb58: e1 a0 20 08     MOV     R2, R8 
c0e1eb5c: eb d0 f4 6d     BL      $c025bd18 <cdev_add>
c0e1eb60: e2 50 40 00     SUBS    R4, R0, #$0
c0e1eb64: 0a 00 00 01     BEQ     $c0e1eb70
c0e1eb68:                                             ; from c0e1eb84
c0e1eb68: e5 9f 00 a0     LDR     R0, =$c0c2228e [$c0e1ec10]
c0e1eb6c: ea ff ff 4f     B       $c0e1e8b0
c0e1eb70:                                             ; from c0e1eb64
c0e1eb70: e5 9f 00 94     LDR     R0, =$500002 [$c0e1ec0c]
c0e1eb74: e1 a0 10 08     MOV     R1, R8 
c0e1eb78: e5 9f 20 94     LDR     R2, =$c0bf8e0d [$c0e1ec14]
c0e1eb7c: eb d0 f5 46     BL      $c025c09c <register_chrdev_region>
c0e1eb80: e3 50 00 00     CMPS    R0, #$0
c0e1eb84: ba ff ff f7     BLT     $c0e1eb68
c0e1eb88: e5 9f 30 88     LDR     R3, =$c0bf8e12 [$c0e1ec18]
c0e1eb8c: e1 a0 10 04     MOV     R1, R4 
c0e1eb90: e5 9f 20 74     LDR     R2, =$500002 [$c0e1ec0c]
c0e1eb94: e5 8d 30 00     STR     R3, [SP]
c0e1eb98: e5 9f 30 7c     LDR     R3, =$c1175968 [$c0e1ec1c]
c0e1eb9c: e5 93 00 00     LDR     R0, [R3]
c0e1eba0: e1 a0 30 04     MOV     R3, R4 
c0e1eba4: eb d8 a6 a9     BL      $c0448650 <device_create>
c0e1eba8: e1 a0 00 04     MOV     R0, R4 
c0e1ebac: e2 8d d0 14     ADD     SP, SP, #$14
c0e1ebb0: e8 bd 8f f0     LDMUW   [SP], { R4-R11, PC }

長いですね。すみませんでした。
注目するべきところは

c0e1eb34: e2 85 00 08     ADD     R0, R5, #$8
c0e1eb38: eb d6 e5 85     BL      $c03d8154 <tty_default_fops>

のところです。
前半のpty_initのソースに、

tty_default_fops(&ptmx_fops);

とありましたが、まさにその部分がこれです。

c0e1eb34: e2 85 00 08     ADD     R0, R5, #$8

はR5に8を足してR0に入れる(R0=R5+8)っていう動きをするのですが、このR0こそptmx_fopsのアドレスになります。
なので、R5の値を特定して8を足してやればR0と同じ、つまりptmx_fopsの値になります。
そこで直前のR5レジスタの動きを見てみましょう。
このディスアセンブラは基本的に
<命令> <命令を受けるレジスタとか>, <命令実行に使うレジスタとか>
といった感じなので、命令を受けてるR5、簡単に言えば命令のとなりにいるR5を探します。
すると、

c0e1e9d8: e5 9f 52 04     LDR     R5, =$c1175a70 [$c0e1ebe4]

というのが見つかります。
LDR命令は32bitの定数値か何かしらのアドレスをレジスタにロードする命令です。
今回の場合は、アドレスc0e1ebe4の中身がロードされています。
そこで、c0e1ebe4の部分をディスアセンブルしてみます。

$ ./arm7-dasm kernel.dump c0008000 c0e1ebe4 kallsyms_kyv31.txt | grep c0e1ebe4
70271 symbols are loaded.
Disassemble whole image.
Disassemble 0xc0e1ebe4 - 0xc1077d00
c0e1ebe4: c1 17 5a 70     TSTGTS  R7, R0 ,ROR R10

マシン語の部分がc1175a70なので、R5にロードにされた値はc1175a70、つまりR5=c1175a70となるので
R5+8=R0=ptmx_fopsのアドレス より、ptmx_fopsのアドレスはc1175a78となります。
これで無事おわりなわけですが、この方法だと少しばかり面倒ですよね...

ptmx_open

そんなわけでptmx_open式の紹介です。
正直、こっちのほうが早いです。
とりあえず、ptmx_openをディスアセンブルします。

$ ./arm7-dasm kernel.dump c0008000 ptmx_open kallsyms_kyv31.txt > ptmx_open.dasm
70271 symbols are loaded.

以下、ディスアセンブル結果

Disassemble 0xc03de998 - 0xc03dea90
c03de998:             <ptmx_open>
c03de998: e9 2d 41 f0     STMPW   [SP], { R4-R8, LR }
c03de99c: e1 a0 60 01     MOV     R6, R1 
c03de9a0: e1 a0 70 00     MOV     R7, R0 
c03de9a4: eb f9 de ec     BL      $c025655c <nonseekable_open>
c03de9a8: e1 a0 00 06     MOV     R0, R6 
c03de9ac: eb ff db 6e     BL      $c03d576c <tty_alloc_file>
c03de9b0: e2 50 40 00     SUBS    R4, R0, #$0
c03de9b4: 1a 00 00 34     BNE     $c03dea8c
c03de9b8: eb 15 dc e3     BL      $c0955d4c <tty_lock>
c03de9bc: e1 a0 00 07     MOV     R0, R7 
c03de9c0: eb fb 33 fc     BL      $c02ab9b8 <devpts_new_index>
c03de9c4: e1 a0 40 00     MOV     R4, R0 
c03de9c8: eb 15 dc dc     BL      $c0955d40 <tty_unlock>
c03de9cc: e3 54 00 00     CMPS    R4, #$0
c03de9d0: ba 00 00 2b     BLT     $c03dea84
c03de9d4: e5 9f 80 b8     LDR     R8, =$c1175a70 [$c03dea94]
c03de9d8: e5 9f 00 b8     LDR     R0, =$c0fc0440 [$c03dea98]
c03de9dc: eb 15 d3 c1     BL      $c09538e8 <mutex_lock>
c03de9e0: eb 15 dc d9     BL      $c0955d4c <tty_lock>
c03de9e4: e1 a0 10 04     MOV     R1, R4 
c03de9e8: e5 98 00 00     LDR     R0, [R8]
c03de9ec: eb ff df e9     BL      $c03d6998 <tty_init_dev>
c03de9f0: e1 a0 50 00     MOV     R5, R0 
c03de9f4: e5 9f 00 9c     LDR     R0, =$c0fc0440 [$c03dea98]
c03de9f8: eb 15 d3 41     BL      $c0953704 <mutex_unlock>
c03de9fc: e3 75 0a 01     CMNS    R5, #$1000
c03dea00: 9a 00 00 05     BLS     $c03dea1c
c03dea04: e1 a0 10 04     MOV     R1, R4 
c03dea08: e1 a0 00 07     MOV     R0, R7 
c03dea0c: eb fb 34 21     BL      $c02aba98 <devpts_kill_index>
c03dea10: e1 a0 40 05     MOV     R4, R5 
c03dea14: eb 15 dc c9     BL      $c0955d40 <tty_unlock>
c03dea18: ea 00 00 19     B       $c03dea84
c03dea1c:                                             ; from c03dea00
c03dea1c: e3 a0 00 10     MOV     R0, #$10
c03dea20: e2 85 10 9c     ADD     R1, R5, #$9c
c03dea24: eb fe 01 71     BL      $c035eff0 <_set_bit>
c03dea28: e1 a0 00 05     MOV     R0, R5 
c03dea2c: e1 a0 10 06     MOV     R1, R6 
c03dea30: eb ff db 60     BL      $c03d57b8 <tty_add_file>
c03dea34: e1 a0 00 07     MOV     R0, R7 
c03dea38: e5 95 10 b4     LDR     R1, [R5, #$b4]
c03dea3c: eb fb 34 29     BL      $c02abae8 <devpts_pty_new>
c03dea40: e2 50 40 00     SUBS    R4, R0, #$0
c03dea44: 1a 00 00 09     BNE     $c03dea70
c03dea48: e5 98 30 00     LDR     R3, [R8]
c03dea4c: e1 a0 00 05     MOV     R0, R5 
c03dea50: e1 a0 10 06     MOV     R1, R6 
c03dea54: e5 93 30 a8     LDR     R3, [R3, #$a8]
c03dea58: e5 93 30 0c     LDR     R3, [R3, #$c]
c03dea5c: e1 2f ff 33     BLX     R3
c03dea60: e2 50 40 00     SUBS    R4, R0, #$0
c03dea64: 1a 00 00 01     BNE     $c03dea70
c03dea68: eb 15 dc b4     BL      $c0955d40 <tty_unlock>
c03dea6c: ea 00 00 06     B       $c03dea8c
c03dea70:                                             ; from c03dea44
c03dea70:                                             ;      c03dea64
c03dea70: eb 15 dc b2     BL      $c0955d40 <tty_unlock>
c03dea74: e1 a0 00 07     MOV     R0, R7 
c03dea78: e1 a0 10 06     MOV     R1, R6 
c03dea7c: eb ff e0 1d     BL      $c03d6af8 <tty_release>
c03dea80: ea 00 00 01     B       $c03dea8c
c03dea84:                                             ; from c03de9d0
c03dea84:                                             ;      c03dea18
c03dea84: e1 a0 00 06     MOV     R0, R6 
c03dea88: eb ff db 5d     BL      $c03d5804 <tty_free_file>
c03dea8c:                                             ; from c03de9b4
c03dea8c:                                             ;      c03dea6c
c03dea8c:                                             ;      c03dea80
c03dea8c: e1 a0 00 04     MOV     R0, R4 
c03dea90: e8 bd 81 f0     LDMUW   [SP], { R4-R8, PC }

c03de9d4になんだか見覚えのあるアドレスがのってますね。

c03de9d4: e5 9f 80 b8     LDR     R8, =$c1175a70 [$c03dea94]

さっきのR5の値ですね。
お察しの通り、ptmx_openを使う場合は2連続でLDRしてるとこを見つけて、上のLDRする値に8を足せばおしまいです。
さっきよりも何倍も早いですね。

オチ

さて、無事にptmx_fopsを手に入れたわけですし、早速device.dbに書き込んで実行したいところですが、
他のアドレスが0xc0n00000番台なのに、0xc1175a78って少し大きすぎませんか?
実は、このptmx_fopsはtextセクションに書かれています。
低レイヤーなことやってる人ならご存知だと思いますが、ここで説明すると長いのですごく簡単に言うと、おいそれとは書き込めない領域です。
つまるところ、KYV31のビル番103以降のやつはptmx_fopsを使ったあれこれができません。
そんなオチでした、まる

次はN-05Dあたりになるのかな...
404KCも手に入りそうなのでそっちをするかもしれません。
しかし国産スマホネタは需要が微妙というか変にマニアックなので、せっせと書いてCTFの事やら書きたいのが本音です。

国産スマホをroot化するには LSM解除編(後半)

前回はマウントをさせまいとしてるのが、
0xc026bae8 - 0xc026bbf4に実体を持つkclsm_sb_mountくんである事を突き詰めて、ディスアセンブルした所で終わりました。
今回はこれを読んで、いい感じに処理を書き換えてroot化できるようにして、ついでにLSMも全部解除しちゃいます。

アセンブリを読む

ここからがやや難しいです。前回ディスアセンブルしたのを読むわけですが、
アドレスに命令にレジスタオペランドがブワアァァァアって並んでて、難しそうに見えがちです。
私も最初はかなり苦戦しましたが、LiveOverflow氏がその辺をわかりやすく解説した動画を上げてくださっており、私自身そこでアセンブリの読み方の基礎を理解できたので、誰かの助けになればと貼っておきます。
アセンブラ入門:https://youtu.be/6jSKldt7Eqs
実演:https://youtu.be/VroEiMOJPm8
再生リスト:https://www.youtube.com/playlist?list=PLhixgUqwRTjxglIswKp9mpkfPNfHkzyeN
ありがたいことにPart8までは有志の方が日本語字幕をつけてくださっています。

前置きが長くなりましたが、読んでいきましょう。
とりあえず、ディスアセンブルした結果を貼ります。

Disassemble 0xc026bae8 - 0xc026bbf4
c026bae8:             <kclsm_sb_mount>
c026bae8: e9 2d 41 f3     STMPW   [SP], { R0-R1, R4-R8, LR }
c026baec: e1 a0 70 03     MOV     R7, R3 
c026baf0: e5 9f 31 00     LDR     R3, =$c0f53a98 <kmalloc_caches> [$c026bbf8]
c026baf4: e1 a0 50 00     MOV     R5, R0 
c026baf8: e1 a0 60 01     MOV     R6, R1 
c026bafc: e5 93 00 30     LDR     R0, [R3, #$30]
c026bb00: e3 50 00 00     CMPS    R0, #$0
c026bb04: 0a 00 00 05     BEQ     $c026bb20
c026bb08: e3 a0 10 d0     MOV     R1, #$d0
c026bb0c: e3 a0 2a 01     MOV     R2, #$1000
c026bb10: eb fa f9 3e     BL      $c012a010 <kmem_cache_alloc_trace>
c026bb14: e2 50 40 00     SUBS    R4, R0, #$0
c026bb18: 1a 00 00 01     BNE     $c026bb24
c026bb1c: ea 00 00 32     B       $c026bbec
c026bb20:                                             ; from c026bb04
c026bb20: e3 a0 40 10     MOV     R4, #$10
c026bb24:                                             ; from c026bb18
c026bb24: e1 a0 00 06     MOV     R0, R6 
c026bb28: e1 a0 10 04     MOV     R1, R4 
c026bb2c: e3 a0 2a 01     MOV     R2, #$1000
c026bb30: eb fb 54 54     BL      $c0140c88 <d_path>
c026bb34: e5 9f 10 c0     LDR     R1, =$c0a43331 [$c026bbfc]
c026bb38: e3 a0 20 07     MOV     R2, #$7
c026bb3c: e1 a0 60 00     MOV     R6, R0 
c026bb40: eb 00 db e6     BL      $c02a2ae0 <strncmp>
c026bb44: e2 50 80 00     SUBS    R8, R0, #$0
c026bb48: 13 a0 80 00     MOVNE   R8, #$0
c026bb4c: 1a 00 00 23     BNE     $c026bbe0
c026bb50: e1 a0 00 06     MOV     R0, R6 
c026bb54: e5 9f 10 a0     LDR     R1, =$c0a43331 [$c026bbfc]
c026bb58: eb 00 db d3     BL      $c02a2aac <strcmp>
c026bb5c: e3 50 00 00     CMPS    R0, #$0
c026bb60: 0a 00 00 07     BEQ     $c026bb84
c026bb64: e1 a0 20 0d     MOV     R2, SP 
c026bb68: e3 c2 3d 7f     BIC     R3, R2, #$1fc0
c026bb6c: e3 c3 30 3f     BIC     R3, R3, #$3f
c026bb70: e5 93 30 0c     LDR     R3, [R3, #$c]
c026bb74: e5 93 31 18     LDR     R3, [R3, #$118]
c026bb78: e3 53 00 01     CMPS    R3, #$1
c026bb7c: 0a 00 00 17     BEQ     $c026bbe0
c026bb80: ea 00 00 0a     B       $c026bbb0
c026bb84:                                             ; from c026bb60
c026bb84: e3 17 00 20     TSTS    R7, #$20
c026bb88: 05 9f 70 70     LDREQ   R7, =$c082bfb4 [$c026bc00]
c026bb8c: 0a 00 00 04     BEQ     $c026bba4
c026bb90: ea 00 00 06     B       $c026bbb0
c026bb94:                                             ; from c026bbac
c026bb94: e1 a0 00 05     MOV     R0, R5 
c026bb98: eb 00 db c3     BL      $c02a2aac <strcmp>
c026bb9c: e2 50 80 00     SUBS    R8, R0, #$0
c026bba0: 0a 00 00 0e     BEQ     $c026bbe0
c026bba4:                                             ; from c026bb8c
c026bba4: e5 b7 10 04     LDR!    R1, [R7, #$4]
c026bba8: e3 51 00 00     CMPS    R1, #$0
c026bbac: 1a ff ff f8     BNE     $c026bb94
c026bbb0:                                             ; from c026bb80
c026bbb0:                                             ;      c026bb90
c026bbb0: e1 a0 20 0d     MOV     R2, SP 
c026bbb4: e3 c2 3d 7f     BIC     R3, R2, #$1fc0
c026bbb8: e3 c3 30 3f     BIC     R3, R3, #$3f
c026bbbc: e5 9f 00 40     LDR    R0, =$c0a4313e [$c026bc04]
c026bbc0: e5 9f 10 40     LDR     R1, =$c082bfc0 <__func__.15903> [$c026bc08]
c026bbc4: e3 e0 80 00     MVN     R8, #$0
c026bbc8: e5 93 30 0c     LDR     R3, [R3, #$c]
c026bbcc: e5 8d 60 00     STR     R6, [SP]
c026bbd0: e5 8d 50 04     STR     R5, [SP, #$4]
c026bbd4: e5 93 21 18     LDR     R2, [R3, #$118]
c026bbd8: e2 83 3f 7f     ADD     R3, R3, #$1fc
c026bbdc: eb 15 97 3c     BL      $c07d18d4 <printk>
c026bbe0:                                             ; from c026bb4c
c026bbe0:                                             ;      c026bb7c
c026bbe0:                                             ;      c026bba0
c026bbe0: e1 a0 00 04     MOV     R0, R4 
c026bbe4: eb fa f5 ef     BL      $c01293a8 <kfree>
c026bbe8: ea 00 00 00     B       $c026bbf0
c026bbec:                                             ; from c026bb1c
c026bbec: e3 e0 80 0b     MVN     R8, #$b
c026bbf0:                                             ; from c026bbe8
c026bbf0: e1 a0 00 08     MOV     R0, R8 
c026bbf4: e8 bd 81 fc     LDMUW   [SP], { R2-R8, PC }

ARMアセンブリなので、見慣れないのがちょくちょくいます。
基本的にBなんとかの命令はx86の命令におけるジャンプ系統の命令で、

  • B命令→JMP命令
  • BEQ命令→JE命令
  • BNE命令→JNE命令
  • BL命令→CALL命令

として読み替えれば大体OKです。
それを踏まえてざっくりと見てみると、strcmpを呼んでジャンプするかしないかを判別してることがわかります。
前半で見たソースと同じ感じですね。

static int kclsm_sb_mount(char *dev_name, struct path *path,
                char *type, unsigned long flags, void *data)
{
    int i, ret = 0;
    char *ptr, *realpath = NULL;

    ptr = kmalloc(PATH_MAX, GFP_KERNEL);
    if (!ptr)
        return -ENOMEM;

    realpath = d_path(path, ptr, PATH_MAX);

    if (strncmp(realpath, KCLSM_SYSTEM_MOUNT_POINT,
            strlen(KCLSM_SYSTEM_MOUNT_POINT)) != 0)
        goto out;

そう考えると、0xc026bb40でBLされてるstrcmpは、ソース最初の方のstrcmpに該当すると考えられます。
さらに、その後の0xc026bb4cのBNEが最後の方の0xc026bbe0までジャンプし、0xc026bbdcのカーネルメッセージを出力するprintkが呼ばれる事がないのを考えると、このジャンプはgoto out(正常処理)だと考えれますし、つじつまが合います。
つまり、このBNE命令を何がなんでも0xc026bbe0に飛ぶようにしてしまえば、mountでsystemが渡されても問題なしとして処理してくれるようになると思われます。
というわけなので書き換えてみましょう。
とりあえず飛べば良いのを考えればB命令(JMP命令)にするのが吉でしょう。
書き換える場合はwrite_valueで書き換えるアドレスと、書き換え後のマシン語を渡せばOKです。
確認のためにアドレスのマシン語を見る場合はread_valueで確認したいアドレスを渡しましょう。
実際にやってみます。

shell@android:/data/local/tmp # ./read_value 0xc026bb4c                        
value = 0x1a000023
shell@android:/data/local/tmp # ./write_value 0xc026bb4c 0xea000023            
old value = 0x1a000023
new value = 0xea000023

アドレスの命令が書き換えれました。
では、リマウントしてみましょう...

shell@android:/data/local/tmp # mount -o rw,remount /system
shell@android:/data/local/tmp # mount | grep system
/dev/block/platform/msm_sdcc.1/by-name/system /system ext4 rw,relatime,data=ordered 0 0

書き込み可でマウントされています!!
dmesgを眺めても、エラーは見当たりません。kclsm_sb_mountの解除に成功しました。


※以下の事は本編とは関係はありませんが、実機でやってる人向けに記録として書いておきます。
さっさと続きを読ませろって人はすみませんが少し多めにスクロールしてください。

実機でやってる人のなかで、もしかしたら解除してリマウントしたらスマホが固まって再起動したっていう人がいるかもしれません。
私自身、KYY22の実機を2台とKYY21を1台持っているのですが、KYY22のうち一つだけがなぜかそうなるんですよね...
解決策としては、後述するmmcプロテクトをリマウント前に解除してリマウントすることで解決します。
が、なぜか重い負荷をかけてもリマウントできてしまうみたいなんです。
原因がよくわかってないのですが、鳩羽つぐにハマり初めた時に、YouTube愛の挨拶のピアノアレンジをKYY22で流しながら諦め半分でリマウントしたら成功しました。
本当に謎です。わかんないです。もし原因がわかる方がいらっしゃったら連絡ください...


mmcプロテクト

無事にリマウントできたわけですし、これでsuバイナリ置いて終わってしまいたいところですが、京セラさんはそこまで甘くありません。

shell@android:/data/local/tmp # mount -o rw,remount /system
shell@android:/data/local/tmp # cp su /system/xbin
shell@android:/data/local/tmp # ls /system/xbin | grep su
su
shell@android:/data/local/tmp # reboot

fan@thinkpad:~/kyy22$ adb shell
shell@android:/ $ cd /data/local/tmp
shell@android:/data/local/tmp $ ./install_backdoor && ./run_root_shell         
Attempt acdb exploit...
KYY22 (102.0.0f00) is not supported.
Attempt put_user exploit...
ioctl: Bad address
Attempt pingpong exploit...
No icmp socket available
Attempt futex exploit...
futex_exploit: Server started
install_mmap: success
shell@android:/data/local/tmp # id
uid=0(root) gid=0(root)
shell@android:/data/local/tmp # ls /system/xbin | grep su
shell@android:/data/local/tmp #

はい。再起動すると消えてしまいます。
実は本体メモリ(mmcblk0)にプロテクトがかかっていて、これが書き込んでも再起動したら無かったことにしています。
しかしこれはMMC規格に標準で搭載された機能を使ったプロテクトみたいなので、あまり苦労せずに解除できます。

kernel.googlesource.com

これをgit cloneしてndk-buildすればバイナリができます。
できるはずなんです...
なぜか私の環境だとうまくコンパイルできませんでした。
プロトタイプ関数書いたり、ボトムアップにしてみたり、ヘッダファイル加えたり、いろいろ修正を試みましたが、全部無理でした。
そこでshiosefineさんに協力をお願いしたところ、普通に通ったみたいです...
もしかしたら私みたいにうまくいかない人がいるかもなので、コンパイル済みの物をここに置いておきます。
https://drive.google.com/open?id=1Is27O_W-GbUJlHRKJbxDxhANLtEO8jHF
では、早速いつもの場所にadb pushして解除していきます。
まずはプロテクトの確認です。
プロテクトの有無、範囲の確認はmmc_utils writeprotect user get <ブロックデバイスへのパス>でできます。

fan@thinkpad:~/tools$ adb push mmc_utils /data/local/tmp
mmc_utils: 1 file pushed. 1.0 MB/s (73596 bytes in 0.070s)

shell@android:/data/local/tmp # chmod 755 mmc_utils                            
shell@android:/data/local/tmp # ./mmc_utils writeprotect user get /dev/block/mmcblk0
Write Protect Group size in blocks/bytes: 16384/8388608
Write Protect Groups 0-183 (Blocks 0-3014655), Temporary Write Protection
Write Protect Groups 184-1877 (Blocks 3014656-30769151), No Write Protection

どうやらmmcblk0の0〜183まで一時的なプロテクトがかかっているようです。
解除はmmc_utils writeprotect user set none <スタートブロック> <解除するブロック数> <ブロックデバイスへのパス>
でできます。

shell@android:/data/local/tmp # ./mmc_utils writeprotect user set none 0 3014656 /dev/block/mmcblk0
shell@android:/data/local/tmp # ./mmc_utils writeprotect user get /dev/block/mmcblk0
Write Protect Group size in blocks/bytes: 16384/8388608
Write Protect Groups 0-1877 (Blocks 0-30769151), No Write Protection

無事に解除できたようです。
実際に試して見ましょう。

shell@android:/data/local/tmp # mount -o rw,remount /system
shell@android:/data/local/tmp # ls /system/xbin | grep su
su
shell@android:/data/local/tmp # reboot

fan@thinkpad:~/kyy22$adb shell
shell@android:/ $ cd /data/local/tmp
shell@android:/data/local/tmp $ ./install_backdoor && run_root_shell
Attempt acdb exploit...
KYY22 (102.0.0f00) is not supported.
Attempt put_user exploit...
ioctl: Bad address
Attempt pingpong exploit...
No icmp socket available
Attempt futex exploit...
futex_exploit: Server started
install_mmap: success
shell@android:/data/local/tmp # id
uid=0(root) gid=0(root)
shell@android:/data/local/tmp # ls /system/xbin | grep su
su

無事に消されずに置けました。
ここで少し注意ですが、mmcプロテクトや書き換えたカーネルは、再起動するとすべて元に戻ります
これの対策は後述するので、一旦置いておきます。
で、無事にsuが置けたので、またカーネルいじってmmcプロテクト解除して権限を調整します。

shell@android:/data/local/tmp # ./write_value 0xc026bb4c 0xea000023        
old value = 0x1a000023
new value = 0xea000023
shell@android:/data/local/tmp # ./mmc_utils writeprotect user set none 0 3014656 /dev/block/mmcblk0
shell@android:/data/local/tmp # mount -o rw,remount /system
shell@android:/data/local/tmp # chmod 6755 /system/xbin/su
shell@android:/data/local/tmp # chown root.root /system/xbin/su

では、suバイナリを実際に使ってみます。
書き損ねましたが、今回はSHARP_android_rooting_tools(DLKeyはroot)からsuバイナリを引っ張りだして使用します。
どうせSuperSU入れれば更新してくれますし。

shell@android:/data/local/tmp # exit
shell@android:/data/local/tmp $ su
root@android:/data/local/tmp # id
uid=0(root) gid=0(root)
root@android:/data/local/tmp # reboot
fan@thinkpad:~/kyy22$ adb shell
shell@android:/ $ su
root@android:/ # id
uid=0(root) gid=0(root)

というわけで無事にroot化できました。
が、他のLSMが解除できてないので、chrootや、insmod、mknod等のややマニアックなコマンドを使おうとするとLSMに殺されてしまいます。
それに、再起動のたびにカーネル書き換えて、mmcプロテクト解除して...は面倒です。次項では、その辺を解決します。

LSMの全解除と自動化

とりあえず、京セラのLSMがどれくらいあるのかを見て見るために、シンボル情報をgrepしてみます。

fan@thinkpad:~/kyy22$ cat kyy22.txt | grep kclsm
c026ba78 kclsm_path_chroot
c026bab0 kclsm_sb_pivotroot
c026bae8 kclsm_sb_mount
c026bc0c kclsm_ptrace_traceme
c026bc60 kclsm_kernel_setup_load_info
c026bd00 kclsm_path_mknod
c026be00 kclsm_sb_umount
c026bf38 kclsm_ptrace_access_check
c026bfb8 kclsm_dentry_open
c082bfb8 kclsm_mount_checklist
c082bfe4 kclsm_module_checklist
c0c1cdc4 kclsm_bootmode_setup
c0c1cdf0 kclsm_kbfm_setup
c0c1ce1c kclsm_init
c0c1ce4c kclsm_sysfs_init
c0c3b320 kclsm_sysfs_exit
c0c50973 __setup_str_kclsm_bootmode_setup
c0c50984 __setup_str_kclsm_kbfm_setup
c0c514d4 __setup_kclsm_bootmode_setup
c0c514e0 __setup_kclsm_kbfm_setup
c0c51a90 __initcall_kclsm_sysfs_init6
c0c52338 __initcall_kclsm_init
c0d93784 kclsm_security_ops
c0d939b8 kclsm_attr_group
c0d939c4 kclsm_attrs
c0d93a14 kclsm_debuggerd_attr
c0d93a24 kclsm_ueventd_attr
c0d93a34 kclsm_vold_attr
c0d93a44 kclsm_rmt_storage_attr
c0d93a54 kclsm_wifi_diag_attr
c0d93a64 kclsm_lkspad_attr
c0d93a74 kclsm_fs_mgr_attr
c0d93a84 kclsm_kflcd_attr
c0d93a94 kclsm_kflcdiag_attr
c0d93aa4 kclsm_ts_daemon_attr
c0d93ab4 kclsm_ts_diag_attr
c0d93ac4 kclsm_sdcardioserver_attr
c0d93ad4 kclsm_usb_init_attr
c0d93ae4 kclsm_disp_ctrl_attr
c0d93af4 kclsm_kdiag_common_attr
c0d93b04 kclsm_bfss_diag_attr
c0d93b14 kclsm_extlibd_attr
c0d93b24 kclsm_process_list_attr
c0d93b34 kclsm_lkspad_client_attr
c0f54f90 kclsm_bootmode
c0f54f94 kclsm_kbfm
c0f54f98 kclsm_kobj

結構多いですね...
しかし、実際に解除するのは例のkclsm.cに書かれてる分でOKです。
(kclsm_path_chroot〜kclsm_dentry_open)
これを解除していくわけですが、実は2つだけ特殊なものがあります。
それが

  • kclsm_path_chroot
  • kclsm_sb_pivotroot

の2つです。
この2つのソースを見てみればわかりますが、

#ifdef CONFIG_SECURITY_KCLSM_PIVOTROOT
static int kclsm_sb_pivotroot(struct path *old_path, struct path *new_path)
{
    pr_warn("no permission in %s pid=%d pname=%s\n",
        __FUNCTION__, current->pid, current->comm);
    return KCLSM_RETURN(-EPERM);
}
#endif

#ifdef CONFIG_SECURITY_KCLSM_CHROOT
static int kclsm_path_chroot(struct path *path)
{
    pr_warn("no permission in %s pid=%d pname=%s\n",
        __FUNCTION__, current->pid, current->comm);
    return KCLSM_RETURN(-EPERM);
}
#endif

このように、カーネルメッセージを表示する処理しかしていません。
ソースを全部のせると長くなるので省略しますが、他の関数は正常処理を行うか、例外処理を行うかが書かれています。
したがって、この2つはいじってもせいぜいエラーを吐かせなくさせるくらいしかできません。
なので、この2つの解除は一旦置いておいて、他のを解除していきます。
基本的にprintkに行き着くのはアウトコースなので、それを避けてるジャンプを探してB命令に書き換えるだけです。
前述の通りソースコードを載せると長くなる上、なんか問題になりそうなのでアセンブリと見比べたい方は、
すみませんが京セラのサイトから自分で落として見てください。


kclsm_ptrace_traceme

uidが0以外、すなわちroot以外のユーザーによるトレースを阻止する。

Disassemble 0xc026bc0c - 0xc026bc54
c026bc0c:             <kclsm_ptrace_traceme>
c026bc0c: e9 2d 40 07     STMPW   [SP], { R0-R2, LR }
c026bc10: e1 a0 20 0d     MOV     R2, SP 
c026bc14: e3 c2 3d 7f     BIC     R3, R2, #$1fc0
c026bc18: e3 c3 30 3f     BIC     R3, R3, #$3f
c026bc1c: e5 93 30 0c     LDR     R3, [R3, #$c]
c026bc20: e5 93 21 f4     LDR     R2, [R3, #$1f4]
c026bc24: e5 92 20 04     LDR     R2, [R2, #$4]
c026bc28: e3 52 00 00     CMPS    R2, #$0
c026bc2c: 13 a0 00 00     MOVNE   R0, #$0
c026bc30: 1a 00 00 07     BNE     $c026bc54
c026bc34: e2 80 0f 7f     ADD     R0, R0, #$1fc
c026bc38: e5 9f 10 18     LDR     R1, =$c082bfcf <__func__.15876> [$c026bc58]
c026bc3c: e5 8d 00 00     STR     R0, [SP]
c026bc40: e5 9f 00 14     LDR     R0, =$c0a431b1 [$c026bc5c]
c026bc44: e5 93 21 18     LDR     R2, [R3, #$118]
c026bc48: e2 83 3f 7f     ADD     R3, R3, #$1fc
c026bc4c: eb 15 97 20     BL      $c07d18d4 <printk>
c026bc50: e3 e0 00 00     MVN     R0, #$0
c026bc54:                                             ; from c026bc30
c026bc54: e8 bd 80 0e     LDMUW   [SP], { R1-R3, PC }

0xc026bc30のBNE命令でrootかそれ以外のユーザーかの処理が行われる。 なのでここをB命令にすることで、rootじゃなくても0が返される。
./write_value 0xc026bc30 0xea000007


kclsm_kernel_setup_load_info

kclsm_module_checklist以外のカーネルモジュールのロードを阻止。

Disassemble 0xc026bc60 - 0xc026bcec
c026bc60:             <kclsm_kernel_setup_load_info>
c026bc60: e5 9f 30 88     LDR     R3, =$c0f54f90 <kclsm_bootmode> [$c026bcf0]
c026bc64: e9 2d 40 37     STMPW   [SP], { R0-R2, R4-R5, LR }
c026bc68: e1 a0 40 00     MOV     R4, R0 
c026bc6c: e5 93 30 04     LDR     R3, [R3, #$4]
c026bc70: e3 53 00 01     CMPS    R3, #$1
c026bc74: 03 a0 00 00     MOVEQ   R0, #$0
c026bc78: 0a 00 00 1b     BEQ     $c026bcec
c026bc7c: e1 a0 20 0d     MOV     R2, SP 
c026bc80: e3 c2 3d 7f     BIC     R3, R2, #$1fc0
c026bc84: e3 c3 30 3f     BIC     R3, R3, #$3f
c026bc88: e5 93 30 0c     LDR     R3, [R3, #$c]
c026bc8c: e5 93 31 f4     LDR     R3, [R3, #$1f4]
c026bc90: e5 93 30 04     LDR     R3, [R3, #$4]
c026bc94: e3 53 00 00     CMPS    R3, #$0
c026bc98: 15 9f 50 54     LDRNE   R5, =$c082bfe0 [$c026bcf4]
c026bc9c: 1a 00 00 04     BNE     $c026bcb4
c026bca0: ea 00 00 06     B       $c026bcc0
c026bca4:                                             ; from c026bcbc
c026bca4: e1 a0 10 04     MOV     R1, R4 
c026bca8: eb 00 db 7f     BL      $c02a2aac <strcmp>
c026bcac: e3 50 00 00     CMPS    R0, #$0
c026bcb0: 0a 00 00 0d     BEQ     $c026bcec
c026bcb4:                                             ; from c026bc9c
c026bcb4: e5 b5 00 04     LDR!    R0, [R5, #$4]
c026bcb8: e3 50 00 00     CMPS    R0, #$0
c026bcbc: 1a ff ff f8     BNE     $c026bca4
c026bcc0:                                             ; from c026bca0
c026bcc0: e1 a0 20 0d     MOV     R2, SP 
c026bcc4: e3 c2 3d 7f     BIC     R3, R2, #$1fc0
c026bcc8: e3 c3 30 3f     BIC     R3, R3, #$3f
c026bccc: e5 9f 00 24     LDR     R0, =$c0a431e3 [$c026bcf8]
c026bcd0: e5 9f 10 24     LDR     R1, =$c082bff0 <__func__.15886> [$c026bcfc]
c026bcd4: e5 93 30 0c     LDR     R3, [R3, #$c]
c026bcd8: e5 8d 40 00     STR     R4, [SP]
c026bcdc: e5 93 21 18     LDR     R2, [R3, #$118]
c026bce0: e2 83 3f 7f     ADD     R3, R3, #$1fc
c026bce4: eb 15 96 fa     BL      $c07d18d4 <printk>
c026bce8: e3 e0 00 00     MVN     R0, #$0
c026bcec:                                             ; from c026bc78
c026bcec:                                             ;      c026bcb0
c026bcec: e8 bd 80 3e     LDMUW   [SP], { R1-R5, PC }

関数の最初の方の

if (kclsm_kbfm == KCLSM_KBFM_ENABLE)
                return 0;

の処理が0xc026bc78のBEQ命令で行われている。
なのでこれをB命令にすることで、kclsm_kbfm == KCLSM_KBFM_ENABLEではなくても0が返される。
./write_value 0xc026bc78 0xea00001b


kclsm_path_mknod

ユーザーによるmknodでの特殊ファイル作成を阻止。

Disassemble 0xc026bd00 - 0xc026bdf0
c026bd00:             <kclsm_path_mknod>
c026bd00: e9 2d 40 f7     STMPW   [SP], { R0-R2, R4-R7, LR }
c026bd04: e2 02 6a 0f     AND     R6, R2, #$f000
c026bd08: e3 56 0a 02     CMPS    R6, #$2000
c026bd0c: 13 56 0a 06     CMPNES  R6, #$6000
c026bd10: e1 a0 50 00     MOV     R5, R0 
c026bd14: 03 a0 60 00     MOVEQ   R6, #$0
c026bd18: 13 a0 60 01     MOVNE   R6, #$1
c026bd1c: 13 a0 60 00     MOVNE   R6, #$0
c026bd20: 1a 00 00 31     BNE     $c026bdec
c026bd24: e1 a0 20 0d     MOV     R2, SP 
c026bd28: e3 c2 4d 7f     BIC     R4, R2, #$1fc0
c026bd2c: e3 c4 40 3f     BIC     R4, R4, #$3f
c026bd30: e5 94 30 0c     LDR     R3, [R4, #$c]
c026bd34: e5 93 71 18     LDR     R7, [R3, #$118]
c026bd38: e3 57 00 01     CMPS    R7, #$1
c026bd3c: 0a 00 00 2a     BEQ     $c026bdec
c026bd40: eb 00 03 78     BL      $c026cb28 <ueventd_pid>
c026bd44: e1 57 00 00     CMPS    R7, R0 
c026bd48: 0a 00 00 27     BEQ     $c026bdec
c026bd4c: e5 94 30 0c     LDR     R3, [R4, #$c]
c026bd50: e5 93 71 18     LDR     R7, [R3, #$118]
c026bd54: eb 00 03 77     BL      $c026cb38 <vold_pid>
c026bd58: e1 57 00 00     CMPS    R7, R0 
c026bd5c: 0a 00 00 22     BEQ     $c026bdec
c026bd60: e5 94 30 0c     LDR     R3, [R4, #$c]
c026bd64: e5 93 31 3c     LDR     R3, [R3, #$13c]
c026bd68: e5 93 41 18     LDR     R4, [R3, #$118]
c026bd6c: eb 00 03 71     BL      $c026cb38 <vold_pid>
c026bd70: e1 54 00 00     CMPS    R4, R0 
c026bd74: 0a 00 00 1c     BEQ     $c026bdec
c026bd78: e5 9f 30 74     LDR     R3, =$c0f53a98 <kmalloc_caches> [$c026bdf4]
c026bd7c: e5 93 00 30     LDR     R0, [R3, #$30]
c026bd80: e3 50 00 00     CMPS    R0, #$0
c026bd84: 0a 00 00 06     BEQ     $c026bda4
c026bd88: e3 a0 10 d0     MOV     R1, #$d0
c026bd8c: e3 a0 2a 01     MOV     R2, #$1000
c026bd90: eb fa f8 9e     BL      $c012a010 <kmem_cache_alloc_trace>
c026bd94: e2 50 40 00     SUBS    R4, R0, #$0
c026bd98: 03 e0 60 0b     MVNEQ   R6, #$b
c026bd9c: 0a 00 00 12     BEQ     $c026bdec
c026bda0: ea 00 00 00     B       $c026bda8
c026bda4:                                             ; from c026bd84
c026bda4: e3 a0 40 10     MOV     R4, #$10
c026bda8:                                             ; from c026bda0
c026bda8: e1 a0 10 04     MOV     R1, R4 
c026bdac: e3 a0 2a 01     MOV     R2, #$1000
c026bdb0: e1 a0 00 05     MOV     R0, R5 
c026bdb4: e3 e0 60 00     MVN     R6, #$0
c026bdb8: eb fb 53 b2     BL      $c0140c88 <d_path>
c026bdbc: e1 a0 20 0d     MOV     R2, SP 
c026bdc0: e3 c2 3d 7f     BIC     R3, R2, #$1fc0
c026bdc4: e5 9f 10 2c     LDR     R1, =$c082c00d <__func__.15931> [$c026bdf8]
c026bdc8: e3 c3 30 3f     BIC     R3, R3, #$3f
c026bdcc: e5 93 30 0c     LDR     R3, [R3, #$c]
c026bdd0: e5 8d 00 00     STR     R0, [SP]
c026bdd4: e5 9f 00 20     LDR     R0, =$c0a43215 [$c026bdfc]
c026bdd8: e5 93 21 18     LDR     R2, [R3, #$118]
c026bddc: e2 83 3f 7f     ADD     R3, R3, #$1fc
c026bde0: eb 15 96 bb     BL      $c07d18d4 <printk>
c026bde4: e1 a0 00 04     MOV     R0, R4 
c026bde8: eb fa f5 6e     BL      $c01293a8 <kfree>
c026bdec:                                             ; from c026bd20
c026bdec:                                             ;      c026bd3c
c026bdec:                                             ;      c026bd48
c026bdec:                                             ;      c026bd5c
c026bdec:                                             ;      c026bd74
c026bdec:                                             ;      c026bd9c
c026bdec: e1 a0 00 06     MOV     R0, R6 
c026bdf0: e8 bd 80 fe     LDMUW   [SP], { R1-R7, PC }

関数の最初の方の

if (!S_ISBLK(mode) && !S_ISCHR(mode))
        return 0;

の処理が0xc026bd20のBNE命令で行われている。
なのでこれをB命令にすることで、!S_ISBLK(mode) && !S_ISCHR(mode)ではなくても0が返される。
./write_value 0xc026bd20 0xea000031


kclsm_sb_umount

/systemのアンマウントを阻止。

Disassemble 0xc026be00 - 0xc026bf1c
c026be00:             <kclsm_sb_umount>
c026be00: e9 2d 40 7f     STMPW   [SP], { R0-R6, LR }
c026be04: e1 a0 50 00     MOV     R5, R0 
c026be08: e5 9f 31 10     LDR     R3, =$c0f54f90 <kclsm_bootmode> [$c026bf20]
c026be0c: e5 93 20 00     LDR     R2, [R3]
c026be10: e3 52 00 01     CMPS    R2, #$1
c026be14: 0a 00 00 3d     BEQ     $c026bf10
c026be18: e5 93 30 04     LDR     R3, [R3, #$4]
c026be1c: e3 53 00 01     CMPS    R3, #$1
c026be20: 0a 00 00 3a     BEQ     $c026bf10
c026be24: e5 9f 30 f8     LDR     R3, =$c0f53a98 <kmalloc_caches> [$c026bf24]
c026be28: e5 93 00 30     LDR     R0, [R3, #$30]
c026be2c: e3 50 00 00     CMPS    R0, #$0
c026be30: 0a 00 00 05     BEQ     $c026be4c
c026be34: e3 a0 10 d0     MOV     R1, #$d0
c026be38: e3 a0 2a 01     MOV     R2, #$1000
c026be3c: eb fa f8 73     BL      $c012a010 <kmem_cache_alloc_trace>
c026be40: e2 50 40 00     SUBS    R4, R0, #$0
c026be44: 1a 00 00 01     BNE     $c026be50
c026be48: ea 00 00 2e     B       $c026bf08
c026be4c:                                             ; from c026be30
c026be4c: e3 a0 40 10     MOV     R4, #$10
c026be50:                                             ; from c026be44
c026be50: e5 95 30 00     LDR     R3, [R5]
c026be54: e1 a0 10 04     MOV     R1, R4 
c026be58: e3 a0 2a 01     MOV     R2, #$1000
c026be5c: e2 8d 00 08     ADD     R0, SP, #$8
c026be60: e5 8d 50 08     STR     R5, [SP, #$8]
c026be64: e5 8d 30 0c     STR     R3, [SP, #$c]
c026be68: eb fb 53 86     BL      $c0140c88 <d_path>
c026be6c: e5 9f 10 b4     LDR     R1, =$c0a43331 [$c026bf28]
c026be70: e1 a0 50 00     MOV     R5, R0 
c026be74: eb 00 db 0c     BL      $c02a2aac <strcmp>
c026be78: e3 50 00 00     CMPS    R0, #$0
c026be7c: 0a 00 00 05     BEQ     $c026be98
c026be80: e1 a0 00 05     MOV     R0, R5 
c026be84: e5 9f 10 a0     LDR     R1, =$c0a43248 [$c026bf2c]
c026be88: eb 00 db 07     BL      $c02a2aac <strcmp>
c026be8c: e3 50 00 00     CMPS    R0, #$0
c026be90: 13 a0 50 00     MOVNE   R5, #$0
c026be94: 1a 00 00 18     BNE     $c026befc
c026be98:                                             ; from c026be7c
c026be98: e1 a0 00 05     MOV     R0, R5 
c026be9c: e5 9f 10 88     LDR     R1, =$c0a43248 [$c026bf2c]
c026bea0: eb 00 db 01     BL      $c02a2aac <strcmp>
c026bea4: e2 50 60 00     SUBS    R6, R0, #$0
c026bea8: 1a 00 00 08     BNE     $c026bed0
c026beac: eb 00 03 31     BL      $c026cb78 <fs_mgr_pid>
c026beb0: e1 a0 20 0d     MOV     R2, SP 
c026beb4: e3 c2 3d 7f     BIC     R3, R2, #$1fc0
c026beb8: e3 c3 30 3f     BIC     R3, R3, #$3f
c026bebc: e5 93 30 0c     LDR     R3, [R3, #$c]
c026bec0: e5 93 31 18     LDR     R3, [R3, #$118]
c026bec4: e1 50 00 03     CMPS    R0, R3 
c026bec8: 01 a0 50 06     MOVEQ   R5, R6 
c026becc: 0a 00 00 0a     BEQ     $c026befc
c026bed0:                                             ; from c026bea8
c026bed0: e1 a0 20 0d     MOV     R2, SP 
c026bed4: e3 c2 3d 7f     BIC     R3, R2, #$1fc0
c026bed8: e3 c3 30 3f     BIC     R3, R3, #$3f
c026bedc: e5 9f 00 4c     LDR     R0, =$c0a43250 [$c026bf30]
c026bee0: e5 9f 10 4c     LDR     R1, =$c082c01e <__func__.15913> [$c026bf34]
c026bee4: e5 93 30 0c     LDR     R3, [R3, #$c]
c026bee8: e5 8d 50 00     STR     R5, [SP]
c026beec: e3 e0 50 00     MVN     R5, #$0
c026bef0: e5 93 21 18     LDR     R2, [R3, #$118]
c026bef4: e2 83 3f 7f     ADD     R3, R3, #$1fc
c026bef8: eb 15 96 75     BL      $c07d18d4 <printk>
c026befc:                                             ; from c026be94
c026befc:                                             ;      c026becc
c026befc: e1 a0 00 04     MOV     R0, R4 
c026bf00: eb fa f5 28     BL      $c01293a8 <kfree>
c026bf04: ea 00 00 02     B       $c026bf14
c026bf08:                                             ; from c026be48
c026bf08: e3 e0 50 0b     MVN     R5, #$b
c026bf0c: ea 00 00 00     B       $c026bf14
c026bf10:                                             ; from c026be14
c026bf10:                                             ;      c026be20
c026bf10: e3 a0 50 00     MOV     R5, #$0
c026bf14:                                             ; from c026bf04
c026bf14:                                             ;      c026bf0c
c026bf14: e1 a0 00 05     MOV     R0, R5 
c026bf18: e2 8d d0 10     ADD     SP, SP, #$10
c026bf1c: e8 bd 80 70     LDMUW   [SP], { R4-R6, PC }

0xc026be14で、スマホがアップデートモードだった場合の処理がBEQ命令で行われている。
なので、これをB命令にすることで、アップデートモードじゃなくてもアンマウントできるようにする。
./write_value 0xc026be14 0xea00003d


kclsm_ptrace_access_check

名前のまんま。ptraceによるプロセスへのちょっかいを阻止する。

Disassemble 0xc026bf38 - 0xc026bfac
c026bf38:             <kclsm_ptrace_access_check>
c026bf38: e9 2d 41 f3     STMPW   [SP], { R0-R1, R4-R8, LR }
c026bf3c: e1 a0 30 0d     MOV     R3, SP 
c026bf40: e3 c3 5d 7f     BIC     R5, R3, #$1fc0
c026bf44: e1 a0 40 00     MOV     R4, R0 
c026bf48: e3 c5 50 3f     BIC     R5, R5, #$3f
c026bf4c: e1 a0 70 01     MOV     R7, R1 
c026bf50: e5 95 30 0c     LDR     R3, [R5, #$c]
c026bf54: e5 93 21 f4     LDR     R2, [R3, #$1f4]
c026bf58: e5 92 60 04     LDR     R6, [R2, #$4]
c026bf5c: e3 56 00 00     CMPS    R6, #$0
c026bf60: 13 a0 00 00     MOVNE   R0, #$0
c026bf64: 1a 00 00 10     BNE     $c026bfac
c026bf68: e5 93 81 18     LDR     R8, [R3, #$118]
c026bf6c: eb 00 02 e9     BL      $c026cb18 <debuggerd_pid>
c026bf70: e1 58 00 00     CMPS    R8, R0 
c026bf74: 0a 00 00 0b     BEQ     $c026bfa8
c026bf78: e3 17 00 01     TSTS    R7, #$1
c026bf7c: 1a 00 00 09     BNE     $c026bfa8
c026bf80: e5 95 30 0c     LDR     R3, [R5, #$c]
c026bf84: e2 84 4f 7f     ADD     R4, R4, #$1fc
c026bf88: e5 9f 00 20     LDR     R0, =$c0a43284 [$c026bfb0]
c026bf8c: e8 8d 00 90     STMU    [SP], { R4, R7 }
c026bf90: e5 9f 10 1c     LDR     R1, =$c082c02e <__func__.15871> [$c026bfb4]
c026bf94: e5 93 21 18     LDR     R2, [R3, #$118]
c026bf98: e2 83 3f 7f     ADD     R3, R3, #$1fc
c026bf9c: eb 15 96 4c     BL      $c07d18d4 <printk>
c026bfa0: e3 e0 00 00     MVN     R0, #$0
c026bfa4: ea 00 00 00     B       $c026bfac
c026bfa8:                                             ; from c026bf74
c026bfa8:                                             ;      c026bf7c
c026bfa8: e1 a0 00 06     MOV     R0, R6 
c026bfac:                                             ; from c026bf64
c026bfac:                                             ;      c026bfa4
c026bfac: e8 bd 81 fc     LDMUW   [SP], { R2-R8, PC }

0xc026bf64のBNE命令でrootかそれ以外のユーザーかの処理が行われる。 なのでここをB命令にすることでrootじゃなくてもptraceできるようになる。
./write_value 0xc026bf64 0xea000010


kclsm_dentry_open

何かしらのシステム関連のファイル(?)が入っている/pstoreを覗けなくする。

Disassemble 0xc026bfb8 - 0xc026c124
c026bfb8:             <kclsm_dentry_open>
c026bfb8: e5 9f 31 68     LDR     R3, =$c0f54f90 <kclsm_bootmode> [$c026c128]
c026bfbc: e9 2d 40 f7     STMPW   [SP], { R0-R2, R4-R7, LR }
c026bfc0: e1 a0 50 00     MOV     R5, R0 
c026bfc4: e5 93 20 00     LDR     R2, [R3]
c026bfc8: e3 52 00 01     CMPS    R2, #$1
c026bfcc: 0a 00 00 52     BEQ     $c026c11c
c026bfd0: e5 93 30 04     LDR     R3, [R3, #$4]
c026bfd4: e3 53 00 01     CMPS    R3, #$1
c026bfd8: 0a 00 00 4f     BEQ     $c026c11c
c026bfdc: e5 9f 31 48     LDR     R3, =$c0f53a98 <kmalloc_caches> [$c026c12c]
c026bfe0: e5 93 00 30     LDR     R0, [R3, #$30]
c026bfe4: e3 50 00 00     CMPS    R0, #$0
c026bfe8: 0a 00 00 05     BEQ     $c026c004
c026bfec: e3 a0 10 d0     MOV     R1, #$d0
c026bff0: e3 a0 2a 01     MOV     R2, #$1000
c026bff4: eb fa f8 05     BL      $c012a010 <kmem_cache_alloc_trace>
c026bff8: e2 50 40 00     SUBS    R4, R0, #$0
c026bffc: 1a 00 00 01     BNE     $c026c008
c026c000: ea 00 00 43     B       $c026c114
c026c004:                                             ; from c026bfe8
c026c004: e3 a0 40 10     MOV     R4, #$10
c026c008:                                             ; from c026bffc
c026c008: e2 85 00 08     ADD     R0, R5, #$8
c026c00c: e1 a0 10 04     MOV     R1, R4 
c026c010: e3 a0 2a 01     MOV     R2, #$1000
c026c014: eb fb 53 1b     BL      $c0140c88 <d_path>
c026c018: e5 9f 11 10     LDR     R1, =$c0a43248 [$c026c130]
c026c01c: e3 a0 20 07     MOV     R2, #$7
c026c020: e1 a0 50 00     MOV     R5, R0 
c026c024: eb 00 da ad     BL      $c02a2ae0 <strncmp>
c026c028: e3 50 00 00     CMPS    R0, #$0
c026c02c: 0a 00 00 09     BEQ     $c026c058
c026c030: e1 a0 00 05     MOV     R0, R5 
c026c034: e5 9f 10 f8     LDR     R1, =$c0a432bd [$c026c134]
c026c038: eb 00 da 9b     BL      $c02a2aac <strcmp>
c026c03c: e3 50 00 00     CMPS    R0, #$0
c026c040: 0a 00 00 04     BEQ     $c026c058
c026c044: e1 a0 00 05     MOV     R0, R5 
c026c048: e5 9f 10 e8     LDR     R1, =$c0a432da [$c026c138]
c026c04c: eb 00 da 96     BL      $c02a2aac <strcmp>
c026c050: e3 50 00 00     CMPS    R0, #$0
c026c054: 1a 00 00 10     BNE     $c026c09c
c026c058:                                             ; from c026c02c
c026c058:                                             ;      c026c040
c026c058: e1 a0 20 0d     MOV     R2, SP 
c026c05c: e3 c2 6d 7f     BIC     R6, R2, #$1fc0
c026c060: e3 c6 60 3f     BIC     R6, R6, #$3f
c026c064: e5 96 30 0c     LDR     R3, [R6, #$c]
c026c068: e5 93 71 18     LDR     R7, [R3, #$118]
c026c06c: e3 57 00 01     CMPS    R7, #$1
c026c070: 0a 00 00 23     BEQ     $c026c104
c026c074: eb 00 02 bb     BL      $c026cb68 <lkspad_pid>
c026c078: e1 57 00 00     CMPS    R7, R0 
c026c07c: 0a 00 00 20     BEQ     $c026c104
c026c080: e5 96 30 0c     LDR     R3, [R6, #$c]
c026c084: e5 93 31 3c     LDR     R3, [R3, #$13c]
c026c088: e5 93 61 18     LDR     R6, [R3, #$118]
c026c08c: eb 00 02 b5     BL      $c026cb68 <lkspad_pid>
c026c090: e1 56 00 00     CMPS    R6, R0 
c026c094: 0a 00 00 1a     BEQ     $c026c104
c026c098: ea 00 00 0d     B       $c026c0d4
c026c09c:                                             ; from c026c054
c026c09c: e1 a0 00 05     MOV     R0, R5 
c026c0a0: e5 9f 10 94     LDR     R1, =$c0a432f7 [$c026c13c]
c026c0a4: eb 00 da 80     BL      $c02a2aac <strcmp>
c026c0a8: e2 50 60 00     SUBS    R6, R0, #$0
c026c0ac: 1a 00 00 14     BNE     $c026c104
c026c0b0: e1 a0 20 0d     MOV     R2, SP 
c026c0b4: e3 c2 3d 7f     BIC     R3, R2, #$1fc0
c026c0b8: e3 c3 30 3f     BIC     R3, R3, #$3f
c026c0bc: e5 93 30 0c     LDR     R3, [R3, #$c]
c026c0c0: e5 93 71 18     LDR     R7, [R3, #$118]
c026c0c4: eb 00 02 9f     BL      $c026cb48 <rmt_storage_pid>
c026c0c8: e1 57 00 00     CMPS    R7, R0 
c026c0cc: 01 a0 50 06     MOVEQ   R5, R6 
c026c0d0: 0a 00 00 0c     BEQ     $c026c108
c026c0d4:                                             ; from c026c098
c026c0d4: e1 a0 20 0d     MOV     R2, SP 
c026c0d8: e3 c2 3d 7f     BIC     R3, R2, #$1fc0
c026c0dc: e3 c3 30 3f     BIC     R3, R3, #$3f
c026c0e0: e5 9f 00 58     LDR     R0, =$c0a43215 [$c026c140]
c026c0e4: e5 9f 10 58     LDR     R1, =$c082c048 <__func__.15940> [$c026c144]
c026c0e8: e5 93 30 0c     LDR     R3, [R3, #$c]
c026c0ec: e5 8d 50 00     STR     R5, [SP]
c026c0f0: e3 e0 50 00     MVN     R5, #$0
c026c0f4: e5 93 21 18     LDR     R2, [R3, #$118]
c026c0f8: e2 83 3f 7f     ADD     R3, R3, #$1fc
c026c0fc: eb 15 95 f4     BL      $c07d18d4 <printk>
c026c100: ea 00 00 00     B       $c026c108
c026c104:                                             ; from c026c070
c026c104:                                             ;      c026c07c
c026c104:                                             ;      c026c094
c026c104:                                             ;      c026c0ac
c026c104: e3 a0 50 00     MOV     R5, #$0
c026c108:                                             ; from c026c0d0
c026c108:                                             ;      c026c100
c026c108: e1 a0 00 04     MOV     R0, R4 
c026c10c: eb fa f4 a5     BL      $c01293a8 <kfree>
c026c110: ea 00 00 02     B       $c026c120
c026c114:                                             ; from c026c000
c026c114: e3 e0 50 0b     MVN     R5, #$b
c026c118: ea 00 00 00     B       $c026c120
c026c11c:                                             ; from c026bfcc
c026c11c:                                             ;      c026bfd8
c026c11c: e3 a0 50 00     MOV     R5, #$0
c026c120:                                             ; from c026c110
c026c120:                                             ;      c026c118
c026c120: e1 a0 00 05     MOV     R0, R5 
c026c124: e8 bd 80 fe     LDMUW   [SP], { R1-R7, PC }

0xc026bfccで、スマホがアップデートモードだった場合の処理がBEQ命令で行われている。
なので、これをB命令にすることで、アップデートモードじゃなくてもpstoreを読み書きできるようにする。 ./write_value 0xc026bfcc 0xea000052


というわけで大体のLSMは解除できました。
かなりやっつけ感がありますが...
これを書いていて、もっと良い方法があるような気がしてきたので、後で修正するかもしれません。
まあ、とりあえずは動くはずです。
これを全部./write_valueするのは面倒なので、スクリプトにしてしまいましょう。

#!/system/bin/sh

tmp=/data/local/tmp

$tmp/install_backdoor

#kclsm_sb_mount
$tmp/write_value 0xc026bb4c 0xea000023

#kclsm_ptrace_traceme
$tmp/write_value 0xc026bc30 0xea000007

#kclsm_kernel_setup_load_info
$tmp/write_value 0xc026bc78 0xea00001b

#kclsm_path_mknod
$tmp/write_value 0xc026bd20 0xea000031

#kclsm_sb_umount
$tmp/write_value 0xc026be14 0xea00003d

#kclsm_ptrace_access_check
$tmp/write_value 0xc026bf64 0xea000010

#kclsm_dentry_open
$tmp/write_value 0xc026bfcc 0xea000052

いつもの勢いで/bin/shにしないように注意してください。(1敗)
ではpushして実行してみましょう。

fan@thinkpad:~/kyy22$ adb push onBoot /data/local/tmp
onBoot: 1 file pushed. 0.0 MB/s (433 bytes in 0.009s)

この意味ありげなファイル名は後で説明します。

root@android:/data/local/tmp # chmod 755 onBoot
root@android:/data/local/tmp # ./onBoot
Attempt acdb exploit...
KYY22 (102.0.0f00) is not supported.
Attempt put_user exploit...
ioctl: Bad address
Attempt pingpong exploit...
No icmp socket available
Attempt futex exploit...
futex_exploit: Server started
install_mmap: success
old value = 0x1a000023
new value = 0xea000023
old value = 0x1a000007
new value = 0xea000007
old value = 0x0a00001b
new value = 0xea00001b
old value = 0x1a000031
new value = 0xea000031
old value = 0x0a00003d
new value = 0xea00003d
old value = 0x1a000010
new value = 0xea000010
old value = 0x0a000052
new value = 0xea000052

しっかりと書き換えられました。
色々試してみましょう。

root@android:/data/local/tmp # umount /system
failed: Device or resource busy
1|root@android:/data/local/tmp # ls /pstore | head
781c8ddd5f3c4ccc5c9dfc8dcdfc8d5f9dfc9c5c4cecbc8d3d5ffd8d6c
781c8ddd5f3c4ccc5c9dfc8dcdfc8d5fad8d3c7cbc8d3d5ffd8d6c
781c8ddd5f3c8decbc5f8dfc9ded8d3c9ced996c7c
781c8ddd5f5c4cfc9dfcdc5f8dfc9ded8d3c9ced996c7c
781c8ddd5f9d3d9dfdadecbcedfc8d5f9dfc9c5c4cecbc8d3d5ffd8d6c
781c8ddd5f9d3d9dfdadecbcedfc8d5fad8d3c7cbc8d3d5ffd8d6c
781c8ddd5f9d3d9dfdadecbcedfc8d5fdcbc0d5cfd5ffd8d6c
781c8ddd5fad2c5ced5c9dfc4c9d5c8d5f8cfcbc7c3c9d2c
781c8ddd5fad2c5ced5c9dfc4c9d5c8d5f8e5f7ebe2f
781c8ddd5fad2c5ced5c9dfc4c9d5c8d5f8e5fa93999
root@android:/data/local/tmp # mknod devzero c 1 5
root@android:/data/local/tmp # 

というわけで、カーネル書き換えでの解除に成功しました。

そして残ったkclsm_sb_pivotrootとkclsm_path_chrootは、reset_security_opsを呼ぶことで解除できます。
これはandroid_mmap_tools(install_backdoor等のツール群)に含まれているreset_security_opsを使えば呼べるはずですが、
シンボル情報にreset_security_opsが含まれているものの、なぜか「reset_security_ops見つかんないよ!」とエラーが出てしまいます。
なので、同じくfi01氏のunlock_security_moduleの中でreset_security_opsを探して呼ぶ処理のみを切り取ってコンパイルした物を今回は使用します。
https://drive.google.com/open?id=1fRFe4jXE2UUMSN-CRC7giDPqQJoRhcFp
これをいつも通りpushしてさっきのスクリプトに加えて実行します。

fan@thinkpad:~/tools$ adb push reset_security_ops_fan /data/local/tmp
./libs/armeabi/reset_security_ops_fan: 1...ushed. 3.2 MB/s (453872 bytes in 0.134s)

__

root@android:/data/local/tmp # chmod 755 reset_security_ops_fan
root@android:/data/local/tmp # ./onBoot
Attempt acdb exploit...
KYY22 (102.0.0f00) is not supported.
Attempt put_user exploit...
ioctl: Bad address
Attempt pingpong exploit...
No icmp socket available
Attempt futex exploit...
futex_exploit: Server started
install_mmap: success
old value = 0x1a000023
new value = 0xea000023
old value = 0x1a000007
new value = 0xea000007
old value = 0x0a00001b
new value = 0xea00001b
old value = 0x1a000031
new value = 0xea000031
old value = 0x0a00003d
new value = 0xea00003d
old value = 0x1a000010
new value = 0xea000010
old value = 0x0a000052
new value = 0xea000052
root@android:/data/local/tmp # ./reset_security_ops_fan


Device detected: KYY22 (102.0.0f00)

Mapping kernel memory...
Attempt acdb exploit...
KYY22 (102.0.0f00) is not supported.
Attempt put_user exploit...
ioctl: Bad address
Attempt perf_swevent exploit...
KYY22 (102.0.0f00) is not supported.
Attempt fj_hdcp exploit...
Attempt diag exploit...
KYY22 (102.0.0f00) is not supported.
Attempting to inject code...
This works only once a boot.
failed to ioctl due to Bad address.
Attempt fb_mem_exploit...
OK.

Dump kernel memory...

Finding kallsyms address in memory...
Checking kallsyms_in_memory working...
OK. Ready to unlock security module.

Essential symbols are:
  prepare_kernel_cred = 0xc009eb68
  commit_creds = 0xc009e654
  remap_pfn_range = 0xc0113c60
  vmalloc_exec = 0xc0120570
  ptmx_fops = 0xc0f6c8f0

Checking reset_security_ops...
Found reset_security_ops. Run it.
OK.

これで全てのLSMの解除が終わりました!!あとは自動化だけです。

と行きたいんですが、実は記事を書く少し前に気づいてしまったんです。
reset_securitu_opsの詳細について...

reset_security_ops

reset_security_opsは簡単に説明するとLSMをdefault_security_opsのみにします。
で、今回アセンブリを読んで解除していったLSM達はdefault_security_opsではなくkclsm_security_opsに含まれています
はいそうです。reset_security_opsを実行すれば全て解除できます。
mmcプロテクトは違うので別途解除が必要ですが...
やらかしました。事前の調べが甘いままでブログを書き始めたのが間違いでした。
前回のを書き終えたあたりで気づきましたが、もう戻るわけにもなぁ...
って感じで続けてしまいました。
とても申し訳ないです...
とりあえず、書き始めた以上は最後までやらないといけないと思うので、自動化をしていきます。

自動化

一気に解除の手間が省けてしまいましたが、再起動した後にしなければいけないのは、

  1. reset_security_opsを呼ぶ
  2. mmcプロテクトの解除

の2つです。
今回これを起動時に実行するために、これまたfi01さん作のVpnFakerを使用します。
VpnFakerはシステムアプリであるVpnDialogsのAPK署名の脆弱性を使って、system権限を奪い取るものです。
これを導入するとVpnDialogsを起動した時に、system権限のコンソールに入れます。
しかし、それとは別にもう一つの機能があって、/data/local/tmp/onBootをsystem権限でスマホ起動時に実行するというものです。
これを使えば、起動時にreset_security_opsを呼べます。
また、mmcプロテクト解除にはroot権限が必須ですが、run_autoexecを使えば/data/local/autoexec.shをinstall_backdoorで得た権限を使ってrootで実行できます。
つまり、VpnFakerでonBootを実行して、reset_security_opsを呼んだ後、onBootの最後にrun_autoexecを実行。
autoexec.shをrootで動かしてmmcプロテクトを解除する流れです。
実際にスクリプトを書いてみましょう。

#onBoot

#!/system/bin/sh

tmp=/data/local/tmp

$tmp/install_backdoor
$tmp/reset_security_ops_fan
$tmp/run_autoexec
$tmp/install_backdoor -u

install_backdoorはuオプションでアンインストール(?)できます。
おまじないっていうやつです。

#autoexec.sh

#!/system/bin/sh

#mmc protect
/data/local/tmp/mmc_utils writeprotect user set none 0 3014656 /dev/block/mmcblk0

スクリプトが書けたので、VpnFakerを導入していきます。
なかなか配布しているところが見つかりませんでしたが、SHARP_android_rooting_toolsに含まれていたので、以下の物を取り出します。

これらを取り出したら、いつものところにadb pushして権限を与えます。

fan@thinkpad:~/Downloads/SHARP_android_rooting_tools$ adb push VpnFakerV2.tar.gz /data/local/tmp
VpnFakerV2.tar.gz: 1 file pushed. 1.1 MB/s (125227 bytes in 0.109s)
fan@thinkpad:~/Downloads/SHARP_android_rooting_tools$ adb push busybox /data/local/tmp
busybox: 1 file pushed. 4.1 MB/s (497964 bytes in 0.116s)
fan@thinkpad:~/Downloads/SHARP_android_rooting_tools$ adb push vpnfaker.sh /data/local/tmp
vpnfaker.sh: 1 file pushed. 0.3 MB/s (822 bytes in 0.003s)
root@android:/data/local/tmp # chmod 755 vpnfaker.sh                           
root@android:/data/local/tmp # chmod 755 busybox                               
root@android:/data/local/tmp # ./vpnfaker.sh                                   
VpnFaker install...
uid=0(root) gid=0(root)

Zygoteを止めるので、再起動したのかと焦りそうになりますが、落ち着いて待ちましょう。
終わったらアプリドロワーにVpnDialogが追加されて、起動するとsystem権限であれこれできるようになってるはずです。
次に、作ったスクリプトをpushして動作を確認します。

fan@thinkpad:~/kyy22$ adb push onBoot /data/local/tmp
onBoot: 1 file pushed. 0.1 MB/s (141 bytes in 0.003s)
fan@thinkpad:~/kyy22$ adb push autoexec.sh /data/local/tmp
autoexec.sh: 1 file pushed. 0.0 MB/s (127 bytes in 0.010s)
root@android:/data/local/tmp # chmod 755 onBoot
root@android:/data/local/tmp # chmod 755 autoexec.sh                           
root@android:/data/local/tmp # mv autoexec.sh ..                               
root@android:/data/local/tmp # ls ..
autoexec.sh
tmp

再起動して試してみます。

root@android:/data/local/tmp # reboot
fan@thinkpad:~/kyy22$ adb shell
shell@android:/ $ su
root@android:/ # mount -o rw,remount /system
root@android:/ # cd /data/local/tmp
shell@android:/data/local/tmp # ./mmc_utils writeprotect user get /dev/block/mmcblk0
Write Protect Group size in blocks/bytes: 16384/8388608
Write Protect Groups 0-1877 (Blocks 0-30769151), No Write Protection

無事にLSM解除、mmcプロテクト解除の自動化ができました。
もし自動化でうまくいかない場合は権限を確認してみてください。

おわりに

調査不足で無駄に長くなってしまいましたが、どうにか完結です。
この次はN-05DとKYV31(まだroot化できてない)らへんをやっていきます。
冬休みの課題が結構ある上に全員強制参加の補習があるので、かなり後になりそうですが。
「ここ間違ってるよ!」みたいなのがあったら遠慮なくお願いします。

国産スマホをroot化するには LSM解除編(前半)

ようやっと続き&本筋です。
前回は、root化の基本と、国産スマホでroot化がしにくい理由がLSMにある事を説明しました。
で、今回はこれを解除していきます。

ツールのビルド

今回の作業で使っていくツールをビルドします。
ビルドにはAndroid NDKを使っていきます。
が、古いツールですので、最新版だとビルドで引っかかります。
なので古いAndroid NDKを使う必要があります。だいたいr9bあたりで通ります。
ふるいのはここから落とせるようになってますが、r9bとなると、もはや載っていません()
なのでリンクを以下に貼っておきます。

2019/12/23:[修正]全部リンクが死んでた上に、アーカイブの最後のr10eでもビルド、動作OKでした。
Windows (64bit)
Windows (32bit)
OS X (64bit)
Linux(64bit)
導入方法は説明してたら長くなるので、使ってるOSに合わせて調べてください。
あと、Gitも必要ですが、こちらも長くなるので、使ってるOSに合わせて調べてください。
これ以降はUbuntu(19.04)環境で話を進めていきます。
Android NDKもGitも準備できたら、ツールのソースを落としていきます。
以下のソースをgit clone --recursive <URL>して落としてください。
backdoor_mmap_tools
android_get_essential_address
落としたらcd <git cloneしたフォルダ>で移動します。
移動したらndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mkでビルドできます。
スペックによりますが、少し時間がかかります。
ビルドが終わったら、./libs/armeabiにバイナリがあるので、どこかわかりやすい場所にまとめましょう。
2つともビルドしたら、android_get_essential_addressの./device_database/device.dbもわかりやすい場所に置いておいてください。
これで必要なツールのビルドは終わりです。

実践

前回書いてた通り、今回はURBANO L02(KYY22)で実践していきます。
ビルド番号は102.0.0f00です。
前代の似たやつでL01(KYY21)がいますが、あれは若干アドレスが違うだけなので、KYY21でも代用できます。

とりあえずツール類を端末内に入れていきます。
今回はツールを/home/fan/toolsにまとめた提で書くので、状況によって読み替えてください。

fan@thinkpad:~$ adb push /home/fan/tools/* /data/local/tmp
/home/fan/tools/device.db: 1 file pushed. 3.1 MB/s (88064 bytes in 0.027s)
/home/fan/tools/disable_ccsecurity: 1 file pushed. 4.4 MB/s (383204 bytes in 0.084s)
/home/fan/tools/fix_cve_2013_6282: 1 file pushed. 5.2 MB/s (387304 bytes in 0.071s)
/home/fan/tools/get_essential_address: 1 file pushed. 5.3 MB/s (403836 bytes in 0.072s)
/home/fan/tools/install_backdoor: 1 file pushed. 5.6 MB/s (457144 bytes in 0.077s)
/home/fan/tools/kallsymsprint: 1 file pushed. 3.6 MB/s (64516 bytes in 0.017s)
/home/fan/tools/load_mmc_sc01e: 1 file pushed. 4.2 MB/s (383196 bytes in 0.087s)
/home/fan/tools/read_value: 1 file pushed. 3.3 MB/s (63976 bytes in 0.018s)
/home/fan/tools/reset_security_ops: 1 file pushed. 3.8 MB/s (383144 bytes in 0.097s)
/home/fan/tools/run_autoexec: 1 file pushed. 4.0 MB/s (383228 bytes in 0.092s)
/home/fan/tools/run_root_shell: 1 file pushed. 3.3 MB/s (383216 bytes in 0.111s)
/home/fan/tools/unload_mmc_sc01e: 1 file pushed. 4.0 MB/s (383192 bytes in 0.091s)
/home/fan/tools/unlock_lsm_fjsec: 1 file pushed. 4.1 MB/s (383144 bytes in 0.089s)
/home/fan/tools/unlock_lsm_miyabi: 1 file pushed. 4.4 MB/s (388488 bytes in 0.084s)
/home/fan/tools/unlock_mmc_protect: 1 file pushed. 4.2 MB/s (387256 bytes in 0.087s)
/home/fan/tools/unlock_mount_fjsec: 1 file pushed. 3.9 MB/s (383144 bytes in 0.094s)
/home/fan/tools/unlock_sec_sc01e: 1 file pushed. 2.7 MB/s (64496 bytes in 0.023s)
/home/fan/tools/unlock_sec_sc04e: 1 file pushed. 3.1 MB/s (64640 bytes in 0.020s)
/home/fan/tools/unlock_security_module: 1 file pushed. 3.1 MB/s (458032 bytes in 0.143s)
/home/fan/tools/write_value: 1 file pushed. 3.4 MB/s (63976 bytes in 0.018s)
21 files pushed. 3.8 MB/s (8032662 bytes in 2.014s)

端末に突っ込んだら、権限を調整します。

fan@thinkpad:~$ adb shell
shell@android:/ $ cd /data/local/tmp
shell@android:/data/local/tmp $ chmod 755 *
shell@android:/data/local/tmp $ chmod 644 device.db

権限を渡し終えたら、get_essential_addressを実行します。
これは、androidカーネル内からroot権限取得や、カーネルをいじくるのに必要なアドレスを探してくれるツールです。
これなしでも求めようと思えば求めれますが、はっきり言って大変ですし、これが通らない場合はカーネルいじくるのにかなり苦労する羽目になります。

shell@android:/data/local/tmp $ ./get_essential_address                        


Device detected: KYY22 (102.0.0f00)

Try without fb_mem_exploit fist...

Try to find address in memory...
Attempt msm_cameraconfig exploit...
Detected kernel physical address at 0x80208000 from iomem

You need to manage to get remap_pfn_range address.

Try copying kernel memory... It will take a long time.
Attempt pingpong exploit...
No icmp socket available
Attempt futex exploit...
futex_exploit: Server started
Search address in memory...
Using kallsyms_in_memory...
Essential address are:
  prepare_kernel_cred = 0xc009eb68
  commit_creds = 0xc009e654
  remap_pfn_range = 0xc0113c60
  vmalloc_exec = 0xc0120570
  ptmx_fops = 0xc0f6c8f0

すんなりと取れました。
次はこのアドレスを元にroot権限を奪ってみます。

shell@android:/data/local/tmp $ ./install_backdoor                             
Attempt acdb exploit...
KYY22 (102.0.0f00) is not supported.
Attempt put_user exploit...
ioctl: Bad address
Attempt pingpong exploit...
No icmp socket available
Attempt futex exploit...
install_mmap: success
shell@android:/data/local/tmp $ ./run_root_shell                               
shell@android:/data/local/tmp # id
uid=0(root) gid=0(root)

not supportedと言いつつやってのけるinstall_backdoorちゃんは可愛いですね。(錯乱)
install_backdoorはmmapを使用してカーネルの権限を奪うものみたいです。
みたいです。というのは、自分もまだ良く理解できてないからです。勉強不足。
これによってカーネルをいじくれます。
で、run_root_shellはinstall_backdoorが奪った権限を使ってrootを奪う感じみたいです。
余談ですが、run_root_shellには2つ種類があります。
一つ目は今使っているこれで、もう一つはこれです。
どちらもfi01氏作なのは変わりないですが、install_backdoorに依存するかしないかの違いがあります。
この違いはN-05D編で利用するので、少し覚えておいてください。

で、root権限が奪えたわけですが、今の状態はroot化とは言えません。
suバイナリを置くべき場所に置けていないからです。
仮rootと呼ばれてる状態ですね。(仮rootっていう言葉自体、ややおかしい気がするので個人的には嫌い)
というわけでsuバイナリを置くべき場所、今回は/system/xbinに置いてみますが、/systemは書き込み可能でマウントされていません。
なのでmountコマンドを使用して書き込み可能でリマウントしてみましょう。

shell@android:/data/local/tmp # mount -o rw,remount /system
mount: Operation not permitted

はい。前回の最後でやった通りですね。LSMちゃんが邪魔をしてきます。
なのでLSMを解除して、root権限がroot権限らしくなるようにします。
とりあえず、邪魔しているのが何処のどいつか確認します。
dmesgを使ってカーネルのメッセージを出力します。

shell@android:/data/local/tmp # dmesg | grep mount                             
<4>#0[ 4765.660521] no permission in kclsm_sb_mount pid=8340 pname=mount realpath=/system dev_name=/dev/block/platform/msm_sdcc.1/by-name/system

というわけで、犯人はkclsm_sb_mountという事がわかりました。
このkclsm_sb_mount挙動を確認するために、カーネルのソースを落としてソースを見てみましょう。
ソースは http://android-dev.kyocera.co.jp/source/versionSelect_URBANO_L02.html
にあるので、そこから自分のビル番に合ったものを取ってきましょう。
落としてきたら展開して中身を見てみます。
どうやら ./kernel/security/kyocera/kclsm.cに記述されているようです。
104行目あたりに、

#ifdef CONFIG_SECURITY_KCLSM_MOUNT
static int kclsm_sb_mount(char *dev_name, struct path *path,
                char *type, unsigned long flags, void *data)
{
    int i, ret = 0;
    char *ptr, *realpath = NULL;

    ptr = kmalloc(PATH_MAX, GFP_KERNEL);KCLSM_SYSTEM_MOUNT_POINT
    if (!ptr)
        return -ENOMEM;

    realpath = d_path(path, ptr, PATH_MAX);

    if (strncmp(realpath, KCLSM_SYSTEM_MOUNT_POINT,
            strlen(KCLSM_SYSTEM_MOUNT_POINT)) != 0)
        goto out;

    if (strcmp(realpath, KCLSM_SYSTEM_MOUNT_POINT) != 0) {
        if (current->pid == 1)
            goto out;
        else
            goto err;
    }

    if (flags & MS_REMOUNT)
        goto err;

    for (i=0; kclsm_mount_checklist[i] != NULL; i++)
        if (strcmp(dev_name, kclsm_mount_checklist[i]) == 0)
            goto out;

err:
    pr_warn("no permission in %s pid=%d pname=%s realpath=%s dev_name=%s\n",
        __FUNCTION__, current->pid, current->comm, realpath, dev_name);
    ret = -EPERM;
out:
    kfree(ptr);
    return KCLSM_RETURN(ret);
}
#endif

といった感じで記述されています。
で、エラー文から察せる通り、realpathというのがmountの時に渡したパスです。
これとKCLSM_SYSTEM_MOUNT_POINT(/system)を比べて、一緒だったらgoto err、一緒じゃなかったらgoto outして正常に処理する感じです。
この処理の分岐の仕方を覚えておいてください。
次にカーネルを書き換えて、この処理をどうにかします。
流れとしては、
1. カーネルをダンプ
2. シンボル情報から、kclsm_sb_mountの実体があるアドレスを特定
3. そのアドレス部分をディスアセンブル
4. write_valueを使って処理をいい感じに書き換え
といった感じです。
では、カーネルをダンプしていきましょう。
ダンプの方法についてですが、どうやらfi01氏がfutex_dumpというものを作っているようです。
しかし、いくら検索してもリンク切れで落とせないので、今回は魔界塔士氏のdumpバイナリを使用させていただきます。
https://drive.google.com/open?id=0B4HY7rXvjVERN2lrM0FqbzZpdUk
落としたら/data/local/tmpにadb pushして権限を調整し、実行します。

fan@thinkpad:~$ adb push /home/fan/tools/dump /data/local/tmp
/home/fan/tools/dump: 1 file pushed. 2.2 MB/s (64088 bytes in 0.028s)

shell@android:/data/local/tmp # chmod 755 dump
shell@android:/data/local/tmp # ./dump 
ptmx_mmap_fd OK 
Dump kernel memory...
Dumped.

shell@android:/data/local/tmp # ls | grep kernel
kernel.dump

kernel.dumpとしてダンプされていますね。
次にシンボル情報を引っ張り出します。
これはkallsymsprintがやってくれます。

shell@android:/data/local/tmp # ./kallsymsprint > kyy22.txt                
[+]mmap
  mem=20000000 length=02000000 offset=a0008000
[+]kallsyms_addresses=c089af60
  count=00016733
[+]kallsyms_num_syms=00016733
[+]kallsyms_names=c08f4c40
[+]kallsyms_markers=c09f66a0
[+]kallsyms_token_table=c09f6c40
[+]kallsyms_token_index=c09f7000
[+]kallsyms_lookup_name

カーネルとシンボル情報がそろったのでディスアセンブルをしていきます。
とりあえずカーネルのダンプとシンボル情報が書かれたテキストファイルを端末から取り出します。

fan@thinkpad:~$ mkdir kyy22
fan@thinkpad:~$ cd kyy22
fan@thinkpad:~/kyy22$ adb pull /data/local/tmp/kernel.dump
/data/local/tmp/kernel.dump: 1 file pulled. 4.2 MB/s (33554432 bytes in 7.682s)
fan@thinkpad:~/kyy22$ adb pull /data/local/tmp/kyy22.txt
/data/local/tmp/kyy22.txt: 1 file pulled. 2.8 MB/s (2753884 bytes in 0.929s)

で、ディスアセンブラですが、これもまたfi01氏が素晴らしいものを作っています。
arm7-dasm
これを落としてコンパイルします。

fan@thinkpad:~/kyy22$ git clone https://github.com/fi01/arm7-dasm
Cloning into 'arm7-dasm'...
remote: Enumerating objects: 71, done.
remote: Total 71 (delta 0), reused 0 (delta 0), pack-reused 71
Unpacking objects: 100% (71/71), done.
fan@thinkpad:~/kyy22$ cd arm7-dasm/
fan@thinkpad:~/kyy22/arm7-dasm$ gcc -o arm7-dasm arm7-dasm.c
arm7-dasm.c: In function ‘read_kallsyms’:
arm7-dasm.c:268:20: warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘size_t’ {aka ‘long unsigned int’} [-Wformat=]
  fprintf(stderr, "%d symbols are loaded.\n", symbol_len);
                   ~^                         ~~~~~~~~~~
                   %ld
fan@thinkpad:~/kyy22/arm7-dasm$ ls
README.md  arm7-dasm  arm7-dasm.c  arm7core.h  arm7dasm.c  emu.h

エラーがでましたが、通ったので良しとします(おい)
使い方についてですが、今回はシンボル情報があるので、README.mdに書いてある通り、
Disassemble with symbol table:
$ ./arm7-dasm [kernel image filename] [image base address] [start address or symbol name] [symbol table file]
といった感じです。
今回の場合、kernel imageはkernel.dumpとしてダンプ済みで、base addressはc0008000、symbol nameはkclsm_sb_mountでsymbol table fileはkyy22.txtとして出力済みなので、

./arm7-dasm kernel.dump c0008000 kclsm_sb_mount kyy22.txt

となります。
実際にやってみます。

fan@thinkpad:~/kyy22$ ./arm7-dasm kernel.dump c0008000 kclsm_sb_mount kyy22.txt > kclsm_sb_mount.dasm
90981 symbols are loaded.
fan@thinkpad:~/kyy22$ head kclsm_sb_mount.dasm 
Disassemble 0xc026bae8 - 0xc026bbf4
c026bae8:             <kclsm_sb_mount>
c026bae8: e9 2d 41 f3     STMPW   [SP], { R0-R1, R4-R8, LR }
c026baec: e1 a0 70 03     MOV     R7, R3 
c026baf0: e5 9f 31 00     LDR     R3, =$c0f53a98 <kmalloc_caches> [$c026bbf8]
c026baf4: e1 a0 50 00     MOV     R5, R0 
c026baf8: e1 a0 60 01     MOV     R6, R1 
c026bafc: e5 93 00 30     LDR     R0, [R3, #$30]
c026bb00: e3 50 00 00     CMPS    R0, #$0
c026bb04: 0a 00 00 05     BEQ     $c026bb20

うまくディスアセンブルできたようです。
で、これからアセンブリを読んでいくわけですが、かなり長くなったので後半にまわします。
後半は処理を書き換えて書き込み可でマウントできるようにして、他のLSMも解除していきます。
シンボル情報を | grep kclsmしてみるとわかりますが、chrootやpivotroot、mknodなんかが使えないです。
これらを解除しないとrootの自由が感じれず、精神衛生上悪いので解除します。

今回始めてマークダウン記法を使ってみましたが、これかなりいい感じです。

国産スマホをroot化するには 基本編

前々からまとめようと思ってたやつです。

今更感が凄まじいですが、国産スマホもroot取ってLSM解除できれば、chroot環境が動いて少しは使えるようになるんじゃないかと思ってるのでまとめます(希望的観測)

あと、この辺の情報って結構少ない上にあちこちに散らばってる感じがするので...

今回はとりあえず、root化の基本と、なぜ国産スマホはroot化しにくいのかをまとめます。

国産スマホのLSM解除の具体的な手法はまた後日...

前提

この記事は、以下の知識を前提として進んでいきます。

全くわからなくても雰囲気はつかめると思いますが、以下の知識があると、もっと楽しめると思います。

1.UNIX系基礎(基本的なコマンドと、権限。あとセキュリティ周り)

2.C言語を読む力

3.android基礎(adbだったりとか)

それから、root権限とroot化の違いは理解しておいてください。(そもそもroot化っていう言葉自体がおかしな気もしますが...)

じゃないと読んでいるうちに混乱してしまいます。(多分)

root化の基本

そもそもroot化ってなんなのか。という話からすすめます。

有志の方が作ったroot化アプリやGUIなPC用root取得ツールなんかが扱いやすいし多いので、root化って結局何をしているのかがわからなくなってしまいがちです。

基本的には/system/xbin以下にsuバイナリを送り込めば、root権限を使うアプリなんかは動いてくれます。

つまり、root化 = /system/xbinにsuバイナリを置く

みたいなイメージです。

で、これを実行するためには大きく分けて2つの方法があります。

1.ブートローダをアンロックし、カスタムリカバリを焼いてリカバリからsuバイナリを置く

2.脆弱性を突いて、root権限を奪取後、suバイナリを置く。

※他にも方法はありますが、今回は割愛します。

 

1は、ぱっと見難しそうですが、カーネルの手が届かないリカバリ領域に任意のイメージを焼いて、そこからsuを置く(最近はMagiskが普通になってきていますが、あれは仕組みが少し違うので...)イメージです。

海外製のスマホだったり、最近の一部の国産スマホはこの手法でroot取れます。

 

2は、脆弱性を使ってroot権限を奪取後、/systemを読み書き可能(rw)でリマウントして、/system/xbinにsuバイナリを置くというものです。

しかし1とは違って、カーネルによるプロテクトだったりが作用するので、あまりお手軽とはいえません。特に今回使う国産スマホは尚更です。

 

時々、SuperSuのアプリを入れるだけでroot化できると勘違いしている人を見かける事がありますが、SuperSuはあくまでもsuバイナリへのアクセスを制御するだけであって、suバイナリがないと動いてくれません(更新はしてくれますが)

国産スマホのroot化が難しいワケ

上で説明した通り、最近の国産スマホブートローダアンロック(以下BLUと記載)できるようになってきています。しかし、昔の(android 3.0〜7.1.1.くらい)国産スマホは基本的にBLUなんてできませんし、一部ではリカバリ非搭載。壊れたらショップに持っていくか捨てろ。みたいなのが多い印象です。おまけに性能もあまり良くない上に消せないプリインストールアプリと不具合が... と脱線してしまいましたが、つまるところrootを取るには"基本的に"上記の2の脆弱性を使ってroot化する方法しかありません。

脆弱性を使ってroot化というと、KingRootなんかのワンクリック系rootツールが有名ですし、成功例も多いです。

では、国産スマホで実行するとどうなるのか。

ほとんどの場合は失敗してしまいますし、うまくいっても再起動したら再実行しないといけなかったりします。

実際、某知恵袋なんかで、

<国産スマホ機種名>がroot化できません!
<国産スマホ機種名>のroot方法を教えてください!

みたいなのをよく見かけます。

実は、国産スマホには基本的にLSM(Linux Security Modules)が搭載されており、こいつがroot化を防いでいます。

KingRoot等のツールは脆弱性を使ってroot権限を奪取して、/systemを書き込み可能でリマウントしてsuバイナリを置く作業をしますが、root権限を奪取しようとしたり、/systemを書き込み可能でリマウントしようとしたらLSMが作動して、うまく作業が実行できないというわけです。なので、ワンクリック系ツールなんかで国産スマホはroot化できません。

しかもLSMはカーネルに組み込まれているため、root権限で簡単に解除できるものではありません。

試しに、KYY22で/systemを読み書き可でリマウントしてみます。(root権限は既に取ったものとします)

root@android:/ # id
uid=0(root) gid=0(root)
root@android:/ # mount -o rw,remount /system
mount: Operation not permitted

といった感じで、カーネルから拒否られます。

 

じゃあどうするんだって話は次回します。

流れの説明が終わったら、URBANO L02(KYY22)とMEDIAS ES(N-05D)を実際にLSM解除してみようと思います。

KYY22に関しては、魔界塔士氏が既にroot化していますが、今回はLSM解除まで話ができたらな...と。

N-05Dに関しては、おそらく私が初めてです。(ネットを見る限りは)

 

ブログを書くのって、こんなに大変なものなんですね...

 

<参考にさせていただいたサイト>

国産スマホのroot化手順について1(概要):魔界塔士のブロマガ - ブロマガ