Linux二进制分析—读书笔记(1)
温故而知新
第1章 Linux环境和相关工具
前言
Linux环境
本章节使用的代码
//test.c
#include <stdio.h>
int main(void)
{
printf("hello world\n");
return 0;
}
gcc test.c -o test
//sleep.c
#include <unistd.h>
int main(void)
{
sleep(100);
return 0;
}
gcc sleep.c -o sleep
//rand.c
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int i = 10;
srand(time(NULL));
while(i--)
printf("%d\n", rand());
return 0;
}
gcc rand.c -o rand
//urand.c
int rand()
{
ret 666;
}
gcc -shared -fPIC urand.c -o urand.so
1.1 linux工具
1.1.1 GDB
常用动态调试。
1.1.2 GNU binutils中的objdump
objdump是一种对代码进行快速反编译的简洁方案,在反编译简单的、未被篡改的二进制文件非常有效,但其主要依赖ELF节头,且不会控制流分析,就显示出了它的局限性。
查看ELF文件中所有的节数据或代码:objdump -D <elf_object>
查看ELF文件中的程序代码:objdump -d <elf_object>
查看ELF文件中所有符号:objdump -tT <elf_object>
1.1.3 GNU binutils中的objcopy
可以用来分析和修改任意类型的ELF目标文件,还可以修改ELF节,或将ELF节复制到ELF二进制中(或从ELF二进制中复制ELF节)。
1.1.4 strace
strace通过使用PTRACE_SYSCALL请求来显示运行中的程序的系统调用活动相关的信息及程序执行中捕捉到的信号量来实现系统调用追踪。
使用strace命令来跟踪一个基本程序:strace /bin/ls -o ls.out
使用starce命令附加到一个现存的进程上:strace -p -o daemon.out
1.1.5 ltrace
ltrace会解析共享库,即一个程序的链接信息,并打印出用到的库函数。
还可以使用 -S 标记来查看系统调用。
1.1.6 readelf
readelf命令是一个非常有用的解析ELF二进制文件的工具。
查询节头表:readelf -S <elf_object>
查询程序头表:readelf -l <elf_object>
查询符号表:readelf -s <elf_object>
查询ELF文件头数据:readelf -e <elf_object>
查询重定位入口:readelf -r <elf_object>
查询动态段:readelf -d <elf_object>
1.2 有用的设备和文件
1.2.1 /proc/<pid>/maps
文件保存了一个进程镜像的布局,通过展现每个内存映射来实现。
1.2.2 /proc/kcore
Linux内核的动态核心文件,ELF文件形式。GDB可以使用/proc/kcore来对内核进行调试和分析。
1.2.3 /boot/System.map
这个文件几乎所有的Linux发行版中都有,包含了整个内核的所有符号。
1.2.4 /proc/kallsyms
与System.map类似,区别就是kallsyms是内核所属的/proc的一个入口并且动态更新。
1.2.5 /proc/iomem
iomem是一个非常有用的proc入口,与/proc/<pid>/maps类似,但它是跟系统内存相关的。
查看内核的text段所映射的物理内存位置:grep Kernel /proc/iomem
1.3 链接器相关的环境指针
1.3.1 LD_PRELOAD环境变量
LD_PRELOAD环境变量可以设置成一个指定库路径,动态链接时可以比其他库有更高的优先级。这就允许预加载库中的函数和符号能搞覆盖掉后续链接的库中的函数和符号。
1.3.2 LD_SHOW_AUXV环境变量
该环境变量能够通知程序加载器来展示程序运行是的辅助向量。辅助向量是放在程序栈(通过内核的ELF常规加载方式)上的信息,附带了传递给动态链接器的程序相关的特定信息。
1.3.3 链接器脚本
链接器脚本是由链接器解释的,把程序划分成相应的节、内存和符号。ld链接器程序有自己解释的一套语言,当有文件输入时,ld链接器程序会用自己的语言来决定输出文件的组织方式。