Skip to content

ARM アセンブリ

静的解析をする際にアセンブリを見る機会があると思います。 iOS のアーキテクチャはすべて ARM なので、ARM アセンブリの読み方を覚えておくとリバースエンジニアリングを円滑に進めることができます。

ここでは ARM アセンブリのリバースエンジニアリングに必要な部分を掻い摘んで説明します。

アセンブリを読む時に知っておくべき概念

オペコード・オペランド

まずはこの以下のコードを見てください

add r1, r1, r0

これはアセンブリの命令の一つです。アセンブリは一行に一命令処理をするのですが、その一行ごとの動作はすべて「オペコード」によって指定されます。

オペコードというのは上のコードのaddの部分のことを指します。add以外の命令については後述します。

上記のadd命令を Python の文法で表すと以下のようになります。

r1 = r1 + r0
# or
r1 += r0

一つでもプログラミング言語を触ったことのある方なら、上記のコードでadd命令が何をするのか理解できたかと思います。

一応解説すると、上記のアセンブリはr1r0r1を足した結果を代入する処理を表しています。

ちなみにadd命令以降につづくr1, r1, r0の部分はそれぞれ「第一、第二、第三オペランド」といいます。

レジスタ

先程登場したr1r0ですが、これはレジスタを意味しています。レジスタは通常のプログラミング言語でいうところの変数と理解して構いません。ただし、名前も個数も決まっており、名前によって役割が違います。

それぞれを紹介します。

レジスタ名 別名 説明
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 など