DreamRaiser
Vous souhaitez réagir à ce message ? Créez un compte en quelques clics ou connectez-vous pour continuer.
-39%
Le deal à ne pas rater :
Ordinateur portable ASUS Chromebook Vibe CX34 Flip
399 € 649 €
Voir le deal

[x86] Simple memory browser

Aller en bas

[x86] Simple memory browser Empty [x86] Simple memory browser

Message par Akabane87 Mer 21 Jan - 13:45

Pour faire un peu suite à mon tuto sur l'injection DLL, voici un petit bout de code utile pour retrouver des adresses mémoire que l'on cherche dans la mémoire code d'un process dans lequel on s'exécute (ce qui veut dire que ce code est sensé être appelé depuis une dll qu'on injecte dans le programme cible).
On peut avoir besoin d'un tel outil dans le cas d'un programme qui hook le code d'un autre programme mis à jour régulièrement ou simplement si on souhaite retrouver des bouts de code connus à l'avance (d'une autre dll par exemple) sans avoir décompilé le programme cible.

memorybrowser.h
Code:
#ifndef MEMORYBROWSER_H
#define MEMORYBROWSER_H

#include<stdio.h>
#include<windows.h>


// The list of all the interesting addresses we use
enum GameAddressId
{
   GAID_CHAT_SEND_MESSAGE_FUNCTION,

   GAID_DETOUR_CRASH_HANDLER_OFFSET,
   GAID_DETOUR_CHAT_RECEIVE_OFFSET,


   GAID_MAX
};

// a structure containing all the parameters and the result for finding a given address
struct MemorySearchEntry
{
   enum ReadType {RT_LOCATION, RT_ADDRESS, RT_REL_ADDRESS};
   MemorySearchEntry() : Pattern((BYTE*)""), PatternMask(""), Offset(0), Occurence(0), ReadType(RT_LOCATION), Address(0) {}
   MemorySearchEntry(BYTE* pattern, char* patternMask, int offset = 0, unsigned int occurence = 1, ReadType readType = RT_LOCATION)
      : Pattern(pattern), PatternMask(patternMask), Offset(offset), Occurence(occurence), ReadType(readType), Address(0) {}

   BYTE* Pattern;
   char* PatternMask;
   int Offset;
   unsigned int Occurence;
   ReadType ReadType;

   ULONG Address;
};

bool RetrieveAddresses();// retrieve all the addresses of the list
bool DumpAddresses();// dump all the addresses of the list


#endif


memorybrowser.cpp
Code:
#include "memorybrowser.h"

#include <string>

// The table of all the addresses alias we use (for dump and debug)
const char* const MemoryPatternTableStrings[GAID_MAX] =
{
   "CHAT_SEND_MESSAGE_FUNCTION",

   "DETOUR_CRASH_HANDLER_OFFSET",      
   "DETOUR_CHAT_RECEIVE_OFFSET",      
};


// The table of all the memory entries we use initialised with all the parameters we need to retrieve the addresses
MemorySearchEntry MemoryPatternTable[GAID_MAX] =
{
   MemorySearchEntry((BYTE*)"\x01\x51\x8B\x4D\x18\x52",   "xxxxxx",   -0x4d,   1, MemorySearchEntry::RT_LOCATION),   //01 51 8B 4D 18 52

   MemorySearchEntry((BYTE*)"\x2C\x56\x57\x8D\x45\xF3",   "xxxxxx",   -0x1A,   1, MemorySearchEntry::RT_LOCATION),   //2C 56 57 8D 45 F3
   MemorySearchEntry((BYTE*)"\x04\x02\x00\x00\x53\x56",   "xxxxxx",   -0x1A,   1, MemorySearchEntry::RT_LOCATION),   //04 02 00 00 53 56
};

// check any match between the given address content and a byte pattern (any other char than 'x' used as wildcard)
bool Match(const BYTE* pData, const BYTE* bMask, const char* szMask)
{
   for(;*szMask;++szMask,++pData,++bMask)
      if(*szMask=='x' && *pData!=*bMask )
         return false;
   return (*szMask) == NULL;
}

// find the unique address fitting with all the parameters
DWORD FindPattern(DWORD dwAddress, DWORD dwLen, BYTE* bMask, char* szMask, unsigned int occurence)
{
   if(occurence == 0)
      return 0;

   for(DWORD i=0; i < dwLen; i++)
      if( Match( (BYTE*)( dwAddress+i ),bMask,szMask) )
         if((--occurence) == 0)
            return (DWORD)(dwAddress+i);

   return 0;
}

bool RetrieveAddresses()
{
   HMODULE hmod = GetModuleHandle((LPCSTR)"ProcessTarget.exe");
   if(hmod == 0)
      return false;
   MEMORY_BASIC_INFORMATION info;
   // Start at PE32 header
   SIZE_T len = VirtualQuery(hmod, &info, sizeof(info));
   BYTE* processBase = (BYTE*)info.AllocationBase;
   BYTE* address = processBase;
   SIZE_T size = 0;
   for (;;)
   {
      len = VirtualQuery(address, &info, sizeof(info));
      if (info.AllocationBase != processBase)
         break;
      address = (BYTE*)info.BaseAddress + info.RegionSize;
      size += info.RegionSize;
   }

   // we now have the size of the memory to browse inside the process

   // process the search !
   bool errorFound = false;
   for(int i = 0; i < GAID_MAX; ++i)
   {
      MemorySearchEntry& entry = MemoryPatternTable[i];
      DWORD dwaddy = FindPattern((DWORD)processBase, (DWORD)size, entry.Pattern, entry.PatternMask, entry.Occurence);
      if(dwaddy == 0)
      {
         errorFound = true;
         continue;
      }
      dwaddy += entry.Offset;
      if(entry.ReadType == MemorySearchEntry::RT_ADDRESS)
         dwaddy = *(DWORD*)dwaddy;
      else if(entry.ReadType == MemorySearchEntry::RT_REL_ADDRESS)
      {
         unsigned int addr = *(DWORD*)dwaddy;
         addr += (dwaddy + 4);
         dwaddy = addr;
      }

      entry.Address = dwaddy;
   }

   return !errorFound;
}

EXTERN_C IMAGE_DOS_HEADER __ImageBase;

bool DumpAddresses()
{
   char dllPath[_MAX_PATH];
   ::GetModuleFileName((HINSTANCE)&__ImageBase, dllPath, _MAX_PATH);
   std::string path = dllPath;
   std::string::size_type pos = path.rfind('\\');
   path = path.substr(0, pos+1);

   std::string filename = path + "addresses.txt";

   FILE* file = fopen(filename.c_str(), "w");
   if (!file)
      return false;
   
   for(int i = 0; i < GAID_MAX; ++i)
   {
      MemorySearchEntry& entry = MemoryPatternTable[i];
      char value[16];
      sprintf(value, " 0x%08X \n", entry.Address);
      std::string str = "#define ";
      str += MemoryPatternTableStrings[i];
      str += value;
      fwrite(str.c_str(), 1, str.size(), file);
   }

   fclose(file);
   return true;
}

La structure MemoryEntry contient à la fois les paramètres nécessaires pour effectuer la recherche dans la mémoire, et le résultat de cette recherche une fois celle-ci effectuée.

Prenons par exemple la première entrée mise en exemple :
MemorySearchEntry((BYTE*)"\x01\x51\x8B\x4D\x18\x52", "xxxxxx", -0x4d, 1, false), //01 51 8B 4D 18 52

Le pattern recherché est la suite d'opcode 01 51 8B 4D 18 52 correspondant à un bout de code supposé ne pas changer selon les updates du jeu, et surtout ne contenant pas d'adresses absolues.

Ce bout de code asm se situe à un offset de +0x4D du début de la fonction (donc le début de la fonction est à -0x4D du pattern) qui nous intéresse (ici une fonction qui envoie les messages du chat du jeu). Les 2 derniers paramètres de l'entrée sont l’occurrence du pattern qui nous intéresse (ici la première occurrence), et le type de valeur à lire.

Comme vous le savez surement les adresses de variables statiques sont inscrites telles quelles dans l'opcode alors que les adresses de jump et de call sont inscrite en adresse relative par rapport à l'instruction de jmp/call.

Nous avons donc ici 3 modes de lecture : MemorySearchEntry::RT_LOCATION qui renvoie directement l'adresse à laquelle se trouve le byte pattern (modulo l'offset et l'occurrence bien sûr). MemorySearchEntry::RT_ADDRESS qui renvoie la valeur contenue à l'adresse trouvée par la recherche (utilisé donc pour une adresse absolue à lire (celle d'une variable statique en général)). Et enfin MemorySearchEntry::RT_REL_ADDRESS qui fait à peu près la même chose que le précédent sauf qu'elle convertie l'adresse relative lue en adresse absolue (pour obtenir une adresse dans une instruction call ou jmp).


La fonction DumpAddresses va dumper dans un fichier texte toutes les adresses que nous avons donné dans la table de patterns sous la forme :
#define CHAT_SEND_MESSAGE_FUNCTION 0x005F4C50 dans le cas où l'on voudrait par exemple définir dans notre programme l'adresse des fonctions à hooker de manière statique.

La manière dynamique d'obtenir le même résultat en utilisant dynamiquement le memory browser est décrire :
#define CHAT_SEND_MESSAGE_FUNCTION MemoryPatternTable[GAID_CHAT_SEND_MESSAGE_FUNCTION].Address
Et bien évidemment s'assurer que ce define n'est pas utilisé avant d'avoir appelé RetrieveAddresses(); Laughing ...
Akabane87
Akabane87
Admin

Messages : 45
Date d'inscription : 30/07/2010

https://dreamraiser.forumactif.com

Revenir en haut Aller en bas

Revenir en haut


 
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum