Iva*_*hev 5 linker executable elf linker-scripts executable-format
我正在尝试使用 x86_64 上的链接器脚本更改堆栈的起始位置。我能够使用这个移动我的可执行起始地址:
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x200000)); . = SEGMENT_START("text-segment", 0x200000) + SIZEOF_HEADERS;
Run Code Online (Sandbox Code Playgroud)
我像这样改变了我的全局变量:
.data ALIGN(0x10000000) :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
Run Code Online (Sandbox Code Playgroud)
我尝试使用以下内容来移动堆栈区域:
. = 0x50000000;
.stack :
{
stack_start = .;
PROVIDE( stack_start = . );
*(.stack)
. += 0x2000;
stack_end = . ;
PROVIDE( stack_end = . );
}
Run Code Online (Sandbox Code Playgroud)
但这并没有让我去任何地方。
这是我用来测试堆栈位置的测试程序:
#include <stdio.h>
#include <stdlib.h>
int global_var = 555;
void test()
{
int local_test = 666;
printf("address of global_var: %p\n", &global_var);
printf("address of local_test: %p\n", &local_test);
}
int main()
{
int local_main = 5;
printf("address of local_main: %p\n", &local_main);
printf("address of test(): %p\n", &test);
printf("address of main(): %p\n", &main);
test();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这是我从 gcc 的默认链接器脚本(无修改)的输出:
address of local_main: 0x7fffffffe26c <---- I want to move local vars
address of test(): 0x40050c
address of main(): 0x400547
address of global_var: 0x600a10
address of local_test: 0x7fffffffe24c <---- I want to move local vars
Run Code Online (Sandbox Code Playgroud)
这是我的链接器脚本的输出:
address of local_main: 0x7fffffffe26c <--- unchanged
address of test(): 0x2005ac
address of main(): 0x2005e7
address of global_var: 0x10000010
address of local_test: 0x7fffffffe24c <--- unchanged
Run Code Online (Sandbox Code Playgroud)
我真的很困惑,因为 nm 输出新位置:
$ nm -n test.out
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
w _Jv_RegisterClasses
w __gmon_start__
U __libc_start_main@@GLIBC_2.2.5
U printf@@GLIBC_2.2.5
0000000000200460 T _init
00000000002004a0 T _start
00000000002004cc t call_gmon_start
00000000002004f0 t deregister_tm_clones
0000000000200520 t register_tm_clones
0000000000200560 t __do_global_dtors_aux
0000000000200580 t frame_dummy
00000000002005ac T test
00000000002005e7 T main
0000000000200650 T __libc_csu_fini
0000000000200660 T __libc_csu_init
00000000002006ec T _fini
00000000002006f8 R _IO_stdin_used
0000000000200870 r __FRAME_END__
0000000000400878 t __frame_dummy_init_array_entry
0000000000400878 t __init_array_start
0000000000400880 t __do_global_dtors_aux_fini_array_entry
0000000000400880 t __init_array_end
0000000000400888 d __JCR_END__
0000000000400888 d __JCR_LIST__
0000000000400890 d _DYNAMIC
0000000000400a78 d _GLOBAL_OFFSET_TABLE_
0000000010000000 D __data_start
0000000010000000 W data_start
0000000010000008 D __dso_handle
0000000010000010 D global_var
0000000010000018 D __TMC_END__
0000000020000000 A __bss_start
0000000020000000 A _edata
0000000020000000 b completed.6092
0000000050000000 B stack_start
0000000050002000 A _end
0000000050002000 B stack_end
Run Code Online (Sandbox Code Playgroud)
虽然我什至不确定 stack_start 和 stack_end 在 x86_64 上是否有效,因为我从 arm online 的链接器脚本教程中获得了这部分内容。我的链接器脚本没有收到错误或警告,所以我不确定发生了什么。
如果您想知道为什么有人会这样做 - 它对安全研究有影响。
有没有办法使用链接器脚本做我想做的事?我简直不敢相信我可以移动我的 .text、.bss 和 .data 部分,但不能移动堆栈。
更新:以下是从http://www.lurklurk.org/linkers/linkers.html#os 中获取的关于为什么使用链接器不可行的解释:
“你可能已经注意到,到目前为止所有关于目标文件和链接器的讨论都只讨论了全局变量;没有提到前面提到的局部变量和动态分配的内存。这些数据不需要任何链接器参与,因为它们的生命周期仅在程序运行时发生——在链接器完成其业务之后很久。”
是否有允许我移动堆栈起始地址的链接器脚本指令?
在 Linux(您似乎正在使用)上:否。
Linux 上的堆栈位置由内核决定,当前值ulimit -s; 它没有以任何方式编码到主可执行文件中。
如果您想知道为什么有人会这样做 - 它对安全研究有影响。
如果您想明确控制堆栈位置,您必须编写一个自定义ELF加载器,该加载器将mmap()按照内核的方式(以及 glibc 期望的方式设置堆栈)来设置堆栈,然后将控制权转移到a.out或ld-linux。
窗户呢?
我接触 Windows 已经很长时间了,但我相信那里的情况是相似的——内核决定堆栈位置。
| 归档时间: |
|
| 查看次数: |
1435 次 |
| 最近记录: |