2016-06-16 5 views
1

私はuprobe tracerのドキュメントを読んでおり、メモリ内の関数のオフセットを計算する方法があります。私はここでそれを引用しています。メモリ内の関数のオフセットを計算する

次の例は、プロービングされたテキストアドレスに命令ポインタと%ax レジスタをダンプする方法を示しています。/binに/のzshでプローブzfree機能:

# cd /sys/kernel/debug/tracing/ 
# cat /proc/`pgrep zsh`/maps | grep /bin/zsh | grep r-xp 
00400000-0048a000 r-xp 00000000 08:03 130904 /bin/zsh 
# objdump -T /bin/zsh | grep -w zfree 
0000000000446420 g DF .text 0000000000000012 Base  zfree 

0x46420は 0x00400000にロードされたオブジェクト/ビン/ zshの中zfreeのオフセットされています。

私は理由はわかりませんが、出力は0x446420で、0x46420を得るには0x400000を引いたものです。それは私に誤りとして縫い目をつけた。なぜ0x400000ですか?

4.5.6-200のカーネルでFedora 23でも同じことを試みました。

まず私は、メモリアドレスのランダム化

echo 0 > /proc/sys/kernel/randomize_va_space 

は、その後、私はバイナリがメモリ内にある場合

$ cat /proc/`pgrep zsh`/maps | grep /bin/zsh | grep r-xp 
555555554000-55555560f000 r-xp 00000000 fd:00 2387155     /usr/bin/zsh 

オフセット

[email protected]:~ $ objdump -T /bin/zsh | grep -w zfree 
000000000005dc90 g DF .text 0000000000000012 Base  zfree 

を取り、zfreeがどこにあるかを考え出し考え出しオフgdb経由

$ gdb -p 21067 --batch -ex 'p zfree' 
$1 = {<text variable, no debug info>} 0x5555555b1c90 <zfree> 

[email protected]:~ $ python 
Python 2.7.11 (default, Mar 31 2016, 20:46:51) 
[GCC 5.3.1 20151207 (Red Hat 5.3.1-2)] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> hex(0x5555555b1c90-0x555555554000) 
'0x5dc90' 

私はobjdumpと同じ結果を得ています。

しかし、私は別のマシンでSLESを試してみました。そこには、アップローブのドキュメントと同じです。

なぜこのような違いがありますか?正しいオフセットを計算するにはどうすればよいですか?

+0

doc:0x00400000にロードされているobject/bin/zshにあります。オフセットはおそらくプログラムのロードアドレスに相対的であると考えられるので、プログラムのロードアドレスを関数の絶対アドレスから引く必要があります。 – dbrank0

+1

多くのシステムのベースアドレスが0x400000である理由については、「なぜLinuxバイナリの仮想メモリアドレスは0x8048000から始まるのですか」(http://stackoverflow.com/questions/2966426)を参照してください。 Fedora 23は '-fPIC -shared'でパッケージをビルドするので、ロードオフセットは0で、ベースアドレスはランダム(ASLR付き)または0x555555554000です。 –

答えて

1

私の知る限りでは、バイナリがどのように検査されたかだけで違いが生じる可能性があります。より正確に言えば - ELFにロードアドレスが固定されているかどうか。簡単な実験をしましょう。二つの方法でそれを構築、その後

int main(void) { return 0; } 

::私たちは、簡単なテストコードを持って

$ gcc -o t1 t.c  # create image with fixed load address 
$ gcc -o t2 t.c -pie # create load-base independent image 

は今、これらの二つの画像のチェック負荷のベースアドレスをすることができます:ここで

$ readelf -l --wide t1 | grep LOAD 
    LOAD   0x000000 0x0000000000400000 0x0000000000400000 0x00067c 0x00067c R E 0x200000 
    LOAD   0x000680 0x0000000000600680 0x0000000000600680 0x000228 0x000230 RW 0x200000 
$ readelf -l --wide t2 | grep LOAD 
    LOAD   0x000000 0x0000000000000000 0x0000000000000000 0x0008cc 0x0008cc R E 0x200000 
    LOAD   0x0008d0 0x00000000002008d0 0x00000000002008d0 0x000250 0x000258 RW 0x2000 

あなたがすることができます最初のイメージに固定ロードアドレス-が必要で、2番目のイメージにはアドレス要件が全くないことを確認してください。

そして今、我々はobjdumpmainを伝えるというアドレスを比較することができます

$ objdump -t t1 | grep ' main' 
00000000004004b6 g  F .text 000000000000000b    main 
$ objdump -t t2 | grep ' main' 
0000000000000710 g  F .text 000000000000000b    main 

我々は見ての通り、アドレスはに格納された画像は、アドレスにロードされている場合mainの最初のバイトが占めることに完全な仮想アドレスであり、プログラムヘッダ。もちろん、2番目の画像は0x0にロードされることはありませんが、代わりにランダムに選択された別の場所にロードされることはありません。

+0

ありがとう!実行可能ファイルにpieを使用する点は何ですか? –

+0

@MarkoKevacセキュリティ上の理由から便利です。任意のロードアドレスを使用することにより、その他の脆弱性を悪用することが難しくなります。グローバルオブジェクトとコードの場所は時々変更されるため、攻撃者は一定のアドレスではもはやリレーできません。例えば。この理由からAndroidはバージョン5.0(Lollipop)以来の非パイ実行ファイルの使用を禁じています – Sergio

+0

何のように? AFAIKでは、実行中のプロセスで.textに書き込むことができないので、関数の固定アドレスがあなたを助けることはできません。いいえ? –

関連する問題