2

ここに C 関数を記述しました (バッファ オーバーフローの脆弱性があります)。

void func(char *str)
{
   char buffer[12];
   int a=9;
   strcpy(buffer,str);
}

gdb でのアセンブリは次のように変換されます

|0x4005b4 <func>         push   %rbp
|0x4005b5 <func+1>       mov    %rsp,%rbp
|0x4005b8 <func+4>       sub    $0x40,%rsp
|0x4005bc <func+8>       mov    %rdi,-0x38(%rbp)
|0x4005c0 <func+12>      mov    %fs:0x28,%rax
|0x4005c9 <func+21>      mov    %rax,-0x8(%rbp)
|0x4005cd <func+25>      xor    %eax,%eax
|0x4005cf <func+27>      movl   $0x9,-0x24(%rbp)
|0x4005d6 <func+34>      mov    -0x38(%rbp),%rdx
|0x4005da <func+38>      lea    -0x20(%rbp),%rax
|0x4005de <func+42>      mov    %rdx,%rsi
|0x4005e1 <func+45>      mov    %rax,%rdi
|0x4005e4 <func+48>      callq  0x400490 <strcpy@plt>
|0x4005e9 <func+53>      mov    -0x8(%rbp),%rax
|0x4005ed <func+57>      xor    %fs:0x28,%rax
|0x4005f6 <func+66>      je     0x4005fd <func+73>
|0x4005f8 <func+68>      callq  0x4004a0 <__stack_chk_fail@plt>
|0x4005fd <func+73>      leaveq
|0x4005fe <func+74>      retq

rdi関数に渡された元の文字配列のアドレスが含まれます。

1.func+8では、この rdi 値を -0x38(rbp) に移動して、関数のローカル変数 str に値を保存していますか、それとも他の意味がありますか?

2. での指導は何をfunc+8達成しますか? の内容を表示するためにgdbまたはLinuxにとにかくありfs segmentますか?

3.指示は何func+12func+25しますか?

編集:これをgcc 4.6.3で-O0でコンパイルしました

4

3 に答える 3

2

fs セグメントに関するあなたの質問に対する答えは、スタック カナリアのようです。コメントとともに、それを非常によく説明しているように見えるブログを見つけました。

http://xorl.wordpress.com/2010/10/14/linux-glibc-stack-canary-values/

于 2013-09-23T19:40:52.637 に答える
2

func+8%rdiはで上書きされるため、パラメータ値を一時変数に保存していますfunc+45。コンパイラは別の方法で処理できたかもしれませんが、この状況ではそれが選択されたと思います。

セグメントの内容を調べる方法を覚えていませんfsが、スタックに置く既知のカナリア値を読み取っていると思われます。正確にはわかりませんが、値が後でチェックされ、同じでない場合はエラーハンドラーが呼び出されることを考えると、スタック保護を設定しているようfunc+12に見えます:func+25

|0x4005e9 <func+53>      mov    -0x8(%rbp),%rax  <-- loads the value on the stack
|0x4005ed <func+57>      xor    %fs:0x28,%rax    <-- compare with original
|0x4005f6 <func+66>      je     0x4005fd <func+73>     <-- if they are different
|0x4005f8 <func+68>      callq  0x4004a0 <__stack_chk_fail@plt> <-- call this
于 2013-09-23T18:03:48.293 に答える
1

これは、上の質問 #3 のごく一部に答えるだけですが、xor %eax %eaxeax はクリアします。

私は x86 をあまり扱っていないので、プリアンブルがそこで何をしているのかを正確に伝えることはできませんが、通常、objdump は gdb よりも優れた逆アセンブルを提供します。

 $ objdump -dS func.o

Disassembly of section .text:

0000000000000000 <func>:
#include <string.h>

void func(char *str)
{
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   48 83 ec 20             sub    $0x20,%rsp
   8:   48 89 7d e8             mov    %rdi,-0x18(%rbp)
    char buffer[12];
    int a=9;
   c:   c7 45 fc 09 00 00 00    movl   $0x9,-0x4(%rbp)
    strcpy(buffer, str);
  13:   48 8b 55 e8             mov    -0x18(%rbp),%rdx
  17:   48 8d 45 f0             lea    -0x10(%rbp),%rax
  1b:   48 89 d6                mov    %rdx,%rsi
  1e:   48 89 c7                mov    %rax,%rdi
  21:   e8 00 00 00 00          callq  26 <func+0x26>
}
  26:   c9                      leaveq 
  27:   c3                      retq   

少なくとも、コンパイラが何をしていると考えているかがわかります。

于 2013-09-23T17:51:07.730 に答える