我能够使用这个移动我的可执行起始地址:
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x200000)); . = SEGMENT_START("text-segment", 0x200000) + SIZEOF_HEADERS;
我改变了我的全局变量:
.data ALIGN(0x10000000) : { *(.data .data.* .gnu.linkonce.d.*) SORT(CONSTRUCTORS) }
我试图使用以下内容来移动堆栈区域:
. = 0x50000000; .stack : { stack_start = .; PROVIDE( stack_start = . ); *(.stack) . += 0x2000; stack_end = . ; PROVIDE( stack_end = . ); }
但那并没有把我带到任何地方.
这是我用来测试堆栈位置的测试程序:
#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; }
这是我从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
这是我的链接器脚本的输出:
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
我很困惑,因为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
虽然我甚至不确定stack_start和stack_end在x86_64上是否有效,因为我从arm online的链接器脚本教程中得到了这一部分.我的链接器脚本没有错误或警告,所以我不确定发生了什么.
如果你想知道为什么会这样做 – 它对安全研究有影响.
有没有办法用链接器脚本做我想做的事情?我简直无法相信我可以移动我的.text,.bss和.data部分,但不能移动堆栈.
更新:以下是从http://www.lurklurk.org/linkers/linkers.html#os开始解释为什么链接器无法实现的原因:
“You may have noticed that all of the discussion of object files and
linkers so far has only talked about global variables; there’s been no
mention of the local variables and dynamically allocated memory
mentioned earlier.These pieces of data don’t need any linker
involvement, because their lifetime only occurs when the program is
running—long after the linker has finished its business.”
Is there a linker script directive that allows me to move my stack start address?
在Linux上(您似乎正在使用):没有.
Linux上的堆栈位置由内核和ulimit -s的当前值决定;它不以任何方式编码到主可执行文件中.
In case you are wondering why would anyone do this – it has implications for security research.
如果你想显式地控制堆栈位置,你必须编写一个自定义的ELF加载器,它将mmap()并按照内核的方式设置堆栈(以及glibc期望它设置的方式),然后将控制转移到.out或ld-linux.
What about Windows?
自从我触及Windows以来已经很长时间了,但我相信那里的情况类似 – 内核决定了堆栈的位置.