awkでリバースエンジニアリング

MIPSだからかもしれませんがr2もghidraもいまいちなのでawkで簡単に見やすくしてみます。

jr raとjを元に分割してみます。

```awk:refunc.awk
BEGIN{a = -1}
/jr.ra$/{a = 2;jr = 1}
/j\t/{a = 2;jr = 0}
{print $0;if(a > 0){a = a - 1};
if(a == 0){if(jr == 1) {print "--"} else { print "-"};
a = -1}}
```

jは関数内でのジャンプに使われるので、区別しました。実行してみます。

```
% mips-unknown-freebsd13.0-objdump -D -b binary -m mips --adjust-vma=0x80010000 threadx.bin | awk -f refunc.awk
```

MIPSは遅延スロットがあるので、命令の一つ先の後に区切りを入れて、こんな感じになります。

```
80010f40:       0800e003        jr      ra
80010f44:       2800bd27        addiu   sp,sp,40
--
80010f48:       e8ffbd27        addiu   sp,sp,-24
80010f4c:       1000bfaf        sw      ra,16(sp)
80010f50:       d522020c        jal     0x80088b54
80010f54:       00000000        nop
80010f58:       0b80043c        lui     a0,0x800b
80010f5c:       1000bf8f        lw      ra,16(sp)
80010f60:       94af8424        addiu   a0,a0,-20588
80010f64:       21304000        move    a2,v0
80010f68:       10808527        addiu   a1,gp,-32752
80010f6c:       0e610208        j       0x80098438
80010f70:       1800bd27        addiu   sp,sp,24
-
80010f74:       d8ffbd27        addiu   sp,sp,-40
80010f78:       1800b2af        sw      s2,24(sp)
80010f7c:       ff00b230        andi    s2,a1,0xff
80010f80:       1400b1af        sw      s1,20(sp)
```

一つの関数内でjr raが複数あるケースは区別がつきません。

関数の最後に関数をよぶ場合は、jr raせずにjの事もあります。

だらだらつながっているダンプよりずいぶん見やすいです。

オフセットの表示が10進で分かりにくいので、16進のコメントを付けてみました。


```awk
$4 ~ /,.*\(.[0-9]/ {
s = index( $4, "," )
e = index( $4, "(" )
l = substr( $4, s + 1, e - s - 1)
if (l < 0) {
l  = 65536 + l
}
s1 = substr( $4, 0, s)
s2 = substr( $4, e, length($4))
$0 = sprintf("%s\t\t;0x%04x",  $0, l)
}
$0
```

マイナスの時は0x10000から引いた値にしました。

```
--
800120b8:       01b0023c        lui     v0,0xb001
800120bc:       ff008430        andi    a0,a0,0xff
800120c0:       ff00a530        andi    a1,a1,0xff
800120c4:       ff00c630        andi    a2,a2,0xff
800120c8:       ff00e730        andi    a3,a3,0xff
800120cc:       2aa047a0        sb      a3,-24534(v0)           ;0xa02a
800120d0:       2ba045a0        sb      a1,-24533(v0)           ;0xa02b
800120d4:       28a046a0        sb      a2,-24536(v0)           ;0xa028
800120d8:       0800e003        jr      ra
800120dc:       29a044a0        sb      a0,-24535(v0)           ;0xa029
--
```

800120ccはb000a02aへのバイトストアになります。

addiuにも16進のコメント付けました。spははぶきました。

```awk
$3 ~ /addi/ && $4 !~ /sp/{
l = substr( $4, 7, length($4) - 6)
if (l < 0) {
l  = 65536 + l
}
s1 = substr( $4, 0, s)
s2 = substr( $4, e, length($4))
if (length($4) < 8) {
$0 = sprintf("%s\t\t\t;0x%04x",  $0, l)
} else {
$0 = sprintf("%s\t\t;0x%04x",  $0, l)
}
}
$0
```

データは逆アセンブルできないものを含むので

```awk
awk '$3 ~ /0x.{8}/ {print $0}'
```

で見ると

```
80010090:       abcdefcc        0xccefcdab
80010094:       78787878        0x78787878
80010098:       78787878        0x78787878
8001009c:       78787878        0x78787878
800100a0:       4452414d        0x4d415244
800100a4:       20434f44        0x444f4320
800a6fc8:       4c4d4e4f        0x4f4e4d4c
800a6fd4:       58595a5b        0x5b5a5958
800a6fd8:       5c5d5e5f        0x5f5e5d5c
...
```

なので、コードは800a6fc8の前までのようです。

一つのスクリプトでいろいろやると分かりにくくなるので、ばらばらに作るのが良さそうです。

r2やghidraみたいな大げさなツール使わなくても十分だったりします。

今のターゲットのバイナリはMIPS32だけでつくられているのでいいのですが、MIPS16が混在したバイナリに対応した逆アセンブラはないので、その場合は厳しいと思います。

なによりobjdumpとawkは軽いです。ローテク万歳。