反汇编objdump和strace学习
1、介绍
程序的编译包括预编译、编译、汇编和链接,链接最终得到可执行程序,而反汇编(Disassembly)指的是将机器码(二进制指令)转换回汇编代码(重点是机器码)
概念:
-
反汇编可以作用于任何包含机器码的文件或内存块。这主要包括:
- 可执行文件 (如 Linux 下的 elf 文件, Windows 下的 .exe 文件)
- 目标文件 (如 .o , .obj 文件)
- 共享库/动态链接库 (如 .so 文件, .dll 文件)
- 运行时的一段内存 (例如在 GDB 中调试时,查看某块内存的指令)
-
反汇编是一个"损失性"的过程。编译器在生成机器码时,会丢弃所有的变量名、函数名(除非用于调试)、注释和数据类型信息。反汇编工具只能尽最大努力将二进制指令翻译回汇编助记符,但它无法还原出原始的源代码结构。
2、操作
1. 使用 objdump 静态反汇编整个程序
c++
# 反汇编整个可执行文件,显示所有函数的汇编代码
objdump -d ./example
# 如果只想看 main 函数,本质就是利用grep命令
objdump -d ./example | grep -A 20 "main\>:"
objdump -t libexample.so 查看动态库文件的符号
objdump -x libexample.so | grep "NEEDED" 查看动态库的依赖项
objdump其它命令:
-d:反汇编代码段。
-S:在反汇编代码中交替显示源代码,需要编译时使用 -g 参数以包含调试信息。
-C:将C++符号名逆向解析。
-l:在反汇编代码中插入源文件名和行号。
-j section:仅反汇编指定的section。
2. 在 GDB 中动态反汇编
c++
(gdb) break main # 在main函数设置断点
(gdb) run # 运行程序
(gdb) disas # 反汇编当前函数 (main)
(gdb) disas recursion # 反汇编 recursion 函数
(gdb) disas /r # 反汇编并同时显示机器码 (在GDB中)
在 GDB 中,当程序因段错误停止时,直接输入 disas 就会反汇编当前停止位置的代码,

