質問: "\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型にキャストして関数呼び出しができてしまうのは何故なのでしょうか? ポインタの初歩的なところでつまづいてしまっていますが、どなたかご教授いただけないでしょうか?
回答: (これは質問への直接回答ではありませんが) > > 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 ```