Execveシェルコードの謎を解く では、execveシェルコードを記述する方法が説明されています。
_#include<stdio.h>
#include<string.h>
unsigned char code[] =
"\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";
main()
{
printf("Shellcode Length: %d\n", strlen(code));
int (*ret)() = (int(*)())code;
ret();
}
_
行int (*ret)() = (int(*)())code;
は何をしますか?
_ int (*ret)() = (int(*)())code;
~~~~~~~~~~~~ ~~~~~~~~~~~~~~
1 2
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3
_
ret
を、パラメーター_()
_を持たない関数へのポインターとして定義し、int
を返します。したがって、これらの_()
_は、関数のパラメーターの定義を示します。
これは、code
を、パラメーター_()
_を持たず、int
を返す関数へのポインターにキャストするためのものです。
code
を関数としてキャストし、それをret
に割り当てます。その後、ret();
を呼び出すことができます。
_unsigned char code[] = "\x31\xc0\x50\x68\x6e\x2f\...
_
これは、16進値で表される一連のマシン命令です。関数としてコードに挿入されます。
(*(void(*)())shellcode)()
==
p = (void(*)()) shellcode;
(*p)();
この関数ポインタ部分をもっと簡単な形に書き直すことはできますか?
これがもっと簡単だと思うかどうかはわかりませんが、多分:
#include <stdio.h>
#include <string.h>
unsigned char code[] =
"\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";
typedef int(*shellcode_t)();
int main(int argc, char ** argv) {
printf("Shellcode Length: %ld\n", strlen(code));
shellcode_t ret = (shellcode_t)code;
ret();
}
Int行は、code []配列を指すことにより、ret()関数を宣言します。つまり、関数はcode []バイナリ命令にマップされます。
\ x構文は、16進文字を文字列に埋め込むための安全な方法です。たとえば、「1」の文字コードは49、つまり16進数の31であるため、「\ x31」を「1」に置き換えることができます。