関数へのポインタでの関数呼び出しについて
解決済
回答 2
投稿
- 評価
- クリップ 1
- VIEW 1,803
プログラミング初心者なので暖かい目で見ていただけると幸いです。
execve("/bin/sh", ["/bin/sh", NULL], NULL)を16進数に変換し、C言語で呼び出すことで、シェルを立ち上げるというやり方について、少し疑問があったので質問させていただきます。
#include <stdio.h>
typedef void (*func)();
char shellcode[] = "\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80";
int main(void) {
((func)&shellcode)();
// ((func)shellcode)(); // こっちでも呼び出せる??
return 0;
}
16進数をリトルエンディアンで文字列としてグローバル変数shellcodeに定義しておき、main関数内で呼び出しを行っています。
簡単のため、事前にtypedefにより、
引数を取らず、void型を返す関数へのポインタ型をfunc型
と定義しています。
私は、アスタリスク演算子はメモリ上のその変数がある番地の値を取得、アンパサンド演算子はメモリ上のその変数がある番地を取得(この部分について、少し自信がないので今回質問させていただきました)していると考えているのですが、
番地でも、その番地に格納された値でもfunc型にキャストして関数呼び出しができてしまうのは何故なのでしょうか?
ポインタの初歩的なところでつまづいてしまっていますが、どなたかご教授いただけないでしょうか?
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+4
shellcode
のように、配列の名前を式の中に書くと、自動で「配列の先頭アドレス」として処理されます。一方、明示的に&shellcode
とアドレスを取ると、それは「配列全体のアドレス」となります(参考)。型は違いますが位置は同じです。
つまり、shellcode
も&shellcode
も、キャストしてしまえば何も変わりません。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+2
(これは質問への直接回答ではありませんが)
execve("/bin/sh", ["/bin/sh", NULL], NULL)を16進数に変換し、C言語で呼び出すことで、シェルを立ち上げると
(略)
16進数をリトルエンディアンで文字列としてグローバル変数shellcodeに定義しておき、main関数内で呼び出し
目的と実装がマッチしていないのですが、大丈夫でしょうか?あなたのコードが実際に行っていることは、shellcode
に格納されているバイト列をマシン語命令とみなして、それを実行時に呼び出すという(かなり危険な)処理になっています。実際に動作させるとクラッシュするのでは?
一応、該当のマシン語命令を逆アセンブルしてみましたが全く意味のない命令列になっています。(Intel x86と仮定)
$ printf "\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80" > shellcode.bin
$ objdump -D -b binary -m i386 shellcode.bin
0: 31 d2 xor %edx,%edx
2: 52 push %edx
3: 68 2f 2f 73 68 push $0x68732f2f
8: 68 2f 62 69 6e push $0x6e69622f
d: 89 e3 mov %esp,%ebx
f: 52 push %edx
10: 53 push %ebx
11: 89 e1 mov %esp,%ecx
13: 8d 42 0b lea 0xb(%edx),%eax
16: cd 80 int $0x80
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.23%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2016/01/29 15:54
printf("%d\n", sizeof *shellcode);
printf("%d\n", sizeof *&shellcode[0]);
printf("%d\n", sizeof *&shellcode);
で、違いが分かりますね。
2016/02/08 01:05
回答ありがとうございます。
頂いた参考記事、とても勉強になりました。
Cを触った時に、ポインタについても少し触れていたものの、理解が浅く、手間取ってしまう場面が多かったのですが、アプローチ(考え方?)が間違っていたようです。
ありがとうございます。