_0x8048424
_(win()
location)へのfp
関数ポインターを上書きして、この問題を解決するために関数win()
が呼び出されるようにしました(マシンはほとんどありません)エンディアン)
_#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
void win()
{
printf("code flow successfully changed\n");
}
int main(int argc, char **argv)
{
volatile int (*fp)();
char buffer[64];
fp = 0;
gets(buffer);
if(fp) {
printf("calling function pointer, jumping to 0x%08x\n", fp);
fp();
}
}
_
これを行うには、buffer
variableをオーバーフローさせ、_python -c "print'A'*64 + '\x24\x84\x04\x08'" | ./stack3
_を実行してfp
を上書きします。
しかし、私の質問はなぜ16進のエスケープシーケンスが必要なのでしょうか?私は多くのチュートリアルでこの表記を見ましたが、どれもそれを説明していません目的
これについて読んだところ、エスケープシーケンスとして使用できることがわかりました。たとえば、_\n
_(これは改行文字です)はprintf("\x0A")
と書くことができ、同じことを行います。だからそれは理にかなっています。
しかし、メモリを上書きするときに、なぜこれが必要なのでしょうか。ここではバッファオーバーフローの目的が理解できませんでした。単純に_python -c "print'A'*64 + '0x24840408'" | ./stack3
_を使用できないのはなぜですか。つまり、ポインタ変数にメモリアドレスを書き込んでいるだけです。
PS私の質問は この質問 に関連していますが、残念ながら、なぜ最初に_\x
_表記が必要なのかという私の質問には回答しません
16進エスケープシーケンス\x{whatever}
は、1バイトのデータを表します。そのバイトは、それを読み取るプログラムに応じてさまざまなものを表すことができます。たとえば、\x78
は、文字"x"
、120、「次のセクションの120番目のバイト」、またはコンテキストで割り当てられた特別な意味を表すことができます。文字列"0x24840408"
を書き込んだ場合、バイト文字列\x30\x78\x32\x34\x38\x34\x30\x34\x30\x38
として解釈されます("0"
から"9"
までの文字は\x30
to \x39
)。ここで文字列を書き込むと、それらは単に対応するバイト文字列として解釈され、コンピューターはそれらのバイトが表す文字を調べません。デバッガーがアドレス"0x8048424"
を出力するとき、実際にメモリに格納されているものを出力していません。実際にそこにある4バイトシーケンス\x24\x84\x04\x08
を解釈し、人間が理解できる文字列を出力することで役立つようにしています。 (また、これらの文字のうち3つが印刷できないか不可視であるため、それが表す文字として\x24\x84\x04\x08
を印刷できません)。
プログラムが別の方法で変換し、"0x24840408"
(または実際に"0x8048424"
)をメモリ内の\x84\x24\x04\x08
に変換することは可能ですが、pythonインタプリタエクスプロイトの開発以外では必要とされないことが多いため、デフォルトではそうしていません。実際に「この4バイトの値をそのままメモリに入れる」という意味の場合は、それがエスケープシーケンスの目的です。
つまり、要約すると、"0x24840408"
はメモリ内で\x30\x78\x32\x34\x38\x34\x30\x34\x30\x38 \x24\x84\x04\x08
は"$[three unprintable characters]"
*を表します(つまり、\ x24は$
を表しますが、それが表す文字列は気にしません。私たちはそれを住所として解釈しています)
*実際には通常"$[one unprintable character]"
になります。文字としての\x08
は「バックスペース」を表すため、その前の\x04
を削除する必要があります。しかし、それは本当の意味ではありません。