来自书本的笔记,转载务必说明出处
Linux 环境及相关工具
Linux 工具
GDB
GNU 调试器(GDB) 不仅可以用来调试有 bug 的应用程序,也可以用来研究甚至改变一个程序的控制流,还可以用来修改代码、寄存器和数据结构。对于一个致力于寻找软件漏洞或者破解一个内部非常复杂的病毒的黑客来讲,这些都是非常常见的工作。 GDB 主要用于分析 ELF 二进制文件和 Linux 进程,是 Linux 黑客的必备工具。
GNU binutils 中的 objdump
object dump(objdump)是一种对代码进行快速反编译的简洁方案,在反编译简单的、未被篡改的二进制文件时非常有用,但是要进行任何真正有挑战性的反编译任务,特别是针对恶意软件时, objdump 就显示出了它的局限性。最主要的一个缺陷就是需要依赖 ELF 节头,并且不会进行控制流分析,这极大地降低了 objdump 的健壮性。
常见例子:
查看 ELF 文件中所有节的数据或代码:
objdump –D <elf_object>
只查看 ELF 文件中的程序代码:
objdump –d <elf_object>
查看所有符号:
objdump –tT <elf_object>
GNU binutils 中的 objcopy
object copy( objcopy) 是一款非常强大的小工具, 很难用一句话对其进行概述。推荐参考 objcopy 的使用手册,里面描述得非常详细。虽然 objcopy 的某些特征只针对特定的 ELF 目标文件,但是,它还可以用来分析和修改任意类型的 ELF 目标文件,还可以修改 ELF 节,或将 ELF 节复制到 ELF 二进制中(或从 ELF 二进制中复制 ELF 节)。
data 节从一个 ELF 目标文件复制到另一个文件中,可以使用下面的命令
objcopy –only-section=.data <infile> <outfile>
strace
system call trace( strace, 系统调用追踪) 是基于 ptrace(2)系统调用的一款工具, strace 通过在一个循环中使用 PTRACE_SYSCALL 请求来显示运行中程序的系统调用(也称为 syscalls)活动相关的信息以及程序执行中捕捉到的信号量。 strace 在调试过程中非常有用,也可以用来收集运行时系统调用相关的信息。
使用 strace 命令来跟踪一个基本的程序:
strace /bin/ls –o ls.out
使用 strace 命令附加到一个现存的进程上:
strace –p <pid> -o daemon.out
原始输出将会显示每个系统调用的文件描述编号, 系统调用会将文件描述符作为参数,如下所示:
SYS_read(3, buf, sizeof(buf));
如果想查看读入到文件描述符 3 中的所有数据,可以运行下面的命令:
strace –e read=3 /bin/ls
也可以使用–e write=fd 命令查看写入的数据。 strace 是一个非常有用的小工具,会在很多地方用到。
ltrace
library trace( ltrace, 库追踪) 是另外一个简洁的小工具,与 strace 非常类似。 ltrace 会解析共享库,即一个程序的链接信息,并打印出用到的库函数。
基本的 ltrace 命令
除了可以查看库函数调用之外,还可以使用-S 标记查看系统调用。 ltrace命令通过解析可执行文件的动态段,并打印出共享库和静态库的实际符号和函数,来提供更细粒度的信息:
ltrace <program> -o program.out
ftrace
function trace( ftrace, 函数追踪) 是书本作者设计的一个工具。 ftrace 的功能与 ltrace 类似,但还可以显示出二进制文件本身的函数调用。书本作者没有找到现成的实现这个功能的 Linux 工具,于是就决定自己编码实现。这个工具可以在网站 https://github.com/elfmaster/ftrace 找到。下一章会对这个工具的使用进行介绍。
readelf
readelf 命令是一个非常有用的解析 ELF 二进制文件的工具。在进行反编译之前,需要收集目标文件相关的信息,该命令能够提供收集信息所需要的特定于 ELF 的所有数据。在本书中,我们将会使用 readelf 命令收集符号、段、节、重定向入口、数据动态链接等相关信息。 readelf 命令是分析 ELF 二进制文件的利器。第 2 章将对该命令进行更深入的介绍,下面是几个常用的标记。
查询节头表:
readelf –S <object>
查询程序头表:
readelf –l <object>
查询符号表:
readelf -s <object>
查询 ELF 文件头数据:
readelf –e <object>
查询重定位入口:
readelf –r <object>
查询动态段:
readelf –d <object>
ERESI——ELF 反编译系统接口
ERESI 工程(http://www.eresi-project.org)中包含着许多 Linux二进制黑客梦寐以求的工具。令人遗憾的是,其中有些工具没有持续更新,有的与 64 位 Linux 不适配。 ERESI 工程支持许多的体系结构,无疑是迄今为止最具创新性的破解 ELF 二进制文件的工具集合。由于书本作者不太熟悉ERESI 工程中工具的用法,并且其中有些不再更新,因此就不再对该工程进行更深入的探讨了。不过,有两篇 Phrack 的文章能够说明 ERESI 工具的创新和强大的特性:
Cerberus ELF interface
Embedded ELF debugging
有用的设备和文件
/proc/
/proc/
/proc/kcore
/proc/kcore 是 proc 文件系统的一项,是 Linux 内核的动态核心文件。也就是说,它是以 ELF 核心文件的形式所展现出来的原生内存转储,GDB 可以使用/proc/kcore 来对内核进行调试和分析。 第 9 章会更深入地介绍/proc/kcore。
/boot/System.map
这个文件在几乎所有的 Linux 发行版中都有, 对内核黑客来说是非常有用的一个文件,包含了整个内核的所有符号。
/proc/kallsyms
kallsyms与System.map类似, 区别就是kallsyms是内核所属的/proc 的一个入口并且可以动态更新。 如果安装了新的 LKM(Linux Kernel Module),符号会自动添加到/proc/kallsyms 中。 /proc/kallsyms 包含了内核中绝大部分的符号,如果在 CONFIG_KALLSYMS_ALL 内核配置中指明,则可以包含内核中全部的符号。
/proc/iomem
omem 是一个非常有用的 proc 入口,与/proc/< pid>/maps 类似,不过它是跟系统内存相关的。例如,如果想知道内核的 text 段所映射的物理内存位置,可以搜索 Kernel 字符串,然后就可以查看 code/text 段、 data段和 bss 段的相关内容:
ECFS
extended core file snapshot( ECFS, 扩展核心文件快照) 是一项特殊的核心转储技术,专门为进程镜像的高级取证分析所设计。这个软件的代码可以在 https://github.com/elfmaster/ecfs 看到。第 8 章将会单独介绍 ECFS 及其使用方法。如果你已经进入到了高级内存取证分析阶段,你会非常想关注这一部分内容。
链接器相关环境指针
LD_PRELOAD 环境变量
LD_PRELOAD 环境变量可以设置成一个指定库的路径,动态链接时可以比其他库有更高的优先级。这就允许预加载库中的函数和符号能够覆盖掉后续链接的库中的函数和符号。这在本质上允许通过重定向共享库函数来行运行时修复。在后续的章节中,这项技术可以用来绕过反调试代码,也可以用作用户级 rootkit。
LD_SHOW_AUXV 环境变量
该环境变量能够通知程序加载器来展示程序运行时的辅助向量。 辅助向量是放在程序栈(通过内核的 ELF 常规加载方式)上的信息,附带了传递给动态链接器的程序相关的特定信息。第 3 章将会对此进行进一步验证,不过这些信息对于反编译和调试来说非常有用。例如,要想获取进程镜像 VDSO 页的内存地址(也可以使用 maps 文件获取,之前介绍过),就需要查询 AT_SYSINFO。
下面是一个带有 LD_SHOW_AUXV 辅助向量的例子:
链接器脚本
链接器脚本是由链接器解释的,把程序划分成相应的节、内存和符号。默认的链接器脚本可以使用 ld –verbose 查看。例如:.bss 节总是放在 data 段的末尾,这就是链接器脚本决定的。gcc 依赖于链接器和其他程序来完成编译的任务,在某些情况下,能够控制可执行文件的布局相当重要。gcc 通过使用–T 标志来指定链接器脚本。