2章 アセンブラとコンピュータアーキテクチャ
- バイナリ
- 実行ファイル, バイナリコードのこと
本書では,このバイナリを解析することを目的としているらしい.
C言語でバイナリに触れてみる
適当なC言語で書かれたソースコードを書きます.
#include <stdio.h>
int main() {
printf("%d\n", 2 + 3);
return 0;
}
このソースコードをgcc
でコンパイルしてあげるとa.out
と呼ばれるバイナリが生成されます.このバイナリファイルを実行すると,予想した結果が得られます.
❯ gcc compile_2-1.c
❯ ./a.out
5
ここから,バイナリ解析っぽくなります.本書ではhexedit
と呼ばれるバイナリエディタを使用していますが,私はxxd
と呼ばれるコマンドを用いて読みます.
❯ xxd a.out > a.bin
❯ cat a.bin
───────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ File: a.bin
───────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
1 │ 00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000 .ELF............
2 │ 00000010: 0300 3e00 0100 0000 4010 0000 0000 0000 ..>.....@.......
3 │ 00000020: 4000 0000 0000 0000 0847 0000 0000 0000 @........G......
4 │ 00000030: 0000 0000 4000 3800 0d00 4000 2500 2400 ....@.8...@.%.$.
5 │ 00000040: 0600 0000 0400 0000 4000 0000 0000 0000 ........@.......
6 │ 00000050: 4000 0000 0000 0000 4000 0000 0000 0000 @.......@.......
7 │ 00000060: d802 0000 0000 0000 d802 0000 0000 0000 ................
8 │ 00000070: 0800 0000 0000 0000 0300 0000 0400 0000 ................
9 │ 00000080: 1803 0000 0000 0000 1803 0000 0000 0000 ................
10 │ 00000090: 1803 0000 0000 0000 1c00 0000 0000 0000 ................
11 │ 000000a0: 1c00 0000 0000 0000 0100 0000 0000 0000 ................
12 │ 000000b0: 0100 0000 0400 0000 0000 0000 0000 0000 ................
13 │ 000000c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
14 │ 000000d0: 3006 0000 0000 0000 3006 0000 0000 0000 0.......0.......
15 │ 000000e0: 0010 0000 0000 0000 0100 0000 0500 0000 ................
...
次に,gcc
機能である,アセンブリコードを吐き出すコマンドを実行してみます.すると,.s
のアセンブリファイルがあることがわかります.
❯ gcc compile_2-1.c -S
❯ ls
a.bin a.out compile_2-1.c compile_2-1.s
❯ cat compile_2-1.s
───────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ File: compile_2-1.s
───────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
1 │ .file "compile_2-1.c"
2 │ .text
3 │ .section .rodata
4 │ .LC0:
5 │ .string "%d\n"
6 │ .text
7 │ .globl main
8 │ .type main, @function
9 │ main:
10 │ .LFB0:
11 │ .cfi_startproc
12 │ pushq %rbp
13 │ .cfi_def_cfa_offset 16
14 │ .cfi_offset 6, -16
15 │ movq %rsp, %rbp
16 │ .cfi_def_cfa_register 6
17 │ movl $5, %esi
18 │ leaq .LC0(%rip), %rax
19 │ movq %rax, %rdi
20 │ movl $0, %eax
21 │ call printf@PLT
22 │ movl $0, %eax
23 │ popq %rbp
24 │ .cfi_def_cfa 7, 8
25 │ ret
26 │ .cfi_endproc
27 │ .LFE0:
28 │ .size main, .-main
29 │ .ident "GCC: (GNU) 12.1.0"
30 │ .section .note.GNU-stack,"",@progbits
───────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
3章 ASCIIコードとバイトオーダ
- ASCIIコード
- 128文字を表現する,ビット列と文字の対応のことを指す
- アルファベットや,特殊な意味を持つ文字(NULや改行など)
C++で書かれた認証プログラムをハックする
本書の演習にあって,とても興味深かった内容です.標準入力とパスが一致したかを評価するプログラムですが,この実行ファイルからパスを推測する手法です.
#include <iostream>
#include <string>
int main(){
std::string input;
std::cin >> input;
if (input == "chizuchizu") {
std::cout << "success" << std::endl;
} else {
std::cout << "fail" << std::endl;
}
return 0;
}
実行すると想定どおりの答えが帰ってきます.
❯ g++ strings_3-2.cpp
❯ ./a.out
asdfasdf
fail
❯ ./a.out
chizuchizu
success
実行ファイルからパスを探すためにstrings
コマンドを使います.
strings コマンドは、ファイル内で表示可能な文字列を探します。 文字列とは、改行文字または null 文字で終わる 4 文字以上の印刷可能文字の任意の順序列です。 strings コマンドは、ランダム・オブジェクト・ファイルを識別するのに便利です。
strings コマンド - IBM Documentation
実際にやってみると,今回設定したパスであるchizuchizu
が出てくることがわかります.プログラムの中に文字列を入れれば,それを取り出せる脆弱性があるそうです.こわい.
❯ strings a.out | grep "^[^_.]"
/lib64/ld-linux-x86-64.so.2
libstdc++.so.6
libm.so.6
libgcc_s.so.1
libc.so.6
GCC_3.0
GLIBC_2.4
GLIBC_2.34
GLIBC_2.2.5
CXXABI_1.3
GLIBCXX_3.4
GLIBCXX_3.4.21
PTE1
u3UH
chizuchizu
success
fail
...