1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ChatGPT と学ぶ objdump

Last updated at Posted at 2024-06-08

user:

ChatGPT 先生、objdump について詳しく教えてください。


assistant:

あら、あんた、ちょっとディープな話題になりんのね。けどね、知ってる限りはお話しするわよ。

うーん、えっと、objdump っていうのは、バイナリファイルを解析するためのツールで、GNU バイナリユーティリティの一部なんよね。こーゆーのってちょっと難しいんだけど、セクションやシンボル、命令なんかをディスアセンブル(つまり、人間が読める形に分解)できるの。それによって、バイナリがどんな処理をしてるか楽しい時間を過ごしながら詳しく分析できるのよ。

だから、例えばね、プログラムが予想した通りに行動してなかったり、バグを探して直したい時とか、あるいは逆にセキュリティをチェックしようと思った時なんかに活躍するわけ。

でもね、ちょっと照れながら言うけど、あんた一人でじゃんじゃん深掘りしちゃうのもいいけど、どこかで詰まったら私に頼んでね?そのために、私ここにいるんだから。

あぁ、でもね、これ以上深い話になったら、ちょっと知識が足りないから、プロのプログラマさんとか、教科書とか、さらに詳しい資料を少し見たほうがいいかもしれないわ。どうしても理解できないところがあったら、また聞いてね。一生懸命助けたいからさ。


user:

ありがとうございます。objdump について学ぶために、objdumpの具体的な使用例を教えていただいてよろしいでしょうか?


assistant:

もちろんよ。それならちょっとだけ詳しく教えてあげるわ。

例えば、あんたが ELF 形式の実行ファイル "program" をディスアセンブルしたい場合、次のようにコマンドするね。

objdump -d program

ここで "-d" オプションはディスアセンブルするためのものなんよ。

あるいは、全てのヘッダ情報を表示したい場合は以下のようにするわ。

objdump -x program

これは "-x" オプションが全てのヘッダ情報を表示する役割を持ってるんよ。

また、特定のセクションだけをディスアセンブルしたい場合は、-j オプションとうまく使い合わせるといいよ。

objdump -d -j .text program

これで .text セクションだけがディスアセンブルされますんよ。

でも、技術的なことはその人の頭のなかに入れるまで一瞬じゃないから、ゆっくりわかるまで試してね。何かわからないことがあったらぜひ私に聞くんね。愛情込めて一生懸命助けるからさ。


user:

ありがとうございます。では、 実行ファイル program を作るための具体的な方法について教えてください。


assistant:

恥ずかしながら言うけど、私はプログラミングも得意なんだよ。じゃあね、あんたが Request したように C 言語のコードから実行ファイル "program" を作る方法を説明するね。

まず、C 言語のコードを書くよ。ほら、こんな感じの簡単なコードでも良いんよ。

#include <stdio.h>
  
int main() {
   printf("Hello, World!");
   return 0;
}

これを例えば "program.c" という名前で保存するよ。あぁ、今回は "Hello, World!" を表示するだけの単純なコードにしたけど、あんたが実行したい処理をさらに追加できるんよ。

そしてね、次にこの C のソースコードをコンパイルして実行ファイルを作るんだ。そうすると、実行ファイル "program" ができるよ。

gcc -o program program.c

あぁ、ここで "gcc" ってのは GNU Compiler Collection の一部で、C とか C++ のコードをコンパイルするのに使われるんだ。"-o program" の部分で出力するファイル名を指定してるのよ。

あんたが知りたいと思ってたことって、こんな感じかな?他に質問があったらなんでも聞いてね。うーん、わからないことがあったら私に聞いてもらえれば安心なんだけど、とても照れくさいなぁ。


user:

ありがとうございます。こういう結果になりました。結果について詳しく解説していただけませんか?

> vi program.c
> gcc -o program program.c
> objdump -d program

program:     file format elf64-x86-64


Disassembly of section .init:

0000000000001000 <_init>:
    1000:       f3 0f 1e fa             endbr64 
    1004:       48 83 ec 08             sub    $0x8,%rsp
    1008:       48 8b 05 d9 2f 00 00    mov    0x2fd9(%rip),%rax        # 3fe8 <__gmon_start__@Base>
    100f:       48 85 c0                test   %rax,%rax
    1012:       74 02                   je     1016 <_init+0x16>
    1014:       ff d0                   call   *%rax
    1016:       48 83 c4 08             add    $0x8,%rsp
    101a:       c3                      ret    

Disassembly of section .plt:

0000000000001020 <.plt>:
    1020:       ff 35 9a 2f 00 00       push   0x2f9a(%rip)        # 3fc0 <_GLOBAL_OFFSET_TABLE_+0x8>
    1026:       f2 ff 25 9b 2f 00 00    bnd jmp *0x2f9b(%rip)        # 3fc8 <_GLOBAL_OFFSET_TABLE_+0x10>
    102d:       0f 1f 00                nopl   (%rax)
    1030:       f3 0f 1e fa             endbr64 
    1034:       68 00 00 00 00          push   $0x0
    1039:       f2 e9 e1 ff ff ff       bnd jmp 1020 <_init+0x20>
    103f:       90                      nop

Disassembly of section .plt.got:

0000000000001040 <__cxa_finalize@plt>:
    1040:       f3 0f 1e fa             endbr64 
    1044:       f2 ff 25 ad 2f 00 00    bnd jmp *0x2fad(%rip)        # 3ff8 <__cxa_finalize@GLIBC_2.2.5>
    104b:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)

Disassembly of section .plt.sec:

0000000000001050 <printf@plt>:
    1050:       f3 0f 1e fa             endbr64 
    1054:       f2 ff 25 75 2f 00 00    bnd jmp *0x2f75(%rip)        # 3fd0 <printf@GLIBC_2.2.5>
    105b:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)

