2011-05-06 10 views
3

メモリ内の値をX86_64の%ripから読み取ろうとしています。私の最初の例では、私はちょうど私がCに次のコードを記述する場合、私はそれを呼び出すと、正しい結果(\x....C3C9)を取得することができます動的に生成されたX86_64を取得してRIP/RBPを基準にした値を返す方法

を読みたい:

void * test() { 
    __asm("mov 0(%rip), %rax"); 
} 

次のように生成されたコードが見えます:

0000000000400624 <test>: 
    400624: 55      push %rbp 
    400625: 48 89 e5    mov %rsp,%rbp 
    400628: 48 8b 05 00 00 00 00 mov 0x0(%rip),%rax  # 40062f <test+0xb> 
    40062f: c9      leaveq 
    400630: c3      retq 

私は今、しかし、メモリに直接このコードを入れて、私は読むことを期待しながら、私はセグメンテーションフォルトを取得し、それを実行した場合\x0000C3C9

int main() 
{ 
    int codesize = 9; 
    unsigned char * code = (unsigned char*)malloc(1024); 
    memcpy(code, "\x48\x8B\x5\x0\x0\x0\x0\xC9\xC3\x00\x00", codesize + 2); 
    mprotect(code, codesize, PROT_EXEC | PROT_READ); 
    goto *code; 
} 

私は間違っていますか?

編集 答えは私がページ整列メモリ領域を割り当てるためにmallocが、mmapを使用しているべきではないということです。

(unsigned char*)mmap(NULL, 1024, PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_SHARED, -1, 0); 

そしてもちろん、私は、コールの戻り値をチェックしているはずですmprotectに失敗したことを示す-1というフラグを返しました。

+0

私は再び彼のコメントを削除した誰かによってコメントが、しかし彼は正しい方向に私をリードしました。彼は正しく、mprotectが失敗している(愚かな私、私はチェックすべきだった)。私は 'malloc'(明らかに)がページ境界に合わせてメモリを返さないと思います。 '(unsigned char *)mmap(NULL、1024、PROT_WRITE | PROT_READ、MAP_ANONYMOUS | MAP_SHARED、-1、0);を使用することによって動作します。 – tverwaes

+1

'PROT_EXEC'を' mmap'呼び出しに追加すると、 'mprotect'は必要ありません。 –

+0

私は、いくつかのカーネルが 'PROT_WRITE'と' PROT_EXEC'を同時に使用できない場所を読んだので、私はそれをしませんでした。私はそれを誤解しましたか? – tverwaes

答えて

1

ほとんどの場合、mprotect()コール中にSIGSEGVが返されます。 malloc()によって返されたメモリのコード実行がOSによって許可されていない場合(おそらく古いカーネルを使用していない場合)、mprotect()はsegfaultsになります。これはバグではなく、機能です。

+0

'mprotect'はセグメンテーションしません。実際には成功しますが、成功できなければ-1を返し、 'errno'を設定します。 –

+0

実際には、引数がページアライメントされていない場合でも、segfaultではなくエラーが返されます。その後のコードはsegfaultsです。 –

+0

確かに、これは私が知る限り問題でした。私は 'malloc'の代わりに静的な文字列を使用していましたが、それはうまくいくようでした。私は静的な文字列はページに整列していると思いますが、 'malloc'文字列はそうではありません。 – tverwaes

0

ret命令は基本的にpop value from the stack; goto valueです。あなたgoto <your_code>retは結局、問題はあなたが(コードサイズがスタックの一番上の変数であるので、多分ret命令がgoto 9にしようと、誰もが知っている...)スタック上のゴミを持っているということです実行されます

asm snippetを間違って使用しているため、基本的には動作しません。

あなたは何をしようとしているのですか?私はあなたのリッピングを取得するために:)


テストプログラムを助けることができる:

static inline unsigned long get_rip(void) 
{ 
    unsigned long val; 
    asm volatile(
     "call 1f\n" 
     "1: popq %0\n" 
     : "=r"(val)); 
    return val; 
} 

int main() 
{ 
    printf("rip = %p\n", (void *)get_rip()); 
    return 0; 
} 
+0

なぜスタックにゴミがありますか?私が 'goto 'を実行したときにスタックにまだ触れていないので、 'main'関数の中にあるかのように実行しています。私はSmalltalk - > ASMコンパイラ(Smalltalkで書かれています)に取り組んでいます。仮想マシンを完全に取り除きたいからです。 X86_64は始めるのに良い場所のようです。たくさんの楽しみがあります:) – tverwaes

+0

リッピング値を取得する方法を示すコードスニペットを投稿しました:) –

+1

'retq'の前に' leaveq'命令を実行すると、スタックポインタは 'main () '、' main() 'が通常の関数プロローグを使用していると仮定します。 – caf

関連する問題