|
概述:
objdump有点象那个快速查看之流的工具,就是以一种可阅读的格式让你更多地了解二进制文件可能带有的附加信息。对于一般只想让自己程序跑起来的程序员,这个命令没有更多意义,对于想进一步了解系统的程序员,应该掌握这种工具,至少你可以自己写写shellcode了,或者看看人家给的exploit中的shellcode是什么东西。
目录:
★ 测试练习前的准备工作
★ Redhat 6.0 objdump命令的man手册
★ objdump应用举例(待增加)
★ 相关命令
★ 测试练习前的准备工作
cp /usr/lib/libpcap.a /home/scz/src
nm -s libpcap.a | more
ar tv libpcap.a
ar xv libpcap.a inet.o
nm -s inet.o
关于nm -s的显示请自己man nm查看
★ Redhat 6.0 objdump命令的man手册
objdump - 显示二进制文件信息
objdump
[-a] [-b bfdname |
--target=bfdname] [-C] [--debugging]
[-d] [-D]
[--disassemble-zeroes]
[-EB|-EL|--endian={big|little}] [-f]
[-h] [-i|--info]
[-j section | --section=section]
[-l] [-m machine ] [--prefix-addresses]
[-r] [-R]
[-s|--full-contents] [-S|--source]
[--[no-]show-raw-insn] [--stabs] [-t]
[-T] [-x]
[--start-address=address] [--stop-address=address]
[--adjust-vma=offset] [--version] [--help]
objfile...
--archive-headers
-a 显示档案库的成员信息,与 ar tv 类似
objdump -a libpcap.a 和 ar -tv libpcap.a 显示结果比较比较显然这个选项没有什么意思。
--adjust-vma=offset
Whendumping information, first add offset to all the section addresses.This is useful if the section addresses do not correspond to the symboltable, which can happen when putting sections at particular addresseswhen using a format which can not represent section addresses, such asa.out.
-b bfdname
--target=bfdname
指定目标码格式。这不是必须的,objdump能自动识别许多格式,
比如:objdump -b oasys -m vax -h fu.o
显示fu.o的头部摘要信息,明确指出该文件是Vax系统下用Oasys
编译器生成的目标文件。objdump -i将给出这里可以指定的
目标码格式列表
--demangle
-C 将底层的符号名解码成用户级名字,除了去掉所有开头的下划线之外,还使得C++函数名以可理解的方式显示出来。
--debugging
显示调试信息。企图解析保存在文件中的调试信息并以C语言的语法显示出来。仅仅支持某些类型的调试信息。
--disassemble
-d 反汇编那些应该还有指令机器码的section
--disassemble-all
-D 与 -d 类似,但反汇编所有section
--prefix-addresses
反汇编的时候,显示每一行的完整地址。这是一种比较老的反汇编格式。显示效果并不理想,但可能会用到其中的某些显示,自己可以对比。
--disassemble-zeroes
一般反汇编输出将省略大块的零,该选项使得这些零块也被反汇编。
-EB
-EL
--endian={big|little}
这个选项将影响反汇编出来的指令。
little-endian就是我们当年在dos下玩汇编的时候常说的高位在高地址,x86都是这种。
--file-headers
-f 显示objfile中每个文件的整体头部摘要信息。
--section-headers
--headers
-h 显示目标文件各个section的头部摘要信息。
--help 简短的帮助信息。
--info
-i 显示对于 -b 或者 -m 选项可用的架构和目标格式列表。
--section=name
-j name 仅仅显示指定section的信息
--line-numbers
-l 用文件名和行号标注相应的目标代码,仅仅和-d、-D或者-r一起使用使用-ld和使用-d的区别不是很大,在源码级调试的时候有用,要求编译时使用了-g之类的调试编译选项。
--architecture=machine
-m machine
指定反汇编目标文件时使用的架构,当待反汇编文件本身没有描述架构信息的时候(比如S-records),这个选项很有用。可以用-i选项列出这里能够指定的架构
--reloc
-r 显示文件的重定位入口。如果和-d或者-D一起使用,重定位部分以反汇编后的格式显示出来。
--dynamic-reloc
-R 显示文件的动态重定位入口,仅仅对于动态目标文件有意义,比如某些共享库。
--full-contents
-s 显示指定section的完整内容。
objdump --section=.text -s inet.o | more
--source
-S 尽可能反汇编出源代码,尤其当编译的时候指定了-g这种调试参数时,效果比较明显。隐含了-d参数。
--show-raw-insn
反汇编的时候,显示每条汇编指令对应的机器码,除非指定了
--prefix-addresses,这将是缺省选项。
--no-show-raw-insn
反汇编时,不显示汇编指令的机器码,这是指定 --prefix-addresses
选项时的缺省设置。
--stabs
Displaythe contents of the .stab, .stab.index, and .stab.excl sections from anELF file. This is only useful on systems (such as Solaris 2.0) in which.stab debugging symbol-table entries are carried in an ELF section. Inmost other file formats, debugging symbol-table entries are interleavedwith linkage symbols, and are visible in the --syms output.
--start-address=address
从指定地址开始显示数据,该选项影响-d、-r和-s选项的输出。
--stop-address=address
显示数据直到指定地址为止,该选项影响-d、-r和-s选项的输出。
--syms
-t 显示文件的符号表入口。类似于nm -s提供的信息
--dynamic-syms
-T 显示文件的动态符号表入口,仅仅对动态目标文件有意义,比如某些
共享库。它显示的信息类似于 nm -D|--dynamic 显示的信息。
--version 版本信息
objdump --version
--all-headers
-x 显示所有可用的头信息,包括符号表、重定位入口。-x 等价于
-a -f -h -r -t 同时指定。
objdump -x inet.o
参看 nm(1)
★ objdump应用举例(待增加)
/*
g++ -g -Wstrict-prototypes -Wall -Wunused -o objtest objtest.c
*/
#include
#include
int main ( int argc, char * argv[] )
{
execl( "/bin/sh", "/bin/sh", "-i", 0 );
return 0;
}
g++ -g -Wstrict-prototypes -Wall -Wunused -o objtest objtest.c
objdump -j .text -Sl objtest | more
/main(查找)
08048750 :
main():
/home/scz/src/objtest.c:7
*/
#include
#include
int main ( int argc, char * argv[] )
{
8048750: 55 pushl %ebp
8048751: 89 e5 movl %esp,%ebp
/home/scz/src/objtest.c:8
execl( "/bin/sh", "/bin/sh", "-i", 0 );
8048753: 6a 00 pushl $0x0
8048755: 68 d0 87 04 08 pushl $0x80487d0
804875a: 68 d3 87 04 08 pushl $0x80487d3
804875f: 68 d3 87 04 08 pushl $0x80487d3
8048764: e8 db fe ff ff call 8048644 <_init+0x40>
8048769: 83 c4 10 addl $0x10,%esp
/home/scz/src/objtest.c:9
return 0;
804876c: 31 c0 xorl %eax,%eax
804876e: eb 04 jmp 8048774
8048770: 31 c0 xorl %eax,%eax
8048772: eb 00 jmp 8048774
/home/scz/src/objtest.c:10
}
8048774: c9 leave
8048775: c3 ret
8048776: 90 nop
如果说上面还不够清楚,可以用下面的命令辅助一下:
objdump -j .text -Sl objtest --prefix-addresses | more
objdump -j .text -Dl objtest | more
去掉调试编译选项重新编译
g++ -O3 -o objtest objtest.c
objdump -j .text -S objtest | more
08048778 :
main():
8048778: 55 pushl %ebp
8048779: 89 e5 movl %esp,%ebp
804877b: 6a 00 pushl $0x0
804877d: 68 f0 87 04 08 pushl $0x80487f0
8048782: 68 f3 87 04 08 pushl $0x80487f3
8048787: 68 f3 87 04 08 pushl $0x80487f3
804878c: e8 db fe ff ff call 804866c <_init+0x40>
8048791: 31 c0 xorl %eax,%eax
8048793: c9 leave
8048794: c3 ret
8048795: 90 nop
与前面-g编译后的二进制代码比较一下,有不少区别。
至于如何写shellcode、如何理解别人给出的shellcode,请参看华中站系统安全版精华区中的"如何写自己的shellcode"
示例-1:[beyes@beyes ELF]$ objdump -h simplesection.o
simplesection.o: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 0000004f 00000000 00000000 00000034 2**2
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
1 .data 00000008 00000000 00000000 00000084 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000004 00000000 00000000 0000008c 2**2
ALLOC
3 .rodata 00000004 00000000 00000000 0000008c 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .comment 0000002e 00000000 00000000 00000090 2**0
CONTENTS, READONLY
5 .note.GNU-stack 00000000 00000000 00000000 000000be 2**0
CONTENTS, READONLY
6 .eh_frame 00000058 00000000 00000000 000000c0 2**2
CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA 上面的输出结果中,"CONTENTS" ,"ALLOC" 等表示该段的属性,其中 "CONTENTS" 表示该段在文件中存在。如 .bss 段没有 "CONTENTS" 属性,表示 .bss 段在 ELF 文件中不存在内容。
经常使用 -s -d 两个选项来查看目标文件。-s 选项将所有段的内容以十六进制形式打印出来;-d 选项可以将所有包含指令的段反汇编。如:[beyes@beyes ELF]$ objdump -s -d simplesection.o
simplesection.o: file format elf32-i386
Contents of section .text:
0000 5589e583 ec188b45 08894424 04c70424 U......E..D$...$
0010 00000000 e8fcffff ffc9c355 89e583e4 ...........U....
0020 f083ec20 c744241c 01000000 8b150400 ... .D$.........
0030 0000a100 00000001 d0034424 1c034424 ..........D$..D$
0040 18890424 e8fcffff ff8b4424 1cc9c3 ...$......D$...
Contents of section .data:
0000 54000000 55000000 T...U...
Contents of section .rodata:
0000 25640a00 %d..
Contents of section .comment:
0000 00474343 3a202847 4e552920 342e362e .GCC: (GNU) 4.6.
0010 30203230 31313036 30332028 52656420 0 20110603 (Red
0020 48617420 342e362e 302d3130 2900 Hat 4.6.0-10).
Contents of section .eh_frame:
0000 14000000 00000000 017a5200 017c0801 .........zR..|..
0010 1b0c0404 88010000 1c000000 1c000000 ................
0020 00000000 1b000000 00410e08 8502420d .........A....B.
0030 0557c50c 04040000 1c000000 3c000000 .W..........<...
0040 1b000000 34000000 00410e08 8502420d ....4....A....B.
0050 0570c50c 04040000 .p......
Disassembly of section .text:
00000000 <func1>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 18 sub $0x18,%esp
6: 8b 45 08 mov 0x8(%ebp),%eax
9: 89 44 24 04 mov %eax,0x4(%esp)
d: c7 04 24 00 00 00 00 movl $0x0,(%esp)
14: e8 fc ff ff ff call 15 <func1+0x15>
19: c9 leave
1a: c3 ret
0000001b <main>:
1b: 55 push %ebp
1c: 89 e5 mov %esp,%ebp
1e: 83 e4 f0 and $0xfffffff0,%esp
21: 83 ec 20 sub $0x20,%esp
24: c7 44 24 1c 01 00 00 movl $0x1,0x1c(%esp)
2b: 00
2c: 8b 15 04 00 00 00 mov 0x4,%edx
32: a1 00 00 00 00 mov 0x0,%eax
37: 01 d0 add %edx,%eax
39: 03 44 24 1c add 0x1c(%esp),%eax
3d: 03 44 24 18 add 0x18(%esp),%eax
41: 89 04 24 mov %eax,(%esp)
44: e8 fc ff ff ff call 45 <main+0x2a>
49: 8b 44 24 1c mov 0x1c(%esp),%eax
4d: c9 leave
4e: c3 ret "Contents of section .text" 就是 .text 代码段的数据以十六进制方式打印出来的内容,总共 0x4f 个字节,最左边一列是偏移量,中间 4 列是十六进制的内容,最有一列是 .text 段的 ASCII 码形式。对照下面的反汇编结果,可以很明显的看到,.text 段里所包含的正是目标文件里所对应的同名 .c 文件中的 func1() 和 main() 里的指令。.text 段的第 1 个字节 0x55 就是 func1() 函数的第 1 条 push %ebp 指令,而最后一个字节的 0xc3 正是 main() 函数的最后一跳指令 ret 。
-t 选项用来打印出符号表入口信息,该选项的功能和 nm 命令比较相似,尽管它们两的显示格式有点不一样。如下所示:$ objdump -t simplesection.o
simplesection.o: file format elf32-i386
SYMBOL TABLE:
00000000 l df *ABS* 00000000 simplesection.c
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000000 l d .rodata 00000000 .rodata
00000004 l O .data 00000004 static_var.1220
00000000 l O .bss 00000004 static_var2.1221
00000000 l d .note.GNU-stack 00000000 .note.GNU-stack
00000000 l d .eh_frame 00000000 .eh_frame
00000000 l d .comment 00000000 .comment
00000000 g O .data 00000004 global_init_var
00000004 O *COM* 00000004 global_uninit_var
00000000 g F .text 0000001b func1
00000000 *UND* 00000000 printf
0000001b g F .text 00000034 main |
|