关键词:二进制文件|分析|命令|工具|方法|10分析工具|00000|4005|二进制|21|来看看

Linux上分析二进制文件的10种方法

在 Linux 上分析二进制文件的 10 种方法

这种简易的命令和工具能够协助你轻轻松松进行分析二进制文件的每日任务。

“这一世界上 10 类人:懂二进制的人与不明白二进制的人。”

大家每日都会与二进制文件相处,但大家对二进制文件却了解很少。我常说的二进制,就是指你每日运作的可执行文件,从命令行工具到完善的程序运行全是。

Linux 出示了一套丰富多彩的工具,让分析二进制文件越来越易如反掌。不管你的工作中人物角色是啥,假如你一直在 Linux 上工作中,掌握这种工具的基础知识将协助你尽快了解你的系统软件。

在本文中,大家将详细介绍在其中一些最时兴的 Linux 工具和命令,在其中绝大多数全是 Linux 发行版的一部分。要是没有寻找,你能随时随地应用你的程序包管理工具来安裝和探寻他们。请记牢:学习培训在恰当的场所应用恰当的工具必须很多的细心和训练。

file

它的功效:协助明确扩展名。

这将就是你开展二进制分析的起始点。大家每日都会与文档相处,并不是全部的文档全是可实行种类,此外也有各式各样的扩展名。在你刚开始以前,你需要掌握要分析的扩展名。是二进制文件、库文件、ASCII 文本文档、视频文件格式、图片文件、PDF、数据库文件等文档吗?

file 命令将协助你确定你所解决的扩展名。

$ file /bin/ls/bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=94943a89d17e9d373b2794dcb1f7e38c95b66c86, stripped$$ file /etc/passwd/etc/passwd: ASCII text$

ldd

它的功效:复印共享资源目标相互依赖。

假如你早已在一个可实行的二进制文件上应用了上边的 file 命令,你毫无疑问会见到輸出中的“动态链接dynamically linked”信息内容。它代表什么意思呢?

在软件开发的情况下,大家尽可能不必重造轮子。有一组普遍的每日任务是大部分软件系统必须的,例如输出打印或从规范键入/开启的文档中载入等。全部这种普遍的每日任务都被抽象性成一组通用性的涵数,随后所有人都能够应用,而不是写成自身的组合。这种常见的涵数被放到一个叫 libc 或 glibc 的库中。

怎样寻找可执行程序所依靠的库?这就是 ldd 命令的功效了。对动态链接的二进制文件运作该命令会显示信息出全部依靠库和他们的相对路径。

$ ldd /bin/ls linux-vdso.so.1 => (0x00007ffef5ba1000) libselinux.so.1 => /lib64/libselinux.so.1 (0x00007fea9f854000) libcap.so.2 => /lib64/libcap.so.2 (0x00007fea9f64f000) libacl.so.1 => /lib64/libacl.so.1 (0x00007fea9f446000) libc.so.6 => /lib64/libc.so.6 (0x00007fea9f079000) libpcre.so.1 => /lib64/libpcre.so.1 (0x00007fea9ee17000) libdl.so.2 => /lib64/libdl.so.2 (0x00007fea9ec13000) /lib64/ld-linux-x86-64.so.2 (0x00007fea9fa7b000) libattr.so.1 => /lib64/libattr.so.1 (0x00007fea9ea0e000) libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fea9e7f2000)$

ltrace

它的功效:库启用定位追踪器。

大家如今了解怎么使用 ldd 命令寻找一个可执行程序所依靠的库。殊不知,一个库能够包括数以百计涵数。在这里几十个涵数中,什么是大家的二进制程序流程已经应用的具体涵数?

ltrace 命令能够显示信息运作时从库中启用的全部涵数。在下面的事例中,你能见到被启用的涵数名字,及其传送给该涵数的主要参数。你也能够在輸出的最右侧见到这种涵数回到的內容。