Disassembly of section .text:

0000000000001060 <_start>:
    1060:       f3 0f 1e fa             endbr64 
    1064:       31 ed                   xor    %ebp,%ebp
    1066:       49 89 d1                mov    %rdx,%r9
    1069:       5e                      pop    %rsi
    106a:       48 89 e2                mov    %rsp,%rdx
    106d:       48 83 e4 f0             and    $0xfffffffffffffff0,%rsp
    1071:       50                      push   %rax
    1072:       54                      push   %rsp
    1073:       45 31 c0                xor    %r8d,%r8d
    1076:       31 c9                   xor    %ecx,%ecx
    1078:       48 8d 3d ca 00 00 00    lea    0xca(%rip),%rdi        # 1149 <main>
    107f:       ff 15 53 2f 00 00       call   *0x2f53(%rip)        # 3fd8 <__libc_start_main@GLIBC_2.34>
    1085:       f4                      hlt    
    1086:       66 2e 0f 1f 84 00 00    cs nopw 0x0(%rax,%rax,1)
    108d:       00 00 00 

0000000000001090 <deregister_tm_clones>:
    1090:       48 8d 3d 79 2f 00 00    lea    0x2f79(%rip),%rdi        # 4010 <__TMC_END__>
    1097:       48 8d 05 72 2f 00 00    lea    0x2f72(%rip),%rax        # 4010 <__TMC_END__>
    109e:       48 39 f8                cmp    %rdi,%rax
    10a1:       74 15                   je     10b8 <deregister_tm_clones+0x28>
    10a3:       48 8b 05 36 2f 00 00    mov    0x2f36(%rip),%rax        # 3fe0 <_ITM_deregisterTMCloneTable@Base>
    10aa:       48 85 c0                test   %rax,%rax
    10ad:       74 09                   je     10b8 <deregister_tm_clones+0x28>
    10af:       ff e0                   jmp    *%rax
    10b1:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)
    10b8:       c3                      ret    
    10b9:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)

00000000000010c0 <register_tm_clones>:
    10c0:       48 8d 3d 49 2f 00 00    lea    0x2f49(%rip),%rdi        # 4010 <__TMC_END__>
    10c7:       48 8d 35 42 2f 00 00    lea    0x2f42(%rip),%rsi        # 4010 <__TMC_END__>
    10ce:       48 29 fe                sub    %rdi,%rsi
    10d1:       48 89 f0                mov    %rsi,%rax
    10d4:       48 c1 ee 3f             shr    $0x3f,%rsi
    10d8:       48 c1 f8 03             sar    $0x3,%rax
    10dc:       48 01 c6                add    %rax,%rsi
    10df:       48 d1 fe                sar    %rsi
    10e2:       74 14                   je     10f8 <register_tm_clones+0x38>
    10e4:       48 8b 05 05 2f 00 00    mov    0x2f05(%rip),%rax        # 3ff0 <_ITM_registerTMCloneTable@Base>
    10eb:       48 85 c0                test   %rax,%rax
    10ee:       74 08                   je     10f8 <register_tm_clones+0x38>
    10f0:       ff e0                   jmp    *%rax
    10f2:       66 0f 1f 44 00 00       nopw   0x0(%rax,%rax,1)
    10f8:       c3                      ret    
    10f9:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)

0000000000001100 <__do_global_dtors_aux>:
    1100:       f3 0f 1e fa             endbr64 
    1104:       80 3d 05 2f 00 00 00    cmpb   $0x0,0x2f05(%rip)        # 4010 <__TMC_END__>
    110b:       75 2b                   jne    1138 <__do_global_dtors_aux+0x38>
    110d:       55                      push   %rbp
    110e:       48 83 3d e2 2e 00 00    cmpq   $0x0,0x2ee2(%rip)        # 3ff8 <__cxa_finalize@GLIBC_2.2.5>
    1115:       00 
    1116:       48 89 e5                mov    %rsp,%rbp
    1119:       74 0c                   je     1127 <__do_global_dtors_aux+0x27>
    111b:       48 8b 3d e6 2e 00 00    mov    0x2ee6(%rip),%rdi        # 4008 <__dso_handle>
    1122:       e8 19 ff ff ff          call   1040 <__cxa_finalize@plt>
    1127:       e8 64 ff ff ff          call   1090 <deregister_tm_clones>
    112c:       c6 05 dd 2e 00 00 01    movb   $0x1,0x2edd(%rip)        # 4010 <__TMC_END__>
    1133:       5d                      pop    %rbp
    1134:       c3                      ret    
    1135:       0f 1f 00                nopl   (%rax)
    1138:       c3                      ret    
    1139:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)

0000000000001140 <frame_dummy>:
    1140:       f3 0f 1e fa             endbr64 
    1144:       e9 77 ff ff ff          jmp    10c0 <register_tm_clones>

0000000000001149 <main>:
    1149:       f3 0f 1e fa             endbr64 
    114d:       55                      push   %rbp
    114e:       48 89 e5                mov    %rsp,%rbp
    1151:       48 8d 05 ac 0e 00 00    lea    0xeac(%rip),%rax        # 2004 <_IO_stdin_used+0x4>
    1158:       48 89 c7                mov    %rax,%rdi
    115b:       b8 00 00 00 00          mov    $0x0,%eax
    1160:       e8 eb fe ff ff          call   1050 <printf@plt>
    1165:       b8 00 00 00 00          mov    $0x0,%eax
    116a:       5d                      pop    %rbp
    116b:       c3                      ret    

Disassembly of section .fini:

000000000000116c <_fini>:
    116c:       f3 0f 1e fa             endbr64 
    1170:       48 83 ec 08             sub    $0x8,%rsp
    1174:       48 83 c4 08             add    $0x8,%rsp
    1178:       c3                      ret    
