2016-05-25 19 views
8

以下のコードでは、文書化されたすべての方法で例外を検出し、診断を生成しています。 C++ try/catchキーワードを使用し、__try/__catch拡張キーワードでSEH例外をキャッチし、WindowsのAddVectoredExceptionHandler()およびSetUnhandledExceptionFilter()winapi関数を使用してVEH/SEHフィルタをインストールします。Windowsでスタックバッファオーバーランを報告するにはどうすればよいですか?

Visual C++ 2003でこれを実行します。
/GS: "hello、world!"と出力します。終了コード0で終了します。
/GS-: "hello、world!"
/GS:出力しない、-1073740791
/GS-終了コードで終了しますと、このビジュアルC++ 2013で実行


0終了コードで終了 "!こんにちは、世界" の出力を/ GSを有効にしてVS2013コンパイル済みプログラムで診断を行うにはどうすればよいですか?

#include "stdafx.h" 
#include <Windows.h> 

#define CALL_FIRST 1 
#define CALL_LAST 0 

LONG WINAPI MyVectoredHandler(struct _EXCEPTION_POINTERS *ExceptionInfo) 
{ 
    UNREFERENCED_PARAMETER(ExceptionInfo); 

    printf("MyVectoredHandler\n"); 
    return EXCEPTION_CONTINUE_SEARCH; 
} 

LONG WINAPI MyUnhandledExceptionFilter(_In_ struct _EXCEPTION_POINTERS *ExceptionInfo) 
{ 
    printf("SetUnhandledExceptionFilter\n"); 

    return EXCEPTION_CONTINUE_SEARCH; 
} 

void f() 
{ 
    __try 
    { 
     char p[20] = "hello,world!"; 
     p[24] = '!'; 
     printf("%s\n", p); 
    } 
    __except (EXCEPTION_EXECUTE_HANDLER) 
    { 
     printf("f() exception\n"); 
    } 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    AddVectoredExceptionHandler(CALL_FIRST, MyVectoredHandler); 
    SetUnhandledExceptionFilter(MyUnhandledExceptionFilter); 

    try{ 
     f(); 
    } 
    catch (...){ 
     printf("catched f exception\n"); 
    } 
    return 0; 
} 
+0

コードによって、未定義の動作が発生します。 "検出"する唯一の信頼できる方法は、範囲外のアクセスを実行する前に境界をチェックすることです。 –

+1

...検出を行うコンテナタイプを使用した場合は何が行われるかなどです。例えば文字列に 'std :: string'を使い、' at'メンバ関数でインデックスを付けます。 – Hurkyl

+0

スタックオーバーランは検出が困難です。スタックフレームを上書きするときにのみトリガされます。ランタイム例外を有効にしてみてください*配列境界を超えました*。それは動作する可能性があります。 – cup

答えて

4

スタックバッファオーバーランの検出を処理するCRT機能(__report_gsfailure())は、スタックフレームの破損がマルウェア攻撃によって引き起こされたと想定しています。そのようなマルウェアは伝統的にfs:[0] SEH例外フィルタ(スタックフレームに格納されています)を利用して、マルウェアのペイロードをトリガする例外ハンドラを取得します。データを実行可能コードに変換する方法の1つ。

CRT関数は、例外をスローすることは安全であると想定できません。 VS2013に付属しているCRTではもはや〜VS2005に戻りません。 OSがサポートしている場合はフェイルファーストし、そうでない場合は、登録済みのVEH/SEH例外ハンドラが例外を認識できないことを保証します。 Kaboomは、デバッガが接続されていない限り、診断なしでデスクトップにクラッシュします。

/SAFESEHオプションは、この種のマルウェア攻撃を打ち負かして、以前ほど深刻なものではありません。まだコードがスタック破損のバグに悩まされていて、あなたのアプリがマルウェアの標的になるほど人気が​​ない段階にいる場合は、CRT機能を置き換えることが考えられます。

あなたの上司と話をしても、あなたのクライアントにとって大きな責任を負うので、これは個人的責任ではありません。歴史は、会社全体を1ヶ月間失業させたプログラマーに、何が起こったのかを物語っていることはめったにありません。しかし、確かに美しいものではなかった。

あなたのmain()関数にどこか近くにこのコードを貼り付け:

__declspec(noreturn) extern "C" 
void __cdecl __report_gsfailure() { 
    RaiseException(STATUS_STACK_BUFFER_OVERRUN, EXCEPTION_NONCONTINUABLE, 0, nullptr); 
} 

そしてすぐに再びそれを削除することを計画し。

+0

カスタム__report_gsfailureを追加するとリンクに失敗しました:エラーLNK2005:___report_gsfailure LIBCMT.lib(gs_report.obj)中に定義 – liuaifu

+1

ええと、これはVS2015で動作することが検証されたコードです。中国語のテキストが何を言っているのか分かりませんが、gs_report.objのような臭いはもう別のライブラリによってすでに取り込まれているので、2つあります。リンカの/ VERBOSEオプションを使用して、gs_report.objが使用された理由を確認してください。そして、強く、強く*/MTの代わりに/ MDを使ってビルドすることを強くお勧めします。 –

+0

このソリューションをお寄せいただきありがとうございます。私の所見によると、msvcrtdは別の__report_gsfailureも取得するので、これはリリースビルドでのみ動作します。 –

3

尋ねられた質問に対する解決方法はありません。

配列をオーバーランさせると、標準C++では未定義の動作が発生するため、特に保証されていません。信頼性の高い結果を出すことに失敗しても、コンパイラには問題はありません。これは許可された動作です。

私は、オーバーランに応答して特定の動作を保証する実装がないことを認識しています.VSは確かにそうではありません。コンパイラがそれをする必要がないので(つまり、本質的に、未定義の動作の意味)、これはほとんど驚くべきことではありません。その理由は、そのような出現を確実にまたは一貫して検出することはしばしば困難であるからである。

これは、配列のオーバーランを検出する唯一の一貫した方法は、配列要素にアクセスして適切なアクションをとるために配列インデックスが有効かどうかをチェックすることです(例えば、不正な操作をする代わりにキャッチできる例外を投げる)。欠点は、任意のコードでエラーを捕らえるためのシンプルで信頼性の高い方法を提供していないことです。

関連する問題