1

J'ai commencé à jouer avec les fonctions spécifiques à Windows, et j'essaie de lire la mémoire d'un proc qui tourne sur ma machine depuis mon propre exécutable.

J'ai ouvert le programme dans IDA, je récupère l'offset de la .rdata. (0x00BB8638) Donc après je me lance dans mon code C++.

https://gist.github.com/109270164362837da0be

Le soucis est dans CheckClientBuild. J'ai du mal à trouver de la doc que j'arrive à comprendre sur ReadProcessMemory et sur l'ASLR (j'en comprend le principe). Pour la base address j'y comprend encore moins de choses, j'ai pas le vocabulaire anglais sur ce domaine pour tout comprendre, je suis parti d'un commentaire sur stackoverflow disant qu'un HANDLE c'est simplement la base address du process. Sauf que là ça fonctionne pas (Et j'ai vérifié treize fois que j'avais pris le bon offset dans IDA). Bref je sais pas trop quoi faire et ca m'énerve.

En gros je comprend plus ce que je dois faire. :x Ce qui est sûr c'est qu'un truc cloche, sur deux Wow.exe de différente version j'ai la même base adress ???

Si vous avez de la doc sur le sujet je prend (hors msdn bien sûr), et un coup de pouce je dirais pas non!

Merci smile

2

Je ne sais pas si je vais pouvoir beaucoup t'aider, partant du principe que WoW est assez protégé contre tout ce qui tente de toucher à l'intégrité de son processus. (warden…)

Commençons par la théorie :
Mais premièrement, un handle (type générique HANDLE sous Win32) c'est juste… Un handle. Ça ne représente pas (nécessairement) un pointeur, c'est juste une manière de référencer un objet, une ressource, une adresse mémoire… Bref, à peu près n'importe quoi.
Lorsque tu es à l'intérieur d'un processus, les modules sont identifiés par un HMODULE ou HINSTANCE (à moins que je ne dise une bêtise, les deux sont aujourd'hui totalement interchangeables). Et l'implémentation actuelle (qui a peu de chances de changer radicalement tant qu'on reste avec Win32), c'est que HMODULE ou HINSTANCE représente l'adresse de base du module. (L'exécutable est lui-même un module)
Il se trouve que les fonctions de processus de Win32 retournent des handle typés génériquement HANDLE. Mais ce sont des handle de processus. (ça aurait sans doute pu être typé HPROCESS, mais ça ne l'est pas.) Ils représentent donc… Un processus. Et à moins d'en connaître plus sur l'implémentation de ces HANDLE, tu devras te contenter des fonctions documentées de l'API Windows wink

Ce que tu cherches toi, si j'ai bien compris, c'est l'adresse de base du module principal, à savoir le HINSTANCE à l'intérieur du processus externe. Et cela a peu, ou pas de rapport avec le HANDLE de processus que tu récupères par ailleurs ^^
Et ne parlons pas des conversions de pointeur en DWORD dans le code que tu as montré… C'est juste super mauvais. tongue


Après, si ce que tu voulais faire était vraiment de lire les données qui t'intéressent à l'adresse qui t'intéresse, tu pourrais te contenter de les lire dans le module dont tu récupère le chemin d'accès. Sinon, pourquoi s'embêter à récupérer celui-ci ? (Je vous le demande bien !)
Je suppose que ce ton but final, c'est lire des données non statiques dans l'exécutable chargé en mémoire, et que le fichier physique t'intéresse peu. Dans ce cas, en récupérer le chemin d'accès ne te sera d'aucune utilité, ce qui t'intéresse, c'est l'adresse de base du module, à l'intérieur de son processus… (Qui est plus ou moins une boîte noire tant que tu ne t'y injectes pas wink)

Il existe plusieurs moyens de récupérer des informations sur le processus, mais avec les derniers OS, et la protection intégrée à WoW (warden), c'est juste non trivial, et ça requiert probablement pas mal de bidouilles et de hacks… (Rien que la lecture de la mémoire en elle-même peut avoir été restreinte… Je ne me suis pas trop penché sur la chose dernièrement parce que je n'en ai pas vraiment besoin.)
Par exemple, tu pourrais injecter une DLL qui ferait ce que tu veux à l'intérieur du processus. Mais ça serait détecté par warden, et c'est donc non trivial (puisque même après avoir réussi, il faut te cacher de warden…)
Tu pourrais essayer de récupérer le PEB, par exemple avec NtQueryInformationProcess et y lire l'adresse de base…

