ごちゃごちゃしたIT勉強記録

自分用メモ。セキュリティ関連の内容を書いてます。

gdbでarmバイナリをデバッグできるようにする

普段はMacVMware Fusionをいれて、仮想マシンLinux環境を動かしているわけですが、CTFの問題を解いているとELFだったとしてもアーキテクチャがARMのものにぶち当たったりします。

GDBでARMのELFをデバッグするためのパッケージとして、gdb-multiarchというものがあります。
これを入れることで、普段だとx86-64x86アーキテクチャのELFしか解析できない(はず)ですが、ARMのアーキテクチャもちゃんと解析できるようになります。

環境

$ uname -a
Linux forensic-virtual-machine 4.13.0-36-generic #40~16.04.1-Ubuntu SMP Fri Feb 16 23:25:58 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="16.04.4 LTS (Xenial Xerus)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 16.04.4 LTS"
VERSION_ID="16.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
VERSION_CODENAME=xenial
UBUNTU_CODENAME=xenial

解析対象

とあるCTFの問題で出てきたバイナリを対象とします(手元にちょうどあったので)

$ file bin_arm 
bin_arm: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.3, for GNU/Linux 3.2.0, not stripped

gdb-multiarchが入っていない場合

まずは、gdb-multiarchが入っていない状態でバイナリを解析してみます。
いつも通りデバッグ対象に上記のファイルを指定します。

gdb bin_arm

試しにmain関数を逆アセンブルした結果を見てみようと思います。

gdb-peda$ disas main
Dump of assembler code for function main:
   0x0001055c <+0>:	add    BYTE PTR [eax+0x2d],cl
   0x0001055f <+3>:	jmp    0xe28eb568
   0x00010564 <+8>:	or     al,dl
   0x00010566 <+10>:	dec    ebp
   0x00010567 <+11>:	loop   0x10571 <main+21>
   0x00010569 <+13>:	add    BYTE PTR [ebx],cl
   0x0001056b <+15>:	in     eax,0xc
   0x0001056d <+17>:	adc    BYTE PTR [ebx],cl
   0x0001056f <+19>:	in     eax,0x8
   0x00010571 <+21>:	xor    BYTE PTR [ebx],bl
   0x00010573 <+23>:	in     eax,0x1
   0x00010575 <+25>:	add    BYTE PTR [ebx-0x1d],dl
   0x00010578 <+28>:	or     BYTE PTR [eax],al
   0x0001057a <+30>:	add    dl,cl
   0x0001057c <+32>:	pusha  
   0x0001057d <+33>:	xor    BYTE PTR [edi-0x6cffff1b],bl
   0x00010583 <+39>:	in     eax,0xc
   0x00010585 <+41>:	xor    BYTE PTR [ebx],bl
   0x00010587 <+43>:	in     eax,0x0
   0x00010589 <+45>:	xor    BYTE PTR [ebx-0x5fdffc1b],dl
   0x0001058f <+51>:	loope  0x105e1 <main+133>
   0x00010591 <+53>:	adc    BYTE PTR [edi-0x891b],bl
   0x00010597 <+59>:	jmp    0x10599 <main+61>
   0x00010599 <+61>:	xor    al,ah
   0x0001059b <+63>:	jecxz  0x105aa <main+78>
   0x0001059d <+65>:	add    BYTE PTR [eax],al
   0x0001059f <+67>:	jmp    0x3004:0xe51b300c
   0x000105a6 <+74>:	and    edx,0x0
   0x000105a9 <+77>:	xor    BYTE PTR [ebx-0x5ffffc1b],dl
   0x000105af <+83>:	loope  0x10573 <main+23>
   0x000105b1 <+85>:	(bad)  
   0x000105b2 <+86>:	(bad)  
   0x000105b3 <+87>:	jmp    0x105b5 <main+89>
   0x000105b5 <+89>:	xor    BYTE PTR [eax+0x530000e1],ah
   0x000105bb <+95>:	jecxz  0x105bf <main+99>
   0x000105bd <+97>:	add    BYTE PTR [eax],al
   0x000105bf <+99>:	sbb    ah,BYTE PTR [eax+eax*1]
   0x000105c2 <+102>:	lahf   
   0x000105c3 <+103>:	in     eax,0x61
   0x000105c5 <+105>:	(bad)  
   0x000105c6 <+106>:	(bad)  
   0x000105c7 <+107>:	jmp    0x105ca <main+110>

