質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

セキュリティー

このタグは、コンピューターシステムの安全性やデータの機密性に関連したトピックの為に使われます。

Q&A

解決済

2回答

2976閲覧

ASLRについて

strike1217

総合スコア651

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

セキュリティー

このタグは、コンピューターシステムの安全性やデータの機密性に関連したトピックの為に使われます。

0グッド

0クリップ

投稿2016/09/23 11:21

実験のためにソースコードを作ってやってみました。
両方ともASLR > 2で設定しています。

.#include <stdio.h>
.#include <stdlib.h>

unsigned long get_sp(){
asm("movl %esp, %eax");
}

int main(){
printf("malloc :%p\n", malloc(16));
printf("stack: 0x%lx\n", get_sp());
return 0;
}

./malloc
malloc :0x23a9010
stack: 0xf55afcf0
./malloc
malloc :0x1cc9010
stack: 0x68fc7050

.#include <stdio.h>

void func(const char* str);

int main(){
printf ("関数mainのアドレスは %pです。\n", main);
printf ("関数funcのアドレスは %pです。\n", func);

return 0;
}

void func(const char* str) {
printf ("%s\n", str);
return;
}

./func
関数mainのアドレスは 0x400546です。
関数funcのアドレスは 0x400579です。
./func
関数mainのアドレスは 0x400546です。
関数funcのアドレスは 0x400579です。

1回目のソースと2回目のソースコードでなぜ結果が異なるのですか?
1回目はランダム化できています。
2回目はできていません。

なぜですか??

ASLRは論理アドレスをランダム化していますが、これは見せかけ上のもので、コンソール上の数字がランダムに変わっているだけですか?
それとも論理アドレスが実際に変わっているのですか?
論理アドレスが変わるということは「実行するたびに、異なる物理アドレスに展開されている」という理解で正しいですか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

rubato6809

2016/09/25 08:00

以上の実験を行ったOS、バージョンは何ですか。Cコンパイラはgccかな?
strike1217

2016/09/25 08:03

失礼しました。 Linuxです。gccコンパイラを使用しています。
guest

回答2

0

ベストアンサー

実はASLRという言葉を初めて知りました(苦笑)が、何の事かは大体見当がつきましたし、yohhoyさんが教えてくださった "-fPIE -pie" オプション付でコンパイルすれば,関数アドレス(main, func等)もランダム化される事を、私はUbuntu 16.04(32bit, 64bit両方)で確認できました。解説される方がいらっしゃらないようなので、でしゃばってみます。

ASLRは論理アドレスをランダム化していますが、
これは見せかけ上のもので、コンソール上の数字がランダムに変わっているだけですか?
それとも論理アドレスが実際に変わっているのですか?

ユーザプログラムが扱えるメモリアドレスは論理アドレスだけです。
実際に、論理アドレスが変わったから、異なるアドレスが表示されたのです。

論理アドレスが変わるということは「実行するたびに、
異なる物理アドレスに展開されている」という理解で正しいですか?

論理アドレスが変わるということは「実行するたびに異なる論理アドレスに展開されている」という事でしかありません。

逆に、論理アドレスが同じなら、物理アドレスも同じ…とはなりません。論理アドレスが同じだろうが違っていようが、おそらく毎回全く異なる物理アドレスが割り当てられるのだろう、と想像していればよいと思います。
ユーザプログラムの動作とは、即ちCPUの動作です。繰返しますが、CPUが扱う(=アクセスできる)アドレスは論理アドレスだけです。その論理アドレスに対応する物理アドレスがどこかなんて、OSか物理デバイスドライバをデバッグするのでもなければ私達に関わりの無い事、そう割りきって構わないと思います。

念の為:論理アドレスを物理アドレスに変換する装置がメモリ管理ユニット(MMU)です。CPU、論理アドレス(virtual address)、物理アドレス(physical address)の関係は、MMUの動作の模式図が単純でわかりやすい(少なくとも私にはw)。論理アドレスと物理アドレスの対応付けをするのがページテーブルであり、ページテーブルを設定するのはOSの仕事です。
MMUを持たないコンピュータもあります。その場合、論理アドレスはそのまま物理アドレスとなってメモリをアクセスします。

1回目はランダム化できています。2回目はできていません。
1回目のソースと2回目のソースコードでなぜ結果が異なるのですか?

データとプログラムでは、メモリ領域を変更することの困難さが違うから、でしょう。

スタック領域は、プロセス起動時にスタックポインタを正しくセットしさえすれば、何番地でも支障なくプログラムは動作します。malloc()が返すメモリアドレスは、元々何番地が割り当てられるか実行するまでわからないのだから、実行の都度アドレスが変化しても動作に支障などあるはずが無い。つまり、これらのデータ領域はランダム化が容易です。

ところが、プログラム自体(機械語コード)は、一般にロードするアドレスを変えると動作できなくなります。位置独立コードをご覧下さい。「PIE」(Position Independent Executable: 位置独立実行形式)とは、ロードするアドレスが変わっても動作できる機械語コードの事です。特別な呼び名が有るくらい普通じゃない、と言えるでしょう。"-fPIE -pie"コンパイルオプションはPIEコードにコンパイルする指定ですね。
即ち、機械語コード(プログラム自体)のランダム化は、PIEコードにコンパイルする必要がある程度に、容易ではないのです。

おまけ:テストプログラムは一本化できます。

  • グローバル変数(含static変数)のアドレスも表示してみる
  • 直接スタックポインタを表示する代りに、スタックに割り当てられるauto変数や関数の引数のアドレスを表示しても良い

C

1#include <stdio.h> 2#include <stdlib.h> 3 4int v_global; 5 6void * get_sp(void) 7{ 8 asm("movl %esp, %eax"); 9} 10 11void func(const char* str) 12{ 13 printf ("%s\n", str); 14} 15 16int main(int argc, char **argv) 17{ 18 func("* print addresses *"); 19 printf("address of main() : %p\n", main); 20 printf("address of func() : %p\n", func); 21 printf("address of v_global : %p\n", &v_global); 22 printf("malloc() returns : %p\n", malloc(16)); 23 printf("stack pointer : %p\n", get_sp()); 24 printf("address of argc : %p\n", &argc); // in stack area 25 return 0; 26}

投稿2016/09/26 15:08

編集2016/09/26 15:15
rubato6809

総合スコア1380

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

strike1217

2016/09/27 01:36

ありがとうございます。 実行ファイルに論理アドレスを割り当てるのはリンカ(コンパイラ)がやっていますよね? 実行時に論理アドレスの割当を変更できるものなんですね!
rubato6809

2016/09/27 02:04

プロセスを起動する都度、リンカが仕事をしている、とお考えなら、たぶん誤解されています。 リンカはビルド(一連のコンパイル作業)の最後に、一度仕事をしてしまえばそれっきりです。 PIEでないコードは特定の番地にロードしなければならないようにリンクされます。PIEなコードはリンクされたものが異なる番地にロードされても動作できる、そのような性質を持ったコードです。そのためには、コンパイル時に生成される機械語コードから違いがあります。もっとも具体的にココという説明ができるほど私は理解してませんが、違うことだけは、gccの -S オプションで生成されるアセンブリコードを、"-fPIE -pie"オプションの有り無しで比較することでも確かめられます。
guest

0

Linuxの話であれば ASLR とは別に PIE(Position-Independent Executables) が存在します。GCCに-fPIE -pieオプション指定でPIE有効になります。

投稿2016/09/25 04:25

yohhoy

総合スコア6191

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問