トップページ
ひらく | たたむ | ページトップ
↓マウスで反転選択した文字を検索
VisualStudio
   
ページ内検索 ページ外検索
検索したい文字を入力して
ENTERを押すと移動します。
\n
[ トップページ ]
[ ____CommandPrompt ] [ ____JScript ] [ ____MySQL ] [ ____Cygwin ] [ ____Java ] [ ____Emacs ] [ ____Make ] [ ____Perl ] [ ____Python ] [ ____OpenGL ] [ ____C# ] [ ____StyleSheet ] [ ____C++ ] [ ____Winsock ] [ ____Thread ] [ ____VisualStudio ] [ ____C ] [ ____Win32API ] [ ____Lua ] [ ____PhotoShop ]
ヘッダ検索
___

■ Debugger


  
    コンソールプログラムならは Control-c で DBG_CONTROL_C 例外を発生させる。


  76FF15DE  add         esp,4

  
  混合ウィンドウでアドレスを見ると問題の箇所がわかる。

test.exe の 0x76ff15de でハンドルされていない例外が発生しました: 
0xC0000005: 場所 0x00000000 を読み込み中にアクセス違反が発生しました。  

    例外の種類には以下のものがある
     EXCEPTION_DEBUG_EVENT
          例外が発生した
            ブレークポイント例外
            

    
     CREATE_PROCESS_DEBUG_EVENT
          プロセスが実行前にロードされた時点で発生する。
          デバッガはこのタイミングで 逆アセンブルコードの表示など必要なことをする。


___

■ WaitForDebugEvent

SYNTAX BOOL WaitForDebugEvent( LPDEBUG_EVENT event, // デバッグイベントの情報が入った構造体へのポインタ DWORD time // 待つ時間 ( msec ) ); DESC デバッグ中のプロセスでデバッグイベントが発生するのを待つ。 WaitForDebugEvent 関数を呼び出すことができるのは デバッグ中のプロセスを作成したスレッドだけ。
___

■ ContinueDebugEvent

SYNTAX BOOL ContinueDebugEvent( DWORD dwProcessId, // 続行するプロセス DWORD dwThreadId, // 続行するスレッド DWORD dwContinueStatus // 続行状態 ); デバッグイベントを報告したスレッドをデバッガが続行できるようにします。 OS に継続を通知する。
___

■ CreateProcess

SYNTAX BOOL CreateProcess( LPCTSTR lpApplicationName, // 実行可能モジュールの名前 LPTSTR cmdline, // コマンドライン文字列 LPSECURITY_ATTRIBUTES lpProcessAttributes, // セキュリティ記述子 LPSECURITY_ATTRIBUTES lpThreadAttributes, // セキュリティ記述子 BOOL bInheritHandles, // ハンドルの継承オプション DWORD dwCreationFlags, // フラグ LPVOID lpEnvironment, // 新しい環境ブロック LPCTSTR sDir, // カレントディレクトリの名前 LPSTARTUPINFO pStartupInfo, // スタートアップ情報 LPPROCESS_INFORMATION pProcessInformation // プロセス情報 ); DESC DESC 新しい 1 個のプロセスと、そのプライマリスレッドを作成 Windows OS の元では 実行ファイルを開くことはプロセスの生成と同じ 任意のプログラムをコマンドラインで、あるいは引数付で実行することができます 実行開始時の状態を指定したり実行したプロセスやプロセスのメインスレッドのハンドルも得られるので プログラムの終了を待つなど柔軟な制御ができる 適当なエディタ機能とCreateProcess()を組み合わせれば 「編集したソースをコマンドラインでコンパイラに渡してコンパイル、コンパイル終了を待って実行」 という簡単な「統合開発環境」を開発することもできる lpProcessAttributes 構造体で子プロセスが 取得したハンドルを 継承 できるかどうかを指定する NULL を指定すると 取得したハンドルを継承できない ノートパッドを起動する。
    PROCESS_INFORMATION pi;
    STARTUPINFO si;

    ZeroMemory( &si, sizeof(si) );
    si.cb=sizeof( si );


    CreateProcess(
        NULL, 
        "notepad",
        NULL,NULL,
        FALSE,
        NORMAL_PRIORITY_CLASS,  // Thread Schedular の 優先順位 は普通
        NULL,NULL,
        &si,&pi 
        );

コマンドライン文字列は引数も含めてすべてを指定する。 コンソールウィンドウを新規に与えるには CREATE_NEW_CONSOLE フラグをたてる

    CreateProcess(
        NULL, 
        "ping localhost",
        NULL,NULL,
        FALSE,
        CREATE_NEW_CONSOLE,
        NULL,NULL,
        &si,&pi 
        );

プロセスの終了まちをする。
      WaitForSingleObject( pi.hProcess, INFINITE );
フラグは次のようなものを指定できる CREATE_NEW_CONSOLE 親のコンソールを継承せず新しいコンソールを持ちます。DETACHED_PROCESS フラグと同時に指定することはできません。 CREATE_NO_WINDOW コンソールアプリケーションを起動する場合にのみ有効です。 このフラグを指定すると、コンソールウィンドウなしでアプリケーションを実行する。 DEBUG_PROCESS 呼び出し側プロセスをデバッガ、新しいプロセスをデバッグ対象として扱う。 OS は、デバッグ対象のプロセス内で発生するすべてのデバッグイベントを呼び出し側スレッドへ通知します。 このフラグを指定してプロセスを作成すると 呼び出し側スレッド(CreateProcess 関数を呼び出したスレッド)だけが 関数を呼び出せます。 DEBUG_ONLY_THIS_PROCESS 呼び出し側プロセスがデバッグ対象であるときに、 このフラグを指定せずに CreateProcess 関数を呼び出すと 呼び出し側プロセスを扱っているデバッガは、新しいプロセスもデバッグ対象とします。 呼び出し側プロセスがデバッグ対象ではない場合、デバッグ関連の動作は発生しません。 プロセスの実行でブロックされるため、スレッドで CreateProcess を実行すると ユーザーの応答をうけることができる。

 DWORD WINAPI func(LPVOID lpArg) {

      PROCESS_INFORMATION pi;
      STARTUPINFO si;

      ZeroMemory(&si,sizeof(si));
      si.cb=sizeof(si);

      CreateProcess(NULL,(LPTSTR)lpArg,NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,
        NULL,NULL,&si,&pi);

      CloseHandle(pi.hThread);

      // 終了まち
      WaitForSingleObject( pi.hProcess, INFINITE );

      CloseHandle(pi.hProcess);

      PostMessage(hwMain,WM_USER,0,0);

      ExitThread(0);

      return 0;
  }
___

■ breakpoint

POINT ブレークポイントを仕込むには、インストラクションポインタの場所に ブレークポイント命令を入れるだけ。 Intel 系 CPU では ニーモニックは INT 3 。 オペコードは CC。
    __asm {
      INT 3
    }
POINT デバッガでブレークポイントを仕込むにはこのオペコードで上書きしてしまえばいい。
___

■ OpenProcess

SYNTAX HANDLE OpenProcess( DWORD dwDesiredAccess, // アクセスフラグ BOOL bInheritHandle, // ハンドルの継承オプション DWORD id // ハンドルを取得したいプロセスのID ); DESC 既存のプロセスオブジェクトのハンドルを開く。
___

■ GetCurrentThread

SYNTAX
___

■ GetThreadContext

SYNTAX BOOL GetThreadContext( HANDLE hThread, // 情報を取得したいスレッドのハンドル LPCONTEXT lpContext // コンテキスト情報 ); RET 0 : 失敗 !0 : 成功 DESC 指定したスレッドのコンテキスト( レジスタ( ISP, ESP )の値など )を取得する。 WARNING 実行中のスレッドには利用することができないので, SuspendThread() を使ってとめる。 情報を取得するには スレッドをとめる必要がある。 スレッドへの THREAD_GET_CONTEXT アクセス権が必要。
    CONTEXT    stCtx  ;
    stCtx.ContextFlags = CONTEXT_FULL ;

    GetThreadContext ( GetCurrentThread ( ) , &stCtx ) );

    // レジスタの値がとれる。
    stCtx.Eip;
    stCtx.Esp;
    stCtx.Ebp;

___

■ スタックトレース(StackTrace)

シンボルテーブル情報があればスタックトレースをできる。

#include< imagehlp.h>  
#pragma comment(lib, "imagehlp.lib")


LONG CALLBACK SWFilter(EXCEPTION_POINTERS *ExInfo)
{
  STACKFRAME sf;
  BOOL bResult;
  PIMAGEHLP_SYMBOL pSym;
  DWORD Disp;

  printf("例外発生\n");

  // シンボル情報格納用バッファの初期化 
  pSym = (PIMAGEHLP_SYMBOL)GlobalAlloc(GMEM_FIXED, 10000);
  pSym->SizeOfStruct = 10000;
  pSym->MaxNameLength = 10000 - sizeof(IMAGEHLP_SYMBOL);

  // スタックフレームの初期化
  ZeroMemory(&sf, sizeof(sf));
  sf.AddrPC.Offset = ExInfo->ContextRecord->Eip;
  sf.AddrStack.Offset = ExInfo->ContextRecord->Esp;
  sf.AddrFrame.Offset = ExInfo->ContextRecord->Ebp;
  sf.AddrPC.Mode = AddrModeFlat;
  sf.AddrStack.Mode = AddrModeFlat;
  sf.AddrFrame.Mode = AddrModeFlat;

  // シンボルハンドラの初期化
  SymInitialize(GetCurrentProcess(), NULL, TRUE);

  // スタックフレームを順に表示する
  for(;;) {
    // 次のスタックフレームの取得
    bResult = StackWalk(
      IMAGE_FILE_MACHINE_I386,
      GetCurrentProcess(),
      GetCurrentThread(),
      &sf,
      NULL, 
      NULL,
      SymFunctionTableAccess,
      SymGetModuleBase,
      NULL);

    // 失敗ならば、ループを抜ける
    if(!bResult || sf.AddrFrame.Offset == 0) break;

    // プログラムカウンタから関数名を取得
    bResult = SymGetSymFromAddr(GetCurrentProcess(), sf.AddrPC.Offset, &Disp, pSym);
    
    // 取得結果を表示
    if(bResult) printf("--- 0x%08x %s() + 0x%x\n", sf.AddrPC.Offset, 
                       pSym->Name, 
                       Disp);
    else printf("%08x, ---", sf.AddrPC.Offset);
  }

  // 後処理
  SymCleanup( GetCurrentProcess() );
  GlobalFree( pSym );

  return(EXCEPTION_EXECUTE_HANDLER);
}



___

■ StackWalk

SYNTAX BOOL StackWalk( DWORD MachineType, // IMAGE_FILE_MACHINE_I386 ; HANDLE hProcess, HANDLE hThread, LPSTACKFRAME StackFrame, PVOID ContextRecord, PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine, PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine, PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine, // 関数ポインタ PTRANSLATE_ADDRESS_ROUTINE TranslateAddress // NULL );
___

■ SymSetOptions

SYMOPT_LOAD_LINES : 行番号をロードする
    SymSetOptions ( dwOpts | SYMOPT_LOAD_LINES ) ;
___

■ SymInitialize

BOOL SymInitialize( HANDLE hProcess, PSTR UserSearchPath, // シンボル情報ファイルの検索パス BOOL fInvadeProcess ); RET TRUE : 成功 FALSE : 失敗 DESC プロセス用のシンボルハンドラを初期化する。 シンボルハンドラの観点では、 プロセスはシンボル情報を収集するときに利用できる便利なオブジェクトです。 シンボルハンドラを利用するのは、 デバッグ対象のプロセス用のシンボルをロードする必要のあるデバッガや他のツールです。
    HANDLE hProcess = GetCurrentProcess () ;

        if ( FALSE == g_cSym.SymInitialize ( hProcess ,
                                             NULL     ,
                                             FALSE     ) )
    

    if ( GetThreadContext ( GetCurrentThread ( ) , &stCtx ) )

___

■ GlobalAlloc

SYNTAX HGLOBAL GlobalAlloc( UINT flag, // 割り当て方法 DWORD sz // サイズ ); RET NULL : 失敗 DESC 指定された Byte 数を Heap から割り当てる。 POINT 「固定メモリ」と「移動可能メモリ」の二種類のメモリを割り当てる機能がある。 固定メモリ 割り当てたメモリ領域のアドレスが返される 移動可能メモリ メモリ領域を識別するハンドルが返され、メモリ領域自体は任意に移動される 移動可能メモリはvmem機構の存在しなかったWin16の時代の名残。 vmem機構の備わったWin32環境ではほとんど意味はない。 ただし、DDEやクリップボードなどへのデータの送受信など 特定の目的で使用する場合はある。

    // 固定 Memory Address として割り振る
    
    // Win32 では 物理 Memory の 移動, Swap はされる
    // 理論上は 固定 ということ
    // 
    GlobalAlloc( GMEM_FIXED, sz );

    
    // 仮想 Memory 空間を移動できる
    GlobalAlloc( GMEM_MOVEABLE, sz );

___

■ SymGetSymFromAddr

SYNTAX BOOL SymGetSymFromAddr( HANDLE hProcess, DWORD Address, // 検索したいシンボルのアドレス( シンボルの境界でなくてもかまいません。 アドレスがシンボルの先頭とシンボルの終わり ( シンボルの先頭にシンボルサイズを足した位置)の間にある場合そのシンボルが見つかる) PDWORD Displacement, // シンボルの先頭からの変位( オフセット)、または 0 を指定します。 PIMAGEHLP_SYMBOL Symbol // シンボル名を受け取る構造体 ); DESC プログラムカウンタから関数名を取得する。 指定されたアドレスに置かれているシンボルを検索します。
___

■ SymGetLineFromAddr

SYNTAX BOOL SymGetLineFromAddr( HANDLE hProcess, DWORD dwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINE Line ); DESC 指定されたアドレスに対応するソースコードの行、ファイル名を検索する。 SymGetLineFromAddr を呼び出すに Line バッファを割り当て、 構造体の必要なメンバ( サイズなど )をセットすること。
        IMAGEHLP_LINE stIHL ;
        ZeroMemory ( &stIHL , sizeof ( IMAGEHLP_LINE ) ) ;

        stIHL.SizeOfStruct = sizeof ( IMAGEHLP_LINE ) ;

        if ( 0 != SymGetLineFromAddr ( dwAddr  ,
                                              &dwDisp ,
                                              &stIHL   ) )
        {
            // Put this on the next line and indented a bit.
            pCurrPos += wsprintf ( pCurrPos                  ,
                                  _T ( "\n\t\t%s, Line %d" ) ,
                                  stIHL.FileName             ,
                                  stIHL.LineNumber            ) ;

            // オフセットがあれば                                  
            if ( 0 != dwDisp )
            {
                pCurrPos += wsprintf ( pCurrPos             ,
                                       _T ( " + %d bytes" ) ,
                                       dwDisp                ) ;
            }
        }

___

■ SymCleanup

SYNTAX BOOL SymCleanup( HANDLE hProcess ); DESC プロセスハンドルに関連付けられているすべてのリソースの割り当てを解除する。
___

■ ReadProcessMemory

SYNTAX BOOL ReadProcessMemory( HANDLE hProcess, // プロセスのハンドル LPCVOID lpBaseAddress, // 読み取り開始アドレス LPVOID buf, // データを格納するバッファ DWORD size, // 読むバイト数 LPDWORD lpNumberOfBytesRead // 読み取ったバイト数 ); DESC 指定されたプロセスのアドレス空間から指定された範囲のデータを 現在のプロセスの指定されたバッファへコピーします。 PROCESS_VM_READ アクセス権付きのハンドルを備えている任意のプロセスは この関数を呼び出せます。 通常は、デバッグ中のプロセスを読み取り対象にする。( それ以外にも使ってもよい。 ) POINT プロセスのハンドルは自身でも良いし、別のプロセスでも良い。 デバッガがデバッグ対象のプロセスの仮想メモリ空間の値を変更するために使う。
___

■ WriteProcessMemory

___

■ SetUnhandledExceptionFilter

SYNTAX LPTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter( LPTOP_LEVEL_EXCEPTION_FILTER callback ); DESC Win32 が各スレッドとプロセスの最上位に置くトップレベル例外ハンドラを呼び出し元アプリケーションに置き換えます この関数の呼び出し後 デバッグ中でないプロセスで例外が発生し その例外が Win32 未処理例外フィルタに到着すると、 そのフィルタによって、callback で指定した例外フィルタ関数が呼ばれる。 コールバックされる関数は次のシグネーチャをもつ
    LONG CALLBACK SWFilter( EXCEPTION_POINTERS * );

















NINJAIDX 15