世の中には色々な実行形式があります。ELF, Coff, PE, MachO, ...そのなかでも一番広く用いられている ELF に目を向け、その構造を解析しようとしています。今の時代なので 64bit 版をやる予定です。まだうまくいって無いですがね。。。
(今のところ)参考にしている文献等
お金はなるべく出したくないので書籍は見ていません。オライリーのタダ PDF 等があればそれを見たいとは思いますが、まだ探してもないです。
という訳で以下を参考にしています。
- WhirlwindTutorialOnCreatingReallyTeensyElfExecutablesForLinux -
- elf.hを読んで実行可能ファイルを直書きする - Qiita
man elf
elf.h
- 16進数ダンプコマンドの違い - security etc...
xxd
がやはりいいですね。
使うツール・環境
Arch Linux
Parallels Desktop に入れて、Mac 側から ssh
接続をして使います。
Vim
単純にアセンブリコードを記述するテキストエディタとして使用します。
NASM
愛用のアセンブラです。Vim でアセンブリコードを書いたら以下のコマンドでバイナリ生成をします。
$ nasm -f bin asm.asm
xxd
できたバイナリファイルを見るために。一方で hexdump
は2バイトごとに勝手にひっくり返してくるので嫌いです。
とりあえず分かってきたこと
- ELF ヘッダの
0x7F, "ELF"
だけ記述すればとりあえずfile
コマンドで ELF だと認識される。 - 続いて
2, 1, 1
とすると ELF 64-bit LSB と出る。 - 続いて
0, 0
とすると ELF 64-bit LSB (SYSV) と出る。 - 続いてゼロ埋めをし、
2, 62
とすると ELF 64-bit LSB executable, x86-64, (SYSV) とでる。- 楽しい。
- nasm で
$
は現在のアドレス、$$
はこのセクションの先頭アドレスを指す。 - 64bit では dw: 2byte, dd: 4byte, dq: 8byte である。
- その他はまだわからない。一応それっぽいファイルを作っても
Segmentation Fault
になる。- 実行形式エラーにはならないから、一応はそれっぽい ELF ができている?
org
のアドレスが分からん。
ということで、暇を見つけて ELF の調査を行っていきます。目指せ、バイナリアン。
ちなみに今のところ適当に書き上げた ELF の実行ファイルはこちらです。上手く動きませんけど。
bits 64
org 0x400000
; e_ident[]
elf_header:
db 0x7F,"ELF" ; magic numbers
db 2, 1, 1 ; 64bit, little endian, current ELF version
db 0, 0 ; No ABI, ABI version 0
db 0, 0, 0, 0, 0, 0, 0 ; zero-padding
dw 2, 62 ; executable file, x64 machine
dd 1 ; current object version
dq _start
dq program_header - $$ ; program header offset
dq 0 ; section header offset
dd 0 ; flags(zero)
dw elf_header_size
dw program_header_size
dw 1 ; progra header number
dw 0, 0, 0 ; section header(none)
elf_header_size equ $ - elf_header
program_header:
dd 1 ; loadable segment(what!?)
dd 0 ; segment offset(what!?)
dq $$ ; first segment virtual address
dq 0 ; reserved
dq filesize, filesize
dq (1 << 2) | (1 << 0) ; readable & executable segment
dq 0x1000 ; align(what!?)
program_header_size equ $ - program_header
_start:
mov ax, 60
mov di, 42
syscall
filesize equ $ - $$