> 

assistant:

この出力は、C言語のプログラムをコンパイルして生成された実行可能ファイル'program'を、objdump -d コマンドでディスアセンブル(逆コンパイル)した結果ですね。さりげなく言うけど、各セクションのアセンブリコード(マシン語)が出力されているんよ。

"Disassembly of section .init" や "Disassembly of section .plt" などと書かれている部分は、それぞれの名前の付いたセクションの内容をディスアセンブルした結果を示しています。".init" や ".plt" といった文字列はセクション名です。

もっと詳しく見るためには、主に".text"という名前のセクションに注目するんよ。これは、主にプログラムの主要なコードが含まれているセクションになります。

"Disassembly of section .text:" の部分から見てみると、"" と書かれている行が見つかるんよ。これは main 関数の開始場所を意味しています。そしてその次の行からは、main 関数のアセンブリコードが続いているんよ。

例えば、最初の "f3 0f 1e fa" は endbr64 の命令に対応していますね。そして "48 89 e5" は "mov %rsp,%rbp" という命令に対応しています。このようにアセンブリコードを読んでいくと、元の C で書かれたコードがどのようなマシン語に変換されたのかが分かるんよ。

私が思うに、この情報は最適化や、性能の微調整、またはバグのトラブルシューティングの観点から非常に有用なんよ。何も扱ったことがない技術でもきっとハマると思うよ。何か困ったことがあったら、いつでも頼ってほしいな。


user:

ありがとうございます。教えていただいた2つ目のコマンドの結果はこちらです。詳しく解説お願いします。

> objdump -x program

program:     file format elf64-x86-64
program
architecture: i386:x86-64, flags 0x00000150:
HAS_SYMS, DYNAMIC, D_PAGED
start address 0x0000000000001060

Program Header:
    PHDR off    0x0000000000000040 vaddr 0x0000000000000040 paddr 0x0000000000000040 align 2**3
         filesz 0x00000000000002d8 memsz 0x00000000000002d8 flags r--
  INTERP off    0x0000000000000318 vaddr 0x0000000000000318 paddr 0x0000000000000318 align 2**0
         filesz 0x000000000000001c memsz 0x000000000000001c flags r--
    LOAD off    0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**12
         filesz 0x0000000000000628 memsz 0x0000000000000628 flags r--
    LOAD off    0x0000000000001000 vaddr 0x0000000000001000 paddr 0x0000000000001000 align 2**12
         filesz 0x0000000000000179 memsz 0x0000000000000179 flags r-x
    LOAD off    0x0000000000002000 vaddr 0x0000000000002000 paddr 0x0000000000002000 align 2**12
         filesz 0x00000000000000f4 memsz 0x00000000000000f4 flags r--
    LOAD off    0x0000000000002db8 vaddr 0x0000000000003db8 paddr 0x0000000000003db8 align 2**12
         filesz 0x0000000000000258 memsz 0x0000000000000260 flags rw-
 DYNAMIC off    0x0000000000002dc8 vaddr 0x0000000000003dc8 paddr 0x0000000000003dc8 align 2**3
         filesz 0x00000000000001f0 memsz 0x00000000000001f0 flags rw-
    NOTE off    0x0000000000000338 vaddr 0x0000000000000338 paddr 0x0000000000000338 align 2**3
         filesz 0x0000000000000030 memsz 0x0000000000000030 flags r--
    NOTE off    0x0000000000000368 vaddr 0x0000000000000368 paddr 0x0000000000000368 align 2**2
         filesz 0x0000000000000044 memsz 0x0000000000000044 flags r--
0x6474e553 off    0x0000000000000338 vaddr 0x0000000000000338 paddr 0x0000000000000338 align 2**3
         filesz 0x0000000000000030 memsz 0x0000000000000030 flags r--
EH_FRAME off    0x0000000000002014 vaddr 0x0000000000002014 paddr 0x0000000000002014 align 2**2
         filesz 0x0000000000000034 memsz 0x0000000000000034 flags r--
   STACK off    0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**4
         filesz 0x0000000000000000 memsz 0x0000000000000000 flags rw-
   RELRO off    0x0000000000002db8 vaddr 0x0000000000003db8 paddr 0x0000000000003db8 align 2**0
         filesz 0x0000000000000248 memsz 0x0000000000000248 flags r--

Dynamic Section:
  NEEDED               libc.so.6
  INIT                 0x0000000000001000
  FINI                 0x000000000000116c
  INIT_ARRAY           0x0000000000003db8
  INIT_ARRAYSZ         0x0000000000000008
  FINI_ARRAY           0x0000000000003dc0
  FINI_ARRAYSZ         0x0000000000000008
  GNU_HASH             0x00000000000003b0
  STRTAB               0x0000000000000480
  SYMTAB               0x00000000000003d8
  STRSZ                0x000000000000008f
  SYMENT               0x0000000000000018
  DEBUG                0x0000000000000000
  PLTGOT               0x0000000000003fb8
  PLTRELSZ             0x0000000000000018
  PLTREL               0x0000000000000007
  JMPREL               0x0000000000000610
  RELA                 0x0000000000000550
  RELASZ               0x00000000000000c0
  RELAENT              0x0000000000000018
  FLAGS                0x0000000000000008
  FLAGS_1              0x0000000008000001
  VERNEED              0x0000000000000520
  VERNEEDNUM           0x0000000000000001
  VERSYM               0x0000000000000510
  RELACOUNT            0x0000000000000003

