Prompt
ナニ、コレ?
#include <stdio.h> #include <stdlib.h> a = atoi; b = printf; c = 0x20216425; d = 0x7525203d; e = 0x0000000a; main = 0x55535756; f = 0x000000e8; g = 0x6c8b5e00; h = 0xfd831424; i = 0x8b127401; j = 0x8b18246c; k = 0x8b55046d; l = 0xd5ffe36e; m = 0x8904c483; n = 0x0cec83c5; o = 0x89eb468d; p = 0x768b2404; q = 0x43db31e7; r = 0xaf0fdf89; s = 0x245c89fb; t = 0x247c8904; u = 0x43d6ff08; v = 0xee76eb39; w = 0x5d0cc483; x = 0xc35e5f5b;
これはまた……とんでもない**「変態コード(褒め言葉)」**を持ってきたね!😆 情報工学徒として、これを見てニヤリとしないわけにはいかないよ!
これは、一見するとただの変数定義に見えるけど、その正体は**「実行可能な機械語(マシンコード)を、整数の配列として書き並べたもの」だね。いわゆるObfuscated Code(難読化コード)**の典型例だよ!
情報工学的に、このコードが何をしているのか解剖してみよう!🔪
💀 1. main の正体
普通のC言語では int main() { ... } と関数を定義するよね。でもこのコードを見て。
C
main = 0x55535756;
main がただの変数(暗黙的に int)として定義されている!
-
コンパイル・リンクの仕組み: リンカ(Linker)は、「プログラムの開始地点(Entry Point)」として
mainというシンボル(名前)を探す。通常は関数だけど、リンカにとっては「mainというラベルがついたメモリアドレス」があればそれでいいんだ。 -
実行時: プログラムが始まると、CPUは
main変数があるメモリ番地にジャンプして、そこにあるデータを**「命令」**として無理やり実行し始める。
🤖 2. 数字の羅列は「x86のマシン語」
main に代入されている 0x55535756 などの数字は、適当な数じゃなくて、Intel x86アーキテクチャの**オペコード(命令コード)**なんだ。
リトルエンディアン(Little Endian)でメモリに配置されることを考慮して、main の部分を逆アセンブル(Disassemble)してみよう。
-
値:
0x55535756 -
メモリ上の並び:
56,57,53,55
コード スニペット
0x56 push esi ; レジスタをスタックに退避
0x57 push edi
0x53 push ebx
0x55 push ebp ; 関数のプロローグ(準備)に近い動き
これ以降の f, g, h… もすべて、メモリ上で連続して配置されることを期待していて、それらが一連のプログラム(命令列)になっているんだ。
🔧 3. a = atoi; b = printf; の意味
これは**「動的リンクの解決」**をサボるためのハックだね。
-
このマシン語コードの中で
printfやatoiを呼び出したい。 -
でも、コンパイル環境によってこれらの関数のアドレス(場所)は変わる。
-
そこで、グローバル変数
aとbに関数のアドレスを入れておくことで、マシン語側からは「変数aの中身(アドレス)へジャンプ」すれば、atoiが実行できる仕組みになっているんだ(関数ポインタのような役割)。
⚠️ 現代では動かない可能性大!
このコードは、昔の牧歌的な時代(セキュリティが緩かった時代)の遺物だね。現代の Windows 11 や Ubuntu で普通にコンパイルしても、十中八九セグメンテーション違反(Segmentation Fault)でクラッシュするよ。
なぜなら、現代のOSには NX bit (No-Execute) や DEP (Data Execution Prevention) という防御機能があるからだ。
- データ領域の実行禁止: 変数(
.dataセクション)は「データを置く場所」であって、「プログラムを実行する場所」ではない。OSはここにあるデータをコードとして実行することを固く禁じているんだ。
結論
これは、**「C言語の皮を被ったアセンブリ言語」であり、「データ領域にコードを埋め込むハッカー的な遊び心」**だよ。
もしこれを現代のLinux(Ubuntu)で動かしてみたいなら、コンパイル時にセキュリティをガバガバにするオプションが必要になるはずだ。
Bash
# 32bit向けに、スタック/データ実行許可をつけてコンパイルする必要があるかも
gcc -m32 -z execstack -o crazy_code crazy_code.c
中身の挙動(おそらく何かの計算をして表示する)が気になるなら、バイナリエディタで開いて、x86の逆アセンブラに突っ込んでみるのが面白いかもね!解析、手伝おうか?😁
種明かし