Bref, c'est non trivial. Je ne peux que te suggérer de regarder ce qui a déjà été fait par d'autres… (Pas évident à trouver, mais très loin d'être impossible wink)
PS : Ce que tu fais, c'est mal, j'espère que tu le sais. embarrassed
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

3

Merci pour les explications top. Pour l'instant la finalité c'est d'avoir une DLL injectée, je bidouille un peu de tout. Elle est déjà injectée, mais j'arrive pas non plus à lire la mémoire (On en revient à ce que tu me disais) depuis la DLL, que ce soit à coup de memcpy ou de VirtualQuery.
Je ne compte pas utiliser ça sur les serveurs de blizzard, ma DLL va être récupérée en quelques secondes si le Warden se met à énumérer les DLLs chargées ... Donc si je veux m'en servir sur offi, je dois obligatoirement passer par une code cave. Mais mon but c'est surtout d'apprendre comment injecter des DLLs, lire la mémoire du process depuis cette DLL et dans le meilleur des cas essayer de remplacer quelques fonctions par certaines de mon cru (Mangos ou TrinityCore, peu importe).

Et sinon oui, tout est affreux dans ce code, quand je fais pas du travail sur les processus c'est bien plus propre grin

4

Mais si tu as une DLL injectée, je ne vois pas pourquoi tu ne pourrais pas lire la mémoire tongue
Tu peux montrer ton code ? (Si ce n'est pas indiscret ^^)
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

5

Pas indiscret du tout, j'essaie en fait de ne pas injecter la DLL si l'adresse mémoire ne pointe pas vers la bonne valeur (C'est la version de build, elle change selon chaque client mais c'est celle de la 4.3.4.15595).

Sauf que comme je ne connais absolument pas l'API Windows je sais pas trop comment lire la mémoire du process une fois ma DLL injectée ... Memcpy ? ReadMemory ? Est-ce que je dois rebase mes adresses à wow.exe - 0x400000 + offset, ou offset - 0x400000 ? Je suis assez largué. En outre j'alloue une console depuis ma DLL mais utiliser printf avec des "%u" et compagnie, ça fait crasher le client (J'ai modifié le code vite fait ce matin avant d'aller en cours, j'ai dû foirer un truc)

Note: Y a beaucoup de trucs totalement faux, erronés, et pas du tout recommendables, mais vu que je joue avec le client hors-ligne ... J'ai pas trop à m'inquiéter de Blizzard et du Warden.

https://gist.github.com/aa98fa4871f8a500a809

6

Mais, tu peux aussi simplement injecter la DLL, et la décharger volontairement si le numéro de build ne correspond pas à ce que tu veux… non ? tongue

Et c'est simple, une fois à l'intérieur, l'adresse de base du module principal (wow.exe ici), c'est la valeur qui est utilisée comme HINSTANCE… Que tu récupères d'ailleurs déjà avec GetModuleHandle(NULL).
Une fois que tu connais cette valeur, tu adresses les données à l'intérieur de l'exécutable comme il te chante.
Par exemple en déclarant BYTE *wowBinary = (BYTE*)GetModuleHandle(NULL);
Si par la suite tu veux lire des données à une adresse spécifique, c'est plutôt simple:

#define READ_DWORD(ptr) (*(DWORD*)(void*)(ptr))
#define READ_WORD(ptr) (*(WORD*)(void*)(ptr))
#define READ_BYTE(ptr) (*(BYTE*)(void*)(ptr))

WORD build = READ_WORD(0x00BB8638);

Quand au code qui tente d'écrire sur la console, regarde si le handle retourné pour stdout n'est pas nul, ça pourrait bien être ça ton problème…
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

7

GoldenCrystal (./6) :
Mais, tu peux aussi simplement injecter la DLL, et la décharger volontairement si le numéro de build ne correspond pas à ce que tu veux… non ? tongue.gif


C'est exactement ce que je fais là, j'ai recodé mon torchon.
GoldenCrystal (./6) :
GetModuleHandle(NULL)


Le soucis avec ça c'est que j'obtiens (HANDLE)-1 des fois, (0xFFFFFFFF), et d'après la msdn je dois utiliser DuplicateHandle confus.

Autre bizarrerie de mon nouveau code actuel, c'est qu'il trouve le processus Wow.exe mais il m'injecte dans des onglets de chrome grin

[EDIT] Et GetModuleHandle() depuis ma DLL ne va pas me retourner ma DLL au lieu du module principal ?

8

0xFFFFFFFF c'est un pseudohandle, autrement dit une valeur spéciale que certaines fonctions considèrent comme signifiant "le process depuis lequel la fonction est appelée."
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

9

C'est pas du tout normal que GetModuleHandle te retourne -1. C'est la manière standard de récupérer le HINSTANCE (outre le récupérer en paramètre de WinMain), et c'est bien précisé dans la documentation :
If this parameter is NULL, GetModuleHandle returns a handle to the file used to create the calling process (.exe file).

Et si la fonction rate elle doit retourner NULL…

D'ailleurs c'est tout aussi peu normal que ta DLL s'injecte dans Chrome… Tu as forcément du rater un truc ! tongue


Quand au DuplicateHandle je ne vois pas en quoi ça te permettrait d'obtenir un handle type HINSTANCE/HMODULE… C'est juste pas le même genre de handles. (Vu qu'ils représentent une adresse dans l'espace mémoire d'un processus particulier (ou de tous les processus la plupart du temps), alors que les handles du système vont typiquement pointer quelque part dans une ou plusieurs tables internes au système d'exploitation)


Sinon, -1 c'est INVALID_HANDLE_VALUE, et en général quand on veut passer une valeur par défaut de HINSTANCE, on utilise plutôt NULL tongue

D'ailleurs petit bonus : http://blogs.msdn.com/b/oldnewthing/archive/2004/03/02/82639.aspx
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

10

Ah oui tiens, ils ont utilisé la même valeur pour INVALID_HANDLE_VALUE et le pseudo-handle, c'est pratique triso
http://msdn.microsoft.com/en-us/library/windows/desktop/ms683179(v=vs.85).aspx

edit : bon ben c'est dans le billet que tu as cité cheeky
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

11

Au passage, à part en de rares exceptions (comme la fonction LoadImage(), qui retourne en fait des handles de plusieurs types différents), les handles de type HANDLE référencent quelque chose de bien plus précis que "n'importe quoi": Ce sont des handles d'objets du kernel, l'équivalent des descripteurs de fichier d'*n*x.
Tous les handles de ce type sont compatibles avec des fonctions comme GetKernelObjectSecurity() et CloseHandle(), et beaucoup partagent des fonctions comme DuplicateHandle() et WaitForSingleObject().
avatar
Maintenant j'ai la flemme de garder une signature à jour sur ce site. Je n'ai même plus ma chaîne Exec sous la main.

12

En fait, tous les handle de Windows dérivent du type HANDLE. Il faut juste savoir au cas par cas quel type de handle (au sens de ce qu'il représente, pas spécialement son type en C) peut être utilisé par quelles fonctions. (Vu que de toutes façons en C, les typedef ne représentent pas vraiment un typage fort)
Il suffit de se référrer à la documentation pour savoir quel type d'opération est autorisée sur quel type de handle. Et cela s'applique aussi au handles qui sont typés avec le type générique HANDLE. C'est pas parce que tu reçois une variable de type HANDLE que tu ne sais pas si le handle (doît) représente(r) un processus, un bitmap, un fichier, un écran, un curseur, une fenêtre…
Le type réel de handle, tu dois le connaître dans ta tête, et si possible nommer ta variable correctement pour que ça apparaisse évident, mais ça ne t'empêchera jamais d'appeler la mauvaise fonction si tu veux faire n'importe quoi. (Ou si tu le fais par erreur)
Après, c'est juste une question de logique.

Bref, c'est pas le type qui est marqué en C qui compte, au final c'est ce que tu sais que tu as le droit de faire ou non. (Et ça peut-être assez difficile au début, d'où l'intérêt de se reporter à la documentation… et d'espérer qu'elle ne soit pas trop erronnée tongue)
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

13

(petite correction : pour les objets graphiques/UI, ce n'est pas le même type de handle, cf le lien que tu as posté hehe)
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

14

Oui, ce sont des handle GDI ou des handle User32. Mais c'est un détail d'implémentation… En quelque sorte… tongue
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

15

C'est pas parce que tu reçois une variable de type HANDLE que tu ne sais pas si le handle (doît) représente(r) un processus, un bitmap, un fichier, un écran, un curseur, une fenêtre…

Là, je te corrige. À part dans les exceptions pré-citées, un handle de type déclaré HANDLE n'est pas censé représenter un bitmap, un curseur ou une fenêtre (et probablement pas un écran non plus): Ce ne sont pas des objets du Kernel.

Il y a plusieurs types d'"objets" Windows: Les trois principaux sont objets du Kernel (HANDLE), objets USER (handles typés, dont HWND) et objets GDI (handles typés dont HBITMAP ou HGDIOBJ)

Après, bien sûr, quelqu'un peut déclarer un HANDLE et s'en servir pour référencer un objet GDI, vu que HANDLE et HGDIOBJ sont tous les deux des typedefs sur void* (tout comme quelqu'un peut déclarer un BOOL et y mettre n'importe quelle valeur entière), mais cela ne sert qu'à rendre le code illisible: J'attribuerais donc cela soit à de l'incompétence, soit à un effort conscient d'obfuscation.
avatar
Maintenant j'ai la flemme de garder une signature à jour sur ce site. Je n'ai même plus ma chaîne Exec sous la main.

16

http://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx
typedef HANDLE HWND;
typedef HANDLE HBITMAP;
typedef HANDLE HICON;


Je sais pas si tu saisis où je veux en venir ?
Handle, c'est le concept. HANDLE c'est le type générique de handle (non spécialisé).
Tous les types de handles sont (aujourd'hui) basés sur ce type, ce sont donc tous en quelque sorte des HANDLE. (Au sens du langage C)

C'est juste pas ça qui compte. Le concept, c'est un handle représente "un truc", et sur "un truc", j'a le droit de faire "ces opérations là et pas d'autres".

Tu peux juste pas dire que HANDLE == handle kernel. C'est tout. (C'est pas parce que c'est souvent, voire presque toujours le cas, que c'en est plus vrai)
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

17

µtoilettes, quoi… gni
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

18

Ces définitions sont obsolètes.

Les vraies sont, de mémoire:
#define DECLARE_HANDLE(h) typedef struct h ## __ { int unused; } *h

DECLARE_HANDLE(HWND);
DECLARE_HANDLE(HBITMAP);
etc.


Edit: Oublié une étoile
avatar
Maintenant j'ai la flemme de garder une signature à jour sur ce site. Je n'ai même plus ma chaîne Exec sous la main.

19

Ah oui, c'est vrai qu'il y a les deux définitions, j'ai complètement zappé… (Le flag STRICT est activé par défaut pour te forcer à faire des cast explicites quand tu en as besoin, mais ça ne t'empêchera pas de faire des conneries là où aucun cast n'est nécessaire pour faire une connerie.)
#ifdef STRICT
typedef void *HANDLE;
#if 0 && (_MSC_VER > 1000)
#define DECLARE_HANDLE(name) struct name##__; typedef struct name##__ *name
#else
#define DECLARE_HANDLE(name) struct name##__{int unused;}; typedef struct name##__ *name
#endif
#else
typedef PVOID HANDLE;
#define DECLARE_HANDLE(name) typedef HANDLE name
#endif
typedef HANDLE *PHANDLE;

Cela dit je maintiens quand même. Le type C du handle, ça ne compte pas.
Même si tu peux appeler CloseHandle sur (à priori) n'importe quel type de handle système (comme tu le fais remarquer à juste titre), ça veut pas dire que toutes les fonctions qui prendront un paramètre HANDLE fonctionneront dessus (ce qui était aussi écrit dans ton post d'ailleurs), donc le raisonnement de départ est débile.
Typiquement c'est pas ce type qui va t'empêcher d'apeller CreateFile sur un handle de processus, même si dans les deux cas ça sera typé exactement HANDLE… tongue Pourtant ça sera pas valide.
(NB : tu noteras qu'à priori les déclarations de handle n'interdisent pas le downcast implicite vers HANDLE à partir d'un handle explicite, mais seulement entre deux types distincts de HANDLE explicites)


Le raisonnement, c'est par exemple :
Fichier (HANDLE) => handle de fichier => handle kernel
Processus (HANDLE) => handle de processus => handle kernel
et non pas HANDLE => handle kernel… C'est juste trop simplifié, et ça exclut trop de choses importantes.



Et Kevin… Commentaire très utile comme d'habitude quand on ne parle pas de Linux… tongue
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

20

Tu as raison sur le fait que tous les objets du kernel n'aient pas les mêmes fonctionnalités.
avatar
Maintenant j'ai la flemme de garder une signature à jour sur ce site. Je n'ai même plus ma chaîne Exec sous la main.

21

Merci à vous, j'ai ma DLL qui s'injecte, ça fonctionne au poil maintenant ^^

Plus qu'à trouver où injecter mes propres fonctions .. sad

[EDIT] FU. J'essaie de lire la build du jeu (12340 ou 15595), avec de l'ASM inline. La string est dans les .rdata de l'exécutable, donc je fais un joli
__asm { mov clientBuild, dword ptr 0x5F5200 }

Mais ça fonctionne pas, quoi que je fasse, il me retourne la valeur décimale du pointeur (0x5F5200)

(C'est là qu'on voit que j'y connais vraiment quedalle à l'ASM grin)

[EDIT2]C'est bon ^^