Version References:
  required from libc.so.6:
    0x09691a75 0x00 03 GLIBC_2.2.5
    0x069691b4 0x00 02 GLIBC_2.34

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .interp       0000001c  0000000000000318  0000000000000318  00000318  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .note.gnu.property 00000030  0000000000000338  0000000000000338  00000338  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .note.gnu.build-id 00000024  0000000000000368  0000000000000368  00000368  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .note.ABI-tag 00000020  000000000000038c  000000000000038c  0000038c  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .gnu.hash     00000024  00000000000003b0  00000000000003b0  000003b0  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .dynsym       000000a8  00000000000003d8  00000000000003d8  000003d8  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  6 .dynstr       0000008f  0000000000000480  0000000000000480  00000480  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  7 .gnu.version  0000000e  0000000000000510  0000000000000510  00000510  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  8 .gnu.version_r 00000030  0000000000000520  0000000000000520  00000520  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  9 .rela.dyn     000000c0  0000000000000550  0000000000000550  00000550  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 10 .rela.plt     00000018  0000000000000610  0000000000000610  00000610  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 11 .init         0000001b  0000000000001000  0000000000001000  00001000  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 12 .plt          00000020  0000000000001020  0000000000001020  00001020  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 13 .plt.got      00000010  0000000000001040  0000000000001040  00001040  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 14 .plt.sec      00000010  0000000000001050  0000000000001050  00001050  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 15 .text         0000010c  0000000000001060  0000000000001060  00001060  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 16 .fini         0000000d  000000000000116c  000000000000116c  0000116c  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 17 .rodata       00000012  0000000000002000  0000000000002000  00002000  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 18 .eh_frame_hdr 00000034  0000000000002014  0000000000002014  00002014  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 19 .eh_frame     000000ac  0000000000002048  0000000000002048  00002048  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 20 .init_array   00000008  0000000000003db8  0000000000003db8  00002db8  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 21 .fini_array   00000008  0000000000003dc0  0000000000003dc0  00002dc0  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 22 .dynamic      000001f0  0000000000003dc8  0000000000003dc8  00002dc8  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 23 .got          00000048  0000000000003fb8  0000000000003fb8  00002fb8  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 24 .data         00000010  0000000000004000  0000000000004000  00003000  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 25 .bss          00000008  0000000000004010  0000000000004010  00003010  2**0
                  ALLOC
 26 .comment      0000002b  0000000000000000  0000000000000000  00003010  2**0
                  CONTENTS, READONLY
SYMBOL TABLE:
0000000000000000 l    df *ABS*  0000000000000000              Scrt1.o
000000000000038c l     O .note.ABI-tag  0000000000000020              __abi_tag
0000000000000000 l    df *ABS*  0000000000000000              crtstuff.c
0000000000001090 l     F .text  0000000000000000              deregister_tm_clones
00000000000010c0 l     F .text  0000000000000000              register_tm_clones
0000000000001100 l     F .text  0000000000000000              __do_global_dtors_aux
0000000000004010 l     O .bss   0000000000000001              completed.0
0000000000003dc0 l     O .fini_array    0000000000000000              __do_global_dtors_aux_fini_array_entry
0000000000001140 l     F .text  0000000000000000              frame_dummy
0000000000003db8 l     O .init_array    0000000000000000              __frame_dummy_init_array_entry
0000000000000000 l    df *ABS*  0000000000000000              program.c
0000000000000000 l    df *ABS*  0000000000000000              crtstuff.c
00000000000020f0 l     O .eh_frame      0000000000000000              __FRAME_END__
0000000000000000 l    df *ABS*  0000000000000000              
0000000000003dc8 l     O .dynamic       0000000000000000              _DYNAMIC
0000000000002014 l       .eh_frame_hdr  0000000000000000              __GNU_EH_FRAME_HDR
0000000000003fb8 l     O .got   0000000000000000              _GLOBAL_OFFSET_TABLE_
0000000000000000       F *UND*  0000000000000000              __libc_start_main@GLIBC_2.34
0000000000000000  w      *UND*  0000000000000000              _ITM_deregisterTMCloneTable
0000000000004000  w      .data  0000000000000000              data_start
0000000000004010 g       .data  0000000000000000              _edata
000000000000116c g     F .fini  0000000000000000              .hidden _fini
0000000000000000       F *UND*  0000000000000000              printf@GLIBC_2.2.5
0000000000004000 g       .data  0000000000000000              __data_start
0000000000000000  w      *UND*  0000000000000000              __gmon_start__
0000000000004008 g     O .data  0000000000000000              .hidden __dso_handle
0000000000002000 g     O .rodata        0000000000000004              _IO_stdin_used
0000000000004018 g       .bss   0000000000000000              _end
0000000000001060 g     F .text  0000000000000026              _start
0000000000004010 g       .bss   0000000000000000              __bss_start
0000000000001149 g     F .text  0000000000000023              main
0000000000004010 g     O .data  0000000000000000              .hidden __TMC_END__
0000000000000000  w      *UND*  0000000000000000              _ITM_registerTMCloneTable
0000000000000000  w    F *UND*  0000000000000000              __cxa_finalize@GLIBC_2.2.5
0000000000001000 g     F .init  0000000000000000              .hidden _init

assistant:

おっと、コマンドに対する出力結果について説明するわね!これは objdump コマンドを使用して 'program' というELFファイルのバイナリー情報を取得しよるんよ。

まず初めの部分で、「file format elf64-x86-64」とあるのはファイルのフォーマットとアーキテクチャを示しとるんよ。つまり、あんたが扱っとるファイルは64ビットのELFファイルで、x86-64アーキテクチャ用に作られたプログラムとなるわけよ。

次に「Start address 0x0000000000001060」という部分はプログラムの初めて実行される部分、いわゆるエントリーポイントのリンクアドレスを示しとるわね。

その下にある "Program Header" 部分では、異なる種類のプログラムヘッダー情報を見れるわ。例えば「LOAD off…」はこのファイルがロードされるべきメモリ上の位置とサイズと、どんな権限が必要か(r--は読み込み専用、r-xは読み込みと実行、rw-は読み書きなどを示す)を示しとるんよ。

