在已编译的二进制文件中显示字符串
show strings in compiled binary
假设我有一个简单的 C 程序,我用 gcc -o hello hello.c
:
编译它
#include<stdio.h>
main()
{
printf("hello");
}
现在我想用 strings
实用程序显示 "strings":
$ strings hello
/lib64/ld-linux-x86-64.so.2
__gmon_start__
libc.so.6
printf
__libc_start_main
GLIBC_2.2.5
fffff.
l$ L
t$(L
|[=11=]H
hello
;*3$"
并且,正如预期的那样,我可以在二进制文件中看到字符串 "hello"。
但是,当我修改我的 C
程序并将 "hello" 作为常量时:
#include<stdio.h>
char s[6] = {'h','e','l','l','o','[=12=]' } ;
main()
{
printf("%s\n", s);
}
我在二进制文件中再也看不到字符串 "hello"。
有人可以解释一下为什么吗?
I don't see the string "hello" in the binary anymore.
我认为这种 预期的 有效行为,因为您不再提供文字 "hello"
,而是提供 6 个单独的 char
文字。
来自 man 1 strings
(强调我的):
For each file given, GNU strings prints the printable character
sequences that are at least 4 characters long (or the number given
with the options below) and are followed by an unprintable character.
By default, it only prints the strings from the initialized and
loaded sections of object files; for other types of files, it prints
the strings from the whole file.
C 语言没有将字符串定义为 first-class 公民。它们被表达为字符串数组或字符串文字。例如,在这样的基本程序中:
#include <stdio.h>
int main(void)
{
char s[] = "my string";
printf("%s\n", s);
return 0;
}
我们可以合理地说 s
数组包含一个字符串。请注意,这是在堆栈上分配的。它具有 自动存储持续时间 ,与您问题中的示例相反,其中 s
在 main
(和任何)函数之外明确定义。
现在,回到你的问题,你的两个程序中的基础对象具有相同的特征:
- 它们属于
char[6]
类型并且具有相同的内容 (C11 §6.2.5/p20),
- 它们具有 静态存储持续时间,这意味着它们必须在程序执行之前在概念上进行初始化 (C11 §5.1.2/p1)。
唯一的区别是修改字符串文字会调用未定义的行为,因此编译器可能会选择将它们放入单独的(例如只读)内存位置。
C11 §6.2.5/p20 类型:
An array type describes a contiguously allocated nonempty set of
objects with a particular member object type, called the element type.
C11 §5.1.2/p1 执行环境:
All objects with static storage duration shall be initialized (set to
their initial values) before program startup.
从更实用的角度来看,除了 strings
命令之外,您还可以使用 gdb
调试器分析您的程序,更具体地说,使用 x/s
命令。这是基本说明:
$ gcc -g hello.c -o hello
$ gdb -q hello
Reading symbols from /home/grzegorz/hello...done.
(gdb) disas /m main
Dump of assembler code for function main:
6 {
0x00000000004004c4 <+0>: push %rbp
0x00000000004004c5 <+1>: mov %rsp,%rbp
7 printf("%s\n", s);
0x00000000004004c8 <+4>: mov [=11=]x60086c,%edi
0x00000000004004cd <+9>: callq 0x4003b8 <puts@plt>
8 }
0x00000000004004d2 <+14>: leaveq
0x00000000004004d3 <+15>: retq
End of assembler dump.
(gdb) x/s 0x60086c
0x60086c <s>: "hello"
您可能想比较您程序的 disas
命令的结果,看看它们之间是否存在差异。
假设我有一个简单的 C 程序,我用 gcc -o hello hello.c
:
#include<stdio.h>
main()
{
printf("hello");
}
现在我想用 strings
实用程序显示 "strings":
$ strings hello
/lib64/ld-linux-x86-64.so.2
__gmon_start__
libc.so.6
printf
__libc_start_main
GLIBC_2.2.5
fffff.
l$ L
t$(L
|[=11=]H
hello
;*3$"
并且,正如预期的那样,我可以在二进制文件中看到字符串 "hello"。
但是,当我修改我的 C
程序并将 "hello" 作为常量时:
#include<stdio.h>
char s[6] = {'h','e','l','l','o','[=12=]' } ;
main()
{
printf("%s\n", s);
}
我在二进制文件中再也看不到字符串 "hello"。
有人可以解释一下为什么吗?
I don't see the string "hello" in the binary anymore.
我认为这种 预期的 有效行为,因为您不再提供文字 "hello"
,而是提供 6 个单独的 char
文字。
来自 man 1 strings
(强调我的):
For each file given, GNU strings prints the printable character sequences that are at least 4 characters long (or the number given with the options below) and are followed by an unprintable character. By default, it only prints the strings from the initialized and loaded sections of object files; for other types of files, it prints the strings from the whole file.
C 语言没有将字符串定义为 first-class 公民。它们被表达为字符串数组或字符串文字。例如,在这样的基本程序中:
#include <stdio.h>
int main(void)
{
char s[] = "my string";
printf("%s\n", s);
return 0;
}
我们可以合理地说 s
数组包含一个字符串。请注意,这是在堆栈上分配的。它具有 自动存储持续时间 ,与您问题中的示例相反,其中 s
在 main
(和任何)函数之外明确定义。
现在,回到你的问题,你的两个程序中的基础对象具有相同的特征:
- 它们属于
char[6]
类型并且具有相同的内容 (C11 §6.2.5/p20), - 它们具有 静态存储持续时间,这意味着它们必须在程序执行之前在概念上进行初始化 (C11 §5.1.2/p1)。
唯一的区别是修改字符串文字会调用未定义的行为,因此编译器可能会选择将它们放入单独的(例如只读)内存位置。
C11 §6.2.5/p20 类型:
An array type describes a contiguously allocated nonempty set of objects with a particular member object type, called the element type.
C11 §5.1.2/p1 执行环境:
All objects with static storage duration shall be initialized (set to their initial values) before program startup.
从更实用的角度来看,除了 strings
命令之外,您还可以使用 gdb
调试器分析您的程序,更具体地说,使用 x/s
命令。这是基本说明:
$ gcc -g hello.c -o hello
$ gdb -q hello
Reading symbols from /home/grzegorz/hello...done.
(gdb) disas /m main
Dump of assembler code for function main:
6 {
0x00000000004004c4 <+0>: push %rbp
0x00000000004004c5 <+1>: mov %rsp,%rbp
7 printf("%s\n", s);
0x00000000004004c8 <+4>: mov [=11=]x60086c,%edi
0x00000000004004cd <+9>: callq 0x4003b8 <puts@plt>
8 }
0x00000000004004d2 <+14>: leaveq
0x00000000004004d3 <+15>: retq
End of assembler dump.
(gdb) x/s 0x60086c
0x60086c <s>: "hello"
您可能想比较您程序的 disas
命令的结果,看看它们之间是否存在差异。