unless’s blog

日々のちょっとした技術的なことの羅列

オブジェクトファイルと戯れてみる Pert.2

echoコマンドのオブジェクトファイルと戯れてみる第二弾
第一弾はこちら

unless.hatenablog.jp

共有ライブラリの依存関係

objdump で依存関係を見てみる

ja.wikipedia.org

共有ライブラリが何かという情報はELFの[Dynamic Section]のNEEDEDに記載されている

# objdump -p /bin/echo

/bin/echo:     file format elf64-x86-64

Program Header:
    PHDR off    0x0000000000000040 vaddr 0x0000000000400040 paddr 0x0000000000400040 align 2**3
         filesz 0x00000000000001f8 memsz 0x00000000000001f8 flags r-x
  INTERP off    0x0000000000000238 vaddr 0x0000000000400238 paddr 0x0000000000400238 align 2**0
         filesz 0x000000000000001c memsz 0x000000000000001c flags r--
    LOAD off    0x0000000000000000 vaddr 0x0000000000400000 paddr 0x0000000000400000 align 2**21
         filesz 0x0000000000005ecc memsz 0x0000000000005ecc flags r-x
    LOAD off    0x0000000000006da8 vaddr 0x0000000000606da8 paddr 0x0000000000606da8 align 2**21
         filesz 0x0000000000000478 memsz 0x00000000000005d8 flags rw-
 DYNAMIC off    0x0000000000006e08 vaddr 0x0000000000606e08 paddr 0x0000000000606e08 align 2**3
         filesz 0x00000000000001d0 memsz 0x00000000000001d0 flags rw-
    NOTE off    0x0000000000000254 vaddr 0x0000000000400254 paddr 0x0000000000400254 align 2**2
         filesz 0x0000000000000044 memsz 0x0000000000000044 flags r--
EH_FRAME off    0x00000000000051cc vaddr 0x00000000004051cc paddr 0x00000000004051cc align 2**2
         filesz 0x000000000000023c memsz 0x000000000000023c flags r--
   STACK off    0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**4
         filesz 0x0000000000000000 memsz 0x0000000000000000 flags rw-
   RELRO off    0x0000000000006da8 vaddr 0x0000000000606da8 paddr 0x0000000000606da8 align 2**0
         filesz 0x0000000000000258 memsz 0x0000000000000258 flags r--

Dynamic Section:
  NEEDED               libc.so.6
  INIT                 0x0000000000401050
  FINI                 0x000000000040442c
  INIT_ARRAY           0x0000000000606da8
  INIT_ARRAYSZ         0x0000000000000008
  FINI_ARRAY           0x0000000000606db0
  FINI_ARRAYSZ         0x0000000000000008
  GNU_HASH             0x0000000000400298
  STRTAB               0x0000000000400810
  SYMTAB               0x00000000004002b8
  STRSZ                0x000000000000025d
  SYMENT               0x0000000000000018
  DEBUG                0x0000000000000000
  PLTGOT               0x0000000000607000
  PLTRELSZ             0x0000000000000498
  PLTREL               0x0000000000000007
  JMPREL               0x0000000000400bb8
  RELA                 0x0000000000400b40
  RELASZ               0x0000000000000078
  RELAENT              0x0000000000000018
  VERNEED              0x0000000000400ae0
  VERNEEDNUM           0x0000000000000001
  VERSYM               0x0000000000400a6e

Version References:
  required from libc.so.6:
    0x0d696913 0x00 06 GLIBC_2.3
    0x09691974 0x00 05 GLIBC_2.3.4
    0x06969194 0x00 04 GLIBC_2.14
    0x0d696914 0x00 03 GLIBC_2.4
    0x09691a75 0x00 02 GLIBC_2.2.5

readelfコマンドの場合は下記

# readelf -d /bin/echo