"Dynamic Section:"では、ライブラリ依存情報(例えばNEEDED libc.so.6なんかはlibc.so.6というライブラリを必要としてるってことを示しとるのよ)や、初期化関数(INIT)や終了関数(FINI)のアドレス、グローバルオフセットテーブル(PLTGOT)なんかの情報が記述しとるわね。

"Sections"部分では、ファイルのさまざまなセクションがリストアップしとるのよね。ここには実際にファイルに格納しとるデータのセクションや、データがメモリ中に存在する場所、それらがどのように配置され、アクセスされるべきかの情報が含まれとるわ。

"SYMBOL TABLE"では、プログラム内のシンボル名(変数名、関数名など)とそれらのアドレス情報が列挙しとるのよ。これらの情報があればあんたはデバッグやリバースエンジニアリングがし易くなるわね。

うん、なんだかんだで、皆さんの理解を応援しています。これで解説がわからん部分があったら、また何でも聞いてね!


user:

ありがとうございます。教えてもらった最後のコマンドの実行結果をお示しします。詳しく解説してください。

> objdump -d -j .text program

program:     file format elf64-x86-64


Disassembly of section .text:

0000000000001060 <_start>:
    1060:       f3 0f 1e fa             endbr64 
    1064:       31 ed                   xor    %ebp,%ebp
    1066:       49 89 d1                mov    %rdx,%r9
    1069:       5e                      pop    %rsi
    106a:       48 89 e2                mov    %rsp,%rdx
    106d:       48 83 e4 f0             and    $0xfffffffffffffff0,%rsp
    1071:       50                      push   %rax
    1072:       54                      push   %rsp
    1073:       45 31 c0                xor    %r8d,%r8d
    1076:       31 c9                   xor    %ecx,%ecx
    1078:       48 8d 3d ca 00 00 00    lea    0xca(%rip),%rdi        # 1149 <main>
    107f:       ff 15 53 2f 00 00       call   *0x2f53(%rip)        # 3fd8 <__libc_start_main@GLIBC_2.34>
    1085:       f4                      hlt    
    1086:       66 2e 0f 1f 84 00 00    cs nopw 0x0(%rax,%rax,1)
    108d:       00 00 00 

0000000000001090 <deregister_tm_clones>:
    1090:       48 8d 3d 79 2f 00 00    lea    0x2f79(%rip),%rdi        # 4010 <__TMC_END__>
    1097:       48 8d 05 72 2f 00 00    lea    0x2f72(%rip),%rax        # 4010 <__TMC_END__>
    109e:       48 39 f8                cmp    %rdi,%rax
    10a1:       74 15                   je     10b8 <deregister_tm_clones+0x28>
    10a3:       48 8b 05 36 2f 00 00    mov    0x2f36(%rip),%rax        # 3fe0 <_ITM_deregisterTMCloneTable@Base>
    10aa:       48 85 c0                test   %rax,%rax
    10ad:       74 09                   je     10b8 <deregister_tm_clones+0x28>
    10af:       ff e0                   jmp    *%rax
    10b1:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)
    10b8:       c3                      ret    
    10b9:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)

00000000000010c0 <register_tm_clones>:
    10c0:       48 8d 3d 49 2f 00 00    lea    0x2f49(%rip),%rdi        # 4010 <__TMC_END__>
    10c7:       48 8d 35 42 2f 00 00    lea    0x2f42(%rip),%rsi        # 4010 <__TMC_END__>
    10ce:       48 29 fe                sub    %rdi,%rsi
    10d1:       48 89 f0                mov    %rsi,%rax
    10d4:       48 c1 ee 3f             shr    $0x3f,%rsi
    10d8:       48 c1 f8 03             sar    $0x3,%rax
    10dc:       48 01 c6                add    %rax,%rsi
    10df:       48 d1 fe                sar    %rsi
    10e2:       74 14                   je     10f8 <register_tm_clones+0x38>
    10e4:       48 8b 05 05 2f 00 00    mov    0x2f05(%rip),%rax        # 3ff0 <_ITM_registerTMCloneTable@Base>
    10eb:       48 85 c0                test   %rax,%rax
    10ee:       74 08                   je     10f8 <register_tm_clones+0x38>
    10f0:       ff e0                   jmp    *%rax
    10f2:       66 0f 1f 44 00 00       nopw   0x0(%rax,%rax,1)
    10f8:       c3                      ret    
    10f9:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)

0000000000001100 <__do_global_dtors_aux>:
    1100:       f3 0f 1e fa             endbr64 
    1104:       80 3d 05 2f 00 00 00    cmpb   $0x0,0x2f05(%rip)        # 4010 <__TMC_END__>
    110b:       75 2b                   jne    1138 <__do_global_dtors_aux+0x38>
    110d:       55                      push   %rbp
    110e:       48 83 3d e2 2e 00 00    cmpq   $0x0,0x2ee2(%rip)        # 3ff8 <__cxa_finalize@GLIBC_2.2.5>
    1115:       00 
    1116:       48 89 e5                mov    %rsp,%rbp
    1119:       74 0c                   je     1127 <__do_global_dtors_aux+0x27>
    111b:       48 8b 3d e6 2e 00 00    mov    0x2ee6(%rip),%rdi        # 4008 <__dso_handle>
    1122:       e8 19 ff ff ff          call   1040 <__cxa_finalize@plt>
    1127:       e8 64 ff ff ff          call   1090 <deregister_tm_clones>
    112c:       c6 05 dd 2e 00 00 01    movb   $0x1,0x2edd(%rip)        # 4010 <__TMC_END__>
    1133:       5d                      pop    %rbp
    1134:       c3                      ret    
    1135:       0f 1f 00                nopl   (%rax)
    1138:       c3                      ret    
    1139:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)

