char sh[] = "\x31\xc0\x31\xdb\x31\xc9\x31\xd2\x52\x68\x6e\x2f\x73\x68"
"\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\xb0\x0b\xcd\x80";
プログラマーがこの文字列に 16 進エンコードを使用したのはなぜですか? たとえば、なぜ\x31
最初の文字に ? ではなく使用するの1
ですか?
コードを逆アセンブラで実行しました。配列には、x86 Linux 用のシェルコードが含まれているようです。
804a014: 31 c0 xor %eax,%eax #set registers to zero
804a016: 31 db xor %ebx,%ebx
804a018: 31 c9 xor %ecx,%ecx
804a01a: 31 d2 xor %edx,%edx
804a01c: 52 push %edx #push a null word
804a01d: 68 6e 2f 73 68 push $0x68732f6e #push "/bin/sh"
804a022: 68 2f 2f 62 69 push $0x69622f2f
804a027: 89 e3 mov %esp,%ebx
804a029: 52 push %edx #push another null word
804a02a: 53 push %ebx #push pointer to string
804a02b: 89 e1 mov %esp,%ecx
804a02d: b0 0b mov $0xb,%al #system call 11: execve
804a02f: cd 80 int $0x80 #call the system
どうやら、/bin/sh
メモリ内で文字列をアセンブルし、そのプログラムそのものを呼び出そうとします。
は要素sh
の配列ですchar
が、バイトの配列と見なすこともできます。まあ、char
8ビット幅だと仮定すると、通常はそうです。
したがって、この変数にコードが含まれている場合は、テキスト配列ではなく、バイト配列として表現する方が明確です。たとえば、印刷可能な文字として容易に表現できない要素が存在する場合があります。コンテンツはコンパイラまたはアセンブラによって生成されるため、元はコードのバイナリ ブロックの形式になっています。そして、それをあなたが提示した16進表現に変換するのが最も簡単で明確です。
16 進数のエスケープ シーケンスです。
C11 (n1570)、§ 6.4.4.4 文字定数
バックスラッシュと 16 進エスケープ シーケンスの文字に続く 16 進数字は
x
、整数文字定数の場合は 1 文字、ワイド文字定数の場合は 1 ワイド文字の構成の一部と見なされます。このように形成された 16 進整数の数値は、目的の文字またはワイド文字の値を指定します。
それを実行するには、おそらく関数ポインタキャストを使用できます。
void (*shell)();
shell = (void(*)()) (&sh);
shell();