第6章 実践的な OllyDBG の使い方
前へ 戻る
いよいよ実践編?ですw
まぁそんな大した内容ではないですが^^;
初回のTargetは krackme01 です。
ToolsからもDLできます。
取りあえず実行してみましょう。Enter ID Numberだそうです。適当(98765432など)に入力してみるとwrong!!と言われてしまいました。シリアルタイプですね(当たり前w
Ollyでロードしてみましょう。入力したIDをチェックしているのは実行後なのでF9で実行して構いません。
シリアルタイプでは
@入力されたシリアルの取得
A正しいかどうかのチェック
B結果の出力
って感じなタイプが多いです。従ってこの辺に注目してやればいいわけです。その際に利用することが多いのはAPIだったり文字列だったりします。文字列だと隠されてる場合も多いので、今回はAPIに注目してみましょう〜。
※APIは基本的に引数を伴い、戻り値をEAXに転送します。戻り値が無いのもありますが・・・w
文字列の取得に使われるAPIはGetWindowTextA,GetDlgItemTextA,GetDlgItemIntAの三つが代表的です。覚えましょう!
逆アセンブラウィンドウで右クリック→検索→ラベル名(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でブレークしているので実際にはまだ文字列の取得は行われていません。
|
ちなみに00401099〜004010A3でスタックにPUSHされているのはGetWindowTextAの引数です。 Count :00401099の100は文字列の最大文字数…最大256文字 Buffer:0040109Eの00403200は取得した文字列を格納するアドレスです。 Count :004010A3は取得対象のコントロールのハンドルです。まぁたくさんあるコントロールを識別するためのIDみたいなものです。 GetWindowTextAの戻り値は取得した文字数で、取得に失敗すると0を返します。…98765432と入力すれば8がEAXに返る。 |
詳しくは以下
|
指定されたウィンドウのタイトルバーのテキストをバッファへコピーします。指定されたウィンドウがコントロールの場合はコントロールのテキストをコピーします。ただし他のアプリケーションのコントロールのテキストを取得することはできません。 |
|
int GetWindowText( HWND hWnd, // ウィンドウまたはコントロールのハンドル LPTSTR lpString, // テキストバッファ int nMaxCount // コピーする最大文字数 ); |
|
パラメータ hWnd ウィンドウ( またはテキストを持つコントロール)のハンドルを指定します。 lpString バッファへのポインタを指定します。このバッファにテキストが格納されます。 nMaxCount バッファにコピーする文字の最大数を指定します。テキストのこのサイズを超える部分は切り捨てられます。NULL 文字も数に含められます。 |
|
戻り値 関数が成功するとコピーされた文字列の文字数が返ります(
終端の NULL
文字は含められません)。タイトルバーやテキストがない場合タイトルバーが空の場合および hWnd パラメータに指定したウィンドウハンドルまたはコントロールハンドルが無効な場合は 0 が返ります。 |
と言うわけでF8でGetWindowTextAを実行してみましょう。ダンプウィンドウの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
004010AEのcorrect!!と004010B3の98765432(入力した文字列)を引数にするAPIが登場しました。lstrcmpAは引数の文字列を比較すると言うそのまんまのAPIですw 比較が正しければ0を返し、違えれば0以外を返します。
|
2 つの文字列を比較します。大文字と小文字を区別して比較を行います。 |
|
int lstrcmp( LPCTSTR lpString1, // 最初の文字列 LPCTSTR lpString2 // 2 番目の文字列 ); |
|
パラメータ lpString1
比較に使われる NULL で終わる文字列へのポインタを指定します。 lpString2
比較に使われる NULL で終わる文字列へのポインタを指定します。 |
|
戻り値 lpString1 パラメータが指す文字列が lpString2 パラメータが指す文字列よりも小さい場合負の値が返ります。lpString1 パラメータが指す文字列が lpString2 パラメータが指す文字列よりも大きい場合正の値が返ります。lpString1 パラメータが指す文字列が lpString2 パラメータが指す文字列と等しい場合 0 が返ります。 |
004010BD . 3C 00
CMP
004010BF . 75 15
JNZ SHORT krackme0.004010D6
戻り値を比較して条件分岐しています。比較結果が一致(AL=0)していれば分岐しないことになりますね。では分岐するとどうなるのでしょう?
004010BFでEnterを押せばジャンプ先に移動できます。
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
|
メッセージボックスの作成表示操作を行います。メッセージボックスはアプリケーション定義のタイトルとメッセージおよび任意の定義済みのアイコンとプッシュボタンの組み合わせによって構成されます。 |
|
int MessageBox( HWND hWnd, // オーナーウィンドウのハンドル LPCTSTR lpText, // メッセージボックス内のテキスト LPCTSTR lpCaption, // メッセージボックスのタイトル UINT uType // メッセージボックスのスタイル ); |
|
パラメータ hWnd
[入力]作成したいメッセージボックスのオーナーウィンドウのハンドルを指定します。NULL を指定するとオーナーウィンドウを持たないメ ッセージボックスが作成されます。 lpText
[入力]表示したいメッセージを保持する NULL で終わる文字列へのポインタを指定します。 lpCaption
[入力]ダイアログボックスのタイトルを保持する NULL で終わる文字列へのポインタを指定します。NULL を指定すると既定のタイトル ( 「エラー」)が表示されます。 uType
[入力]メッセージボックスの内容と動作を指定します。フラググループの任意の組み合わせにより指定します。 |
|
戻り値 関数が成功すると押されたボタンに応じた値が返ります。 |
wrong!!と表示されたくないので、004010BFでの分岐はジャンプしたくないと言うことが分かりました。従ってlstrcmpの戻り値を0にしてやればいいことになります。
以上より、正解IDは「correct!!」でした〜。試しに入力してみてください。lstrcmpで0が返って、correct!!のメッセージボックスが出力されるはずです。
※ちなみにlstrcmpを使ってるようなチェッカはチェッカじゃありませんw