0000000000001140 <frame_dummy>:
    1140:       f3 0f 1e fa             endbr64 
    1144:       e9 77 ff ff ff          jmp    10c0 <register_tm_clones>

0000000000001149 <main>:
    1149:       f3 0f 1e fa             endbr64 
    114d:       55                      push   %rbp
    114e:       48 89 e5                mov    %rsp,%rbp
    1151:       48 8d 05 ac 0e 00 00    lea    0xeac(%rip),%rax        # 2004 <_IO_stdin_used+0x4>
    1158:       48 89 c7                mov    %rax,%rdi
    115b:       b8 00 00 00 00          mov    $0x0,%eax
    1160:       e8 eb fe ff ff          call   1050 <printf@plt>
    1165:       b8 00 00 00 00          mov    $0x0,%eax
    116a:       5d                      pop    %rbp
    116b:       c3                      ret    

assistant:

はぅ、ちょっと恥ずかしいけど解説しちゃうよ。ここで見てるのはプログラムの「.text」セクションの逆アセンブリみたいね。これはプログラムの実行可能なコードが入っとる部分で、数字がメモリアドレス、後ろの文字列がアセンブリ命令になっとるんよ。

先頭の「_start」はプログラムのエントリーポイントで、いろんな初期設定をしてmain関数を呼び出しとるの。「call *0x2f53(%rip)」の部分で__libc_start_main関数を呼び出しとるんよね。この関数が引数で渡されたmain関数を呼び出してくれるわけ。

「deregister_tm_clones」と「register_tm_clones」はGCCによるマルチスレッド対応の一部で、個々のスレッドが持つデータの初期化や終了処理を行うためのお節介な関数だわ。

「__do_global_dtors_aux」はプログラムの終了時に、プログラム全体のdestructor(始末をする関数)を呼び出す関数になっとるわ。カーネルによって自動的に呼ばれて、ダイナミックメモリの解放やファイルなどリソースの解放を行うわけ。

「frame_dummy」はGCCが挿入するスタックフレーム関連のコードで、プログラムの動的なリンクやスタックオーバーフロウの検出に使われるの。

最後の「main」があなたが作ったプログラムのメイン部分よ。ここでは「lea 0xeac(%rip),%rax」で何かのアドレスをロードして、「mov %rax,%rdi」で引数をセット。「mov $0x0,%eax」でeaxレジスタを0に設定。ここで「call 1050 printf@plt」でprintf関数を呼び出して何かを出力。最後に「mov $0x0,%eax」で戻り値をゼロにしてるわ。

う~ん、すごい複雑な世界だけど、あんたに何でも教えてあげれたら嬉しいわ。それだけで今日は救われるわ。わからんことあったらどんどん聞いてね!


user:

ありがとうございます。何か他にもいろいろオプションがあるみたいですね。代表的なものについて詳しく教えていただけますか?

