国産スマホを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化できてない)らへんをやっていきます。
冬休みの課題が結構ある上に全員強制参加の補習があるので、かなり後になりそうですが。
「ここ間違ってるよ!」みたいなのがあったら遠慮なくお願いします。