マインスイーパをサンプルアプリケーションとして使用して、リバースエンジニアリングについて学習しようとしています。私はこれを発見しました MSDN記事 すべての地雷を明らかにする単純なWinDbgコマンドで、それは古く、詳細に説明されておらず、本当に私が探しているものではありません。
IDA Pro逆アセンブラー と WinDbgデバッガー があり、両方にwinmine.exeをロードしました。誰かがこれらのプログラムのいずれかに対して、鉱山フィールドを表すデータ構造の場所を見つけるという点で実用的なヒントを提供できますか?
WinDbgではブレークポイントを設定できますが、ブレークポイントを設定するポイントとメモリの場所を想像するのは困難です。同様に、IDA Proで静的コードを表示するとき、鉱山フィールドを表す関数またはデータ構造の検索を開始する場所がわからない。
Stackoverflowで私を正しい方向に向けることができるリバースエンジニアはいますか?
リバースエンジニアリングを真剣に考えている場合は、トレーナーとチートエンジンを忘れてください。
優れたリバースエンジニアは、まずOS、コアAPI関数、プログラムの一般構造(実行ループ、Windows構造、イベント処理ルーチン)、ファイル形式(PE)を理解する必要があります。 Petzoldの古典的な「Windowsのプログラミング」は、オンラインMSDNだけでなく(www.Amazon.com/exec/obidos/ISBN=157231995X)にも役立ちます。
最初に、地雷原の初期化ルーチンをどこで呼び出すことができるかを考える必要があります。私は次のことを考えました:
F2アクセラレータコマンドをチェックアウトすることにしました。
アクセラレータ処理コードを見つけるには、ウィンドウメッセージ処理手順(WndProc)を見つけます。 CreateWindowExおよびRegisterClass呼び出しによって追跡できます。
読むには:
IDAの[インポート]ウィンドウを開き、[CreateWindow *]を見つけてそこにジャンプし、[Xrefをオペランド(X)にジャンプ]コマンドを使用して、呼び出される場所を確認します。呼び出しは1つだけにする必要があります。
上記のRegisterClass関数とそのパラメーターWndClass.lpfnWndProcを見てください。私の場合、すでに関数mainWndProcに名前を付けています。
.text:0100225D mov [ebp+WndClass.lpfnWndProc], offset mainWndProc
.text:01002264 mov [ebp+WndClass.cbClsExtra], edi
.text:01002267 mov [ebp+WndClass.cbWndExtra], edi
.text:0100226A mov [ebp+WndClass.hInstance], ecx
.text:0100226D mov [ebp+WndClass.hIcon], eax
.text:01002292 call ds:RegisterClassW
関数名でEnterキーを押します(「N」を使用してより良い名前に変更します)
今見てみましょう
.text:01001BCF mov edx, [ebp+Msg]
これはメッセージIDであり、F2ボタンを押す場合はWM_COMMAND値を含める必要があります。 111hと比較される場所を見つける必要があります。これは、IDAでedxをトレースダウンするか、WinDbgで 条件付きブレークポイントを設定 でゲームでF2を押すことで実行できます。
どちらの方法でも次のようなものにつながります
.text:01001D5B sub eax, 111h
.text:01001D60 jz short loc_1001DBC
111hを右クリックし、「シンボリック定数」->「標準シンボリック定数を使用」を使用し、WM_と入力してEnterキーを押します。あなたは今持っているはずです
.text:01001D5B sub eax, WM_COMMAND
.text:01001D60 jz short loc_1001DBC
これは、メッセージID値を見つける簡単な方法です。
アクセラレータの取り扱いを理解するには、チェックアウト:
単一の答えにはかなりの量のテキストがあります。興味があれば、別の投稿を書くことができます。長いストーリーの短い地雷原はバイトの配列[24x36]として格納され、0x0Fはバイトが使用されていないことを示します(より小さいフィールドを再生)、0x10-空のフィールド、0x80-鉱山。
OK、F2ボタンで続けましょう。
キーボードアクセラレータの使用 によると、F2ボタンが押されたときwndProc関数
... WM_COMMANDまたはWM_SYSCOMMANDメッセージを受信します。 wParamパラメーターの下位ワードには、アクセラレーターの識別子が含まれています。
OK、WM_COMMANDが処理される場所は既に見つかりましたが、対応するwParamパラメーター値を決定する方法は?これが Resource hacker の出番です。バイナリでフィードすると、すべてが表示されます。私にとってアクセラレータテーブルのようなものです。
alt text http://files.getdropbox.com/u/1478671/2009-07-29_161532.jpg
ここでわかるように、F2ボタンはwParamの510に対応しています。
それでは、WM_COMMANDを処理するコードに戻りましょう。 wParamと異なる定数を比較します。
.text:01001DBC HandleWM_COMMAND: ; CODE XREF: mainWndProc+197j
.text:01001DBC movzx eax, Word ptr [ebp+wParam]
.text:01001DC0 mov ecx, 210h
.text:01001DC5 cmp eax, ecx
.text:01001DC7 jg loc_1001EDC
.text:01001DC7
.text:01001DCD jz loc_1001ED2
.text:01001DCD
.text:01001DD3 cmp eax, 1FEh
.text:01001DD8 jz loc_1001EC8
コンテキストメニューまたは「H」キーボードショートカットを使用して10進数値を表示すると、ジャンプを確認できます
.text:01001DBC HandleWM_COMMAND: ; CODE XREF: mainWndProc+197j
.text:01001DBC movzx eax, Word ptr [ebp+wParam]
.text:01001DC0 mov ecx, 528
.text:01001DC5 cmp eax, ecx
.text:01001DC7 jg loc_1001EDC
.text:01001DC7
.text:01001DCD jz loc_1001ED2
.text:01001DCD
.text:01001DD3 cmp eax, 510
.text:01001DD8 jz loc_1001EC8 ; here is our jump
いくつかのprocを呼び出してwndProcを終了するコードチャンクにつながります。
.text:01001EC8 loc_1001EC8: ; CODE XREF: mainWndProc+20Fj
.text:01001EC8 call sub_100367A ; startNewGame ?
.text:01001EC8
.text:01001ECD jmp callDefAndExit ; default
それは新しいゲームを開始する機能ですか?最後の部分でそれを見つけてください!乞うご期待。
その関数の最初の部分を見てみましょう
.text:0100367A sub_100367A proc near ; CODE XREF: sub_100140C+CAp
.text:0100367A ; sub_1001B49+33j ...
.text:0100367A mov eax, dword_10056AC
.text:0100367F mov ecx, uValue
.text:01003685 Push ebx
.text:01003686 Push esi
.text:01003687 Push edi
.text:01003688 xor edi, edi
.text:0100368A cmp eax, dword_1005334
.text:01003690 mov dword_1005164, edi
.text:01003696 jnz short loc_10036A4
.text:01003696
.text:01003698 cmp ecx, dword_1005338
.text:0100369E jnz short loc_10036A4
2つの値(dword_10056AC、uValue)がレジスタeaxおよびecxに読み込まれ、別の2つの値(dword_1005164、dword_1005338)と比較されます。
WinDBG( 'bp 01003696'; on break 'p eax; p ecx')を使用して実際の値を見てください-私にとって地雷原の次元のように見えました。カスタム地雷原サイズで遊んでみると、最初のペアは新しい次元であり、2番目は現在の次元であることが示されました。新しい名前を設定しましょう。
.text:0100367A startNewGame proc near ; CODE XREF: handleButtonPress+CAp
.text:0100367A ; sub_1001B49+33j ...
.text:0100367A mov eax, newMineFieldWidth
.text:0100367F mov ecx, newMineFieldHeight
.text:01003685 Push ebx
.text:01003686 Push esi
.text:01003687 Push edi
.text:01003688 xor edi, edi
.text:0100368A cmp eax, currentMineFieldWidth
.text:01003690 mov dword_1005164, edi
.text:01003696 jnz short loc_10036A4
.text:01003696
.text:01003698 cmp ecx, currentMineFieldHeight
.text:0100369E jnz short loc_10036A4
少し後で新しい値が現在の値を上書きし、サブルーチンが呼び出されます
.text:010036A7 mov currentMineFieldWidth, eax
.text:010036AC mov currentMineFieldHeight, ecx
.text:010036B2 call sub_1002ED5
そして私がそれを見たとき
.text:01002ED5 sub_1002ED5 proc near ; CODE XREF: sub_1002B14:loc_1002B1Ep
.text:01002ED5 ; sub_100367A+38p
.text:01002ED5 mov eax, 360h
.text:01002ED5
.text:01002EDA
.text:01002EDA loc_1002EDA: ; CODE XREF: sub_1002ED5+Dj
.text:01002EDA dec eax
.text:01002EDB mov byte ptr dword_1005340[eax], 0Fh
.text:01002EE2 jnz short loc_1002EDA
私は地雷原アレイを見つけたと完全に確信していました。 360xバイトの長さの配列(dword_1005340)を0xFで初期化するサイクルの原因。
なぜ360h = 864ですか?行には32バイトが必要で、864は32で割ることができるといういくつかのキューがあります。したがって、配列は27 * 32セルを保持できます(UIは最大24 * 30フィールドを許可しますが、境界の配列の周りに1バイトのパディングがあります)。
次のコードは、地雷原の上部と下部の境界線(0x10バイト)を生成します。その混乱の中でループの繰り返しを見ることができることを願っています;)私は紙とペンを使わなければなりませんでした
.text:01002EE4 mov ecx, currentMineFieldWidth
.text:01002EEA mov edx, currentMineFieldHeight
.text:01002EF0 lea eax, [ecx+2]
.text:01002EF3 test eax, eax
.text:01002EF5 Push esi
.text:01002EF6 jz short loc_1002F11 ;
.text:01002EF6
.text:01002EF8 mov esi, edx
.text:01002EFA shl esi, 5
.text:01002EFD lea esi, dword_1005360[esi]
.text:01002EFD
.text:01002F03 draws top and bottom borders
.text:01002F03
.text:01002F03 loc_1002F03: ; CODE XREF: sub_1002ED5+3Aj
.text:01002F03 dec eax
.text:01002F04 mov byte ptr MineField?[eax], 10h ; top border
.text:01002F0B mov byte ptr [esi+eax], 10h ; bottom border
.text:01002F0F jnz short loc_1002F03
.text:01002F0F
.text:01002F11
.text:01002F11 loc_1002F11: ; CODE XREF: sub_1002ED5+21j
.text:01002F11 lea esi, [edx+2]
.text:01002F14 test esi, esi
.text:01002F16 jz short loc_1002F39
そして、残りのサブルーチンは左右の境界線を描画します
.text:01002F18 mov eax, esi
.text:01002F1A shl eax, 5
.text:01002F1D lea edx, MineField?[eax]
.text:01002F23 lea eax, (MineField?+1)[eax+ecx]
.text:01002F23
.text:01002F2A
.text:01002F2A loc_1002F2A: ; CODE XREF: sub_1002ED5+62j
.text:01002F2A sub edx, 20h
.text:01002F2D sub eax, 20h
.text:01002F30 dec esi
.text:01002F31 mov byte ptr [edx], 10h
.text:01002F34 mov byte ptr [eax], 10h
.text:01002F37 jnz short loc_1002F2A
.text:01002F37
.text:01002F39
.text:01002F39 loc_1002F39: ; CODE XREF: sub_1002ED5+41j
.text:01002F39 pop esi
.text:01002F3A retn
WinDBGコマンドをスマートに使用すると、クールな地雷原ダンプ(カスタムサイズ9x9)を提供できます。国境をチェックしてください!
0:000> db /c 20 01005340 L360
01005340 10 10 10 10 10 10 10 10-10 10 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005360 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005380 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010053a0 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010053c0 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010053e0 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005400 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005420 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005440 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005460 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005480 10 10 10 10 10 10 10 10-10 10 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010054a0 0f 0f 0f 0f 0f 0f 0f 0f-0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010054c0 0f 0f 0f 0f 0f 0f 0f 0f-0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010054e0 0f 0f 0f 0f 0f 0f 0f 0f-0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
うーん、トピックを閉じるには別の投稿が必要なようです
ソースを逆アセンブルしようとしているように見えますが、実行する必要があるのは、実行中のプログラムのメモリ空間を調べることです。 16進エディタ HxD には、まさにそれを可能にする機能があります。
メモリ空間に入ったら、ボードをいじりながらメモリのスナップショットを撮るだけです。変化するものとそうでないものを分離します。 16進メモリ内のデータ構造の位置を把握していると思われる場合は、メモリ内で編集してみて、結果としてボードが変化するかどうかを確認してください。
あなたが望むプロセスは、ビデオゲームの「トレーナー」を構築するのと同じです。これらは通常、健康や弾薬などの値がメモリ内のどこに存在するかを見つけ、その場で変更することに基づいています。ゲームトレーナーの作成方法に関する優れたチュートリアルを見つけることができる場合があります。
このコードプロジェクトの記事をご覧ください。これは、あなたが言及したブログ投稿よりも少し深いものです。
http://www.codeproject.com/KB/trace/minememoryreader.aspx
この記事は、掃海艇に関するものではありませんが、WinDbgを使用してメモリを探索するためのステップバイステップガイドを提供します。
http://www.codingthewheel.com/archives/extracting-hidden-text-with-windbg
繰り返しになりますが、これは掃海艇に関するものではありませんが、これは間違いなく私のメモリデバッグのための思考の糧を与えてくれました。ここには豊富なチュートリアルがあります。
http://memoryhacking.com/forums/index.php
また、 CheatEngine (Nick D.による言及)をダウンロードし、付属のチュートリアルを実行してください。
「WinDbgではブレークポイントを設定できますが、ブレークポイントを設定するポイントとメモリの場所を想像するのは困難です。同様に、IDA Proで静的コードを表示するとき、どこから始めてもわからない地雷原を表す関数またはデータ構造を見つけます。」
丁度!
まあ、あなたは鉱山テーブルの構築中に呼び出されるrandom()のようなルーチンを探すことができます。この book は、リバースエンジニアリングを実験していたときに非常に役立ちました。 :)
一般に、ブレークポイントを設定するのに適した場所は、メッセージボックスの呼び出し、サウンドを再生する呼び出し、タイマー、およびその他のwin32 APIルーチンです。
ところで、私は今掃海艇を OllyDbg でスキャンしています。
更新:nemo 素晴らしいツールを思い出した Cheat Engine by Eric "Dark Byte" Heijnen 。
チートエンジン(CE)は、他のプロセスのメモリスペースを監視および変更するための優れたツールです。そのbasic機能以外に、CEには、プロセスの逆アセンブルされたメモリを表示したり、他のプロセスにコードを挿入したりするなどの特別な機能があります。
(そのプロジェクトのreal値は、ソースコード-Delphi-をダウンロードして、それらのメカニズムがどのように実装されているかを確認できることです。 o)
このトピックに関する非常に良い記事は ninformed にあります。これは、マインスイーパの反転(Win32アプリのリバースエンジニアリングの概要として)を非常に詳細に説明しており、非常に優れたリソースです。
このWebサイトの方が役立つ場合があります。
http://www.subversity.net/reversing/hacking-minesweeper
これを行う一般的な方法は次のとおりです。
バウンティに応えて
さて、2回目の読書では、リバースエンジニアリングの方法に関する通常の質問ではなく、WinDBGのようなデバッガの使用方法に関するガイドが必要であるかのように見えます。検索する必要がある値を示すWebサイトを既に示しましたので、質問はどのように検索するのですか?
Minesweeperがインストールされていないため、この例ではメモ帳を使用しています。しかし、考え方は同じです。
入力する
s <options> <memory start> <memory end> <pattern>
「?」を押してから「s」を押すと、ヘルプが表示されます。
必要なメモリパターンが見つかったら、Alt + 5を押して、メモリビューアを起動してNiceディスプレイを表示できます。
WinDBGはある程度慣れる必要がありますが、他のデバッガーと同様に優れています。
鉱山に関する情報は、少なくとも行(つまり、2D配列または配列の配列)のメモリに連続して配置されると想定するのはかなり合理的です。したがって、同じ行のいくつかの隣接するセルを開いて、プロセスのメモリダンプを作成し、それらを比較して、同じメモリ領域で繰り返し変更を探します(つまり、最初のステップで1バイトが変更され、次のステップでバイトがまったく同じ値に変更されたなど)。
また、それがパックされたビット配列である可能性もあります(鉱山ごとに3ビットで、すべての可能な状態を記録するのに十分でなければなりません-クローズ/オープン、鉱山/非鉱山、フラグ付き/フラグなし)パターンは再現可能ですが、見つけるのは難しくなります)。しかし、それは対処するのに便利な構造ではなく、マインスイーパのメモリ使用量がボトルネックだとは思わないので、この種のものが使用される可能性は低いです。
地雷は、おそらく何らかの二次元配列に格納されます。これは、ポインターの配列または単一のCスタイルのブール配列のいずれかであることを意味します。
フォームがマウスアップイベントを受け取るたびに、このデータ構造が参照されます。インデックスは、おそらく整数除算を使用して、マウス座標を使用して計算されます。これはおそらく、オペランドの1つがオフセットとcmp
を使用して計算されるx
または同様の命令を探す必要があることを意味します。ここで、x
は整数除算を含む計算。オフセットは、データ構造の先頭へのポインターになります。
デバッガーでトレースを開始する適切なポイントは、マウスを上げたときです。メインウィンドウプロシージャを見つけます(spyxxなどのツールはウィンドウのプロパティを検査でき、イベントハンドラーアドレスもその1つです)。それに割り込んで、マウスイベントを処理する場所を見つけます。アセンブラーで認識できる場合は、スイッチがあります(windows.hでマウスを上げるためのWM_XXXの値を見てください)。
ブレークポイントをそこに置き、ステップインを開始します。マウスボタンを放してから画面が更新されるまでの間に、victumは探しているデータ構造にアクセスします。
辛抱強く、いつでも何が行われているのかを特定しようとしますが、現在の目的に興味がないと思われるコードを深く見すぎないでください。デバッガーで数回実行して特定することがあります。
通常のwin32アプリケーションワークフローの知識も役立ちます。
厳密には「リバースエンジニアのツール」ではなく、私のようなバカでさえ使用できるおもちゃの詳細ですが、 チートエンジン を確認してください。これにより、メモリのどの部分がいつ変更されたかを簡単に追跡できます。また、ポインタを使用して、変更されたメモリ部分を追跡することもできます(おそらく必要ありませんが)。素敵なインタラクティブなチュートリアルが含まれています。