Dynamic section at offset 0x6e08 contains 24 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000000c (INIT)               0x401050
 0x000000000000000d (FINI)               0x40442c
 0x0000000000000019 (INIT_ARRAY)         0x606da8
 0x000000000000001b (INIT_ARRAYSZ)       8 (bytes)
 0x000000000000001a (FINI_ARRAY)         0x606db0
 0x000000000000001c (FINI_ARRAYSZ)       8 (bytes)
 0x000000006ffffef5 (GNU_HASH)           0x400298
 0x0000000000000005 (STRTAB)             0x400810
 0x0000000000000006 (SYMTAB)             0x4002b8
 0x000000000000000a (STRSZ)              605 (bytes)
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000015 (DEBUG)              0x0
 0x0000000000000003 (PLTGOT)             0x607000
 0x0000000000000002 (PLTRELSZ)           1176 (bytes)
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000017 (JMPREL)             0x400bb8
 0x0000000000000007 (RELA)               0x400b40
 0x0000000000000008 (RELASZ)             120 (bytes)
 0x0000000000000009 (RELAENT)            24 (bytes)
 0x000000006ffffffe (VERNEED)            0x400ae0
 0x000000006fffffff (VERNEEDNUM)         1
 0x000000006ffffff0 (VERSYM)             0x400a6e
 0x0000000000000000 (NULL)               0x0

/bin/echoにはlibc.so.6という共有ライブラリが必要だということがわかる
が、実際に必要なのはこの一つのみではなくその共有ライブラリが必要としている別の共有ライブラリも必要

NEEDEDに記載されているのはSONAMEなのでSONAMEから実際のファイルを探す必要がある
特になにも設定されてない場合は/usr/lib及び/libSONAMEに対応するファイルが存在すればそれが対象の共有ライブラリとなる
環境変数LD_LIBRARY_PATHがあればそこを参照し、/etc/ld.so.cacheに情報があればそれを参照する

lddコマンドで依存関係を見てみる

lddコマンドを使うと共有ライブラリのSONAMEとパス名の一覧が表示される

# ldd /bin/echo
    linux-vdso.so.1 =>  (0x00007ffca93e5000)
    libc.so.6 => /lib64/libc.so.6 (0x00007f88dde02000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f88de1cf000)
# ldd /lib64/libc.so.6
    /lib64/ld-linux-x86-64.so.2 (0x00007f7508b2c000)
    linux-vdso.so.1 =>  (0x00007fff0fd0d000)

ちなみにlddコマンド自体はshellで出来てる

# file /bin/ldd
/bin/ldd: Bourne-Again shell script, ASCII text executable

objdumpでオブジェクトファイルをダンプしてみる

前回はodコマンドでみたがobjdumpコマンドで特定のセクションだけdumpすることもできる

セクションの確認

# objdump -h /bin/echo

