0

同じメッセージについて他にも質問がありますが、特定の関数を呼び出す一連のマシンコードを実行しようとすると、特にこれに遭遇するようです。私の場合、exit(0)を呼び出します。これは、同じプログラムのCで通常どおりに呼び出された場合に正常に機能します。ただし、演​​習として、EIPをいくつかのマシンコード(「シェルコード」と呼ぶ場合があります)のアドレスに設定した場合、たとえば

const char code[] = 
"\x6A\x00"      // push        0"
"\xFF\x15\x00\x00\x00\x00"  //system call, 'read access violation':   call dword ptr [__imp__exit]
"\x5D"  //pop ebp    
"\xC3"; //ret

「アクセス違反の読み取り場所0x00000000」というメッセージが表示されます。「\x6A\ x00」命令は実行されますが、exit(0)を呼び出すとこの例外がスローされます。

これはVS2010で/GS-を使用してコンパイルされたCであり、実行権限で「シェルコード」を実行していますが、実行不可能なメモリやスタック保護がまだ行われていますか?この命令がエラーを引き起こすのはなぜですか?

    int main() 
{ 

    void *exec = VirtualAlloc(0, sizeof(code), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    memcpy(exec, code, sizeof(code));
//EIP = exec in debug->immediate
    exit(0);

}
4

1 に答える 1

1

シェルコードを分解すると、次のようになります(AT&T構文)。

00000000 <_code>:
   0:   6a 00                   push   $0x0
   2:   ff 15 00 00 00 00       call   *0x0
   8:   5d                      pop    %ebp
   9:   c3                      ret

命令は、callアドレス0を介してメモリ間接ジャンプを実行しています。メモリアドレス0からターゲットをロードし、その場所にジャンプしています。メモリアドレス0は無効であるため(まれに有効になる場合がありますが、これは例外ではありません)、アクセス違反が発生します。

通常、Cコードをコンパイルすると、外部関数へのジャンプはプレースホルダーに置き換えられ、それらのプレースホルダーはリンク時にリンカーによって入力されます。実行時にシェルコードを生成する場合、リンカーの支援がないため、自分で生成する必要があります。目的のターゲットアドレスを把握し、シェルコードに直接入力する必要があります。シェルコードが実行されるアドレスが正確にわからない場合は、位置に依存しないトリックを使用することもできます。

于 2012-12-11T02:46:53.903 に答える