私は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
本当にやってるの?
X86_64では、セグメント化されたアドレス指定は使用されなくなりましたが、特別なオペレーティングシステムのデータ構造にアクセスするために、FS
レジスタとGS
レジスタの両方をベースポインタアドレスとして使用できます。したがって、表示されているのは、FS
レジスタに保持されている値からのオフセットでロードされた値であり、FS
レジスタの内容のビット操作ではありません。
具体的には、LinuxのFS:0x28
が特別なセンチネルスタックガード値を格納しており、コードがスタックガードチェックを実行しているということです。たとえば、コードをさらに調べると、FS:0x28
の値がスタックに格納され、スタックの内容が呼び出され、XOR
が次のように実行されていることがわかります。 FS:0x28
の元の値。 2つの値が等しい場合、つまり、同じ値の2つをXOR
'するとゼロ値になるため、ゼロビットが設定されている場合は、test
ルーチンにジャンプします。それ以外の場合は、スタックが何らかの理由で破損し、スタックに格納されている番兵の値が変更されたことを示す特別な関数にジャンプします。
GCCを使用している場合、 これはで無効にできます
-fno-stack-protector
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.