How to disassemble one single function using objdump?
我的系统上安装了二进制文件,并希望查看给定功能的反汇编。 最好使用
从这些问题中,我了解到,如果我只知道边界地址,则可以分解一部分代码。 从这个答案中,我学到了如何将拆分的调试符号转换回一个文件。
但是即使对单个文件进行操作,甚至反汇编所有代码(即没有开始或停止地址,但对
查看调试部分的详细信息,我发现
我建议使用gdb作为最简单的方法。您甚至可以单线完成它,例如:
1 | gdb -batch -ex 'file /bin/ls' -ex 'disassemble main' |
gdb
使用这种格式,它实际上非常接近
1 | gdb -batch -ex"disassemble/rs $FUNCTION""$EXECUTABLE" |
main.c
1 2 3 4 5 6 7 8 9 10 11 12 13 | #include int myfunc(int i) { i = i + 2; i = i * 2; return i; } int main(void) { assert(myfunc(1) == 6); assert(myfunc(2) == 8); return 0; } |
编译和反汇编
1 2 | gcc -O0 -ggdb3 -std=c99 -Wall -Wextra -pedantic -o main.out main.c gdb -batch -ex"disassemble/rs myfunc" main.out |
拆卸:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | Dump of assembler code for function myfunc: main.c: 3 int myfunc(int i) { 0x0000000000001135 <+0>: 55 push %rbp 0x0000000000001136 <+1>: 48 89 e5 mov %rsp,%rbp 0x0000000000001139 <+4>: 89 7d fc mov %edi,-0x4(%rbp) 4 i = i + 2; 0x000000000000113c <+7>: 83 45 fc 02 addl $0x2,-0x4(%rbp) 5 i = i * 2; 0x0000000000001140 <+11>: d1 65 fc shll -0x4(%rbp) 6 return i; 0x0000000000001143 <+14>: 8b 45 fc mov -0x4(%rbp),%eax 7 } 0x0000000000001146 <+17>: 5d pop %rbp 0x0000000000001147 <+18>: c3 retq End of assembler dump. |
已在Ubuntu 16.04,GDB 7.11.1上测试。
objdump + AWK解决方法
如以下所述打印段落:https://unix.stackexchange.com/questions/82944/how-to-grep-for-text-in-a-file-and-display-the-paragraph-that-has-the -文本
1 | objdump -d main.out | awk -v RS= '/^[[:xdigit:]]+ <FUNCTION>/' |
例如。:
1 | objdump -d main.out | awk -v RS= '/^[[:xdigit:]]+ <myfunc>/' |
给出:
1 2 3 4 5 6 7 8 9 | 0000000000001135 <myfunc>: 1135: 55 push %rbp 1136: 48 89 e5 mov %rsp,%rbp 1139: 89 7d fc mov %edi,-0x4(%rbp) 113c: 83 45 fc 02 addl $0x2,-0x4(%rbp) 1140: d1 65 fc shll -0x4(%rbp) 1143: 8b 45 fc mov -0x4(%rbp),%eax 1146: 5d pop %rbp 1147: c3 retq |
使用
1 | objdump -S main.out | awk '/^[[:xdigit:]]+ <FUNCTION>:$/{flag=1;next}/^[[:xdigit:]]+ <.*>:$/{flag=0}flag' |
改编自:如何在两个标记模式之间选择可能会用awk / sed多次出现的线条
邮件列表回复
邮件列表上有一个2010线程,它表明不可能:https://sourceware.org/ml/binutils/2010-04/msg00445.html
除了Tom提出的
Nicolas Clifton给了它WONTFIX https://sourceware.org/ml/binutils/2015-07/msg00004.html,可能是因为GDB解决方法涵盖了该用例。
使用Objdump反汇编一个函数
我有两种解决方案:
1.基于命令行
此方法非常有效,而且非常短。我将objdump与-d选项一起使用,并将其通过管道传输到awk。反汇编的输出看起来像
1 2 3 4 | 000000000000068a <main>: 68a: 55 push %rbp 68b: 48 89 e5 mov %rsp,%rbp 68e: 48 83 ec 20 sub $0x20,%rsp |
节或函数用空行分隔。因此,将FS(字段分隔符)更改为换行符,将RS(记录分隔符)更改为两次换行符,可以轻松搜索建议的功能,因为只需在$ 1字段中查找!
1 2 3 4 | objdump -d name_of_your_obj_file | awk -F" " -v RS=" " '$1 ~ /main/' |
当然,您可以将main替??换为要输出的任何功能。
2. Bash脚本
我为此问题编写了一个小的bash脚本。只需将其复制并保存为dasm文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #!/bin/bash # Author: abu # Description: puts disassembled objectfile to std-out if [ $# = 2 ]; then sstrg="^[[:xdigit:]]{2,}+.*<$2>:$" objdump -d $1 | awk -F" " -v RS=" " '$1 ~ /'"$sstrg"'/' elif [ $# = 1 ]; then objdump -d $1 | awk -F" " -v RS=" " '{ print $1 }' else echo"You have to add argument(s)" echo"Usage: "$0" arg1 arg2" echo"Description: print disassembled label to std-out" echo" arg1: name of object file" echo" arg2: name of function to be disassembled" echo" "$0" arg1 ... print labels and their rel. addresses" fi |
更改x-access并通过以下方式调用:
1 2 | chmod +x dasm ./dasm test main |
这比使用脚本调用gdb快得多。另外,使用objdump不会将库加载到内存中,因此更安全!
Vitaly Fadeev为此脚本编写了自动补全功能,这确实是一个不错的功能,可以加快键入速度。
脚本可以在这里找到。
就像gdb解决方案一样工作(因为它将偏移量移向零),除了它没有延迟(在我的PC上大约5毫秒完成工作,而gdb解决方案大约需要150毫秒):
objdump_func:
1 2 3 4 5 6 7 8 | #!/bin/sh # $1 -- function name; rest -- object files fn=$1; shift 1 exec objdump -d"$@" | awk" /^[[:xdigit:]].*<$fn>/,/^\$/ { print \$0 }" | awk -F: -F' ' 'NR==1 { offset=strtonum("0x"$1); print $0; } NR!=1 { split($0,a,":"); rhs=a[2]; n=strtonum("0x"$1); $1=sprintf("%x", n-offset); printf"%4s:%s ", $1,rhs }' |
此解决方案的完整符号名称(D lang版本):
-
通过键入
dasm test ,然后按TabTab,您将获得所有功能的列表。 -
通过键入
dasm test m ,然后按TabTab,将显示以m开头的所有功能,或者如果仅存在一个功能,则该功能将自动完成。
文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # bash completion for dasm _dasm() { local cur=${COMP_WORDS[COMP_CWORD]} if [[ $COMP_CWORD -eq 1 ]] ; then # files COMPREPLY=( $( command ls *.o -F 2>/dev/null | grep"^$cur" ) ) elif [[ $COMP_CWORD -eq 2 ]] ; then # functions OBJFILE=${COMP_WORDS[COMP_CWORD-1]} COMPREPLY=( $( command nm --demangle=dlang $OBJFILE | grep" W" | cut -d"" -f 3 | tr"()"" " | grep"$cur" ) ) else COMPREPLY=($(compgen -W"" --"$cur")); fi } complete -F _dasm dasm |
为了简化awk相对于其他答案来解析objdump输出的用法:
1 | objdump -d filename | sed '/<functionName>:/,/^$/!d' |