a.out直接編集すると実行できる?


アニメ『シャイニング・ハーツ ~幸せのパン~』

パンを見てるだけで幸せな気分になります。

タイトルの件、やってみます。
HELLOと表示するプログラム。

takk@deb9:~/tmp$ cat t.c
#include <stdio.h>

int main()
{
	printf("HELLO\n");

	return 0;
}

takk@deb9:~/tmp$ 

ビルド、実行。

takk@deb9:~/tmp$ gcc t.c
takk@deb9:~/tmp$ ./a.out
HELLO
takk@deb9:~/tmp$ 

まあ、動きますよね。

では、a.outを直接編集します。HELLOの文字列を変更してみます。
HELLOの位置を確認。

takk@deb9:~/tmp$ strings a.out -td | grep HELLO
   1876 HELLO
takk@deb9:~/tmp$ 

HELLOをTELLOに置換。

takk@deb9:~/tmp$ echo T | dd seek=1876 of=a.out bs=1 count=1 conv=notrunc
1+0 レコード入力
1+0 レコード出力
1 byte copied, 0.000119262 s, 8.4 kB/s
takk@deb9:~/tmp$

a.outが置換できたか確認しましょう。

takk@deb9:~/tmp$ !st
strings a.out -td | grep HELLO
takk@deb9:~/tmp$ ^HELLO^ELLO^
strings a.out -td | grep ELLO
   1876 TELLO
takk@deb9:~/tmp$ 

さて、a.outは実行できるでしょうか。

takk@deb9:~/tmp$ ./a.out
TELLO
takk@deb9:~/tmp$ 

TELLOと表示されました。
a.outを1Byteだけ変えたプログラムが、まさか実行できるとは思いませんでした。

では、HELLOを表示するプログラムと、TELLOを表示するプログラム、それぞれ普通にビルドすると、実行ファイルはどのぐらい差分が出るのでしょうか。

takk@deb9:~/tmp$ gcc t.c
takk@deb9:~/tmp$ sed 's/HE/TE/' t.c
#include <stdio.h>

int main()
{
	printf("TELLO\n");

	return 0;
}

takk@deb9:~/tmp$ sed 's/HE/TE/' t.c > t2.c
takk@deb9:~/tmp$ 

これで、t.cがHELLO、t2.cがTELLOと表示するソースファイルとなりました。
t.cはすでにビルド済なので、t2.cをビルドしてa2.outを生成します。

takk@deb9:~/tmp$ gcc -o a2.out t2.c
takk@deb9:~/tmp$ 

cmpします。

takk@deb9:~/tmp$ cmp a.out a2.out
a.out a2.out 異なります: バイト 41、行 1
takk@deb9:~/tmp$ 

当然異なりますね。

異なる箇所の先頭と末尾を表示。

takk@deb9:~/tmp$ cmp -l a.out a2.out | head
cmp: a.out でファイル終端 (EOF) に達しました
  41 370   0
  42  31  32
 645 165   4
 646 372 320
 647  67 116
 648  52 231
 649 117 205
 650 305 154
 651 200 214
 652 173  70
takk@deb9:~/tmp$ ^head^tail^
cmp -l a.out a2.out | tail
cmp: a.out でファイル終端 (EOF) に達しました
8577   0  21
8581   0   3
8593 354   0
8594  30   0
8601  14 355
8602   1  30
8609   0  14
8610   0   1
8617   1   0
8625   0   1
takk@deb9:~/tmp$ 

なんだか、同じデータが見受けられますが、格納位置のずれがあるようです。
lsで2つのファイルを比べてみると、サイズも異なります。

takk@deb9:~/tmp$ ls -l a*.out
-rwxr-xr-x 1 takk takk 8632  8月  7 20:15 a.out
-rwxr-xr-x 1 takk takk 8640  8月  7 20:16 a2.out
takk@deb9:~/tmp$ 

ずれる要因で思いつくのはファイル名ぐらいですね。

ファイル名の文字数を合わせてみます。

takk@deb9:~/tmp$ mv t.c t1.c
takk@deb9:~/tmp$ gcc -o a1.out t1.c
takk@deb9:~/tmp$ ls -l a1.out a2.out
-rwxr-xr-x 1 takk takk 8640  8月  7 20:25 a1.out
-rwxr-xr-x 1 takk takk 8640  8月  7 20:16 a2.out
takk@deb9:~/tmp$ 

サイズがぴったり同じになりました。

再度、cmp。

takk@deb9:~/tmp$ cmp -l a1.out a2.out
 645 202   4
 646  74 320
 647 222 116
 648   0 231
 649 164 205
 650 352 154
 651 327 214
 652 337  70
 653 122 303
 654 160  33
 655 353 306
 656 322 312
 657 245 215
 658  41  30
 659 315 235
 660  36 126
 661  45 215
 662  11 314
 663  20 164
 664 272 351
1877 110 124
5991  61  62
takk@deb9:~/tmp$ 

今度は、ずれはないようです。
cmpの結果は8進数で読みにくいので、16進ダンプの比較をします。

takk@deb9:~/tmp$ hd a1.out > a1.txt
takk@deb9:~/tmp$ hd a2.out > a2.txt
takk@deb9:~/tmp$ diff a1.txt a2.txt
41,42c41,42
< 00000280  47 4e 55 00 82 3c 92 00  74 ea d7 df 52 70 eb d2  |GNU..<..t...Rp..|
< 00000290  a5 21 cd 1e 25 09 10 ba  01 00 00 00 01 00 00 00  |.!..%...........|
---
> 00000280  47 4e 55 00 04 d0 4e 99  85 6c 8c 38 c3 1b c6 ca  |GNU...N..l.8....|
> 00000290  8d 18 9d 56 8d cc 74 e9  01 00 00 00 01 00 00 00  |...V..t.........|
118c118
< 00000750  01 00 02 00 48 45 4c 4c  4f 00 00 00 01 1b 03 3b  |....HELLO......;|
---
> 00000750  01 00 02 00 54 45 4c 4c  4f 00 00 00 01 1b 03 3b  |....TELLO......;|
288c288
< 00001760  6e 74 72 79 00 74 31 2e  63 00 5f 5f 46 52 41 4d  |ntry.t1.c.__FRAM|
---
> 00001760  6e 74 72 79 00 74 32 2e  63 00 5f 5f 46 52 41 4d  |ntry.t2.c.__FRAM|
takk@deb9:~/tmp$ 

3箇所に差分があり、一番下のブロック(1760)は、ファイル名の違い、真ん中のブロック(750)は、文字列HELLOとTELLOの違い。一番上のブロック(280)は、何かは分かりませんが、ビルド時間か何かでしょうか。

いずれにしても、1Byteの差分では収まりませんね。

Leave a Reply

Your email address will not be published. Required fields are marked *

CAPTCHA