$ ltrace ls__libc_start_main(0x4028c0, 1, 0x7ffd94023b88, 0x412950 strrchr("ls", '/') = nilsetlocale(LC_ALL, "") = "en_US.UTF-8"bindtextdomain("coreutils", "/usr/share/locale") = "/usr/share/locale"textdomain("coreutils") = "coreutils"__cxa_atexit(0x40a930, 0, 0, 0x736c6974756572) = 0isatty(1) = 1getenv("QUOTING_STYLE") = nilgetenv("COLUMNS") = nilioctl(1, 21523, 0x7ffd94023a50) = 0<< snip >>fflush(0x7ff7baae61c0) = 0fclose(0x7ff7baae61c0) = 0 exited (status 0) $

hexdump

它的功效:以 ASCII、十进制、十六进制或八进制显示文件內容。

一般状况下,如果你用一个程序运行开启一个文档,而它不清楚如何处理该文件时,便会出現这类状况。试着用 vim 开启一个可执行文件或视频文件格式,你显示屏上面见到的仅仅抛出去的错码。

在 hexdump 中开启不明文档,能够协助你见到文档的主要内容。你也能够挑选应用一些命令行选择项来查询用 ASCII 表达的文档数据信息。这将会会协助你掌握到它是啥种类的文档。

$ hexdump -C /bin/ls | head00000000  7f 45 4c 46 02 01 01 00  00 00 00 00 00 00 00 00  |.ELF............|00000010  02 00 3e 00 01 00 00 00  d4 42 40 00 00 00 00 00  |..>[email protected]|00000020  40 00 00 00 00 00 00 00  f0 c3 01 00 00 00 00 00  |@...............|00000030  00 00 00 00 40 00 38 00  09 00 40 00 1f 00 1e 00  |[email protected]@.....|00000040  06 00 00 00 05 00 00 00  40 00 00 00 00 00 00 00  |[email protected]|00000050  40 00 40 00 00 00 00 00  40 00 40 00 00 00 00 00  |@[email protected]@[email protected]|00000060  f8 01 00 00 00 00 00 00  f8 01 00 00 00 00 00 00  |................|00000070  08 00 00 00 00 00 00 00  03 00 00 00 04 00 00 00  |................|00000080  38 02 00 00 00 00 00 00  38 02 40 00 00 00 00 00  |[email protected]|00000090  38 02 40 00 00 00 00 00  1c 00 00 00 00 00 00 00  |[email protected]|$

strings

它的功效:打印文件中的可复印标识符的字符串数组。

假如你仅仅在二进制中找寻可复印的标识符,那麼 hexdump 针对你的应用情景而言好像有点儿心存侥幸,你能应用 strings 命令。

在软件开发的情况下,各种各样文字/ASCII 信息内容会被加上到在其中,例如打印信息、调试信息、协助信息内容、不正确等。要是这种信息内容都存有于二进制文件中,就可以用 strings 命令将其转储到显示屏上。

$ strings /bin/ls

readelf

它的功效:显示信息相关 ELF 文档的信息内容。

ELF是可执行文件或二进制文件的流行文件格式,不但是 Linux 系统软件,也是各种各样 UNIX 系统软件的流行格式文件。假如你早已应用了像 file 命令那样的工具,它对你说文档是 ELF 文件格式,那麼下一步便是应用 readelf 命令和它的各种各样选择项来进一步分析文档。

在应用 readelf 命令时,有一份具体的 ELF 标准的参照是十分有效的。你能这里寻找该标准。 

$ readelf -h /bin/lsELF Header:  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00  Class:                             ELF64  Data:                              2's complement, little endian  Version:                           1 (current)  OS/ABI:                            UNIX - System V  ABI Version:                       0  Type:                              EXEC (Executable file)  Machine:                           Advanced Micro Devices X86-64  Version:                           0x1  Entry point address:               0x4042d4  Start of program headers:          64 (bytes into file)  Start of section headers:          115696 (bytes into file)  Flags:                             0x0  Size of this header:               64 (bytes)  Size of program headers:           56 (bytes)  Number of program headers:         9  Size of section headers:           64 (bytes)  Number of section headers:         31  Section header string table index: 30$

objdump

它的功效:从目标文档中显示。

二进制文件是根据你撰写的源代码建立的,这种源代码会根据一个称为c语言编译器的专用工具开展编译器。这一c语言编译器会转化成相对性于源码的机器语言命令,随后由 CPU 实行特殊的每日任务。这种机器语言编码能够根据被称作汇编语言的助记词来讲解。汇编语言是一组命令,它能够协助你了解由程序流程所开展并最后在 CPU 上实行的实际操作。

objdump 实用程序载入二进制或可执行文件,并将汇编语言命令转储到显示屏上。汇编语言专业知识针对了解 objdump 指令的輸出尤为重要。

请记牢:汇编语言是特殊于系统架构的。

$ objdump -d /bin/ls | head/bin/ls: file format elf64-x86-64Disassembly of section .init:0000000000402150 <[email protected]@Base>: 402150: 48 83 ec 08 sub $0x8,%rsp 402154: 48 9a 05 6d 8e 21 00 mov 0x218e6d(%rip),%rax # 61afc8 <__gmon_start__> 40215b: 48 85 c0 test %rax,%rax$

strace

它的功效:追踪系统进程和数据信号。

假如你试过前边提及的 ltrace,那么就把 strace 看做是相近的。唯一的差别是,strace 专用工具并不是跟踪启用的库,只是跟踪系统进程。系统进程就是你与核心连接来进行工作中的。

举个事例,假如你要把一些物品复印到显示屏上,你能应用标准库 libc 中的 printf 或 puts 涵数;可是,在最底层,最后会有一个名叫 write 的系统进程来具体把物品复印到显示屏上。

$ strace -f /bin/lsexecve("/bin/ls", ["/bin/ls"], [/* 17 vars */]) = 0brk(NULL) = 0x686000mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f967956a000access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3fstat(3, {st_mode=S_IFREG|0644, st_size=40661, ...}) = b250map(NULL, 40661, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9679560000close(3) = 0<< snip >>fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = b250map(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9679569000write(1, "R2 RH\n", 7R2 RH) = 7close(1) = b250unmap(0x7f9679569000, 4096) = 0close(2) = 0exit_group(0) = ? exited with 0 $

nm

它的功效:列举目标文档中的标记。

假如你所应用的二进制文件沒有被脱离,nm 指令将给你出示在编译器全过程中置入到二进制文件中的有使用价值的信息内容。nm 能够协助你从二进制文件中鉴别自变量和函数。你能想像一下,假如你无法打开二进制文件的源码时,这将是多么的有效。

以便展现 nm,大家迅速撰写了一个微信小程序,用 -g 选择项编译器,大家会见到这一二进制文件沒有被脱离。

$ cat hello.c#include int main() { printf("Hello world!"); return 0;}$$ gcc -g hello.c -o hello$$ file hellohello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=3de46c8efb99ace4ad525d3328121568ba3d8a5d, not stripped$$ ./helloHello world!$$$ nm hello | tail0000000000600e20 d __JCR_END__0000000000600e20 d __JCR_LIST__00000000004005b0 T __libc_csu_fini0000000000400540 T __libc_csu_init U [email protected]@GLIBC_2.2.5000000000040051d T main U [email protected]@GLIBC_2.2.50000000000400490 t register_tm_clones0000000000400430 T _start0000000000601030 D __TMC_END__$

gdb

它的功效:GNU 调试器。

行吧,并不一定的二进制文件中的物品都能够开展静态数据剖析。大家的确实行了一些运作二进制文件的指令,例如 ltrace 和 strace;殊不知,手机软件由各种各样标准构成,这种标准将会会造成 实行不一样的取代相对路径。

剖析这种相对路径的唯一方式 是在运作时自然环境,在一切给出的部位终止或中止程序流程,并可以剖析信息内容,随后再向下实行。

这就是调试器的功效,在 Linux 上,gdb 便是调试器的事实标准。它能够协助你载入程序流程,在特殊的地区设定单步,剖析运行内存和 CPU 的存储器,及其大量的作用。它是对上边提及的别的专用工具的填补,能够给你做大量的运作时剖析。

有一点必须留意的是,一旦你应用 gdb 载入一个程序流程,你能见到它自身的 (gdb) 提示符。全部进一步的指令都将在这个 gdb 命令提示符中运作,直至你撤出。

大家将应用大家以前编译器的 hello 程序流程,应用 gdb 来看看它的原理。

$ gdb -q ./helloReading symbols from /home/flash/hello...done.(gdb) break mainBreakpoint 1 at 0x400521: file hello.c, line 4.(gdb) info breakNum Type Disp Enb Address What1 breakpoint keep y 0x0000000000400521 in main at hello.c:4(gdb) runStarting program: /home/flash/./helloBreakpoint 1, main () at hello.c:44 printf("Hello world!");Missing separate debuginfos, use: debuginfo-install glibc-2.17-260.el7_6.6.x86_64(gdb) bt#0 main () at hello.c:4(gdb) cContinuing.Hello world![Inferior 1 (process 29620) exited normally](gdb) q$

结束语

一旦你习惯应用这种原生态的 Linux 二进制分析工具,并了解了他们出示的輸出,你也就能够转为更高級和技术专业的开源系统二进制分析工具,例如 radare2。

猜你喜欢