94

Minesweeper をサンプル アプリケーションとして使用して、リバース エンジニアリングについて学習しようとしています。すべての鉱山を明らかにする単純なWinDbgコマンドに関するこのMSDNの記事を見つけましたが、それは古く、詳細に説明されておらず、実際に私が探しているものではありません.

IDA Pro 逆アセンブラーとWinDbg デバッガーがあり、両方に winmine.exe をロードしました。地雷原を表すデータ構造の場所を見つけるという点で、これらのプログラムのいずれかに関する実用的なヒントを誰かが提供できますか?

WinDbg ではブレークポイントを設定できますが、どの時点で、どのメモリの場所にブレークポイントを設定するかを想像するのは難しいです。同様に、IDA Pro で静的コードを表示すると、地雷原を表す関数またはデータ構造をどこから探し始めればよいかわかりません。

私を正しい方向に導くことができる Stackoverflow のリバース エンジニアはいますか?

4

10 に答える 10

125

パート 1/3


リバース エンジニアリングに真剣に取り組んでいる場合は、トレーナーやチート エンジンのことは忘れてください。

優れたリバース エンジニアは、まず OS、コア API 関数、プログラムの一般的な構造 (実行ループ、Windows 構造、イベント処理ルーチンとは)、ファイル形式 (PE) について理解する必要があります。Petzold の古典的な "Programming Windows" (www.amazon.com/exec/obidos/ISBN=157231995X) とオンラインの MSDN が役に立ちます。

まず、地雷原の初期化ルーチンをどこで呼び出すことができるかを考える必要があります。私は次のことを考えました:

  • ゲームを起動すると
  • ハッピーフェイスをクリックすると
  • Game->Newをクリックするか、F2を押したとき
  • レベル難易度変更時

F2アクセラレータコマンドを調べてみることにしました。

アクセラレータ処理コードを見つけるには、ウィンドウ メッセージ処理プロシージャ (WndProc) を見つけます。これは、CreateWindowEx および RegisterClass 呼び出しによって追跡できます。

読むには:

IDA の [インポート] ウィンドウを開き、"CreateWindow*" を見つけてジャンプし、"Jump xref to operand (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 を右クリックし、"Symbolic constant" -> "Use standard symbolic constant" を使用し、WM_ と入力して Enter を押します。あなたは今持っているはずです

.text:01001D5B                 sub     eax, WM_COMMAND
.text:01001D60                 jz      short loc_1001DBC

メッセージ ID の値を見つける簡単な方法です。

アクセラレータの処理を理解するには、以下を確認してください。

1 つの回答に対してかなりの量のテキストです。もし興味があれば、私は別のいくつかの記事を書くことができます. バイト [24x36] の配列として保存された長い話の短い地雷原。

パート 2/3


では、F2 ボタンを押してみましょう。

Using Keyboard Accelerator when the F2 button is press wndProc 関数によると

... WM_COMMAND または WM_SYSCOMMAND メッセージを受け取ります。wParam パラメータの下位ワードには、アクセラレータの識別子が含まれます。

さて、WM_COMMAND が処理される場所は既に見つかりましたが、対応する wParam パラメータ値を決定する方法は? ここで、リソース ハッカーの出番です。バイナリをフィードすると、すべてが表示されます。私にとってアクセラレータテーブルのように。

代替テキスト 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

それは新しいゲームを開始する機能ですか?最後の部分でそれを見つけてください!乞うご期待。

パート 3/3

その関数の最初の部分を見てみましょう

.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

私は地雷原アレイを見つけたと完全に確信していました。360h バイトの長さの配列 (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  ................................

うーん、トピックを閉じるには別の投稿が必要なようです

于 2009-07-24T12:39:34.777 に答える
15

ソースを逆アセンブルしようとしているように見えますが、実行中のプログラムのメモリ空間を調べる必要があります。16 進エディタHxDには、まさにそれを可能にする機能があります。

http://www.freeimagehosting.net/uploads/fcc1991162.png

メモリ空間に入ったら、ボードをいじりながらメモリのスナップショットを撮るだけです。変化するものと変化しないものを分離します。データ構造が 16 進メモリ内のどこにあるのかを把握していると思われる場合は、それがメモリ内にある間にそれを編集してみて、結果としてボードが変更されるかどうかを確認してください。

必要なプロセスは、ビデオ ゲームの「トレーナー」を作成するのと同じです。それらは通常、ヘルスや弾薬などの値がメモリ内のどこにあるかを見つけて、その場で変更することに基づいています。ゲーム トレーナーの作成方法に関する優れたチュートリアルを見つけることができるかもしれません。

于 2009-07-21T16:27:47.390 に答える
12

このコード プロジェクトの記事を確認してください。これは、あなたが言及したブログ投稿よりも少し詳細です。

http://www.codeproject.com/KB/trace/minememoryreader.aspx

編集

また、この記事はマインスイーパに関するものではありませんが、WinDbg を使用してメモリを探索するための適切なステップ バイ ステップ ガイドを提供します。

http://www.codingthewheel.com/archives/extracting-hidden-text-with-windbg

編集 2

繰り返しますが、これはマインスイーパに関するものではありませんが、メモリのデバッグについて考える材料を与えてくれたことは間違いありません。ここには豊富なチュートリアルがあります。

http://memoryhacking.com/forums/index.php

また、CheatEngine (Nick D. が言及) をダウンロードし、付属のチュートリアルを実行してください。

于 2009-07-07T11:02:04.780 に答える
9

「WinDbg ではブレークポイントを設定できますが、ブレークポイントを設定するポイントとメモリの場所を想像するのは困難です。同様に、IDA Pro で静的コードを表示すると、どこから始めればよいかさえわかりません。地雷原を表す関数またはデータ構造を見つけます。」

丁度!

さて、地雷テーブルの構築中に呼び出される random() のようなルーチンを探すことができます。このは、リバース エンジニアリングを試していたときに大いに役立ちました。:)

