反汇编objdump和strace学习

反汇编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 -9kill -KILL
相关推荐
知识分享小能手11 小时前
MongoDB入门学习教程,从入门到精通,MongoDB分片配置完全指南(15)
数据库·学习·mongodb
23.12 小时前
【Linux】grep -F 及 双横线--的妙用
linux·命令模式
橙露12 小时前
Linux 驱动入门:字符设备驱动框架与编写流程
linux·运维·服务器
Dyanic12 小时前
AMSFusion:一种基于注意力机制的自适应多尺度红外与可见光图像融合网络
图像处理·人工智能·学习
少许极端12 小时前
算法奇妙屋(四十三)-贪心算法学习之路10
学习·算法·贪心算法
hong16168812 小时前
TypeScript类型断言
linux·javascript·typescript
南境十里·墨染春水13 小时前
Linux学习进展 进程管理命令 及文件压缩解压
linux·运维·笔记·学习
航Hang*13 小时前
第2章:进阶Linux系统——第4节:配置与管理NFS服务器
linux·运维·服务器·笔记·学习·vmware
橘子编程13 小时前
操作系统原理:从入门到精通全解析
java·linux·开发语言·windows·计算机网络·面试
ZhiqianXia13 小时前
Pytorch 学习笔记(8): PyTorch FX
pytorch·笔记·学习