64位Linux默认使用小内存模型,它将所有代码和静态数据置于2GB地址限制之下.这可确保您可以使用32位绝对地址.较旧版本的gcc使用静态数组的32位绝对地址,以便为相对地址计算保存额外的指令.但是,这不再有效.如果我尝试在汇编中创建一个32位的绝对地址,我会收到链接器错误:"在创建共享对象时,不能使用".data"重定位R_X86_64_32S;使用-fPIC重新编译".当然,此错误消息具有误导性,因为我没有创建共享对象,-fPIC也没有帮助.到目前为止我发现的是:gcc版本4.8.5对静态数组使用32位绝对地址,gcc版本6.3.0不使用.版本5可能也没有.binutils 2.24中的链接器允许32位绝对地址,而2.28则不允许.
这种变化的后果是必须重新编译旧库并破坏传统汇编代码.
现在我想问一下:这个改变是什么时候做的?它在某处记录了吗?是否有一个链接器选项,使其接受32位绝对地址?
好吧,据我所知ET_EXEC用于表示该文件是可执行文件,而ET_DYN表示该文件是一个共享库。所以可以肯定的是,我用 C 编写了一个简单的程序,但问题是readelf -h产生了以下内容:
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
.
.
.
Run Code Online (Sandbox Code Playgroud)
我认为这与我使用的编译器有关,所以我对/bin 中的一些实用程序做了同样的事情,但不幸的是得到了相同的结果。那么问题来了:为什么 readelf 将可执行文件识别为共享库?
我有一个独立的 Linux 独立 x86_64 hello world 工作岗位:
电源
.text
.global _start
_start:
asm_main_after_prologue:
/* Write */
mov $1, %rax /* syscall number */
mov $1, %rdi /* stdout */
lea msg(%rip), %rsi /* buffer */
mov $len, %rdx /* len */
syscall
/* Exit */
mov $60, %rax /* syscall number */
mov $0, %rdi /* exit status */
syscall
msg:
.ascii "hello\n"
len = . - msg
Run Code Online (Sandbox Code Playgroud)
我可以组装和运行:
as -o main.o main.S
ld -o main.out main.o
./main.out
Run Code Online (Sandbox Code Playgroud)
由于RIP …
首先,我尝试对其进行一些逆向工程:
printf '
#include <stdio.h>
int main() {
puts("hello world");
}
' > main.c
gcc -std=c99 -pie -fpie -ggdb3 -o pie main.c
echo 2 | sudo tee /proc/sys/kernel/randomize_va_space
readelf -s ./pie | grep -E 'main$'
gdb -batch -nh \
-ex 'set disable-randomization off' \
-ex 'start' -ex 'info line' \
-ex 'start' -ex 'info line' \
-ex 'set disable-randomization on' \
-ex 'start' -ex 'info line' \
-ex 'start' -ex 'info line' \
./pie \
;
Run Code Online (Sandbox Code Playgroud)
输出:
64: 000000000000063a 23 …Run Code Online (Sandbox Code Playgroud) 这是一个非常简单的 C++ 程序:
// main.cpp
int main() {}
Run Code Online (Sandbox Code Playgroud)
我Makefile生成以下命令来编译程序。
? make
g++ -O0 -fverbose-asm -o main main.cpp
Run Code Online (Sandbox Code Playgroud)
我检查命令file以查看它是一个 ELF 可执行文件:
? file main
main: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=921d352e49a0e4262aece7e72418290189520782, for GNU/Linux 3.2.0, not stripped
Run Code Online (Sandbox Code Playgroud)
一切似乎都很好,直到我尝试检查 ELF 标头:
? readelf -e main
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
...
Type: DYN …Run Code Online (Sandbox Code Playgroud)