This commit is contained in:
firmianay 2017-10-23 20:54:45 +08:00
parent 8e734441a3
commit e580953d01
4 changed files with 324 additions and 131 deletions

View File

@ -1,4 +1,4 @@
# 1.1 CTF 介
# 1.1 CTF
- [概述](#概述)
- [赛事介绍](#赛事介绍)

View File

@ -65,6 +65,13 @@ $ ls
a.out hello.c hello.i hello.o hello.s
```
这里要注意的是gcc 默认使用动态链接,所以这里生成的 a.out 实际上是共享目标文件。
```text
$ file a.out
a.out: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=533aa4ca46d513b1276d14657ec41298cafd98b1, not stripped
```
更多的内容我们会在 1.5.3 中专门对 ELF 文件进行讲解。
## C 语言标准库
C 运行库CRT是一套庞大的代码库以支撑程序能够正常地运行。其中 C 语言标准库占据了最主要地位。

View File

@ -29,28 +29,38 @@ void main(void) {
}
```
然后分别执行下列命令生成个文件:
然后分别执行下列命令生成个文件:
```text
$ gcc -c elfDemo.c -o elfDemo.o
$ gcc -m32 -c elfDemo.c -o elfDemo.o
$ gcc elfDemo.c -o elfDemo
$ gcc -m32 elfDemo.c -o elfDemo.out
$ gcc -m32 -static elfDemo.c -o elfDemo_static.out
```
使用 ldd 命令打印所依赖的共享库:
```text
$ ldd elfDemo
linux-gate.so.1 (0xf76e3000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf74e5000)
/lib/ld-linux.so.2 (0xf76e5000)
$ ldd elfDemo.out
linux-gate.so.1 (0xf77b1000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf7597000)
/lib/ld-linux.so.2 => /usr/lib/ld-linux.so.2 (0xf77b3000)
$ ldd elfDemo_static.out
not a dynamic executable
```
elfDemo_static.out 采用了静态链接的方式。
使用 file 命令查看相应的文件格式:
```text
$ file elfDemo.o
elfDemo.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
$ file elfDemo
elfDemo: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=355f04de44bc77b1d0b98f98e80282f8daad2340, not stripped
$ file elfDemo.out
elfDemo.out: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=50036015393a99344897cbf34099256c3793e172, not stripped
$ file elfDemo_static.out
elfDemo_static.out: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, for GNU/Linux 3.2.0, BuildID[sha1]=276c839c20b4c187e4b486cf96d82a90c40f4dae, not stripped
$ file -L /usr/lib32/libc.so.6
/usr/lib32/libc.so.6: ELF 32-bit LSB shared object, Intel 80386, version 1 (GNU/Linux), dynamically linked, interpreter /usr/lib32/ld-linux.so.2, BuildID[sha1]=449cba91635c01f9cbc303b1c962b38aff6a4431, for GNU/Linux 2.6.32, not stripped
/usr/lib32/libc.so.6: ELF 32-bit LSB shared object, Intel 80386, version 1 (GNU/Linux), dynamically linked, interpreter /usr/lib32/ld-linux.so.2, BuildID[sha1]=ee88d1b2aa81f104ab5645d407e190b244203a52, for GNU/Linux 3.2.0, not stripped
```
于是我们得到了 Linux 可执行文件格式 ELF Executable Linkable Format文件的三种类型
@ -59,12 +69,12 @@ $ file -L /usr/lib32/libc.so.6
- elfDemo.o
- 可执行文件Executable File
- 包含了可以直接执行的文件。
- elfDemo
- elfDemo_static.out
- 共享目标文件Shared Object File
- 包含了用于链接的代码和数据,分两种情况。一种是链接器将其与其他的可重定位文件和共享目标文件链接起来,生产新的目标文件。另一种是动态链接器将多个共享目标文件与可执行文件结合,作为进程映像的一部分。
- elfDemo.out
- libc-2.25.so
此时他们的结构如图:
![](../pic/1.5.3_elfdemo.png)
@ -76,28 +86,32 @@ $ file -L /usr/lib32/libc.so.6
### elfDemo.o
接下来,我们更深入地探索目标文件,使用 objdump 来查看目标文件的内部结构:
```text
[firmy@manjaro elfDemo.c_dir]$ objdump -h elfDemo.o
$ objdump -h elfDemo.o
elfDemo.o: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 0000005b 00000000 00000000 00000034 2**0
0 .group 00000008 00000000 00000000 00000034 2**2
CONTENTS, READONLY, GROUP, LINK_ONCE_DISCARD
1 .text 00000078 00000000 00000000 0000003c 2**0
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
1 .data 00000008 00000000 00000000 00000090 2**2
2 .data 00000008 00000000 00000000 000000b4 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000004 00000000 00000000 00000098 2**2
3 .bss 00000004 00000000 00000000 000000bc 2**2
ALLOC
3 .rodata 00000004 00000000 00000000 00000098 2**0
4 .rodata 00000004 00000000 00000000 000000bc 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .comment 0000001b 00000000 00000000 0000009c 2**0
5 .text.__x86.get_pc_thunk.ax 00000004 00000000 00000000 000000c0 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
6 .comment 00000012 00000000 00000000 000000c4 2**0
CONTENTS, READONLY
5 .note.GNU-stack 00000000 00000000 00000000 000000b7 2**0
7 .note.GNU-stack 00000000 00000000 00000000 000000d6 2**0
CONTENTS, READONLY
6 .eh_frame 00000064 00000000 00000000 000000b8 2**2
8 .eh_frame 0000007c 00000000 00000000 000000d8 2**2
CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
```
可以看到目标文件中除了最基本的代码段、数据段和BSS段以外还有一些别的段。注意到 .bss 段没有 `CONTENTS` 属性,表示它实际上并不存在,.bss 段只是为为未初始化的全局变量和局部静态变量预留了位置而已。
可以看到目标文件中除了最基本的代码段、数据段和 BSS 段以外,还有一些别的段。注意到 .bss 段没有 `CONTENTS` 属性,表示它实际上并不存在,.bss 段只是为为未初始化的全局变量和局部静态变量预留了位置而已。
#### 代码段
```text
@ -105,68 +119,88 @@ $ objdump -x -s -d elfDemo.o
......
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 0000005b 00000000 00000000 00000034 2**0
......
1 .text 00000078 00000000 00000000 0000003c 2**0
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
......
Contents of section .text:
0000 5589e583 ec0883ec 08ff7508 68000000 U.........u.h...
0010 00e8fcff ffff83c4 1090c9c3 8d4c2404 .............L$.
0020 83e4f0ff 71fc5589 e55183ec 14c745f4 ....q.U..Q....E.
0030 1e000000 8b150000 0000a104 00000001 ................
0040 c28b45f4 01d083ec 0c50e8fc ffffff83 ..E......P......
0050 c410908b 4dfcc98d 61fcc3 ....M...a..
0000 5589e553 83ec04e8 fcffffff 05010000 U..S............
0010 0083ec08 ff75088d 90000000 005289c3 .....u.......R..
0020 e8fcffff ff83c410 908b5dfc c9c38d4c ..........]....L
0030 240483e4 f0ff71fc 5589e551 83ec14e8 $.....q.U..Q....
0040 fcffffff 05010000 00c745f4 1e000000 ..........E.....
0050 8b880000 00008b55 f401ca8b 80040000 .......U........
0060 0001d083 ec0c50e8 fcffffff 83c41090 ......P.........
0070 8b4dfcc9 8d61fcc3 .M...a..
......
Disassembly of section .text:
00000000 <func>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 08 sub $0x8,%esp
6: 83 ec 08 sub $0x8,%esp
9: ff 75 08 pushl 0x8(%ebp)
c: 68 00 00 00 00 push $0x0
11: e8 fc ff ff ff call 12 <func+0x12>
16: 83 c4 10 add $0x10,%esp
19: 90 nop
1a: c9 leave
1b: c3 ret
3: 53 push %ebx
4: 83 ec 04 sub $0x4,%esp
7: e8 fc ff ff ff call 8 <func+0x8>
8: R_386_PC32 __x86.get_pc_thunk.ax
c: 05 01 00 00 00 add $0x1,%eax
d: R_386_GOTPC _GLOBAL_OFFSET_TABLE_
11: 83 ec 08 sub $0x8,%esp
14: ff 75 08 pushl 0x8(%ebp)
17: 8d 90 00 00 00 00 lea 0x0(%eax),%edx
19: R_386_GOTOFF .rodata
1d: 52 push %edx
1e: 89 c3 mov %eax,%ebx
20: e8 fc ff ff ff call 21 <func+0x21>
21: R_386_PLT32 printf
25: 83 c4 10 add $0x10,%esp
28: 90 nop
29: 8b 5d fc mov -0x4(%ebp),%ebx
2c: c9 leave
2d: c3 ret
0000001c <main>:
1c: 8d 4c 24 04 lea 0x4(%esp),%ecx
20: 83 e4 f0 and $0xfffffff0,%esp
23: ff 71 fc pushl -0x4(%ecx)
26: 55 push %ebp
27: 89 e5 mov %esp,%ebp
29: 51 push %ecx
2a: 83 ec 14 sub $0x14,%esp
2d: c7 45 f4 1e 00 00 00 movl $0x1e,-0xc(%ebp)
34: 8b 15 00 00 00 00 mov 0x0,%edx
3a: a1 04 00 00 00 mov 0x4,%eax
3f: 01 c2 add %eax,%edx
41: 8b 45 f4 mov -0xc(%ebp),%eax
44: 01 d0 add %edx,%eax
46: 83 ec 0c sub $0xc,%esp
49: 50 push %eax
4a: e8 fc ff ff ff call 4b <main+0x2f>
4f: 83 c4 10 add $0x10,%esp
52: 90 nop
53: 8b 4d fc mov -0x4(%ebp),%ecx
56: c9 leave
57: 8d 61 fc lea -0x4(%ecx),%esp
5a: c3 ret
0000002e <main>:
2e: 8d 4c 24 04 lea 0x4(%esp),%ecx
32: 83 e4 f0 and $0xfffffff0,%esp
35: ff 71 fc pushl -0x4(%ecx)
38: 55 push %ebp
39: 89 e5 mov %esp,%ebp
3b: 51 push %ecx
3c: 83 ec 14 sub $0x14,%esp
3f: e8 fc ff ff ff call 40 <main+0x12>
40: R_386_PC32 __x86.get_pc_thunk.ax
44: 05 01 00 00 00 add $0x1,%eax
45: R_386_GOTPC _GLOBAL_OFFSET_TABLE_
49: c7 45 f4 1e 00 00 00 movl $0x1e,-0xc(%ebp)
50: 8b 88 00 00 00 00 mov 0x0(%eax),%ecx
52: R_386_GOTOFF global_init_var
56: 8b 55 f4 mov -0xc(%ebp),%edx
59: 01 ca add %ecx,%edx
5b: 8b 80 04 00 00 00 mov 0x4(%eax),%eax
5d: R_386_GOTOFF .data
61: 01 d0 add %edx,%eax
63: 83 ec 0c sub $0xc,%esp
66: 50 push %eax
67: e8 fc ff ff ff call 68 <main+0x3a>
68: R_386_PC32 func
6c: 83 c4 10 add $0x10,%esp
6f: 90 nop
70: 8b 4d fc mov -0x4(%ebp),%ecx
73: c9 leave
74: 8d 61 fc lea -0x4(%ecx),%esp
77: c3 ret
```
`Contents of section .text``.text` 的数据的十六进制形式,总共 0x5b 个字节最左边一列是偏移量中间4列是内容最右边一列是 ASCII 码形式。下面的 `Disassembly of section .text` 是反汇编结果。
`Contents of section .text``.text` 的数据的十六进制形式,总共 0x78 个字节,最左边一列是偏移量,中间 4 列是内容,最右边一列是 ASCII 码形式。下面的 `Disassembly of section .text` 是反汇编结果。
#### 数据段和只读数据段
```text
......
Sections:
Idx Name Size VMA LMA File off Algn
1 .data 00000008 00000000 00000000 00000090 2**2
2 .data 00000008 00000000 00000000 000000b4 2**2
CONTENTS, ALLOC, LOAD, DATA
3 .rodata 00000004 00000000 00000000 00000098 2**0
4 .rodata 00000004 00000000 00000000 000000bc 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
......
Contents of section .data:
@ -175,7 +209,7 @@ Contents of section .rodata:
0000 25640a00 %d..
.......
```
`.data` 段保存已经初始化了的全局变量和局部静态变量。`elfDemo.c` 中共有两个这样的变量,`global_init_var` 和 `local_static_init_var`每个变量4个字节一共8个字节。由于小端序的原因`0a000000` 表示 `global_init_var` 值(`10`)的十六进制 `0x0a``14000000` 表示 `local_static_init_var` 值(`20`)的十六进制 `0x14`
`.data` 段保存已经初始化了的全局变量和局部静态变量。`elfDemo.c` 中共有两个这样的变量,`global_init_var` 和 `local_static_init_var`,每个变量 4 个字节,一共 8 个字节。由于小端序的原因,`0a000000` 表示 `global_init_var` 值(`10`)的十六进制 `0x0a``14000000` 表示 `local_static_init_var` 值(`20`)的十六进制 `0x14`
`.rodata` 段保存只读数据,包括只读变量和字符串常量。`elfDemo.c` 中调用 `printf` 的时候,用到了一个字符串变量 `%d\n`,它是一种只读数据,保存在 `.rodata` 段中,可以从输出结果看到字符串常量的 ASCII 形式,以 `\0` 结尾。
@ -183,35 +217,11 @@ Contents of section .rodata:
```text
Sections:
Idx Name Size VMA LMA File off Algn
2 .bss 00000004 00000000 00000000 00000098 2**2
3 .bss 00000004 00000000 00000000 000000bc 2**2
ALLOC
```
`.bss` 段保存未初始化的全局变量和局部静态变量。
##### objcopy
如果我们要将一个二进制文件比如图片、MP3音乐等东西作为目标文件中的一个段可以使用 objcopy 工具,比如我们有一个图片文件 “image.jpg”
```text
$ objcopy -I binary -O elf32-i386 -B i386 image.jpg image.o
$ objdump -ht image.o
image.o: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .data 0000642f 00000000 00000000 00000034 2**0
CONTENTS, ALLOC, LOAD, DATA
SYMBOL TABLE:
00000000 l d .data 00000000 .data
00000000 g .data 00000000 _binary_image_jpg_start
0000642f g .data 00000000 _binary_image_jpg_end
0000642f g *ABS* 00000000 _binary_image_jpg_size
```
这一技巧可能出现在 CTF 隐写题中,使用 foremost 工具可以将图片提取出来:
```text
$ foremost image.o
```
## ELF 文件结构
对象文件参与程序链接构建程序和程序执行运行程序。ELF 结构几相关信息在 `/usr/include/elf.h` 文件中。
@ -223,7 +233,7 @@ $ foremost image.o
- **段Section** 包含了链接视图中大量的目标文件信息。
- **段表Section Header Table** 包含了描述文件中所有段的信息。
### 32位数据类型
#### 32位数据类型
名称 | 长度 | 对其 | 描述 | 原始类型
----|----|----|----|----
Elf32_Addr | 4 | 4 | 无符号程序地址 | uint32_t
@ -232,8 +242,8 @@ Elf32_Off | 4 | 4 | 无符号偏移地址 | uint32_t
Elf32_Sword | 4 | 4 | 有符号整型 | int32_t
Elf32_Word | 4 | 4 | 无符号整型 | uint32_t
### 文件头
32位 ELF 文件头定义如下:
#### 文件头
32位 ELF 文件头必然存在于 ELF 文件的开头,表明这是一个 ELF 文件。定义如下:
```text
typedef struct
{
@ -253,10 +263,11 @@ typedef struct
Elf32_Half e_shstrndx; /* Section header string table index */
} Elf32_Ehdr;
```
`e_ident` 保存着 ELF 的幻数和其他信息,最前面四个字节是幻数,用字符串表示为 `\177ELF`,其后的字节如果是 32 位则是 ELFCLASS32 (1),如果是 64 位则是 ELFCLASS64 (2),再其后的字节表示端序,小端序为 ELFDATA2LSB (1),大端序为 ELFDATA2LSB (2)。最后一个字节则表示 ELF 的版本。
现在我们使用 readelf 命令来查看 elfDome 的文件头:
现在我们使用 readelf 命令来查看 elfDome.out 的文件头:
```text
$ readelf -h elfDemo
$ readelf -h elfDemo.out
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
@ -264,12 +275,12 @@ ELF Header:
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Type: DYN (Shared object file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x8048310
Entry point address: 0x3e0
Start of program headers: 52 (bytes into file)
Start of section headers: 6092 (bytes into file)
Start of section headers: 6288 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
@ -279,7 +290,59 @@ ELF Header:
Section header string table index: 29
```
### 段
#### 程序头
程序头表是由 ELF 头的 `e_phoff` 指定的偏移量和 `e_phentsize`、`e_phnum` 共同确定大小的表格组成。`e_phentsize` 表示表格中程序头的大小,`e_phnum` 表示表格中程序头的数量。
程序头的定义如下:
```
typedef struct
{
Elf32_Word p_type; /* Segment type */
Elf32_Off p_offset; /* Segment file offset */
Elf32_Addr p_vaddr; /* Segment virtual address */
Elf32_Addr p_paddr; /* Segment physical address */
Elf32_Word p_filesz; /* Segment size in file */
Elf32_Word p_memsz; /* Segment size in memory */
Elf32_Word p_flags; /* Segment flags */
Elf32_Word p_align; /* Segment alignment */
} Elf32_Phdr;
```
使用 readelf 来查看程序头:
```
$ readelf -l elfDemo.out
Elf file type is DYN (Shared object file)
Entry point 0x3e0
There are 9 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x00000034 0x00000034 0x00120 0x00120 R E 0x4
INTERP 0x000154 0x00000154 0x00000154 0x00013 0x00013 R 0x1
[Requesting program interpreter: /lib/ld-linux.so.2]
LOAD 0x000000 0x00000000 0x00000000 0x00780 0x00780 R E 0x1000
LOAD 0x000ef4 0x00001ef4 0x00001ef4 0x00130 0x0013c RW 0x1000
DYNAMIC 0x000efc 0x00001efc 0x00001efc 0x000f0 0x000f0 RW 0x4
NOTE 0x000168 0x00000168 0x00000168 0x00044 0x00044 R 0x4
GNU_EH_FRAME 0x000624 0x00000624 0x00000624 0x00044 0x00044 R 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x10
GNU_RELRO 0x000ef4 0x00001ef4 0x00001ef4 0x0010c 0x0010c R 0x1
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame
03 .init_array .fini_array .dynamic .got .got.plt .data .bss
04 .dynamic
05 .note.ABI-tag .note.gnu.build-id
06 .eh_frame_hdr
07
08 .init_array .fini_array .dynamic .got
```
#### 段
段表Section Header Table是一个以 `Elf32_Shdr` 结构体为元素的数组每个结构体对应一个段它描述了各个段的信息。ELF 文件头的 `e_shoff` 成员给出了段表在 ELF 中的偏移,`e_shnum` 成员给出了段描述符的数量,`e_shentsize` 给出了每个段描述符的大小。
```text
typedef struct
@ -300,25 +363,25 @@ typedef struct
使用 readelf 命令查看目标文件中完整的段:
```text
$ readelf -S elfDemo.o
There are 15 section headers, starting at offset 0x424:
There are 15 section headers, starting at offset 0x41c:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .group GROUP 00000000 000034 000008 04 12 16 4
[ 2] .text PROGBITS 00000000 00003c 000078 00 AX 0 0 1
[ 3] .rel.text REL 00000000 000340 000048 08 I 12 2 4
[ 3] .rel.text REL 00000000 000338 000048 08 I 12 2 4
[ 4] .data PROGBITS 00000000 0000b4 000008 00 WA 0 0 4
[ 5] .bss NOBITS 00000000 0000bc 000004 00 WA 0 0 4
[ 6] .rodata PROGBITS 00000000 0000bc 000004 00 A 0 0 1
[ 7] .text.__x86.get_p PROGBITS 00000000 0000c0 000004 00 AXG 0 0 1
[ 8] .comment PROGBITS 00000000 0000c4 00001b 01 MS 0 0 1
[ 9] .note.GNU-stack PROGBITS 00000000 0000df 000000 00 0 0 1
[10] .eh_frame PROGBITS 00000000 0000e0 00007c 00 A 0 0 4
[11] .rel.eh_frame REL 00000000 000388 000018 08 I 12 10 4
[12] .symtab SYMTAB 00000000 00015c 000140 10 13 13 4
[13] .strtab STRTAB 00000000 00029c 0000a2 00 0 0 1
[14] .shstrtab STRTAB 00000000 0003a0 000082 00 0 0 1
[ 8] .comment PROGBITS 00000000 0000c4 000012 01 MS 0 0 1
[ 9] .note.GNU-stack PROGBITS 00000000 0000d6 000000 00 0 0 1
[10] .eh_frame PROGBITS 00000000 0000d8 00007c 00 A 0 0 4
[11] .rel.eh_frame REL 00000000 000380 000018 08 I 12 10 4
[12] .symtab SYMTAB 00000000 000154 000140 10 13 13 4
[13] .strtab STRTAB 00000000 000294 0000a2 00 0 0 1
[14] .shstrtab STRTAB 00000000 000398 000082 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
@ -327,7 +390,7 @@ Key to Flags:
```
注意ELF 段表的第一个元素是被保留的,类型为 NULL。
### 字符串表
#### 字符串表
字符串表以段的形式存在,包含了以 null 结尾的字符序列。对象文件使用这些字符串来表示符号和段名称引用字符串时只需给出在表中的偏移即可。字符串表的第一个字符和最后一个字符为空字符以确保所有字符串的开始和终止。通常段名为 `.strtab` 的字符串表是 **字符串表Strings Table**,段名为 `.shstrtab` 的是段表字符串表Section Header String Table
偏移 | +0 | +1 | +2 | +3 | +4 | +5 | +6 | +7 | +8 | +9
@ -344,7 +407,38 @@ Key to Flags:
13 | helloworld
18 | world
### 符号表
可以使用 readelf 读取这两个表:
```
$ readelf -x .strtab elfDemo.o
Hex dump of section '.strtab':
0x00000000 00656c66 44656d6f 2e63006c 6f63616c .elfDemo.c.local
0x00000010 5f737461 7469635f 696e6974 5f766172 _static_init_var
0x00000020 2e323139 35006c6f 63616c5f 73746174 .2195.local_stat
0x00000030 69635f75 6e696e69 745f7661 722e3231 ic_uninit_var.21
0x00000040 39360067 6c6f6261 6c5f696e 69745f76 96.global_init_v
0x00000050 61720067 6c6f6261 6c5f756e 696e6974 ar.global_uninit
0x00000060 5f766172 0066756e 63005f5f 7838362e _var.func.__x86.
0x00000070 6765745f 70635f74 68756e6b 2e617800 get_pc_thunk.ax.
0x00000080 5f474c4f 42414c5f 4f464653 45545f54 _GLOBAL_OFFSET_T
0x00000090 41424c45 5f007072 696e7466 006d6169 ABLE_.printf.mai
0x000000a0 6e00
$ readelf -x .shstrtab elfDemo.o
Hex dump of section '.shstrtab':
0x00000000 002e7379 6d746162 002e7374 72746162 ..symtab..strtab
0x00000010 002e7368 73747274 6162002e 72656c2e ..shstrtab..rel.
0x00000020 74657874 002e6461 7461002e 62737300 text..data..bss.
0x00000030 2e726f64 61746100 2e746578 742e5f5f .rodata..text.__
0x00000040 7838362e 6765745f 70635f74 68756e6b x86.get_pc_thunk
0x00000050 2e617800 2e636f6d 6d656e74 002e6e6f .ax..comment..no
0x00000060 74652e47 4e552d73 7461636b 002e7265 te.GNU-stack..re
0x00000070 6c2e6568 5f667261 6d65002e 67726f75 l.eh_frame..grou
0x00000080 7000
```
#### 符号表
目标文件的符号表保存了定位和重定位程序的符号定义和引用所需的信息。符号表索引是这个数组的下标。索引0指向表中的第一个条目,作为未定义的符号索引。
```text
typedef struct
@ -386,7 +480,7 @@ Symbol table '.symtab' contains 20 entries:
19: 0000002e 74 FUNC GLOBAL DEFAULT 2 main
```
### 重定位
#### 重定位
重定位是连接符号定义与符号引用的过程。可重定位文件必须具有描述如何修改段内容的信息,从而运行可执行文件和共享对象文件保存进程程序映像的正确信息。
```text
/* Relocation table entry without addend (in section of type SHT_REL). */
@ -409,7 +503,7 @@ typedef struct
```text
$ readelf -r elfDemo.o
Relocation section '.rel.text' at offset 0x340 contains 9 entries:
Relocation section '.rel.text' at offset 0x338 contains 9 entries:
Offset Info Type Sym.Value Sym. Name
00000008 00001002 R_386_PC32 00000000 __x86.get_pc_thunk.ax
0000000d 0000110a R_386_GOTPC 00000000 _GLOBAL_OFFSET_TABLE_
@ -418,10 +512,10 @@ Relocation section '.rel.text' at offset 0x340 contains 9 entries:
00000040 00001002 R_386_PC32 00000000 __x86.get_pc_thunk.ax
00000045 0000110a R_386_GOTPC 00000000 _GLOBAL_OFFSET_TABLE_
00000052 00000d09 R_386_GOTOFF 00000000 global_init_var
00000058 00000309 R_386_GOTOFF 00000000 .data
0000005d 00000309 R_386_GOTOFF 00000000 .data
00000068 00000f02 R_386_PC32 00000000 func
Relocation section '.rel.eh_frame' at offset 0x388 contains 3 entries:
Relocation section '.rel.eh_frame' at offset 0x380 contains 3 entries:
Offset Info Type Sym.Value Sym. Name
00000020 00000202 R_386_PC32 00000000 .text
00000044 00000202 R_386_PC32 00000000 .text

View File

@ -8,11 +8,14 @@
- [ltrace](#ltrace)
- [md5sum](#md5sum)
- [nm](#nm)
- [objcopy](#objcopy)
- [objdump](#objdump)
- [od](#od)
- [readelf](#readelf)
- [socat](#socat)
- [ssdeep](#ssdeep)
- [strace](#strace)
- [strip](#strip)
- [strings](#strings)
- [xxd](#xxd)
@ -70,6 +73,13 @@ $ yaourt -S foremost
## ldd
**ldd** 命令用于打印程序或者库文件所依赖的共享库列表。
ldd 实际上仅是 shell 脚本,重点是环境变量 `LD_TRACE_LOADED_OBJECTS`,在执行文件时把它设为 `1`,则与执行 ldd 效果一样。
```
$ ldd [executable]
$ LD_TRACE_LOADED_OBJECTS=1 [executable]
```
## ltrace
**ltrace** 命令用于跟踪进程调用库函数的情况。
@ -103,16 +113,60 @@ $ yaourt -S foremost
```
## objcopy
如果我们要将一个二进制文件比如图片、MP3音乐等东西作为目标文件中的一个段可以使用 objcopy 工具,比如我们有一个图片文件 “image.jpg”
```text
$ objcopy -I binary -O elf32-i386 -B i386 image.jpg image.o
$ objdump -ht image.o
image.o: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .data 0000642f 00000000 00000000 00000034 2**0
CONTENTS, ALLOC, LOAD, DATA
SYMBOL TABLE:
00000000 l d .data 00000000 .data
00000000 g .data 00000000 _binary_image_jpg_start
0000642f g .data 00000000 _binary_image_jpg_end
0000642f g *ABS* 00000000 _binary_image_jpg_size
```
三个变量的使用方法如下:
```c
const char *start = _binary_image_jpg_start; // 数据的起始地址
const char *end = _binary_image_jpg_end; // 数据的末尾地址+1
int size = (int)_binary_image_jpg_size; // 数据大小
```
这一技巧可能出现在 CTF 隐写题中,使用 foremost 工具可以将图片提取出来:
```text
$ foremost image.o
```
## objdump
**objdump** 命令是用查看目标文件或者可执行的目标文件的构成的gcc工具。
#### 重要参数
```text
-d, --disassemble Display assembler contents of executable sections
-S, --source Intermix source code with disassembly
-s, --full-contents Display the full contents of all sections requested
-R, --dynamic-reloc Display the dynamic relocation entries in the file
```
#### 常见用法
对特定段进行转储:
```
$ objdump -s -j [section] [binary]
```
对地址进行指定和转储:
```
$ objdump -s --start-address=[address] --stop-address=[address] [binary]
```
当包含调试信息时,还可以使用 `-l``-S` 来分别对应行号和源码。
结合使用 *objdump**grep*
```shell
$ objdump -d [executable] | grep -A 30 [function_name]
@ -129,6 +183,32 @@ $ for i in `objdump -d print_flag | tr '\t' ' ' | tr ' ' '\n' | egrep '^[0-9a-f]
```
## od
**od** 命令用于输出文件的八进制、十六进制或其它格式编码的字节,通常用于显示或查看文件中不能直接显示在终端的字符。
#### 重要参数
```test
-A, --address-radix=RADIX output format for file offsets; RADIX is one
of [doxn], for Decimal, Octal, Hex or None
-t, --format=TYPE select output format or formats
-v, --output-duplicates do not use * to mark line suppression
```
另外加上 `z` 可以显示 ASCII 码。
#### 常见用法
用十六进制转存每个字节:
```shell
$ od -t x1z -A x [file]
```
转存字符串:
```
$ od -A x -s [file]
$ od -A n -s [file]
```
## readelf
**readelf** 命令用来显示一个或者多个 elf 格式的目标文件的信息,可以通过它的选项来控制显示哪些信息。
@ -142,6 +222,7 @@ $ for i in `objdump -d print_flag | tr '\t' ' ' | tr ' ' '\n' | egrep '^[0-9a-f]
-r --relocs Display the relocations (if present)
-d --dynamic Display the dynamic section (if present)
```
另外 `-w` 选项表示 DWARF2 调试信息。
#### 常见用法
查找库中函数的偏移量,常用于**ret2lib**
@ -223,6 +304,17 @@ $ ssdeep -bm hash.txt modified.elf
```
## strip
**strip** 命令用于删除可执行文件中的符号和段。
#### 重要参数
```text
-g -S -d --strip-debug Remove all debugging symbols & sections
-R --remove-section=<name> Also remove section <name> from the output
```
使用 `-d` 后,可以删除不使用的信息,并保留函数名等。用 gdb 进行调试时,只要保留了函数名,都可以进行调试。另外如果对 `.o``.a` 文件进行 strip 后,就不能和其他目标文件进行链接了。
## strings
**strings** 命令在对象文件或二进制文件中查找可打印的字符串。字符串是4个或更多可打印字符的任意序列以换行符或空字符结束。strings命令对识别随机对象文件很有用。