アニメ『グラゼニ』
お金はもちろん好きですから、おもしろいですこのアニメ。
コツコツってのは、お金の話に思いがちですが、コツコツ勉強するってのも将来得るお金につながります。コツコツお金を貯めた方がいいのか、投資をしてコツコツ勉強、スポーツする方がいいのか。
どちらにしても努力が必要ですね。
今回は文字列数Byteのケチなネタです。
「a.out直接編集すると実行できる?」では、a.outを1Byteだけ書き換えて、HELLOプログラムをTELLOと表示するプログラムに改造しました。
1文字だけの変更なので簡単でしたが、さすがに出力する文字列を長くはできないでしょう。短くはできますが。
果たしてそうでしょうか。HELLOの文字列が格納されているメモリの周囲について確認していきたいと思います。
まずは、objdumpを使い、a.outのアセンブラを確認。
takk@deb9:~/tmp$ objdump -d a.out > asm.txt takk@deb9:~/tmp$
冒頭部分だけ見てみます。
takk@deb9:~/tmp$ head -20 asm.txt a.out: ファイル形式 elf64-x86-64 セクション .init の逆アセンブル: 0000000000000530 <_init>: 530: 48 83 ec 08 sub $0x8,%rsp 534: 48 8b 05 a5 0a 20 00 mov 0x200aa5(%rip),%rax # 200fe0 <__gmon_start__> 53b: 48 85 c0 test %rax,%rax 53e: 74 02 je 542 <_init+0x12> 540: ff d0 callq *%rax 542: 48 83 c4 08 add $0x8,%rsp 546: c3 retq セクション .plt の逆アセンブル: 0000000000000550 <.plt>: 550: ff 35 b2 0a 20 00 pushq 0x200ab2(%rip) # 201008 <_GLOBAL_OFFSET_TABLE_+0x8> 556: ff 25 b4 0a 20 00 jmpq *0x200ab4(%rip) # 201010 <_GLOBAL_OFFSET_TABLE_+0x10> takk@deb9:~/tmp$
よくわからないですよね。
では、main関数の辺りを見てみましょう。main関数は、正規表現でmain.:を探せば見つかります。
takk@deb9:~/tmp$ grep 'main.:' asm.txt -A10 00000000000006b0 <main>: 6b0: 55 push %rbp 6b1: 48 89 e5 mov %rsp,%rbp 6b4: 48 8d 3d 99 00 00 00 lea 0x99(%rip),%rdi # 754 <_IO_stdin_used+0x4> 6bb: e8 a0 fe ff ff callq 560 <puts@plt> 6c0: b8 00 00 00 00 mov $0x0,%eax 6c5: 5d pop %rbp 6c6: c3 retq 6c7: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1) 6ce: 00 00 takk@deb9:~/tmp$
ん~。どこかで見たプログラムです。そうです。前回「GDBアセンブラ表示とメモリダンプ」のgdbでdisassembleしたソースと似ています。
takk@deb9:~/tmp$ gdb a.out 省略 (gdb) b main Breakpoint 1 at 0x6b4: file t.c, line 5. (gdb) r Starting program: /home/takk/tmp/a.out Breakpoint 1, main () at t.c:5 5 printf("HELLO\n"); (gdb) disass Dump of assembler code for function main: 0x00005555555546b0 <+0>: push %rbp 0x00005555555546b1 <+1>: mov %rsp,%rbp => 0x00005555555546b4 <+4>: lea 0x99(%rip),%rdi # 0x555555554754 0x00005555555546bb <+11>: callq 0x555555554560 <puts@plt> 0x00005555555546c0 <+16>: mov $0x0,%eax 0x00005555555546c5 <+21>: pop %rbp 0x00005555555546c6 <+22>: retq End of assembler dump. (gdb)
objdumpで出力したアセンブラと異なるところは、アドレス部が、非常に大きな数字(0x00005555555546**)になっている点と、 #の後が、同じく大きな数字(0x555555554754)となっている点です。
よく見ると、法則があります。objdumpで表示されたアドレスに、0x0000555555554000を足した数字となっています。
法則さえわかれば、怖くないです。objdumpで、HELLOの定義内容を確認してみます。
takk@deb9:~/tmp$ objdump -s a.out | grep -C3 HELLO セクション .fini の内容: 0744 4883ec08 4883c408 c3 H...H.... セクション .rodata の内容: 0750 01000200 48454c4c 4f00 ....HELLO. セクション .eh_frame_hdr の内容: 075c 011b033b 38000000 06000000 f4fdffff ...;8........... 076c 84000000 14feffff ac000000 24feffff ............$... takk@deb9:~/tmp$
HELLOがあるセクションは、.rodataという名前がついてますね。
アドレスは0750とありますが、実際にHELLOが配置されているのは、ダンプ内容を見ると0754です。
最初に確認したobjdumpでのアセンブラ表示のコメントのアドレス 754と一致します。
6b4: 48 8d 3d 99 00 00 00 lea 0x99(%rip),%rdi # 754 <_IO_stdin_used+0x4>
さらに、
.rodataのセクションの後に、.eh_frame_hdrセクションがありますが、0x75c番地から始まっているので、少し余裕があるようです。
a.outの生ダンプを見てみます。HELLOの位置を確認すると、
takk@deb9:~/tmp$ hd a.out | grep HELLO 00000750 01 00 02 00 48 45 4c 4c 4f 00 00 00 01 1b 03 3b |....HELLO......;| takk@deb9:~/tmp$
4f の後は、00 00 00、その後に.eh_frame_hdrセクションのデータである01 1b 03 3bが続いています。
つまり、HELLOの後は3Byte分余裕があります。文字列の終端であるNULL(0)は絶対必要なので、実質2Byteです。
2Byteほど文字列を伸ばしてみましょう。HELLOをHELOOOに変更します。
takk@deb9:~/tmp$ echo OOO | dd seek=1880 bs=1 count=3 conv=notrunc of=b.out 3+0 レコード入力 3+0 レコード出力 3 bytes copied, 0.00010077 s, 29.8 kB/s takk@deb9:~/tmp$ hd b.out | grep HELLO 00000750 01 00 02 00 48 45 4c 4c 4f 4f 4f 00 01 1b 03 3b |....HELLOOO....;| takk@deb9:~/tmp$ ./b.out HELLOOO takk@deb9:~/tmp$
実行できました。
コメント