5

x86_64 でリンカー スクリプトを使用して、スタックの開始位置を変更しようとしています。これを使用して、実行可能な開始アドレスを移動できました。

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 のリンカ スクリプト チュートリアルからその部分をオンラインで取得したためです。リンカー スクリプトでエラーや警告が表示されないため、何が起こっているのかわかりません。

なぜ誰かがこれを行うのか疑問に思っている場合は、セキュリティ研究に影響があります。

リンカー スクリプトを使用してやりたいことを実行する方法はありますか? .text、.bss、および .data セクションは移動できるが、スタックは移動できないとは信じられません。


更新: http://www.lurklurk.org/linkers/linkers.html#osから取られた説明は、これがリンカで実行できない理由です:

「これまでのオブジェクト ファイルとリンカーに関するすべての説明は、グローバル変数についてのみ説明していることに気付いたかもしれません。前述のローカル変数と動的に割り当てられたメモリについては言及されていません。これらのデータには、リンカーの関与は必要ありません。なぜなら、それらの寿命は、プログラムが実行されているとき、つまりリンカーが業務を終了してからずっと後にしか発生しないからです。」

4

1 に答える 1

5

スタックの開始アドレスを移動できるリンカー スクリプト ディレクティブはありますか?

Linux(使用しているように見える)の場合:いいえ。

ulimit -sLinux 上のスタックの場所は、カーネルと;の現在の値によって決定されます。メインの実行可能ファイルにエンコードされることはありません。

なぜ誰かがこれを行うのか疑問に思っている場合は、セキュリティ研究に影響があります。

スタックの場所を明示的に制御したい場合は、カーネルが行う方法 (および glibc が期待する方法) でスタックをセットアップするカスタムELFローダーを作成し、制御をorに転送する必要があります。mmap()a.outld-linux

Windowsはどうですか?

Windows に触れてから長い時間が経ちましたが、状況は似ていると思います。カーネルがスタックの場所を決定します。

于 2012-12-31T22:12:30.543 に答える