如何只打印目标文件中函数的二进制代码?
How to just print the binary code of a function in an object file?
我能够像下面这样反汇编目标文件。但我只想将原始数字(如 55、48 等)转储到文件中的特定函数(例如 add4)的二进制格式的指令中。
我可以编写一个程序来解析 otool 的输出。但是有没有更简单的方法呢?
我的 OS 是 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 [=10=]x4, %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 [=10=]x2, %rdi
0000000000000030 48 89 f8 movq %rdi, %rax
0000000000000033 5d popq %rbp
0000000000000034 c3 retq
您可以使用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
您可以使用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”。
上面的输出可以有多个 spaces 和每行末尾的 space ,所以我们先删除它们,因为它会弄乱我们的 sed。
$ objdump -d add.o | grep add4 -A10 | cut -f 2 | grep -v ':' | sed 's/ */ /g' | sed 's/ $//g'
添加 '\x' 部分,首先是中间的 spaces,然后是每行中的第一个十六进制。
$ 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' > add4.bin
printf 之后的最后两个 seds 用于删除出于某种原因保留在 printf 输出中的引号。
Hexdumping 我们得到的文件:
$ 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
我能够像下面这样反汇编目标文件。但我只想将原始数字(如 55、48 等)转储到文件中的特定函数(例如 add4)的二进制格式的指令中。
我可以编写一个程序来解析 otool 的输出。但是有没有更简单的方法呢?
我的 OS 是 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 [=10=]x4, %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 [=10=]x2, %rdi
0000000000000030 48 89 f8 movq %rdi, %rax
0000000000000033 5d popq %rbp
0000000000000034 c3 retq
您可以使用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
您可以使用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”。 上面的输出可以有多个 spaces 和每行末尾的 space ,所以我们先删除它们,因为它会弄乱我们的 sed。
$ objdump -d add.o | grep add4 -A10 | cut -f 2 | grep -v ':' | sed 's/ */ /g' | sed 's/ $//g'
添加 '\x' 部分,首先是中间的 spaces,然后是每行中的第一个十六进制。
$ 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' > add4.bin
printf 之后的最后两个 seds 用于删除出于某种原因保留在 printf 输出中的引号。
Hexdumping 我们得到的文件:
$ 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