一般に、ブレーク ポイントを設定するのに適した場所は、メッセージ ボックスの呼び出し、サウンドを再生するための呼び出し、タイマー、およびその他の win32 API ルーチンです。

ところで、私は現在OllyDbgで掃海艇をスキャンしています。

更新: nemoは素晴らしいツール、 Eric "Dark Byte" Heijnen によるCheat Engineを思い出させました。

チート エンジン (CE) は、他のプロセスのメモリ空間を監視および変更するための優れたツールです。その基本的な機能を超えて、CE には、プロセスの逆アセンブルされたメモリの表示や、他のプロセスへのコードの挿入などの特別な機能があります。

(このプロジェクトの本当の価値は、ソース コード (Delphi) をダウンロードして、それらのメカニズムがどのように実装されているかを確認できることです。私は何年も前にそれを行いました :o)

于 2009-05-31T06:09:09.580 に答える
5

このトピックに関する非常に優れた記事がUninformedにあります。マインスイーパのリバース (Win32 アプリのリバース エンジニアリングの紹介として) について非常に詳細に説明しており、非常に優れたリソースです。

于 2009-07-22T02:51:43.960 に答える
4

このウェブサイトはもっと役立つかもしれません:

http://www.subversity.net/reversing/hacking-minesweeper

これを行う一般的な方法は次のとおりです。

  1. なんとかソースコードを入手。
  2. 分解して、残りのシンボルが役立つことを願っています。
  3. データ型を推測して操作し、メモリ スキャナを使用して可能性を制限します。

バウンティへの対応

さて、2 回目の読み取りでは、リバース エンジニアリングの方法に関する通常の質問ではなく、WinDBG のようなデバッガーの使用方法に関するガイドが必要であるかのように見えます。検索する必要がある値を示す Web サイトは既に示しましたが、問題は、どのように検索するかということです。

マインスイーパがインストールされていないため、この例ではメモ帳を使用しています。しかし、考え方は同じです。

代替テキスト

入力します

s <options> <memory start> <memory end> <pattern>

「?」を押してから「s」を押すと、ヘルプが表示されます。

必要なメモリ パターンが見つかったら、alt+5 を押してメモリ ビューアーを表示し、見栄えを良くすることができます。

代替テキスト

WinDBG は慣れるまでに時間がかかりますが、他のデバッガーと同じくらい優れています。

于 2009-05-31T04:32:44.653 に答える
0

地雷は、おそらくある種の 2 次元配列に格納されます。これは、ポインターの配列か、ブール値の単一の C スタイル配列のいずれかであることを意味します。

フォームがマウスアップ イベントを受け取るたびに、このデータ構造が参照されます。インデックスは、おそらく整数除算を使用して、マウス座標を使用して計算されます。つまり、オペランドの 1 つがオフセットを使用して計算され、が整数除算を含む計算の結果である、cmpまたは同様の命令を探す必要があることを意味します。オフセットは、データ構造の先頭へのポインタになります。xx

于 2009-07-21T23:57:21.147 に答える
0

デバッガーでトレースを開始する適切なポイントは、マウスを離したときです。したがって、メイン ウィンドウ プロシージャを見つけます (spyxx のようなツールはウィンドウのプロパティを検査でき、イベント ハンドラーのアドレスはその 1 つです)。それに割り込んで、マウスイベントを処理する場所を見つけます。アセンブラーで認識できる場合は、スイッチがあります (windows.h でマウスアップの WM_XXX の値を見てください)。

そこにブレークポイントを置いて、ステップインを開始します。マウス ボタンを放してから画面が更新されるまでの間のどこかで、探しているデータ構造にビクタムがアクセスします。

辛抱強く、いつでも何が行われているかを特定するようにしてください。ただし、現在の目的にとって面白くないと思われるコードを深く調べすぎないようにしてください。それを突き止めるには、デバッガーで数回実行する必要がある場合があります。

通常の win32 アプリケーションのワークフローに関する知識も役に立ちます。

于 2009-07-21T04:51:14.933 に答える
0

厳密には「リバース エンジニアのツール」ではなく、私のような馬鹿でも使えるおもちゃのようなものですが、Cheat Engineをチェックしてください。メモリのどの部分がいつ変更されたかを追跡するのがいくらか簡単になり、変更されたメモリ部分をポインタで追跡するための準備さえあります (おそらくそれは必要ありません)。素敵なインタラクティブなチュートリアルが含まれています。

于 2009-07-22T21:32:05.670 に答える
0

地雷に関する情報は、メモリ内で少なくとも行 (つまり、2D 配列または配列の配列) で連続して配置されていると想定するのが妥当です。したがって、同じ行でいくつかの隣接するセルを開いて、プロセスのメモリ ダンプを作成し、それらを比較して、同じメモリ領域で繰り返される変更を探します (つまり、最初のステップで 1 バイトが変更され、次のステップで 1 バイトが変更された)。バイトが次のステップでまったく同じ値に変更されるなど)。

また、パックされたビット配列である可能性もあります (鉱山ごとに 3 ビットで、考えられるすべての状態 (閉鎖/オープン、鉱山/非鉱山、フラグ付き/非フラグ付き) を記録するのに十分なはずです) である可能性もあるので、それにも注意します (パターンも再現可能ですが、見つけるのは困難です)。しかし扱いに都合の良い構造ではないし、マインスイーパではメモリ使用量がボトルネックになることもなかったと思うので、この種のものが使われることはまずないだろう。

于 2009-07-22T02:46:23.517 に答える