web-dev-qa-db-ja.com

このメモリアドレス%fs:0x28(fs [0x28])がランダムな値を持つのはなぜですか?

私はCコードを書き、それを逆アセンブルし、レジスターを読んで、プログラムがアセンブリーでどのように機能するかを理解しました。

int test(char *this){
    char sum_buf[6];
    strncpy(sum_buf,this,32);
    return 0;
}

私が調べてきたコードの一部は、テスト関数です。出力を逆アセンブルすると、テスト関数が得られます...

   0x00000000004005c0 <+12>:        mov    %fs:0x28,%rax
=> 0x00000000004005c9 <+21>:        mov    %rax,-0x8(%rbp)
... stuff ..
   0x00000000004005f0 <+60>:        xor    %fs:0x28,%rdx
   0x00000000004005f9 <+69>:        je     0x400600 <test+76>
   0x00000000004005fb <+71>:        callq  0x4004a0 <__stack_chk_fail@plt>
   0x0000000000400600 <+76>:        leaveq 
   0x0000000000400601 <+77>:        retq 

私が知りたいのは何ですかmov %fs:0x28,%rax本当にやってるの?

27
Dr.Knowitall

X86_64では、セグメント化されたアドレス指定は使用されなくなりましたが、特別なオペレーティングシステムのデータ構造にアクセスするために、FSレジスタとGSレジスタの両方をベースポインタアドレスとして使用できます。したがって、表示されているのは、FSレジスタに保持されている値からのオフセットでロードされた値であり、FSレジスタの内容のビット操作ではありません。

具体的には、LinuxのFS:0x28が特別なセンチネルスタックガード値を格納しており、コードがスタックガードチェックを実行しているということです。たとえば、コードをさらに調べると、FS:0x28の値がスタックに格納され、スタックの内容が呼び出され、XORが次のように実行されていることがわかります。 FS:0x28の元の値。 2つの値が等しい場合、つまり、同じ値の2つをXOR 'するとゼロ値になるため、ゼロビットが設定されている場合は、testルーチンにジャンプします。それ以外の場合は、スタックが何らかの理由で破損し、スタックに格納されている番兵の値が変更されたことを示す特別な関数にジャンプします。

GCCを使用している場合、 これはで無効にできます

-fno-stack-protector
45
Jason
glibc:
  uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (_dl_random);
# ifdef THREAD_SET_STACK_GUARD
  THREAD_SET_STACK_GUARD (stack_chk_guard); 

the _dl_random from kernel.
0
leesagacious