bamboo’s blog

Bambooの気まぐれブログ

hookコードでレジスタ書き出し(CTRPF)

概要

 きっかけはどぅーむーんさんのツイート。

内容としては、hookコードでレジスタ確認を行うというもの。実装は少々面倒かもしれないが、面白そうだったので組んでみることにした。(十分なテストを行っていないため、間違い等あればコメント欄まで)

手順

 以下の手順で実装する。今回の方法ではlrとpcを参照できないため、確認するレジスタはr0~r13(sp)とする。

  1. r0~r13, cpsrをスタックに退避。
  2. スタックから値を読み込み、実行コードの下部に書き込む。
  3. 上書きしたレジスタを復元し、スタックポインタを戻す。

※hook処理にもスタックは使われる。spはあくまでhookコード開始時の値であり、hookアドレス時点での値ではないため注意。

コード

上記の手順に沿って実装。ちなみに各レジスタの役割は以下のように割り振った。

  • r0 ・・・cpsrの格納と復元及び偶数番目のレジスタのロード
  • r1・・・奇数番目のレジスタのロード
  • r2・・・ロードするレジスタのポインタ
  • r3・・・書き込み先のポインタ
  • r4・・・push前のスタックポインタの値
E92D3FFF    @ push {r0-r13}
E10F0000    @ mrs r0, cpsr
E52D0004    @ push {r0}
E28D2004    @ add r2, sp, #4
E28F3028    @ add r3, pc, #0x28
E28D403C    @ add r4, sp, #0x3C
E0C200D8    @ ldrd r0, [r2], #8
E0C300F8    @ strd r0, [r3], #8
E1520004    @ cmp r2, r4
BAFFFFFB    @ blt #-12
E49D0004    @ pop {r0}
E129F000    @ msr cpsr, r0
E8BD001F    @ pop {r0-r4}
E28DD024    @ add sp, sp, #0x24
E12FFF1E    @ bx lr

以下各コード解説。(コードをクリックして詳細確認)

push {r0-r13}  確認対象とするレジスタをスタックに積む。

mrs r0, cpsr  cpsrの値をr0にコピー。

push {r0}  r0(中身はcpsrの値)をスタックに積む。

add r2, sp, #4  r2に読み込みを開始するレジスタの位置を読み込む。この時r2はスタックに退避したr0の位置を指している。

add r3, pc, #0x28  r3に書き込み開始位置を読み込む。今回はhookコード終了命令(bx lr)の8byte先を指している。

add r4, sp, #0x3C  r4にpush前のspの位置を読み込む。

ldrd r0, [r2], #8  r2から値をロード。ldrdはダブルワードをロードする命令なので、r0には偶数レジスタが、r1には奇数レジスタが読み込まれる。ポインタを次の読み込み元にずらすため、ロード後r2には8が加算される。

strd r0, [r3], #8  r3のメモリアドレスにレジスタ2つ分書き込む。次のレジスタを書き込むため、ストア後r3には8が加算される。

cmp r2, r4  r2とr4を比較。r2は次のロード開始位置、r4は元のスタックポインタの位置を指している。つまり、「ロードすべきレジスタが残っているか」を判断している。

blt #-12  r2の方が小さければまだロードしていないレジスタがあるということなので、次のレジスタのロードを開始する。

pop {r0}  スタックに積んでいたcpsrの値をr0に読み込む。

msr cpsr, r0  r0の値をcpsrにコピー。これで元のcpsrの値が復元される。

pop {r0-r4}  処理に使用したレジスタ(r0~r4)は復元する必要があるため、スタックから復元する。

add sp, sp, #0x24  スタックポインタを元の位置に戻す。

bx lr  lrに分岐し、hookコード終了。

D3000000 XXXXXXXX    // フックするアドレス
FD000000 00000078    // フック開始(0x78 byte)
E92D3FFF  E10F0000
E52D0004 E28D2004
E28F3028 E28D403C
E0C200D8 E0C300F8
E1520004 BAFFFFFB
E49D0004 E129F000
E8BD001F E28DD024
E12FFF1E 00000000
00000000 00000000    // r0, r1
00000000 00000000    // r2, r3
00000000 00000000    // r4, r5
00000000 00000000    // r6, r7
00000000 00000000    // r8, r9
00000000 00000000    // r10, r11
00000000 00000000    // r12, sp
D2000000 00000000

CTRPFのコードに直すと上記の通り。これでr0~r13(sp)のレジスタ値が取得できる。