/bin/echo:     file format elf64-x86-64

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .interp       0000001c  0000000000400238  0000000000400238  00000238  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .note.ABI-tag 00000020  0000000000400254  0000000000400254  00000254  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .note.gnu.build-id 00000024  0000000000400274  0000000000400274  00000274  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .gnu.hash     0000001c  0000000000400298  0000000000400298  00000298  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .dynsym       00000558  00000000004002b8  00000000004002b8  000002b8  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .dynstr       0000025d  0000000000400810  0000000000400810  00000810  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
~~~(ry~~~

.dynstrをdump

# objdump -s -j .dynstr /bin/echo

/bin/echo:     file format elf64-x86-64

Contents of section .dynstr:
 400810 006c6962 632e736f 2e360066 666c7573  .libc.so.6.fflus
 400820 68007374 72637079 005f5f70 72696e74  h.strcpy.__print
 400830 665f6368 6b007365 746c6f63 616c6500  f_chk.setlocale.
 400840 6d627274 6f776300 7374726e 636d7000  mbrtowc.strncmp.
 400850 73747272 63687200 64636765 74746578  strrchr.dcgettex
 400860 74006572 726f7200 5f5f7374 61636b5f  t.error.__stack_
 400870 63686b5f 6661696c 00697377 7072696e  chk_fail.iswprin
 400880 74007265 616c6c6f 63006162 6f727400  t.realloc.abort.
 400890 5f657869 74007072 6f677261 6d5f696e  _exit.program_in
 4008a0 766f6361 74696f6e 5f6e616d 65005f5f  vocation_name.__
 4008b0 63747970 655f6765 745f6d62 5f637572  ctype_get_mb_cur
 4008c0 5f6d6178 0063616c 6c6f6300 7374726c  _max.calloc.strl
 4008d0 656e0075 6e676574 63006d65 6d736574  en.ungetc.memset
 4008e0 005f5f65 72726e6f 5f6c6f63 6174696f  .__errno_locatio
 4008f0 6e006d65 6d636d70 005f5f66 7072696e  n.memcmp.__fprin
 400900 74665f63 686b0073 74646f75 74006c73  tf_chk.stdout.ls
 400910 65656b00 6d656d63 70790066 636c6f73  eek.memcpy.fclos
 400920 65006d61 6c6c6f63 006d6273 696e6974  e.malloc.mbsinit
 400930 005f5f75 666c6f77 006e6c5f 6c616e67  .__uflow.nl_lang
 400940 696e666f 005f5f63 74797065 5f625f6c  info.__ctype_b_l
 400950 6f630067 6574656e 76005f5f 66726561  oc.getenv.__frea
 400960 64696e67 00737464 65727200 66736361  ding.stderr.fsca
 400970 6e660066 696c656e 6f006677 72697465  nf.fileno.fwrite
 400980 005f5f66 70656e64 696e6700 70726f67  .__fpending.prog
 400990 72616d5f 696e766f 63617469 6f6e5f73  ram_invocation_s
 4009a0 686f7274 5f6e616d 65006664 6f70656e  hort_name.fdopen
 4009b0 0062696e 64746578 74646f6d 61696e00  .bindtextdomain.
 4009c0 73747263 6d70005f 5f6c6962 635f7374  strcmp.__libc_st
 4009d0 6172745f 6d61696e 00667365 656b6f00  art_main.fseeko.
 4009e0 5f5f6f76 6572666c 6f770066 70757473  __overflow.fputs
 4009f0 5f756e6c 6f636b65 64006672 6565005f  _unlocked.free._
 400a00 5f70726f 676e616d 65005f5f 70726f67  _progname.__prog
 400a10 6e616d65 5f66756c 6c005f5f 6378615f  name_full.__cxa_
 400a20 61746578 6974005f 5f676d6f 6e5f7374  atexit.__gmon_st
 400a30 6172745f 5f00474c 4942435f 322e3300  art__.GLIBC_2.3.
 400a40 474c4942 435f322e 332e3400 474c4942  GLIBC_2.3.4.GLIB
 400a50 435f322e 31340047 4c494243 5f322e34  C_2.14.GLIBC_2.4
 400a60 00474c49 42435f32 2e322e35 00        .GLIBC_2.2.5.

objdumpでオブジェクトファイルを逆アセンブルしてみる

objdumpでオブジェクトファイルを逆アセンブル

-dオプションで逆アセンブルができるので下記のように実行

# objdump -d /bin/echo

/bin/echo:     file format elf64-x86-64


Disassembly of section .init:

0000000000401050 <.init>:
  401050:   48 83 ec 08             sub    $0x8,%rsp
  401054:   48 8b 05 85 5f 20 00    mov    0x205f85(%rip),%rax        # 606fe0 <__ctype_b_loc@plt+0x205c60>
  40105b:   48 85 c0                test   %rax,%rax
  40105e:   74 05                   je     401065 <__uflow@plt-0x1b>
  401060:   e8 2b 03 00 00          callq  401390 <__ctype_b_loc@plt+0x10>
  401065:   48 83 c4 08             add    $0x8,%rsp
  401069:   c3                      retq

Disassembly of section .plt:

0000000000401070 <__uflow@plt-0x10>:
  401070:   ff 35 92 5f 20 00       pushq  0x205f92(%rip)        # 607008 <__ctype_b_loc@plt+0x205c88>
  401076:   ff 25 94 5f 20 00       jmpq   *0x205f94(%rip)        # 607010 <__ctype_b_loc@plt+0x205c90>
  40107c:   0f 1f 40 00             nopl   0x0(%rax)
~~~(ry~~~

アドレスとバイト列もみたい場合は下記のようにオプションを指定すれば見れるようになる

# objdump -d --prefix-address --show-raw-insn /bin/echo

/bin/echo:     file format elf64-x86-64


Disassembly of section .init:
0000000000401050 <.init> 48 83 ec 08              sub    $0x8,%rsp
0000000000401054 <.init+0x4> 48 8b 05 85 5f 20 00     mov    0x205f85(%rip),%rax        # 0000000000606fe0 <__ctype_b_loc@plt+0x205c60>
000000000040105b <.init+0xb> 48 85 c0                 test   %rax,%rax
000000000040105e <.init+0xe> 74 05                    je     0000000000401065 <__uflow@plt-0x1b>
0000000000401060 <.init+0x10> e8 2b 03 00 00          callq  0000000000401390 <__ctype_b_loc@plt+0x10>
0000000000401065 <.init+0x15> 48 83 c4 08             add    $0x8,%rsp
0000000000401069 <.init+0x19> c3                      retq

Disassembly of section .plt:
0000000000401070 <__uflow@plt-0x10> ff 35 92 5f 20 00     pushq  0x205f92(%rip)        # 0000000000607008 <__ctype_b_loc@plt+0x205c88>
0000000000401076 <__uflow@plt-0xa> ff 25 94 5f 20 00      jmpq   *0x205f94(%rip)        # 0000000000607010 <__ctype_b_loc@plt+0x205c90>
000000000040107c <__uflow@plt-0x4> 0f 1f 40 00            nopl   0x0(%rax)
~~~(ry~~~

特定のセクションのみ逆アセンブルすることもできる

# objdump -d -j .dynstr /bin/echo

/bin/echo:     file format elf64-x86-64


Disassembly of section .dynstr:

0000000000400810 <.dynstr>:
  400810:   00 6c 69 62             add    %ch,0x62(%rcx,%rbp,2)
  400814:   63 2e                   movslq (%rsi),%ebp
  400816:   73 6f                   jae    400887 <__uflow@plt-0x7f9>
  400818:   2e 36 00 66 66          cs add %ah,%ss:0x66(%rsi)
  40081d:   6c                      insb   (%dx),%es:(%rdi)
  40081e:   75 73                   jne    400893 <__uflow@plt-0x7ed>
  400820:   68 00 73 74 72          pushq  $0x72747300
  400825:   63 70 79                movslq 0x79(%rax),%esi
~~~(ry~~~

ソースファイルとの対応を表示

デバッグ情報が含まれてるオブジェクトファイルの場合は-Sオプションでそのソースファイルがあれば ソースコードをその場に挿入してくれる

# cat hello.c
#include <stdio.h>

int main(void)
{
    printf("Hello World\n");
    return 0;
}
# gcc -g -o hello hello.c
# ll
total 16
-rwxr-xr-x 1 root root 9432 Mar 21 03:15 hello
-rw-r--r-- 1 root root   82 Mar 21 03:08 hello.c
# objdump -d -S hello
~~~~(ry~~~
000000000040051d <main>:
#include <stdio.h>

int main(void)
{
  40051d:   55                      push   %rbp
  40051e:   48 89 e5                mov    %rsp,%rbp
    printf("Hello World\n");
  400521:   bf d0 05 40 00          mov    $0x4005d0,%edi
  400526:   e8 d5 fe ff ff          callq  400400 <puts@plt>
    return 0;
  40052b:   b8 00 00 00 00          mov    $0x0,%eax
}
  400530:   5d                      pop    %rbp
  400531:   c3                      retq
  400532:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
  400539:   00 00 00
  40053c:   0f 1f 40 00             nopl   0x0(%rax)
~~~(ry~~~

とりあえず今回は逆アセンブルまでしてみた
たぶん次回もあると思うが今回はここまで

参考

www.oreilly.co.jp