Luk*_*ith 22 c gcc shared-libraries static-libraries
我有一个正在建设的图书馆.当我运行以下任何一个时,我的所有对象都会连续编译和链接:
ar rcs lib/libryftts.a $^
gcc -shared $^ -o lib/libryftts.so
在我的Makefile中.我也能够成功安装它们/usr/local/lib
当我用nm测试文件时,所有的功能都在那里.我的问题是,当我跑步gcc testing/test.c -lryftts -o test && file ./test
或gcc testing/test.c lib/libryftts.a -o test && file ./test
它说:
test: ELF 64-bit LSB shared object
而不是test: ELF 64-bit LSB executable
像我期望的那样.我究竟做错了什么?
Emp*_*ian 30
我究竟做错了什么?
没有.
听起来您的GCC -pie
默认配置为构建二进制文件.这些二进制文件实际上是共享库(类型ET_DYN
),除了它们像普通可执行文件一样运行.
所以你应该运行你的二进制文件,并且(如果它有效)不用担心它.
或者您可以链接您的二进制文件,gcc -no-pie ...
并且应该生成PIE
类型的不可执行文件ET_EXEC
,对此file
将说明ELF 64-bit LSB executable
.
file
5.36清楚地说
file
如果可执行文件是否为PIE,则5.36实际上会清晰地打印出来,如下所示:https : //unix.stackexchange.com/questions/89211/how-to-test-whether-a-linux-binary-was-compiled-as-位置无关代码/ 435038#435038
例如,PIE可执行文件显示为:
main.out:ELF 64位LSB Pie可执行文件,x86-64,版本1(SYSV),动态链接,未剥离
非PIE则为:
main.out:ELF 64位LSB可执行文件,x86-64,版本1(SYSV),静态链接,未剥离
该功能是在5.33中引入的,但仅进行了简单的chmod +x
检查。在此之前,它只是shared object
为PIE 打印。
在5.34中,本来打算开始检查更专业的DF_1_PIE
ELF元数据,但是由于在提交9109a696f3289ba00eaa222fd432755ec4287e28的实现中存在错误,它实际上使事情变得混乱,并将GCC PIE可执行文件显示为shared objects
。
该错误已在5.36 修订为03084b161cf888b5286dbbcd964c31ccad4f64d9。
该错误特别存在于具有file
5.34的Ubuntu 18.10中。
ld -pie
由于巧合,在链接汇编代码时它不会显示出来。
源代码细分显示在file
此答案的“ 5.36源代码分析”部分。
Linux内核5.0根据以下信息确定是否可以使用ASLR: ET_DYN
file
“混乱” 的根本原因是PIE可执行文件和共享库都是位置无关的,可以放置在随机存储位置中。
在fs / binfmt_elf.c,内核仅接受这两种类型的ELF文件:
/* First of all, some simple consistency checks */
if (interp_elf_ex->e_type != ET_EXEC &&
interp_elf_ex->e_type != ET_DYN)
goto out;
Run Code Online (Sandbox Code Playgroud)
然后,仅将for ET_DYN
设置load_bias
为不为零的值。该load_bias
是那么什么决定了ELF偏移:如何在Linux中确定的PIE可执行文件的文本部分的地址?
/*
* If we are loading ET_EXEC or we have already performed
* the ET_DYN load_addr calculations, proceed normally.
*/
if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) {
elf_flags |= elf_fixed;
} else if (loc->elf_ex.e_type == ET_DYN) {
/*
* This logic is run once for the first LOAD Program
* Header for ET_DYN binaries to calculate the
* randomization (load_bias) for all the LOAD
* Program Headers, and to calculate the entire
* size of the ELF mapping (total_size). (Note that
* load_addr_set is set to true later once the
* initial mapping is performed.)
*
* There are effectively two types of ET_DYN
* binaries: programs (i.e. PIE: ET_DYN with INTERP)
* and loaders (ET_DYN without INTERP, since they
* _are_ the ELF interpreter). The loaders must
* be loaded away from programs since the program
* may otherwise collide with the loader (especially
* for ET_EXEC which does not have a randomized
* position). For example to handle invocations of
* "./ld.so someprog" to test out a new version of
* the loader, the subsequent program that the
* loader loads must avoid the loader itself, so
* they cannot share the same load range. Sufficient
* room for the brk must be allocated with the
* loader as well, since brk must be available with
* the loader.
*
* Therefore, programs are loaded offset from
* ELF_ET_DYN_BASE and loaders are loaded into the
* independently randomized mmap region (0 load_bias
* without MAP_FIXED).
*/
if (elf_interpreter) {
load_bias = ELF_ET_DYN_BASE;
if (current->flags & PF_RANDOMIZE)
load_bias += arch_mmap_rnd();
elf_flags |= elf_fixed;
} else
load_bias = 0;
Run Code Online (Sandbox Code Playgroud)
我通过以下实验进行了确认:对于gcc和ld中与位置无关的可执行文件,-fPIE选项是什么?
file
5.36行为细分
file
从源头研究了工作原理之后。我们将得出以下结论:
Elf32_Ehdr.e_type == ET_EXEC
executable
Elf32_Ehdr.e_type == ET_DYN
DT_FLAGS_1
存在动态部分条目
DF_1_PIE
在中设置DT_FLAGS_1
:
pie executable
shared object
pie executable
shared object
以下是一些实验可以证实这一点:
Executable generation ELF type DT_FLAGS_1 DF_1_PIE chdmod +x file 5.36
--------------------------- -------- ---------- -------- -------------- --------------
gcc -fpie -pie ET_DYN y y y pie executable
gcc -fno-pie -no-pie ET_EXEC n n y executable
gcc -shared ET_DYN n n y pie executable
gcc -shared ET_DYN n n n shared object
ld ET_EXEC n n y executable
ld -pie --dynamic-linker ET_DYN y y y pie executable
ld -pie --no-dynamic-linker ET_DYN y y y pie executable
Run Code Online (Sandbox Code Playgroud)
已在Ubuntu 18.10,GCC 8.2.0,Binutils 2.31.1中进行了测试。
每种实验的完整测试示例在以下位置描述:
gcc -pie
和gcc -no-pie
:gcc和ld中与位置无关的可执行文件的-fPIE选项是什么?
请记住,-pie
自Ubuntu 17.10起,默认情况下已启用该功能,相关信息:x86-64 Linux中不再允许使用32位绝对地址?
gcc -shared
(.so
共享库):https : //github.com/cirosantilli/cpp-cheat/tree/b80ccb4a842db52d719a16d3716b02b684ebbf11/shared_library/basic
ld
实验:如何在Linux中创建静态链接的位置无关可执行ELF?ELF type
和DF_1_PIE
分别通过以下方式确定:
readelf --file-header main.out | grep Type
readelf --dynamic main.out | grep FLAGS_1
Run Code Online (Sandbox Code Playgroud)
file
5.36源代码分析
要分析的密钥文件是magic / Magdir / elf。
这种不可思议的格式仅取决于固定位置的字节值来确定文件类型。
格式本身记录在:
man 5 magic
Run Code Online (Sandbox Code Playgroud)
因此,在这一点上,您将需要准备以下文件:
在文件末尾,我们看到:
0 string \177ELF ELF
!:strength *2
>4 byte 0 invalid class
>4 byte 1 32-bit
>4 byte 2 64-bit
>5 byte 0 invalid byte order
>5 byte 1 LSB
>>0 use elf-le
>5 byte 2 MSB
>>0 use \^elf-le
Run Code Online (Sandbox Code Playgroud)
\177ELF
是每个ELF文件开头的4个魔术字节。\177
是的八进制0x7F
。
然后,通过与Elf32_Ehdr
标准中的结构进行比较,我们看到字节4(第5个字节,魔术标识符之后的第一个字节)确定ELF类:
e_ident[EI_CLASSELFCLASS]
Run Code Online (Sandbox Code Playgroud)
其一些可能的值为:
ELFCLASS32 1
ELFCLASS64 2
Run Code Online (Sandbox Code Playgroud)
在file
源代码中,我们有:
1 32-bit
2 64-bit
Run Code Online (Sandbox Code Playgroud)
和32-bit
和64-bit
是字符串file
输出到标准输出!
因此,现在我们shared object
在该文件中搜索,然后导致:
0 name elf-le
>16 leshort 0 no file type,
!:mime application/octet-stream
>16 leshort 1 relocatable,
!:mime application/x-object
>16 leshort 2 executable,
!:mime application/x-executable
>16 leshort 3 ${x?pie executable:shared object},
Run Code Online (Sandbox Code Playgroud)
因此,这elf-le
是一种标识符,已包含在代码的前一部分中。
字节16正是ELF类型:
Elf32_Ehdr.e_type
Run Code Online (Sandbox Code Playgroud)
其某些值是:
ET_EXEC 2
ET_DYN 3
Run Code Online (Sandbox Code Playgroud)
因此,ET_EXEC
总是打印为executable
。
ET_DYN
但是有两种可能性,具体取决于${x
:
pie executable
shared object
${x
问:文件是否可以由用户,组或其他人执行?如果是,请显示pie executable
,否则shared object
。
此扩展是在的varexpand
函数中完成的src/softmagic.c
:
static int
varexpand(struct magic_set *ms, char *buf, size_t len, const char *str)
{
[...]
case 'x':
if (ms->mode & 0111) {
ptr = t;
l = et - t;
} else {
ptr = e;
l = ee - e;
}
break;
Run Code Online (Sandbox Code Playgroud)
但是,还有另外一种技巧!在src/readelf.c
function中dodynamic
,如果存在DT_FLAGS_1
动态节(PT_DYNAMIC
)的标志条目,则st->mode
存在或不存在DF_1_PIE
标志将覆盖其中的权限:
case DT_FLAGS_1:
if (xdh_val & DF_1_PIE)
ms->mode |= 0111;
else
ms->mode &= ~0111;
break;
Run Code Online (Sandbox Code Playgroud)
5.34中的错误是初始代码编写为:
if (xdh_val == DF_1_PIE)
Run Code Online (Sandbox Code Playgroud)
这意味着,如果设置了另一个标志(默认情况下GCC会这样做),则可DF_1_NOW
执行文件显示为shared object
。
该DT_FLAGS_1
标志条目不会在ELF标准描述所以它必须是一个Binutils的扩展。
该标志在Linux内核5.0或glibc 2.27中没有任何用处,因此我似乎只是在提供信息,以指示文件是否为PIE。
归档时间: |
|
查看次数: |
10680 次 |
最近记录: |