ばぁど・うぉっちんぐ

セキュリティを頑張りたいプログラマ。自由と春を求めて羽ばたく渡り鳥。

ばぁどのハニーポット・うぉっちんぐ - マルウェア解析の練習として、C言語で書いたコードを静的解析してみる -

ばぁどです。

現在、ハニーポットで採取したマルウェアを仮想環境内で静的解析して遊んでおります。

本当はマルウェアの解析結果をアウトプットできれば面白そうなのですが、諸事情により自作したC言語ソースコードコンパイルして吐かれた実行ファイルに対して静的解析を行っていきます。

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オプションです。

オプション 説明
-d ( --disassemble) 機械語に対応するアセンブラニーモニックを表示する。逆アセンブルをするときに用いる。

要するに逆アセンブルするときに使われるオプションです。

もうこの時点で専門用語満載ですね。 一つ一つ解説します。

アセンブラ

アセンブリ言語機械語に変換する翻訳ソフトのこと。

アセンブリ言語

コンピュータが理解できる言葉であるマシン語を人間が理解できる言語に置き換えたもの。

ニーモニック

アセンブリ言語で用いられる英単語もしくは英単語の略語。 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の演算回路を構成するレジスタの一種で、論理演算や四則演算などによるデータの入出力と結果の保持に用いられるレジスタのことである。

アキュムレーターとは - IT用語辞典 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 返り値。

まとめ

所感

今回はバイナリファイルの静的解析の真似事をしてみました。

色々と抜け落ちている知識が多々あり、コンピュータ科学の基礎の基礎が抜け落ちていることを痛感しました。大学で何を学んでいたのでしょうか・・・うう・・・

今回大学の教科書などを引っ張り出して調査しながら記事を書きました。 至らない点もあると思います。何か間違った記述などあればコメントいただけると幸いです。