3、strace使用
3.1 介绍
- strace命令是一个集诊断、调试、统计于一体的工具,我们可以用它来监控用户空间进程和内核的交互。监控程序运行时的系统调用,可以查看程序是在哪一个系统调用步骤出问题的。
- 当进程需要访问硬件设备(比如,读取磁盘文件,接收网络数据等等)时,必须由用户态模式切换至内核态模式,通过系统调用访问硬件设备
- 系统调用的代码执行时会使CPU的状态由用户态转为内核态,程序运行于内核态。
3.2 strace的参数
c++
-c 统计每一系统调用的所执行的时间,次数和出错的次数等.
-d 输出strace关于标准错误的调试信息.
-f 跟踪由fork调用所产生的子进程.
-ff 如果提供-o filename,则所有进程的跟踪结果输出到相应的filename.pid中,pid是各进程的进程号.
-F 尝试跟踪vfork调用.在-f时,vfork不被跟踪.
-h 输出简要的帮助信息.
-i 输出系统调用的入口指针.
-q 禁止输出关于脱离的消息.
-r 打印出相对时间关于,,每一个系统调用.
-t 在输出中的每一行前加上时间信息.
-tt 在输出中的每一行前加上时间信息,微秒级.
-ttt 微秒级输出,以秒了表示时间.
-T 显示每一调用所耗的时间.
-v 输出所有的系统调用.一些调用关于环境变量,状态,输入输出等调用由于使用频繁,默认不输出.
-V 输出strace的版本信息.
-x 以十六进制形式输出非标准字符串
-xx 所有字符串以十六进制形式输出.
-a column
设置返回值的输出位置.默认 为40.
-e expr
指定一个表达式,用来控制如何跟踪.格式如下:
[qualifier=][!]value1[,value2]...
qualifier只能是 trace,abbrev,verbose,raw,signal,read,write其中之一.value是用来限定的符号或数字.默认的 qualifier是 trace.感叹号是否定符号.例如:
-eopen等价于 -e trace=open,表示只跟踪open调用.而-etrace!=open表示跟踪除了open以外的其他调用.有两个特殊的符号 all 和 none.
注意有些shell使用!来执行历史记录里的命令,所以要使用\\.
-e trace=set
只跟踪指定的系统 调用.例如:-e trace=open,close,rean,write表示只跟踪这四个系统调用.默认的为set=all.
-e trace=file
只跟踪有关文件操作的系统调用.
-e trace=process
只跟踪有关进程控制的系统调用.
-e trace=network
跟踪与网络有关的所有系统调用.
-e strace=signal
跟踪所有与系统信号有关的 系统调用
-e trace=ipc
跟踪所有与进程通讯有关的系统调用
-e abbrev=set
设定 strace输出的系统调用的结果集.-v 等与 abbrev=none.默认为abbrev=all.
-e raw=set
将指 定的系统调用的参数以十六进制显示.
-e signal=set
指定跟踪的系统信号.默认为all.如 signal=!SIGIO(或者signal=!io),表示不跟踪SIGIO信号.
-e read=set
输出从指定文件中读出 的数据.例如:
-e read=3,5
-e write=set
输出写入到指定文件中的数据.
-o filename
将strace的输出写入文件filename
-p pid
跟踪指定的进程pid.
-s strsize
指定输出的字符串的最大长度.默认为32.文件名一直全部输出.
-u username
以username 的UID和GID执行被跟踪的命令
3.3 demo
-
一般可以直接stace + 程序,如使用strace跟踪cp命令
c++strace cp \~/.bashrc bashrc execve("/bin/cp", ["cp", "/home/xxxx/.bashrc", "bashrc"], 0x7ffcc7ed9f60 /\* 50 vars \*/) \= 0 -
跟踪特定的系统调用
c++strace -e read cp \~/.bashrc bashrc ..............省略若干行...... read(3, "\\177ELF\\2\\1\\1\\0\\0\\0\\0\\0\\0\\0\\0\\0\\3\\0\>\\0\\1\\0\\0\\0\\20b\\0\\0\\0\\0\\0\\0"..., 832) \= 832 read(3, "\\177ELF\\2\\1\\1\\0\\0\\0\\0\\0\\0\\0\\0\\0\\3\\0\>\\0\\1\\0\\0\\0\\340\\33\\0\\0\\0\\0\\0\\0"..., 832) \= 832 read(3, "\\177ELF\\2\\1\\1\\0\\0\\0\\0\\0\\0\\0\\0\\0\\3\\0\>\\0\\1\\0\\0\\0\\260\\20\\0\\0\\0\\0\\0\\0"..., 832) \= 832 read(3, "\\177ELF\\2\\1\\1\\3\\0\\0\\0\\0\\0\\0\\0\\0\\3\\0\>\\0\\1\\0\\0\\0\\20\\35\\2\\0\\0\\0\\0\\0"..., 832) \= 832 read(3, "\\177ELF\\2\\1\\1\\0\\0\\0\\0\\0\\0\\0\\0\\0\\3\\0\>\\0\\1\\0\\0\\0 \\25\\0\\0\\0\\0\\0\\0"..., 832) \= 832 read(3, "\\177ELF\\2\\1\\1\\0\\0\\0\\0\\0\\0\\0\\0\\0\\3\\0\>\\0\\1\\0\\0\\0P\\16\\0\\0\\0\\0\\0\\0"..., 832) \= 832 read(3, "\\177ELF\\2\\1\\1\\0\\0\\0\\0\\0\\0\\0\\0\\0\\3\\0\>\\0\\1\\0\\0\\0000b\\0\\0\\0\\0\\0\\0"..., 832) \= 832 read(3, "nodev\\tsysfs\\nnodev\\ttmpfs\\nnodev\\tbd"..., 1024) \= 450 read(3, "", 1024) \= 0 read(3, "# \~/.bashrc: executed by bash(1)"..., 131072) \= 3771 read(3, "", 131072) \= 0 +++ exited with 0 +++ -
strace -p pid 跟踪正在执行的程序,可以利用-o输出到指定文件中,然后利用tail 或者tail -f 查看
-
打印系统调用的摘要信息
c++strace -c cp \~/.bashrc bashrc % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 18.22 0.001218 53 23 mmap 16.11 0.001077 72 15 close 15.48 0.001035 65 16 mprotect 9.41 0.000629 52 12 openat 6.97 0.000466 42 11 read 6.76 0.000452 38 12 fstat 4.38 0.000293 29 10 10 access 3.99 0.000267 89 3 stat 2.35 0.000157 79 2 2 statfs 2.21 0.000148 74 2 munmap 2.06 0.000138 46 3 brk 2.03 0.000136 136 1 write 1.99 0.000133 67 2 rt_sigaction 1.06 0.000071 71 1 arch_prctl 1.02 0.000068 68 1 geteuid 1.00 0.000067 67 1 prlimit64 0.99 0.000066 66 1 1 lseek 0.99 0.000066 66 1 rt_sigprocmask 0.99 0.000066 66 1 set_tid_address 0.99 0.000066 66 1 fadvise64 0.99 0.000066 66 1 set_robust_list 0.00 0.000000 0 1 execve ------ ----------- ----------- --------- --------- ---------------- 100.00 0.006685 121 13 total -
SIGSEGV信号,段错误,指针指向的地址无效,访问了不存在的内容或者越界等
- SIGTERM (15): kill
- SIGKILL (9): kill -9 或 kill -KILL