反汇编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
相关推荐
朱一头zcy1 小时前
[Win11家庭中文版]如何关闭基于虚拟化的安全性VBS(为了解决VBS启用状态下 VMware性能很差 频繁闪退或有各种不一样的崩溃报错)
linux·经验分享·vbs
xlp666hub1 小时前
【Linux驱动实战】:带参数的内核模块
linux·c
Shining05961 小时前
前沿模型系列(三)《检索增强的语言模型》
人工智能·学习·其他·语言模型·自然语言处理·大模型·rag
芥子沫1 小时前
Linux下编程有什么优势?
linux·运维·服务器
QYQ_11272 小时前
嵌入式学习——51单片机(下)
嵌入式硬件·学习·51单片机
REDcker2 小时前
Linux systemd发展演进与实战指南
linux·运维·服务器
白太岁2 小时前
Linux 进程调度模块
linux·运维·服务器
17(无规则自律)2 小时前
【Linux驱动实战】:最简单的内核模块
linux·c语言·驱动开发·嵌入式硬件
听忆.2 小时前
系统集成项目管理(中项随笔-现代化基础设施)
经验分享