第6章 実践的な OllyDBG の使い方

前へ  戻る     次へ

いよいよ実践編?ですw

まぁそんな大した内容ではないですが^^;


初回のTargetは krackme01 です。

ToolsからもDLできます。


 取りあえず実行してみましょう。Enter ID Numberだそうです。適当(98765432など)に入力してみるとwrong!!と言われてしまいました。シリアルタイプですね(当たり前w

 Ollyでロードしてみましょう。入力したIDをチェックしているのは実行後なのでF9で実行して構いません。

 

 シリアルタイプでは

@入力されたシリアルの取得

A正しいかどうかのチェック

B結果の出力

 って感じなタイプが多いです。従ってこの辺に注目してやればいいわけです。その際に利用することが多いのはAPIだったり文字列だったりします。文字列だと隠されてる場合も多いので、今回はAPIに注目してみましょう〜。

APIは基本的に引数を伴い、戻り値をEAXに転送します。戻り値が無いのもありますが・・・w

 

文字列の取得に使われるAPIGetWindowTextAGetDlgItemTextAGetDlgItemIntAの三つが代表的です。覚えましょう!

逆アセンブラウィンドウで右クリック→検索→ラベル名(Ctrl+N)で選択されているモジュールのAPIの一覧が表示されます。GetWindowTextAと入力してみますと、GetWまで入力した時点でGetWindowTextAが選択されました。通常APIはめちゃめちゃあるのでこの方法で探して下さいw。

GetWindowTextAを選択して、右クリック→すべての参照にブレークポイントをセット を選びます。画面上のメニュー下のBと書かれたタブをクリックするとBPの一覧が見ることが出来ます。JMP DWORD PTR DS:[<&user32.GetWindowText>;  user32.GetWindowTextA はあっても邪魔なだけなので消して結構です(CALLではなくJMPで始まるやつw)

 

 と言うわけで以下の行にBPがセットされたはずです。

004010A9   . E8 74000000    CALL <JMP.&user32.GetWindowTextA>        ; \GetWindowTextA

 

もし、このアドレスで入力した文字列の取得が行われているならここでブレークするはずです。と言うわけで試してみましょう。

98765432とダミーシリアルを入力してOKをクリック。

00401099   . 68 00010000    PUSH 100                                 ; /Count = 100 (256.)

0040109E   . 68 00324000    PUSH krackme0.00403200                   ; |Buffer = krackme0.00403200

004010A3   . FF35 08314000  PUSH DWORD PTR DS:[403108]               ; |hWnd = 016B135A (class='Edit',parent=05270AF6)

004010A9   . E8 74000000    CALL <JMP.&user32.GetWindowTextA>        ; \GetWindowTextA

案の定ブレークしましたね。004010A9でブレークしているので実際にはまだ文字列の取得は行われていません。

 

ちなみに00401099004010A3でスタックにPUSHされているのはGetWindowTextA引数(ひきすう)です。

Count 00401099100は文字列の最大文字数…最大256文字

Buffer0040109E00403200は取得した文字列を格納するアドレスです。

Count 004010A3は取得対象のコントロールのハンドルです。まぁたくさんあるコントロールを識別するためのIDみたいなものです。

GetWindowTextAの戻り値は取得した文字数で、取得に失敗すると0を返します。…98765432と入力すれば8EAXに返る。

 

詳しくは以下

GetWindowText

指定されたウィンドウのタイトルバーのテキストをバッファへコピーします。指定されたウィンドウがコントロールの場合はコントロールのテキストをコピーします。ただし他のアプリケーションのコントロールのテキストを取得することはできません。

int GetWindowText(

  HWND hWnd,        // ウィンドウまたはコントロールのハンドル

  LPTSTR lpString,  // テキストバッファ

  int nMaxCount     // コピーする最大文字数

);

パラメータ

hWnd

ウィンドウ( またはテキストを持つコントロール)のハンドルを指定します。

lpString

バッファへのポインタを指定します。このバッファにテキストが格納されます。

nMaxCount

バッファにコピーする文字の最大数を指定します。テキストのこのサイズを超える部分は切り捨てられます。NULL 文字も数に含められます。

戻り値

関数が成功するとコピーされた文字列の文字数が返ります( 終端の NULL 文字は含められません)。タイトルバーやテキストがない場合タイトルバーが空の場合および hWnd パラメータに指定したウィンドウハンドルまたはコントロールハンドルが無効な場合は 0 が返ります。

 

と言うわけでF8GetWindowTextAを実行してみましょう。ダンプウィンドウの403200を見ると入力したダミーシリアルが見えるはずです。

 

004010AE   . 68 18304000    PUSH krackme0.00403018                   ; /String2 = "correct!!"

004010B3   . 68 00324000    PUSH krackme0.00403200                   ; |String1 = "98765432"

004010B8   . E8 89000000    CALL <JMP.&kernel32.lstrcmpA>            ; \lstrcmpA

 

004010AEcorrect!!004010B398765432(入力した文字列)を引数にするAPIが登場しました。lstrcmpAは引数の文字列を比較すると言うそのまんまのAPIですw 比較が正しければ0を返し、違えれば0以外を返します。

 

lstrcmp

2 つの文字列を比較します。大文字と小文字を区別して比較を行います。

int lstrcmp(

  LPCTSTR lpString1,  // 最初の文字列

  LPCTSTR lpString2   // 2 番目の文字列

);

パラメータ

lpString1

比較に使われる NULL で終わる文字列へのポインタを指定します。

lpString2

比較に使われる NULL で終わる文字列へのポインタを指定します。

戻り値

lpString1 パラメータが指す文字列が lpString2 パラメータが指す文字列よりも小さい場合負の値が返ります。lpString1 パラメータが指す文字列が lpString2 パラメータが指す文字列よりも大きい場合正の値が返ります。lpString1 パラメータが指す文字列が lpString2 パラメータが指す文字列と等しい場合 0 が返ります。

 

004010BD   . 3C 00          CMP AL,0

004010BF   . 75 15          JNZ SHORT krackme0.004010D6

 

戻り値を比較して条件分岐しています。比較結果が一致(AL=0)していれば分岐しないことになりますね。では分岐するとどうなるのでしょう?

004010BFEnterを押せばジャンプ先に移動できます。

 

004010D6   > 6A 00          PUSH 0                                   ; /Style = MB_OK|MB_APPLMODAL

004010D8   . 68 22304000    PUSH krackme0.00403022                   ; |Title = "wrong!!"

004010DD   . 68 22304000    PUSH krackme0.00403022                   ; |Text = "wrong!!"

004010E2   . 6A 00          PUSH 0                                   ; |hOwner = NULL

004010E4   . E8 45000000    CALL <JMP.&user32.MessageBoxA>           ; \MessageBoxA

 

文字通り、メッセージボックスを出力するAPIです。メッセージボックスを出すんだ、って程度の認知でもいいですw

 

MessageBox

メッセージボックスの作成表示操作を行います。メッセージボックスはアプリケーション定義のタイトルとメッセージおよび任意の定義済みのアイコンとプッシュボタンの組み合わせによって構成されます。

int MessageBox(

  HWND hWnd,          // オーナーウィンドウのハンドル

  LPCTSTR lpText,     // メッセージボックス内のテキスト

  LPCTSTR lpCaption,  // メッセージボックスのタイトル

  UINT uType          // メッセージボックスのスタイル

);

パラメータ

hWnd

[入力]作成したいメッセージボックスのオーナーウィンドウのハンドルを指定します。NULL を指定するとオーナーウィンドウを持たないメ  ッセージボックスが作成されます。

lpText

[入力]表示したいメッセージを保持する NULL で終わる文字列へのポインタを指定します。

lpCaption

[入力]ダイアログボックスのタイトルを保持する NULL で終わる文字列へのポインタを指定します。NULL を指定すると既定のタイトル ( 「エラー」)が表示されます。

uType

[入力]メッセージボックスの内容と動作を指定します。フラググループの任意の組み合わせにより指定します。

戻り値

関数が成功すると押されたボタンに応じた値が返ります。

 

 wrong!!と表示されたくないので、004010BFでの分岐はジャンプしたくないと言うことが分かりました。従ってlstrcmpの戻り値を0にしてやればいいことになります。

 以上より、正解IDは「correct!!」でした〜。試しに入力してみてください。lstrcmp0が返って、correct!!のメッセージボックスが出力されるはずです。

※ちなみにlstrcmpを使ってるようなチェッカはチェッカじゃありませんw 


前へ  戻る     次へ