U+E000 私用領域

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

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

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

アセンブリを読む

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

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

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

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

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

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

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

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

    realpath = d_path(path, ptr, PATH_MAX);

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

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

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

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

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

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


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

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


mmcプロテクト

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

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

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

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

kernel.googlesource.com

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

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

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

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

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

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

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

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

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

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

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

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

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

LSMの全解除と自動化

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

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

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

  • kclsm_path_chroot
  • kclsm_sb_pivotroot

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

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

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

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


kclsm_ptrace_traceme

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

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

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


kclsm_kernel_setup_load_info

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

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

関数の最初の方の

if (kclsm_kbfm == KCLSM_KBFM_ENABLE)
                return 0;

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


kclsm_path_mknod

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

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

関数の最初の方の

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

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


kclsm_sb_umount

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

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

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


kclsm_ptrace_access_check

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

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

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


kclsm_dentry_open

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

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

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


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

#!/system/bin/sh

tmp=/data/local/tmp

$tmp/install_backdoor

#kclsm_sb_mount
$tmp/write_value 0xc026bb4c 0xea000023

#kclsm_ptrace_traceme
$tmp/write_value 0xc026bc30 0xea000007

#kclsm_kernel_setup_load_info
$tmp/write_value 0xc026bc78 0xea00001b

#kclsm_path_mknod
$tmp/write_value 0xc026bd20 0xea000031

#kclsm_sb_umount
$tmp/write_value 0xc026be14 0xea00003d

#kclsm_ptrace_access_check
$tmp/write_value 0xc026bf64 0xea000010

#kclsm_dentry_open
$tmp/write_value 0xc026bfcc 0xea000052

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

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

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

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

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

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

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

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

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

__

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


Device detected: KYY22 (102.0.0f00)

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

Dump kernel memory...

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

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

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

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

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

reset_security_ops

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

自動化

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

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

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

#onBoot

#!/system/bin/sh

tmp=/data/local/tmp

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

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

#autoexec.sh

#!/system/bin/sh

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

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

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

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

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

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

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

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

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

おわりに

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