Cir*_*四事件 4 linux glibc linux-kernel aslr position-independent-code
首先,我尝试对其进行一些逆向工程:
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 FUNC GLOBAL DEFAULT 14 main
Temporary breakpoint 1, main () at main.c:4
4 puts("hello world");
Line 4 of "main.c" starts at address 0x5575f5fd263e <main+4> and ends at 0x5575f5fd264f <main+21>.
Temporary breakpoint 2 at 0x5575f5fd263e: file main.c, line 4.
Temporary breakpoint 2, main () at main.c:4
4 puts("hello world");
Line 4 of "main.c" starts at address 0x55e3fbc9363e <main+4> and ends at 0x55e3fbc9364f <main+21>.
Temporary breakpoint 3 at 0x55e3fbc9363e: file main.c, line 4.
Temporary breakpoint 3, main () at main.c:4
4 puts("hello world");
Line 4 of "main.c" starts at address 0x55555555463e <main+4> and ends at 0x55555555464f <main+21>.
Temporary breakpoint 4 at 0x55555555463e: file main.c, line 4.
Temporary breakpoint 4, main () at main.c:4
4 puts("hello world");
Line 4 of "main.c" starts at address 0x55555555463e <main+4> and ends at 0x55555555464f <main+21>.
Run Code Online (Sandbox Code Playgroud)
这表明它是0x555555554000+ 随机偏移 + 63e。
但后来我尝试 grep Linux 内核和 glibc 源代码555555554,但没有成功。
哪个代码的哪一部分计算该地址?
我在回答时遇到了这个问题:gcc 和 ld 中与位置无关的可执行文件的 -fPIE 选项是什么?
0x555555554000 的一些互联网搜索给出了提示:ThreadSanitizer 存在问题https://github.com/google/sanitizers/wiki/ThreadSanitizerCppManual
问:当我运行程序时,它说:致命:ThreadSanitizer 无法映射影子内存(某些内容已映射到 0x555555554000 < 0x7cf000000000)。该怎么办?您需要启用 ASLR:
Run Code Online (Sandbox Code Playgroud)$ echo 2 >/proc/sys/kernel/randomize_va_space这可能会在未来的内核中修复,请参阅https://bugzilla.kernel.org/show_bug.cgi?id=66721 ...
Run Code Online (Sandbox Code Playgroud)$ gdb -ex 'set disable-randomization off' --args ./a.out
和https://lwn.net/Articles/730120/ “稳定的内核更新”。由 hmh(订阅者)于 2017 年 8 月 7 日 20:40 UTC(星期一)发布https://marc.info/?t=150213704600001&r=1&w=2 ( https://patchwork.kernel.org/patch/9886105/,提交c715b72c1ba4 )
将 x86_64 和 arm64 PIE 基础从 0x555555554000 移动到 0x000100000000 破坏了 AddressSanitizer。这是对以下内容的部分还原:
- 提交eab09532d400( “binfmt_elf:使用ELF_ET_DYN_BASE只为PIE”)(https://patchwork.kernel.org/patch/9807325/ https://lkml.org/lkml/2017/6/21/560)
- 提交 02445990a96e(“arm64:将 ELF_ET_DYN_BASE 移动到 4GB/4MB”)(https://patchwork.kernel.org/patch/9807319/)
恢复的代码是:
Run Code Online (Sandbox Code Playgroud)b/arch/arm64/include/asm/elf.h /* * This is the base location for PIE (ET_DYN with INTERP) loads. On - * 64-bit, this is raised to 4GB to leave the entire 32-bit address + * 64-bit, this is above 4GB to leave the entire 32-bit address * space open for things that want to use the area for 32-bit pointers. */ -#define ELF_ET_DYN_BASE 0x100000000UL +#define ELF_ET_DYN_BASE (2 * TASK_SIZE_64 / 3) +++ b/arch/x86/include/asm/elf.h /* * This is the base location for PIE (ET_DYN with INTERP) loads. On - * 64-bit, this is raised to 4GB to leave the entire 32-bit address + * 64-bit, this is above 4GB to leave the entire 32-bit address * space open for things that want to use the area for 32-bit pointers. */ #define ELF_ET_DYN_BASE (mmap_is_ia32() ? 0x000400000UL : \ - 0x100000000UL) + (TASK_SIZE / 3 * 2))
因此,0x555555554000 与ELF_ET_DYN_BASE宏(在fs/binfmt_elf.c 中ET_DYNload_bias引用为as not random)有关,对于 x86_64 和 arm64,它就像 TASK_SIZE 的 2/3。如果没有CONFIG_X86_32,x86_64 的 TASK_SIZE 为2^47 - 一页arch/x86/include/asm/processor.h
/*
* User space process size. 47bits minus one guard page. The guard
* page is necessary on Intel CPUs: if a SYSCALL instruction is at
* the highest possible canonical userspace address, then that
* syscall will enter the kernel with a non-canonical return
* address, and SYSRET will explode dangerously. We avoid this
* particular problem by preventing anything from being mapped
* at the maximum canonical address.
*/
#define TASK_SIZE_MAX ((1UL << 47) - PAGE_SIZE)
Run Code Online (Sandbox Code Playgroud)
旧版本:
/*
* User space process size. 47bits minus one guard page.
*/
#define TASK_SIZE_MAX ((1UL << 47) - PAGE_SIZE)
Run Code Online (Sandbox Code Playgroud)
新版本也有支持的5level与__VIRTUAL_MASK_SHIFT56位的- v4.17/source/arch/x86/include/asm/processor.h(但不想使用它的用户启用之前+提交b569bab78d8d“..不是所有的用户空间已经准备好处理宽地址”) )。
因此,0x555555554000load_bias = ELF_PAGESTART(load_bias - vaddr);从公式(2^47-1page)*(2/3)(或 2^56 对于较大系统)向下舍入(由,vaddr 为零):
$ echo 'obase=16; (2^47-4096)/3*2'| bc -q
555555554AAA
$ echo 'obase=16; (2^56-4096)/3*2'| bc -q
AAAAAAAAAAA000
Run Code Online (Sandbox Code Playgroud)
2/3 * TASK_SIZE 的一些历史记录:
commit 9b1bbf6ea9b2 "use ELF_ET_DYN_BASE only for PIE"有有用的评论:" ELF_ET_DYN_BASE 位置最初是为了让加载程序远离 ET_EXEC 二进制文件...... "
不要用 2*TASK_SIZE 溢出 32 位“[uml-user] [PATCH] x86,UML:修复 ELF_ET_DYN_BASE 中的整数溢出”,2015 年和“ARM:8320/1:修复 ELF_ET_DYN_BASE 中的整数溢出”,2015 年:
几乎所有的拱门都将 ELF_ET_DYN_BASE 定义为 TASK_SIZE 的 2/3。尽管似乎有些架构以错误的方式做到了这一点。问题是 2*TASK_SIZE 可能会溢出 32 位,因此真正的 ELF_ET_DYN_BASE 会出错。通过在乘法之前除以 TASK_SIZE 来修复此溢出:
(TASK_SIZE / 3 * 2)
Run Code Online (Sandbox Code Playgroud)diff --git a/include/asm-i386/elf.h b/include/asm-i386/elf.h +/* This is the location that an ET_DYN program is loaded if exec'ed. Typical + use of this is to invoke "./ld.so someprog" to test out a new version of + the loader. We need to make sure that it is out of the way of the program + that it will "exec", and that there is sufficient room for the brk. */ + +#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3)
| 归档时间: |
|
| 查看次数: |
1427 次 |
| 最近记录: |