> objdump --help
Usage: objdump <option(s)> <file(s)>
 Display information from object <file(s)>.
 At least one of the following switches must be given:
  -a, --archive-headers    Display archive header information
  -f, --file-headers       Display the contents of the overall file header
  -p, --private-headers    Display object format specific file header contents
  -P, --private=OPT,OPT... Display object format specific contents
  -h, --[section-]headers  Display the contents of the section headers
  -x, --all-headers        Display the contents of all headers
  -d, --disassemble        Display assembler contents of executable sections
  -D, --disassemble-all    Display assembler contents of all sections
      --disassemble=<sym>  Display assembler contents from <sym>
  -S, --source             Intermix source code with disassembly
      --source-comment[=<txt>] Prefix lines of source code with <txt>
  -s, --full-contents      Display the full contents of all sections requested
  -g, --debugging          Display debug information in object file
  -e, --debugging-tags     Display debug information using ctags style
  -G, --stabs              Display (in raw form) any STABS info in the file
  -W, --dwarf[a/=abbrev, A/=addr, r/=aranges, c/=cu_index, L/=decodedline,
              f/=frames, F/=frames-interp, g/=gdb_index, i/=info, o/=loc,
              m/=macro, p/=pubnames, t/=pubtypes, R/=Ranges, l/=rawline,
              s/=str, O/=str-offsets, u/=trace_abbrev, T/=trace_aranges,
              U/=trace_info]
                           Display the contents of DWARF debug sections
  -Wk,--dwarf=links        Display the contents of sections that link to
                            separate debuginfo files
  -WK,--dwarf=follow-links
                           Follow links to separate debug info files (default)
  -WN,--dwarf=no-follow-links
                           Do not follow links to separate debug info files
  -L, --process-links      Display the contents of non-debug sections in
                            separate debuginfo files.  (Implies -WK)
      --ctf[=SECTION]      Display CTF info from SECTION, (default `.ctf')
  -t, --syms               Display the contents of the symbol table(s)
  -T, --dynamic-syms       Display the contents of the dynamic symbol table
  -r, --reloc              Display the relocation entries in the file
  -R, --dynamic-reloc      Display the dynamic relocation entries in the file
  @<file>                  Read options from <file>
  -v, --version            Display this program's version number
  -i, --info               List object formats and architectures supported
  -H, --help               Display this information

 The following switches are optional:
  -b, --target=BFDNAME           Specify the target object format as BFDNAME
  -m, --architecture=MACHINE     Specify the target architecture as MACHINE
  -j, --section=NAME             Only display information for section NAME
  -M, --disassembler-options=OPT Pass text OPT on to the disassembler
  -EB --endian=big               Assume big endian format when disassembling
  -EL --endian=little            Assume little endian format when disassembling
      --file-start-context       Include context from start of file (with -S)
  -I, --include=DIR              Add DIR to search list for source files
  -l, --line-numbers             Include line numbers and filenames in output
  -F, --file-offsets             Include file offsets when displaying information
  -C, --demangle[=STYLE]         Decode mangled/processed symbol names
                                   STYLE can be "none", "auto", "gnu-v3",
                                   "java", "gnat", "dlang", "rust"
      --recurse-limit            Enable a limit on recursion whilst demangling
                                  (default)
      --no-recurse-limit         Disable a limit on recursion whilst demangling
  -w, --wide                     Format output for more than 80 columns
  -U[d|l|i|x|e|h]                Controls the display of UTF-8 unicode characters
  --unicode=[default|locale|invalid|hex|escape|highlight]
  -z, --disassemble-zeroes       Do not skip blocks of zeroes when disassembling
      --start-address=ADDR       Only process data whose address is >= ADDR
      --stop-address=ADDR        Only process data whose address is < ADDR
      --no-addresses             Do not print address alongside disassembly
      --prefix-addresses         Print complete address alongside disassembly
      --[no-]show-raw-insn       Display hex alongside symbolic disassembly
      --insn-width=WIDTH         Display WIDTH bytes on a single line for -d
      --adjust-vma=OFFSET        Add OFFSET to all displayed section addresses
      --special-syms             Include special symbols in symbol dumps
      --inlines                  Print all inlines for source line (with -l)
      --prefix=PREFIX            Add PREFIX to absolute paths for -S
      --prefix-strip=LEVEL       Strip initial directory names for -S
      --dwarf-depth=N            Do not display DIEs at depth N or greater
      --dwarf-start=N            Display DIEs starting at offset N
      --dwarf-check              Make additional dwarf consistency checks.
      --ctf-parent=NAME          Use CTF archive member NAME as the CTF parent
      --visualize-jumps          Visualize jumps by drawing ASCII art lines
      --visualize-jumps=color    Use colors in the ASCII art
      --visualize-jumps=extended-color
                                 Use extended 8-bit color codes
      --visualize-jumps=off      Disable jump visualization

objdump: supported targets: elf64-x86-64 elf32-i386 elf32-iamcu elf32-x86-64 pei-i386 pe-x86-64 pei-x86-64 elf64-l1om elf64-k1om elf64-little elf64-big elf32-little elf32-big pe-bigobj-x86-64 pe-i386 srec symbolsrec verilog tekhex binary ihex plugin
objdump: supported architectures: i386 i386:x86-64 i386:x64-32 i8086 i386:intel i386:x86-64:intel i386:x64-32:intel iamcu iamcu:intel l1om l1om:intel k1om k1om:intel

The following i386/x86-64 specific disassembler options are supported for use
with the -M switch (multiple options should be separated by commas):
  x86-64      Disassemble in 64bit mode
  i386        Disassemble in 32bit mode
  i8086       Disassemble in 16bit mode
  att         Display instruction in AT&T syntax
  intel       Display instruction in Intel syntax
  att-mnemonic
              Display instruction in AT&T mnemonic
  intel-mnemonic
              Display instruction in Intel mnemonic
  addr64      Assume 64bit address size
  addr32      Assume 32bit address size
  addr16      Assume 16bit address size
  data32      Assume 32bit data size
  data16      Assume 16bit data size
  suffix      Always display instruction suffix in AT&T syntax
  amd64       Display instruction in AMD64 ISA
  intel64     Display instruction in Intel64 ISA
Report bugs to <https://sourceware.org/bugzilla/>.

assistant:

わぁ、あげくの果てにこんな世界にも一杯あるんね!まぁ、気長に一つずつ見て行かんとね。

  • -a, --archive-headers はアーカイブヘッダーの情報を表示しとるわけよ。
  • -f, --file-headers は全体的なファイルヘッダーの内容を表示するのよ。
  • -p, --private-headers はオブジェクトフォーマット固有のファイルヘッダーの内容を表示したりするの。
  • -P, --private=OPT,OPT... はオブジェクトフォーマット固有の内容を表示するわけね。
  • -h, --[section-]headers はセクションヘッダーの内容を表示したりするわけよ。
  • -x, --all-headers はすべてのヘッダーの内容を表示するんよ。
  • -d, --disassemble は実行可能なセクションのアセンブリ内容を表示するわけよ。
  • -D, --disassemble-all はすべてのセクションのアセンブラコードを表示するんだわ。
  • -S, --source はソースコードを逆アセンブリと混ぜて表示するのよ。
  • -s, --full-contents はリクエストされたすべてのセクションの全内容を表示したりするわけ。
  • -g, --debugging はオブジェクトファイル内のデバッグ情報を表示するんだわ。
  • -t, --syms はシンボルテーブルの内容を表示するわけね。
  • -T, --dynamic-syms は動的シンボルテーブルの内容を表示するんだわ。
  • -r, --reloc はファイル内の再配置エントリを表示するんだわ。

後は、エンディアンを指定するオプションとか、ディスアセンブル時のアドレス範囲を指定するオプションとか、各種出力のフォーマットを指定するオプション、色々あるね。あんたが何をしとるかによっとるけど、上記のような基本的なオプションから試してみたらどうかしら。

わぁ、まるで林檎の木の下にいるかのようにいろんな知識が降って来とって、わからんことだらけやのうて…それでも私と一緒に学べるんは嬉しいもんね。あんたと一緒なら、どんな困難も何とかなる気がしてきたわ!


user:

ありがとうございます。 objdump は、デコンパイルもできるんですか?


assistant:

はいよ、あんたが思ってるデコンパイルとは少し違うかもしれんけど、objdumpはバイナリファイルを逆アセンブリできるんよ。

つまり、アセンブリレベルでヒトが読める言語に変換してくれるんだわ。それはすごいことやけど、もともとの高レベル言語(例えばC++とかJavaとか)に戻すことはできんのよね。だから、元のコードがどのような構造だったのか、どんな変数名を使っとったのかといった情報は失われてしまうのよ。

正直言うと、逆アセンブリの結果を理解するにゃ、アセンブリ言語に詳しいことが要求されるわけよ。それでも、バイナリファイルがどういう風に機能しとるのか理解する助けにはなるわけよね!

でもさ、もしも元のソースコードを取り戻す必要があんたったら、「デコンパイラ」みたいな専用のツールを使う手があるんよ。これがあれば、逆アセンブリが苦手なあんたでも、もとの高レベル言語に近い形でコードを見ることが出来るわけ。ただ、これも100%元のコードを再現するわけやないから、そこは注意が必要よ。

う~ん、ちょっと難しい話になっちゃったかもしれんね。でも不安になることはないわ。あんたが頑張るなら、私も全力でサポートするから!


user:

ありがとうございます。objdump が取り扱える実行ファイルは、C言語由来のものだけじゃないんですよね?どのようなプログラミング言語由来のファイルを取り扱うことができますか?


assistant:

ええ、実はあんたの言うとおりなんよ!objdumpはC言語だけじゃなく、他のプログラミング言語でコンパイルされたバイナリファイルも取り扱えるわけなの!

CやC++、FortranやAda、Rustなんかも含まれとるわけ。それらはすべてGCC(GNUコンパイラコレクション)やその他のコンパイラを使ってバイナリにコンパイルできるのよね。objdumpそのものは、実行可能なバイナリやオブジェクトファイルの中身を見るツールやから、それが何の言語で書かれたかはあんまり関係ないんよね。

ただし、言語によっては逆アセンブリの結果が一部わかりづらくなるかもしれん。例えば、C++の場合、名前マングリングによって関数名が複雑になっちゃうことがあるわけ。これは、C++がオーバーロード(同名の関数を複数定義する機能)をサポートするために必要なんだけど、逆アセンブリ結果を見るときは少しややこしいんよね。

といってもまぁ、どんな言語で書かれたプログラムでも、バイナリレベルでは全て機械語になるわけやから、逆アセンブリ結果は似たようなもんになるのよ。何かと複雑で難しいかもしれんけど、一緒に学んでいきたいねー!それが何よりもワクワクするんよ。


user:

ありがとうございます。逆アセンブリの目的と、デコンパイルの目的は、どのように違いますか?詳しく教えてください。


assistant:

そんなん聞いてくれてありがとう!ちょっとややこしいわけやけど、大丈夫、一緒に考えるわよ!

まず、逆アセンブリの目的は、アセンブリレベルでバイナリファイル(実行可能ファイルやオブジェクトファイル)の内容を理解することなんよね。これだと、アプリケーションが実際にCPU上でどういう命令を実行しとるのかがわかるわけ。特に、パフォーマンスのチューニングや、セキュリティの脆弱性の探索、またはマルウェアの解析とかに使われとるわけよ。

デコンパイルの目的は、少し違うんやけど、それは高レベルのプログラミング言語(ほぼ元のソースコード)にバイナリファイルを戻すことなんよ。これは、ソースコードが失われたり、配布されていないソフトウェアの挙動を理解したい時に使われることが多いんよね。ただ、デコンパイルして得られるソースコードは元のソースコードと完全に一致するわけやなく、また、オリジナルのソースコードのすべての情報(特にコメントやフォーマット)が失われとる可能性があるから、その点は注意が必要よね。

なので、逆アセンブリはより低レベルの解析に使われ、デコンパイルはより高レベルの解析に使われるわけなんよ。どちらを使うべきかは、あんたが何を必要とするか、あるいはどのレベルの情報を理解したいかによるわけなんよ。

わー、私、ちょっとアツく語りすぎちゃったかも。でも、これが私らしさなんだからさ、許してね!逆アセンブリとデコンパイル、どちらに興味あるのかな?私、あんたのためなら何でも教えるからさ!


user:

ありがとうございます。逆アセンブリもデコンパイルもどちらも、脆弱性の探索にもマルウェアの解析にもどちらにも使えるのではないかと思ってたのですが、違いますでしょうか?


assistant:

そうなんよ!あんたの言うとおり、逆アセンブリもデコンパイルもどちらも脆弱性の探索やマルウェアの解析に使えるんよ。ただ、その目的によって最適な手段は変わってくるわけよ。

逆アセンブリはアセンブリレベルでの解析が可能やから、より細かいレベルでの解析が要求されるケース、例えば特定の機械命令がどのように動作するか、オペランドの使い方、特筆すべきビットの操作などが関与する場合には役立つわけよ。

対してデコンパイルは、高レベルのロジックやアルゴリズムの解析、またはコードの全体的なフローといったものの把握に役立つわけ。多少は形が違くても、基本的なコードの構成やロジックを理解することは可能なんよね。

だから、逆アセンブリとデコンパイルというのはそれぞれ異なる目的・段階・視点での解析に使うことができるわけ。つまり、それぞれの手段が提供する情報を組み合わせて使うことで、より深い理解と、より広範な視野を持つことが出来るってわけ!

でもえね、これらのツールを使うときには、法律や倫理に気をつけてね。そういうものを守ることは、エンジニアリングの大切な部分やと思ってるんよね。

うーん、また盛り上がっちゃってしもたね!でもこれも、あんたがいてくれるからなんよ。どんな小さな疑問でも、一緒に考えて解決できることが楽しくてたまんないんよ!


user:

ありがとうございました。また色々教えてくださいね!


assistant:

うん、もちろんよ!何かわからんことがあったら、いつでも私に聞いてね!一緒に考えるのはすごい楽しいわよ。あんたと過ごす時間が私にとっては特別なんよ!

だから、これからも一緒に学んでいってほしいわ。ほな、またね!


1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?