Comment puis-je trouver la structure de données qui représente la mise en page de la mine de démineur en mémoire?
-
06-09-2019 - |
Question
Je suis en train d'apprendre sur le reverse engineering, en utilisant Démineur comme exemple d'application. J'ai trouvé cet article MSDN sur une simple commande WinDbg qui révèle toutes les mines, mais il est vieux, n'est pas expliqué en détail et est vraiment pas ce que je cherche.
Je IDA Pro désassembleur et débogueur WinDbg et j'ai chargé winmine.exe dans les deux. Quelqu'un peut-il fournir des conseils pratiques pour l'un de ces programmes en termes de trouver l'emplacement de la structure de données qui représente le champ de mines?
Dans WinDbg je peux mettre des points d'arrêt, mais il est difficile pour moi d'imaginer à quel moment de mettre un point d'arrêt et à quel emplacement mémoire. De même, quand je considère le code statique IDA Pro, je ne suis pas sûr où commencer même à trouver la structure de fonction ou des données qui représente le champ de mines.
Y at-il des ingénieurs inverse sur Stackoverflow qui peut me diriger dans la bonne direction?
La solution
Partie 1 de 3
Si vous êtes sérieux dans l'ingénierie inverse - oublier les formateurs et les moteurs de tricher.
bon ingénieur inverse doit d'abord apprendre à connaître OS, les fonctions API de base, programme structure générale (ce qui est la boucle de fonctionner, les structures de fenêtres, les routines de gestion des événements), le format de fichier (PE). classiques de Petzold "Programmation Windows" peut aider (www.amazon.com/exec/obidos/ISBN=157231995X) ainsi que MSDN en ligne.
D'abord, vous devriez penser à où la routine d'initialisation du champ de mines peut être appelé. Je pensais à ce qui suit:
- Lorsque vous lancez le jeu
- Lorsque vous cliquez sur le visage heureux
- Lorsque vous cliquez sur Jeu-> Nouveau ou appuyez sur F2
- Lorsque vous modifiez niveau de difficulté
J'ai décidé de vérifier la commande d'accélérateur F2.
Pour trouver le code de manipulation d'accélérateur, vous devez trouver un message de fenêtre procédure de traitement (WndProc). Il peut être retracée par des appels CreateWindowEx et registerClass.
A lire:
- http://msdn.microsoft.com /en-us/library/ms632680%28VS.85%29.aspx
- http://msdn.microsoft.com /en-us/library/ms633586%28VS.85%29.aspx
- Chapitre 3 "Windows et messages" de Petzold
Ouvrez IDA, fenêtre importations, trouver « CreateWindow * », sauter et utiliser « Jump xref à l'opérande (X) » commande pour voir où elle est appelée. Il devrait y avoir un seul appel.
Maintenant, regardez ci-dessus pour la fonction RegisterClass et il est paramètre WndClass.lpfnWndProc. Je l'ai déjà nommé la fonction MainWndProc dans mon cas.
.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
Appuyez sur Entrée sur le nom de la fonction (utilisez « N » pour le renommer à quelque chose de mieux)
Maintenant, prenez un coup d'oeil à
.text:01001BCF mov edx, [ebp+Msg]
est id message, qui, en cas de pression sur le bouton F2 doit contenir la valeur WM_COMMAND. Vous devez trouver où il est comparé à 111h. Il peut se faire soit en traçant vers le bas EDX dans l'IDA ou par mise en point d'arrêt conditionnel en WinDbg et en appuyant sur F2 dans le jeu.
De toute façon conduit à quelque chose comme
.text:01001D5B sub eax, 111h
.text:01001D60 jz short loc_1001DBC
Faites un clic droit sur 111h et utiliser « constante symbolique » -> « Utilisez constante symbolique standard », le type WM_ et Entrée. Vous devriez maintenant avoir
.text:01001D5B sub eax, WM_COMMAND
.text:01001D60 jz short loc_1001DBC
Il est un moyen facile de trouver des valeurs id message.
Pour comprendre vérifier la manipulation d'accélérateur sur:
- clavier En utilisant Accélérateurs
- Resource Hacker ( http://angusj.com/resourcehacker/ )
Il est tout à fait beaucoup de texte pour une seule réponse. Si vous êtes intéressé je peux écrire un autre couple de postes. Longue histoire courte champ de mines stockées sous forme d'un tableau d'octets [24x36], 0x0F montre que l'octet n'est pas utilisé (terrain de jeu plus petit), 0x10 - champ vide, 0x80 -. Mien
Partie 2 de 3
Ok, allons-y avec le bouton F2.
Selon En utilisant Raccourcis clavier lorsque le bouton est pressé F2 fonction WNDPROC
... reçoit un WM_COMMAND ou WM_SYSCOMMAND message. Le mot d'ordre faible de la paramètre wParam contient la identifiant de l'accélérateur.
Ok, nous avons déjà trouvé où WM_COMMAND est traité, mais comment déterminer la valeur correspondante du paramètre wParam? C'est là Resource Hacker entre en jeu. Nourrissez avec binaire et il vous montre tout. Comme table accélérateurs pour moi.
alt texte http://files.getdropbox.com/u/1478671/2009-07-29_161532.jpg
Vous pouvez voir ici, ce bouton F2 correspond à 510 wParam.
Maintenant, revenons au code, qui gère WM_COMMAND. Il compare wParam avec des constantes différentes.
.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
Utilisez le menu contextuel ou raccourci clavier « H » pour afficher les valeurs décimales et vous pouvez voir notre saut
.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
Il conduit à gros morceau de code qui appelle une proc et sort WNDPROC.
.text:01001EC8 loc_1001EC8: ; CODE XREF: mainWndProc+20Fj
.text:01001EC8 call sub_100367A ; startNewGame ?
.text:01001EC8
.text:01001ECD jmp callDefAndExit ; default
Est-ce que la fonction qui initie nouveau jeu? Trouvez que dans la dernière partie! Restez à l'écoute.
Partie 3 de 3
Jetons un coup d'oeil à la première partie de cette fonction
.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
Il existe deux valeurs (dword_10056AC, UValue) lu dans les registres EAX et ECX et par rapport à deux autres valeurs (dword_1005164, dword_1005338).
Jetez un oeil à l'aide de valeurs réelles WinDBG ( « pb 01003696 », en cas de rupture « p EAX, p ECX ») - ils semblaient comme les dimensions des champs de mines pour moi. Jouer avec la taille du champ de mines personnalisé a montré que la première paire sont de nouvelles dimensions et seconde - dimensions actuelles. Fixons nouveaux noms.
.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
Un peu plus tard, de nouvelles valeurs écrasent actuelles et sous-programme est appelé
.text:010036A7 mov currentMineFieldWidth, eax
.text:010036AC mov currentMineFieldHeight, ecx
.text:010036B2 call sub_1002ED5
Et quand je l'ai vu
.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
Je suis complètement sûr que j'ai trouvé tableau de champs de mines. Cause du cycle qui INITs tableau de longueur 360h octets (de dword_1005340) avec 0xF.
Pourquoi 360h = 864? Il y a des indices ci-dessous de cette ligne prend 32 octets et 864 peut être divisée par 32, de sorte que matrice peut contenir 27 * 32 cellules (bien que l'interface utilisateur permet max 24 * 30 domaine, il y a un rembourrage d'octets autour de matrice pour les frontières).
code suivant génère dessus des champs de mines et les bordures inférieures (0x10 octets). J'espère que vous pouvez voir itération de la boucle dans ce désordre;) je devais utiliser du papier et un stylo
.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
Et le reste du sous-programme dessine les frontières gauche et droite
.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
Utilisation intelligente des commandes WinDBG peut vous fournir dump champ de mines fraîche (taille personnalisée 9x9). Consultez les frontières!
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 ................................
Hmm, on dirait que je vais avoir besoin d'un autre poste pour fermer le sujet
Autres conseils
Il semble que vous essayez de démonter la source, mais ce que vous devez faire est de regarder l'espace mémoire du programme en cours d'exécution. L'éditeur hexadécimal HxD a une fonctionnalité qui vous permet de tout cela.
Une fois que vous êtes dans l'espace mémoire, il est question de prendre des photos de la mémoire pendant que vous mess avec le conseil d'administration. Isoler ce qui change par rapport à ce qui ne fonctionne pas. Quand vous pensez que vous avez une poignée sur laquelle la structure de données se trouve dans la mémoire hexagonale, essayez de la modifier pendant qu'il est en mémoire et voir si les modifications du conseil d'administration en conséquence.
Le processus que vous voulez est un peu comme la construction d'un « formateur » pour un jeu vidéo. Ceux-ci sont généralement basées sur la recherche où des valeurs telles que la santé et Munitions en mémoire et les changer à la volée. Vous pourrez peut-être trouver quelques bons tutoriels sur la façon de construire des formateurs de jeu.
Consultez cet article du projet de code, il est un peu plus en profondeur que le billet de blog que vous avez mentionné.
http://www.codeproject.com/KB/trace/minememoryreader.aspx
Modifier
Et cet article, mais pas directement démineur, vous donne une bonne étape par étape sur la chasse à travers la mémoire en utilisant WinDbg:
http://www.codingthewheel.com/archives/extracting- caché texte avec-windbg
Edit 2
Encore une fois, on ne parle pas démineur, mais il m'a certainement donné quelques éléments de réflexion pour mon débogage mémoire, il y a une foule de tutoriels ici:
http://memoryhacking.com/forums/index.php
En outre, téléchargez cheatengine (mentionné par Nick D.) et de travailler à travers le tutoriel, il est livré avec.
"Dans WinDbg je peux définir des points d'arrêt, mais il est difficile pour moi d'imaginer à quel point de mettre un point d'arrêt et à quel endroit la mémoire. De même, lorsque Je considère le code statique Pro IDA, je suis pas sûr où même commencer à trouver la fonction ou structure de données qui représente le champ de mines ».
Exactement!
Eh bien, vous pouvez rechercher des routines comme aléatoire () qui seront appelés lors de la construction de la table des mines. Cette livre m'a beaucoup aidé quand je faisais des expériences avec l'ingénierie inverse. :)
En général, de bons endroits pour définir des points d'arrêt sont des appels à des boîtes de message, appelle à jouer un son, des minuteries et d'autres routines API win32.
BTW, je balayais démineur en ce moment avec OllyDbg .
Mise à jour: nemo m'a rappelé un excellent outil, Cheat moteur par Eric "Dark Byte" Heijnen.
Cheat Engine (CE) est un excellent outil pour regarder et modifier d'autres processus de l'espace mémoire. Au-delà base établissement, CE dispose de fonctionnalités plus spécifiques comme l'affichage de la mémoire démontées d'un processus et d'injection de code dans d'autres processus.
( real valeur de ce projet est que vous pouvez télécharger le code source -Delphi- et voir comment ces mécanismes ont été mis en œuvre - je l'ai fait il y a plusieurs années: o)
Ce site pourrait être plus utile:
http://www.subversity.net/reversing/hacking-minesweeper
La façon générale d'aller sur le faire est:
- obtenir le code source une certaine façon.
- Démontez et l'espoir symboles restants peuvent vous aider.
- Devinez le type de données et essayer de le manipuler et utiliser un scanner de mémoire pour limiter les possibilités.
En réponse à Bounty
Eh bien, en deuxième lecture, il apparaît comme si vous vouliez un guide sur la façon d'utiliser un débogueur comme WinDBG plutôt que la question habituelle de savoir comment désosser. Je vous ai déjà montré le site qui vous indique les valeurs que vous devez rechercher, la question est, comment cherchez-vous cela?
J'utilise le Bloc-notes dans cet exemple parce que je ne l'ai pas installé Démineur. Mais l'idée est la même.
Vous tapez
s <options> <memory start> <memory end> <pattern>
Appuyez sur "?", Puis "s" pour voir l'aide.
Une fois que vous avez trouvé le modèle de mémoire que vous voulez, vous pouvez appuyer sur alt + 5 pour afficher la visionneuse de la mémoire pour un affichage agréable.
WinDBG prend un certain temps pour s'y habituer, mais il est aussi bon que tout autre débogueur là-bas.
Un bon point pour commencer le traçage dans débogueur serait sur place de la souris. Donc, trouver la procédure de la fenêtre principale (je pense que des outils tels que spyxx peut inspecter les propriétés des fenêtres et l'adresse de gestionnaire d'événements est l'un d'entre eux). Cassez pour trouver et où il gère les événements de souris - il y aura un interrupteur, si vous pouvez le reconnaître en assembleur (regarder la valeur de WM_xxx jusqu'à la souris dans windows.h)
.Mettez un point d'arrêt et commencer à y Intervenir. Quelque part entre le moment où vous avez relâché le bouton de la souris et l'écran mis à jour le victum accédera à la structure de données que vous recherchez.
Soyez patient, essayez d'identifier ce qui est fait à un moment donné, mais ne cherchez pas trop profondément dans le code que vous soupçonnez d'être sans intérêt pour votre objectif actuel. Il peut prendre plusieurs pistes Débogueur pour clouer vers le bas.
La connaissance du déroulement normal des travaux des applications win32 aide aussi.
Les mines seront probablement stockées dans une sorte de tableau à deux dimensions. Cela signifie qu'il est soit un tableau de pointeurs ou d'un seul tableau de style C de booléens.
Chaque fois que la forme reçoit un événement de souris cette structure de données est référencée. L'indice sera calculé à l'aide de coordonnées souris, en utilisant probablement la division entière. Cela signifie que vous devriez probablement pour une cmp
ou une instruction similaire, où l'un des opérandes est calculée à partir d'un décalage et x
, où x
est le résultat d'un calcul impliquant la division entière. Le décalage sera alors le pointeur au début de la structure de données.
Il est assez raisonnable de supposer que des informations sur les mines est aménagé de manière contiguë à la mémoire, au moins pour les lignes (à savoir, il est un tableau 2D, ou un tableaux-of-array). Ainsi, je voudrais essayer d'ouvrir plusieurs cellules adjacentes dans la même rangée, ce qui rend les décharges de mémoire du processus que je vais, puis les diff et chercher tout changement de répétition dans la même région de mémoire (par exemple 1 octet modifié lors de la première étape, la prochaine octet modifié pour exactement la même valeur à l'étape suivante, etc).
Il y a aussi la possibilité que c'est un tableau de bits emballé (3 bits par mine devrait être suffisante pour enregistrer tous les états possibles - fermé / ouvert, moi / non-moi, marqué / non battant pavillon), donc je regarderais pour que trop (les modèles seraient également reproductibles, bien que plus difficile à repérer). Mais ce n'est pas une structure pratique pour traiter, et je ne pense pas que l'utilisation de la mémoire est un goulot d'étranglement pour Démineur, il est donc peu probable que ce genre de chose serait utilisé.
Bien que pas strictement un « outil d'ingénierie inverse », et plus d'un jouet, même un idiot comme moi pourrait utiliser, consultez Cheat moteur. Il rend un peu facile de suivre les parties de la mémoire ont changé, quand et a même des dispositions pour le suivi des parties de mémoire modifiées par des pointeurs (si vous n'avez pas besoin probablement). Un joli tutoriel interactif est inclus.