コース目次 / 第1章

先頭数バイトが、正体を語る

テキストファイルとコンパイル済みバイナリをfileで見分け、odで先頭バイトを直接見て、ELFのマジックナンバーを確認します。ファイルの正体は拡張子ではなく中身の先頭バイトで決まると理解します。

第1章 / 全5章目安 約10分この章のゴール: fileとodで、ファイルの先頭バイトから形式を見分けられるようになる

まず、簡単なプログラムを用意する

hello.c として保存し、コンパイルします。

#include <stdio.h>

int main(void) {
    const char *secret = "SECRET_MESSAGE_INSIDE_THE_BINARY";
    printf("Hello, World!\n");
    return 0;
}
gcc -O0 -o hello hello.c
echo "Hello, World!" > note.txt

hello(コンパイル済みバイナリ)とnote.txt(ただのテキスト)、2つのファイルができました。

fileで、見分ける

file note.txt
note.txt: ASCII text
file hello
hello: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=f234a7ef1df338a01973a7df9f28017ad750951c, for GNU/Linux 3.2.0, not stripped

fileコマンドは、拡張子を一切見ていません。拡張子の無いhelloでも、正しく「ELF 64-bit … executable」と判定しました。fileは中身の先頭バイトを見て判定しています。

odで、その先頭バイトを、自分の目で見る

od -A x -t x1z hello | head -2
000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00  >.ELF............<
000010 03 00 3e 00 01 00 00 00 60 10 00 00 00 00 00 00  >..>.....`.......<

od -A x -t x1zは、ファイルを16進数のバイト列として表示します(-A x: アドレスを16進で、-t x1z: 1バイトずつ16進+右側にASCII表示)。先頭4バイトが7f 45 4c 46——45 4c 46はASCIIでE・L・Fです。これが「ELFファイルです」という宣言、マジックナンバーです。fileコマンドは、まさにこの4バイトを見て判定していました。

od -A x -t x1z note.txt
000000 48 65 6c 6c 6f 2c 20 57 6f 72 6c 64 21 0a  >Hello, World!.<

note.txtには、マジックナンバーがありません。先頭からいきなり印字可能な文字(48=H、65=e…)が並んでいるので、fileは「ASCII text」と判定しました。ファイルの正体は、拡張子ではなく先頭バイトが決めています。

こうなっていればOK

卒業まであと3章です。

この章はまだ完了していません。