ところどころ(bad)となっており、マシンコードを適切にアセンブリコードに変換できていないことが分かるかと思います。
あと、みるからにアセンブリコードが変(いつも見ている感じとはなんか違和感がある)です。

ということで、なにも手を加えずgdbでarmバイナリに突撃すると爆死します...

gdb-multiarchを入れてやってみる

では早速入れてやってやってみましょう。いつも通りaptで入れます。

sudo apt install gdb-multiarch

準備はこれで終了です。では早速起動。

$ gdb-multiarch bin_arm 
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from bin_arm...(no debugging symbols found)...done.
gdb-peda$ 

普通にgdbと同じように起動してしまったので、「これこのまんまでいけるんか?」と不安になりますがそのまま行きます。
また、見て分かる通り、gdb-pedaを入れている方であればgdb-multiarchを起動しても同じようにいけます(おそらく同じ.gdbinitを見にいっているかと)

というわけで、逆アセンブルしたmain関数のアセンブリコードを見てみます。

gdb-peda$ disas main
Dump of assembler code for function main:
   0x0001055c <+0>:	push	{r11, lr}
   0x00010560 <+4>:	add	r11, sp, #4
   0x00010564 <+8>:	sub	sp, sp, #8
   0x00010568 <+12>:	str	r0, [r11, #-8]
   0x0001056c <+16>:	str	r1, [r11, #-12]
   0x00010570 <+20>:	ldr	r3, [r11, #-8]
   0x00010574 <+24>:	cmp	r3, #1
   0x00010578 <+28>:	bgt	0x105a0 <main+68>
   0x0001057c <+32>:	ldr	r3, [pc, #96]	; 0x105e4 <main+136>
   0x00010580 <+36>:	ldr	r0, [r3]
   0x00010584 <+40>:	ldr	r3, [r11, #-12]
   0x00010588 <+44>:	ldr	r3, [r3]
   0x0001058c <+48>:	mov	r2, r3
   0x00010590 <+52>:	ldr	r1, [pc, #80]	; 0x105e8 <main+140>
   0x00010594 <+56>:	bl	0x10374 <fprintf@plt>
   0x00010598 <+60>:	mvn	r3, #0
   0x0001059c <+64>:	b	0x105d8 <main+124>
   0x000105a0 <+68>:	ldr	r3, [r11, #-12]
   0x000105a4 <+72>:	add	r3, r3, #4
   0x000105a8 <+76>:	ldr	r3, [r3]
   0x000105ac <+80>:	mov	r0, r3
   0x000105b0 <+84>:	bl	0x104c0 <check>
   0x000105b4 <+88>:	mov	r3, r0
   0x000105b8 <+92>:	cmp	r3, #0
   0x000105bc <+96>:	bne	0x105cc <main+112>
   0x000105c0 <+100>:	ldr	r0, [pc, #36]	; 0x105ec <main+144>
   0x000105c4 <+104>:	bl	0x10350 <puts@plt>
   0x000105c8 <+108>:	b	0x105d4 <main+120>
   0x000105cc <+112>:	ldr	r0, [pc, #28]	; 0x105f0 <main+148>
   0x000105d0 <+116>:	bl	0x10350 <puts@plt>
   0x000105d4 <+120>:	mov	r3, #0
   0x000105d8 <+124>:	mov	r0, r3
   0x000105dc <+128>:	sub	sp, r11, #4
   0x000105e0 <+132>:	pop	{r11, pc}
   0x000105e4 <+136>:	andeq	r1, r2, r0, asr r0
   0x000105e8 <+140>:	andeq	r0, r1, r4, ror #12
   0x000105ec <+144>:	andeq	r0, r1, r8, ror r6
   0x000105f0 <+148>:	andeq	r0, r1, r4, lsl #13
End of assembler dump.

ちゃんと表示されているっぽい!
ぶっちゃけARMのアセンブリの解析はほとんどやっていないので、どの命令がどの処理をするのかわかってません。
(噂だとオペランドを3つとるとかなんとか....)

なので、ひとまずはこれを使って勉強していこうと思います。