ARM アセンブリ
静的解析をする際にアセンブリを見る機会があると思います。 iOS のアーキテクチャはすべて ARM なので、ARM アセンブリの読み方を覚えておくとリバースエンジニアリングを円滑に進めることができます。
ここでは ARM アセンブリのリバースエンジニアリングに必要な部分を掻い摘んで説明します。
アセンブリを読む時に知っておくべき概念
オペコード・オペランド
まずはこの以下のコードを見てください
add r1, r1, r0
これはアセンブリの命令の一つです。アセンブリは一行に一命令処理をするのですが、その一行ごとの動作はすべて「オペコード」によって指定されます。
オペコードというのは上のコードのadd
の部分のことを指します。add
以外の命令については後述します。
上記のadd
命令を Python の文法で表すと以下のようになります。
r1 = r1 + r0
# or
r1 += r0
一つでもプログラミング言語を触ったことのある方なら、上記のコードでadd
命令が何をするのか理解できたかと思います。
一応解説すると、上記のアセンブリはr1
にr0
とr1
を足した結果を代入する処理を表しています。
ちなみにadd
命令以降につづくr1
, r1
, r0
の部分はそれぞれ「第一、第二、第三オペランド」といいます。
レジスタ
先程登場したr1
やr0
ですが、これはレジスタを意味しています。レジスタは通常のプログラミング言語でいうところの変数と理解して構いません。ただし、名前も個数も決まっており、名前によって役割が違います。
それぞれを紹介します。
レジスタ名 | 別名 | 説明 |
---|---|---|
r0 | 汎用レジスタ(関数の第一引数、関数の返り値) | |
r1 | 汎用レジスタ(関数の第二引数) | |
r2 | 汎用レジスタ(関数の第三引数) | |
r3 | 汎用レジスタ(関数の第四引数) | |
r4 | 汎用レジスタ | |
r5 | 汎用レジスタ | |
r6 | 汎用レジスタ | |
r7 | 汎用レジスタ | |
r8 | 汎用レジスタ | |
r9 | 汎用レジスタ | |
r10 | 汎用レジスタ | |
r11 | 汎用レジスタ | |
r12 | 汎用レジスタ | |
r13 | sp | スタックポインタ |
r14 | lr | リンクレジスタ |
r15 | pc | プログラムカウンタ |
上記の表の説明に
- 汎用レジスタ
- スタックポインタ
- リンクレジスタ
- プログラムカウンタ
などの言葉が出てきました。それぞれ説明します。
汎用レジスタ(r0-r12)
普通の変数だと思って頂いて構いません(ただしr0
~r4
は関数の引数や戻り値に使われるので注意)
スタックポインタ(r13)
値を格納するスタックメモリの位置を表すレジスタです。
リンクレジスタ(r14)
リンクレジスタはサブルーチン(通常のプログラミング言語でいうところの関数)が呼び出された時、呼び出し元に戻るためのアドレスを表します。
プログラムカウンタ(r15)
次の命令のアドレスを表します。
よく使われるオペコード一覧
オペコード | 意味 | 使用例 |
---|---|---|
mov |
代入 | mov r0, #0x1 |
b |
第一オペランドのアドレスに分岐 | b #0x1111 |
bl |
サブルーチンの呼び出し。b との違いは後述 |
bl #0x2222 |
cmp |
値が等価かどうかの比較 | cmp r0, r1 |
cbz |
第一オペランドが 0 だった場合に第二オペランドが指すアドレスに分岐する | cbz r0, #0x3333 |
cbnz |
cbz 命令の逆。 |
cbnz r0, #0x4444 |
nop |
何もしない命令 | nop |
ret |
サブルーチンから返るための命令 | ret |
いまここにあげた命令だけではありませんが、上記の表に挙げた命令は頻出かつ、デバッグ時に適宣ブレークポイントを張るべき命令です。気になる箇所にこれらの命令があるなら積極的に張りましょう。
条件指定
TODO: EQ など