ばぁどです。
現在、ハニーポットで採取したマルウェアを仮想環境内で静的解析して遊んでおります。
本当はマルウェアの解析結果をアウトプットできれば面白そうなのですが、諸事情により自作したC言語のソースコードをコンパイルして吐かれた実行ファイルに対して静的解析を行っていきます。
#include<stdio.h>
int main(void)
{
int a, b, total;
a = 10;
b = 5;
total = a + b;
printf("%d\n", total);
}
$ cc sample.c
$ ls -la
total 24
drwxr-xr-x 2 root root 4096 Oct 30 19:47 .
drwxr-xr-x 5 root root 4096 Oct 30 19:44 ..
-rwxr-xr-x 1 root root 8424 Oct 30 19:47 a.out
-rw-r--r-- 1 root root 114 Oct 30 19:47 sample.c
今回はこのa.out
を使っていきます。
実行
$ ./a.out
15
念の為実行結果。
まずは表層解析から
file コマンド
$ file a.out
a.out: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=079b654a11e71cd0b8af95851abb964f267f561b, not stripped
ELF形式ですね。Linux で動く実行形式のファイルです。
strings コマンド
$strings a.out
/lib64/ld-linux-x86-64.so.2
libc.so.6
printf
__cxa_finalize
__libc_start_main
GLIBC_2.2.5
_ITM_deregisterTMCloneTable
__gmon_start__
_ITM_registerTMCloneTable
AWAVA
AUATL
[]A\A]A^A_
;*3$"
GCC: (Debian 7.2.0-12) 7.2.1 20171025
crtstuff.c
deregister_tm_clones
__do_global_dtors_aux
completed.7001
__do_global_dtors_aux_fini_array_entry
frame_dummy
__frame_dummy_init_array_entry
sample.c
__FRAME_END__
__init_array_end
_DYNAMIC
__init_array_start
__GNU_EH_FRAME_HDR
_GLOBAL_OFFSET_TABLE_
__libc_csu_fini
_ITM_deregisterTMCloneTable
_edata
printf@@GLIBC_2.2.5
__libc_start_main@@GLIBC_2.2.5
__data_start
__gmon_start__
__dso_handle
_IO_stdin_used
__libc_csu_init
__bss_start
main
__TMC_END__
_ITM_registerTMCloneTable
__cxa_finalize@@GLIBC_2.2.5
.symtab
.strtab
.shstrtab
.interp
.note.ABI-tag
.note.gnu.build-id
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_r
.rela.dyn
.rela.plt
.init
.plt.got
.text
.fini
.rodata
.eh_frame_hdr
.eh_frame
.init_array
.fini_array
.dynamic
.got.plt
.data
.bss
.comment
おおう。。なかなか大量にあるんだな・・・
静的解析で用いるコマンドの解説
今回、利用するコマンドはobjdump
です。
オブジェクトファイルの情報を表示してくれます。
コマンドのオプション
今回使用するのは、-d
オプションです。
要するに逆アセンブルするときに使われるオプションです。
もうこの時点で専門用語満載ですね。
一つ一つ解説します。
アセンブリ言語を機械語に変換する翻訳ソフトのこと。
コンピュータが理解できる言葉であるマシン語を人間が理解できる言語に置き換えたもの。
アセンブリ言語で用いられる英単語もしくは英単語の略語。
ADDやLD(LOAD)など様々なニーモニックコードが存在する。
人が理解できるプログラム言語から機械が理解できる機械語へ変換すること。
アセンブルの逆。
機械が理解できる機械語から人が理解できる形式へ変換すること。
objdumpの結果
※長いため省略します
$objdump -d a.out
a.out: file format elf64-x86-64
Disassembly of section .init:
00000000000004f0 <_init>:
4f0: 48 83 ec 08 sub $0x8,%rsp
4f4: 48 8b 05 ed 0a 20 00 mov 0x200aed(%rip),%rax # 200fe8 <__gmon_start__>
4fb: 48 85 c0 test %rax,%rax
4fe: 74 02 je 502 <_init+0x12>
500: ff d0 callq *%rax
502: 48 83 c4 08 add $0x8,%rsp
506: c3 retq
Disassembly of section .plt:
0000000000000510 <.plt>:
510: ff 35 f2 0a 20 00 pushq 0x200af2(%rip) # 201008 <_GLOBAL_OFFSET_TABLE_+0x8>
516: ff 25 f4 0a 20 00 jmpq *0x200af4(%rip) # 201010 <_GLOBAL_OFFSET_TABLE_+0x10>
・
・
・
$ objdump -d > sample.txt
root@kali:~/work/c# wc -l sample.txt
189 sample.txt
全部で189行になりました。
initを調べてみる
全部解析しようとすると、時間がいくらあっても足りないのでinitメソッドのみ何をやっているかを調べてみます。
1行目 4f0: 48 83 ec 08 sub $0x8,%rsp
2行目 4f4: 48 8b 05 ed 0a 20 00 mov 0x200aed(%rip),%rax # 200fe8 <__gmon_start__>
3行目 4fb: 48 85 c0 test %rax,%rax
4行目 4fe: 74 02 je 502 <_init+0x12>
5行目 500: ff d0 callq *%rax
6行目 502: 48 83 c4 08 add $0x8,%rsp
7行目 506: c3 retq
1行目
4f0: 48 83 ec 08 sub $0x8,%rsp
%rsp
というのが肝ですね。通常RSP
と記述されるもので、レジスタと呼ばれているものです。RSP
はスタックに関するレジスタでありスタックの一番上のメモリアドレスを示しているとのこと。
また、sub
は引き算をする時に使われるニーモニックコードです。
第一オペランド($0x8)から第二オペランド(%rsp)を引いて、第一オペランドに格納するという動きをするとのこと。
なので、この一行は変数$0x8
からスタックの一番上のメモリアドレスの値を引くという動作になると読めそうです。
2行目
4f4: 48 8b 05 ed 0a 20 00 mov 0x200aed(%rip),%rax # 200fe8 <__gmon_start__>
mov
が使われています。
mov
は値のコピーをするときに使われるもの。
%rip
は次に実行される命令を指すレジスタ。
%rax
というのは%rsp
同様レジスタであり、アキュムレーターを指しているとのこと。
アキュムレーターとは、CPUの演算回路を構成するレジスタの一種で、論理演算や四則演算などによるデータの入出力と結果の保持に用いられるレジスタのことである。
アキュムレーターとは何? Weblio辞書
3行目
4fb: 48 85 c0 test %rax,%rax
test
はビット01をテストしているとのこと。
4行目
4fe: 74 02 je 502 <_init+0x12>
je
は条件分岐のニーモニックコードとのこと。
前の結果が0なら分岐、ゼロフラグ=1なら分岐なので、3行目のtest
の結果次第で条件が分岐するということでしょうか。
5行目
ff d0 callq *%rax
callq
は関数呼び出しのニーモニックコードです。
また、呼び出しに使われているのも*
が使用されているのでポインタをさし示すことになるので、レジスタRAX
の番地にある処理を実行せよという表記になるのかな・・
6行目
48 83 c4 08 add $0x8,%rsp
今回はadd
ですね。
sub
とほぼ同じ挙動なのですが、$0x8
の値と%rsp
の値を足して、$0x8
に格納するという処理が行われます。
7行目
506: c3 retq
retq
は呼び出し元への処理の返却を表しています。
ニーモニックコード |
意味 |
詳細 |
add |
add |
値の足し算。 |
sub |
subtract |
値の引き算。 |
mov |
move |
値のコピー。第一オペランドに第二オペランドの数値をコピーする。 |
test |
test |
ビットの01をテスト。 |
retq |
return |
返り値。 |
まとめ
- 静的解析で利用するコマンドは
objdump
- 機械語から人間が理解できる言語に変換することを逆アセンブリという
- バイナリファイルを静的解析するには逆アセンブリが必要
- 逆アセンブリしたファイルの中身を知りたいときはニーモニックに関する知識が必要
- マルウェアの静的解析をブログ記事にするのは若干ビビる
所感
今回はバイナリファイルの静的解析の真似事をしてみました。
色々と抜け落ちている知識が多々あり、コンピュータ科学の基礎の基礎が抜け落ちていることを痛感しました。大学で何を学んでいたのでしょうか・・・うう・・・
今回大学の教科書などを引っ張り出して調査しながら記事を書きました。
至らない点もあると思います。何か間違った記述などあればコメントいただけると幸いです。