【问题标题】:How to just print the binary code of a function in an object file?如何在目标文件中打印函数的二进制代码?
【发布时间】:2019-02-19 17:35:07
【问题描述】:

我可以像下面这样反汇编一个目标文件。但我只想将特定函数(例如 add4)的原始数字(如 55、48、...)以二进制格式转储到文件中。

我可以编写一个程序来解析 otool 的输出。但是有没有更简单的方法呢?

我的操作系统是 Mac OS X。

$ cat add.c
long x;
long add2(long num) {
  return num + 2;
}
long add4(long num) {
  return num + 4;
}
$ clang -c -o add.o add.c
$ otool -tvjV add.o 
add.o:
(__TEXT,__text) section
_add4:
0000000000000000    55  pushq   %rbp
0000000000000001    48 89 e5    movq    %rsp, %rbp
0000000000000004    48 89 7d f8     movq    %rdi, -0x8(%rbp)
0000000000000008    48 8b 7d f8     movq    -0x8(%rbp), %rdi
000000000000000c    48 83 c7 04     addq    $0x4, %rdi
0000000000000010    48 89 f8    movq    %rdi, %rax
0000000000000013    5d  popq    %rbp
0000000000000014    c3  retq
0000000000000015    66 2e 0f 1f 84 00 00 00 00 00   nopw    %cs:_add4(%rax,%rax)
000000000000001f    90  nop
_add2:
0000000000000020    55  pushq   %rbp
0000000000000021    48 89 e5    movq    %rsp, %rbp
0000000000000024    48 89 7d f8     movq    %rdi, -0x8(%rbp)
0000000000000028    48 8b 7d f8     movq    -0x8(%rbp), %rdi
000000000000002c    48 83 c7 02     addq    $0x2, %rdi
0000000000000030    48 89 f8    movq    %rdi, %rax
0000000000000033    5d  popq    %rbp
0000000000000034    c3  retq

【问题讨论】:

    标签: macos object disassembly objdump otool


    【解决方案1】:

    您可以使用nm -nU add.o 来获取符号地址。您可以搜索感兴趣的符号并获取其地址和后续地址。这为您提供了符号的开始和(大致)长度。然后,您可以使用任何工具从文件中进行十六进制转储以仅读取该部分。

    例如:

    exec 3< <(nm -nU add.o | grep -A1 -w _add4 | cut -d ' ' -f 1)
    read start <&3
    read end <&3
    3<&-
    offset=$(otool -lV add.o | grep -A3 -w "segname __TEXT" | grep -m1 offset | cut -c 12-)
    if [ -n "$end" ] ; then length_arg="-n $(( "0x$end" - "0x$start" ))" ; fi
    hexdump -C -s $((0x$start + $offset)) $length_arg add.o
    

    【讨论】:

    • 如果符号是最后一个(例如,_add2)怎么办?
    • 嗯,它可能是__TEXT,__text 部分中的最后一个符号,但后续部分中可能还有一个符号。如果读取end 失败,您可以将-n &lt;length&gt; 选项留给hexdump。这将转储到文件的末尾。
    • 没有。 hexdump 只是失败了。这是输出。 $ eval `nm -nU add.o | grep -A1 _add2 | cut -d ' ' -f 1 | \ (read start ; read end ; echo "hexdump -C -s 0x$start -n" $(( "0x$end" - "0x$start" )) add.o )` hexdump: -32: bad length value
    • 我认为结果不正确。结果中的第一个字符是 0xcf。但应该是 55。eval `nm -nU add.o | grep -A1 _add4 | cut -d ' ' -f 1 | \ &gt; (read start ; read end ; echo "hexdump -C -s 0x$start -n" $(( "0x$end" - "0x$start" )) add.o )` 00000000 cf fa ed fe 07 00 00 01 03 00 00 00 01 00 00 00 |................| 00000010 04 00 00 00 b0 01 00 00 00 20 00 00 00 00 00 00 |......... ......| 00000020
    • 嗯。 cf fa ed fe 是 64 位 Mach-O 对象的魔力。你的目标文件是通用的/胖的吗?
    【解决方案2】:

    您可以使用 objdump 然后提取操作码部分。可以按如下方式进行。

    $ objdump -d add.o | grep add4 -A10 | cut -f 2 | grep -v ':'

    grep 的 -v 标志告诉它打印所有不包含冒号的行。

    输出:

        55                   
        48 89 e5             
        48 89 7d f8          
        48 8b 45 f8          
        48 83 c0 04          
        5d                
        c3
    

    -A10 告诉 grep 在匹配后打印 10 行。

    现在要将其输出到文件中,我们首先将操作码格式化为十六进制,例如 '\x45'。 上面的输出可以有多个空格,并且每行末尾都有一个空格,所以我们先删除它们,因为它会弄乱我们的 sed。

    $ objdump -d add.o | grep add4 -A10 | cut -f 2 | grep -v ':' | sed 's/ */ /g' | sed 's/ $//g'

    添加 '\x' 部分,首先是中间的空格,然后是每行中的第一个十六进制。

    $ objdump -d add.o | grep add4 -A10 | cut -f 2 | grep -v ':' | sed 's/ */ /g' | sed 's/ $//g' | sed 's/ /\\x/g' | sed 's/^/\\x/g'

    \x55
    \x48\x89\xe5
    \x48\x89\x7d\xf8
    \x48\x8b\x45\xf8
    \x48\x83\xc0\x04
    \x5d
    \xc3
    

    将其全部折叠成一行并添加引号。

    $ objdump -d add.o | grep add4 -A10 | cut -f 2 | grep -v ':' | sed 's/ */ /g' | sed 's/ $//g' | sed 's/ /\\x/g' | sed 's/^/\\x/g' | tr -d '\n' | sed 's/^/\"/g' | sed 's/$/\"/g'

    "\x55\x48\x89\xe5\x48\x89\x7d\xf8\x48\x8b\x45\xf8\x48\x83\xc0\x04\x5d\xc3"
    

    现在我们得到了一个 C 风格的字符串,我们只需将它传递给 printf,然后将输出重定向到一个文件。

    $ printf $(objdump -d add.o | grep add4 -A10 | cut -f 2 | grep -v ':' | sed 's/ */ /g' | sed 's/ $//g' | sed 's/ /\\x/g' | sed 's/^/\\x/g' | tr -d '\n' | sed 's/^/\"/g' | sed 's/$/\"/g') | sed 's/^\"//g' | sed 's/\"$//g' &gt; add4.bin

    printf 之后的最后两个 sed 用于删除由于某种原因保留在 printf 输出中的引号。

    十六进制转储我们得到的文件:

    $ hexdump -C add4.bin

    00000000  55 48 89 e5 48 89 7d f8  48 8b 45 f8 48 83 c0 04  |UH..H.}.H.E.H...|
    00000010  5d c3                                             |].|
    00000012
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-21
      • 2013-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-03
      • 1970-01-01
      相关资源
      最近更新 更多