android端末でchroot使ってディストリ動かしたときのメモ
root前提なので自己責任で。
Kali Linuxの開発元Offensive Securityがスマホ向けに出してるNetHunterを活用してLinuxディストリ動かそうというお話。
androidとLinux
義務教育で習ったようにandroidはLinuxカーネルで動いています。
なので各ディストリ用のファイルやらを用意してやれば、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のイメージしか作れないです...
なので、microSDにext4パテを作ってそこにイメージを展開、mountのbindを使って本体とつなぐことにします。
Linux Deployの設定はこんな感じ。
アーキテクチャとかパーティションは機種によって違うので、CPU-Z使うなりdmesgでマウントログ見たりで対応してください。
間違ったパーティションに上書きして泣いても自己責任で。
microSDにはext4なパーティションを作ってスロットに突っ込んでください。
あとは右上のボタンからInstallを選択すればmicroSDにディストリのイメージが書き込まれます。
今回はNetHunterのスクリプトで動かすので、作ったらLinux Deployは消しても大丈夫です。
スクリプト書き換え
今更ながら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 : 起動用スクリプト。引数をつけることでSSHやVNCとかをコントロールできる。
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にext4なmicroSDのパテが生えてるので、これを
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
することでmicroSDにchrootしてくれます。
その他にも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
でとりあえず起動できます。
終了するときは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を取ります。
- XDAフォーラムhttps://forum.xda-developers.com/android/software-hacking/root-tool-dirtycow-apk-adb-t3525120
- 必要なファイルhttp://www.mediafire.com/file/r3i900n7jb2zfoo/EXPLOIT_ADB.rar/file
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は、ファイル内に埋もれてるファイルを表示してくれます。
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氏制作のツールを使用させていただきます。
これをいつもどおり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を使用します。
これを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で流しながら諦め半分でリマウントしたら成功しました。
本当に謎です。わかんないです。もし原因がわかる方がいらっしゃったら連絡ください...
ちなみに勝手に再起動問題は、YouTubeで愛の挨拶流しながらマウントさせると、再起動しませんでした。
— てんぷ (@_t3mp_) 2019年4月4日
本当に何でなのか自分でもわかんない...
— てんぷ (@_t3mp_) 2019年4月4日
スマホが癒されて再起動しなくなった説で自己解決。
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規格に標準で搭載された機能を使ったプロテクトみたいなので、あまり苦労せずに解除できます。
これを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プロテクトは違うので別途解除が必要ですが...
やらかしました。事前の調べが甘いままでブログを書き始めたのが間違いでした。
前回のを書き終えたあたりで気づきましたが、もう戻るわけにもなぁ...
って感じで続けてしまいました。
とても申し訳ないです...
とりあえず、書き始めた以上は最後までやらないといけないと思うので、自動化をしていきます。
自動化
一気に解除の手間が省けてしまいましたが、再起動した後にしなければいけないのは、
- reset_security_opsを呼ぶ
- 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に含まれていたので、以下の物を取り出します。
- SHARP_android_rooting_tools/files/sh/vpnfaker.sh
- SHARP_android_rooting_tools/files/etc/VpnFakerV2.tar.gz
- SHARP_android_rooting_tools/files/bin/busybox
これらを取り出したら、いつものところに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に関しては、おそらく私が初めてです。(ネットを見る限りは)
ブログを書くのって、こんなに大変なものなんですね...
<参考にさせていただいたサイト>
Hello,World
Hello,World!