Valhalla Legends Forums Archive | C/C++ Programming | Memory Patcher

AuthorMessageTime
Telos
I wrote a small name spoofer for warcraft 3 a few weeks ago and ended up writing this class to improve it a little afterwards hope it helps someone. It is by no means perfect but for most basic patching it should get the job done

[code]
// CMemoryPatcher.hpp

#ifndef _CMEMORYPATCHER_H_INCLUDED
#define _CMEMORYPATCHER_H_INCLUDED

#pragma once

#include <windows.h>

class CMemoryPatcher {
   public:
      CMemoryPatcher();
      ~CMemoryPatcher();

      void      SetPatch( LPCSTR pszPatch, DWORD dwPatchLength );
      bool      ApplyPatch( LPCSTR pszWindowTitle );
      bool      RemovePatch( LPCSTR pszWindowTitle );
      void      SetPatchAddress( DWORD dwPatchAddress ) { m_PatchAddress = reinterpret_cast<LPVOID>(dwPatchAddress); }
      DWORD      FindAddress( LPCSTR pszWindowTitle, LPVOID pvSearch, SIZE_T sizetLength, DWORD dwStartAddress, DWORD dwEndAddress, DWORD dwInterval, DWORD dwOptionalOffset );

   private:
      DWORD      GetProcessByName( LPCSTR WindowTitle );
      bool      Patch( LPCSTR pszWindowTitle, bool bApply );

      LPVOID      m_PatchAddress;
      LPBYTE      m_PatchBuffer;
      LPBYTE      m_OldBuffer;
      DWORD      m_PatchLength;

      DWORD      m_ProcessID;
      HWND      m_WindowHandle;
};

#endif // _CMEMORYPATCHER_H_INCLUDED
[/code]

[code]
// CMemoryPatcher.cpp

#include "CMemoryPatcher.h"

CMemoryPatcher::CMemoryPatcher()
{
   m_PatchAddress = NULL;
   m_PatchBuffer = NULL;
   m_OldBuffer = NULL;
}

CMemoryPatcher::~CMemoryPatcher()
{
   if( m_PatchBuffer )
   {
      delete [] m_PatchBuffer;
      delete [] m_OldBuffer;
   }
}

DWORD CMemoryPatcher::GetProcessByName( LPCSTR WindowTitle )
{
   m_WindowHandle = FindWindow( NULL, WindowTitle );

   if( m_WindowHandle )
      return GetWindowThreadProcessId( m_WindowHandle, &m_ProcessID );

   return 0;
}

/*
   SetPatch
   (LPCSTR) The patch data (typically a string of hex)
   (DWORD ) The length of the patch
*/
void CMemoryPatcher::SetPatch( LPCSTR pszPatch, DWORD dwPatchLength )
{
   if( m_PatchBuffer )
   {
      delete [] m_PatchBuffer;
      delete [] m_OldBuffer;
   }

   m_PatchLength = dwPatchLength;

   m_PatchBuffer = (LPBYTE)new char[ m_PatchLength ];
   m_OldBuffer = (LPBYTE)new char[ m_PatchLength ];
   memcpy( m_PatchBuffer, pszPatch, m_PatchLength );
}

bool CMemoryPatcher::ApplyPatch( LPCSTR pszWindowTitle )
{
   return Patch( pszWindowTitle, true );
}

bool CMemoryPatcher::RemovePatch( LPCSTR pszWindowTitle )
{
   return Patch( pszWindowTitle, false );
}

/*
   Patch
   (LPCSTR) Title of the window to patch
   ( bool ) Apply/Remove

   Returns the success of the function
*/
bool CMemoryPatcher::Patch( LPCSTR pszWindowTitle, bool bApply )
{
   if( (bApply && !m_PatchBuffer) || (!bApply && !m_OldBuffer) )
      return false;

   HANDLE hProcessHandle;
   bool bCompleted = false;

   GetProcessByName( pszWindowTitle );

   if( m_ProcessID )
   {
      hProcessHandle = OpenProcess( PROCESS_ALL_ACCESS, NULL, m_ProcessID );

      if( hProcessHandle )
      {
         DWORD dwOldMemoryAttributes;

         if( VirtualProtectEx( hProcessHandle, m_PatchAddress, m_PatchLength, PAGE_READWRITE, &dwOldMemoryAttributes ) )
         {
            SIZE_T sizetWrittenBytes = 0;

            if( bApply )
               ReadProcessMemory( hProcessHandle, m_PatchAddress, m_OldBuffer, m_PatchLength, &sizetWrittenBytes );
            else
               ReadProcessMemory( hProcessHandle, m_PatchAddress, m_PatchBuffer, m_PatchLength, &sizetWrittenBytes );

            if( bApply )
            {
               if( WriteProcessMemory( hProcessHandle, m_PatchAddress, m_PatchBuffer, m_PatchLength, &sizetWrittenBytes ) )
               {
                  bCompleted = true;
               }
            } else {
               if( WriteProcessMemory( hProcessHandle, m_PatchAddress, m_OldBuffer, m_PatchLength, &sizetWrittenBytes ) )
               {
                  bCompleted = true;
               }
            }

            VirtualProtectEx( hProcessHandle, m_PatchAddress, m_PatchLength, dwOldMemoryAttributes, &dwOldMemoryAttributes );
         }

         CloseHandle( hProcessHandle );
      }
   }

   return bCompleted;
}

/*
   FindAddress
   (LPCSTR) Title of the window
   (LPVOID) The data to search for
   (SIZE_T) Length of the data to search for
   (DWORD ) The address at which to start searching
   (DWORD ) The address at which to end searching
   (DWORD ) The interval to search at
   (DWORD ) The [optional] offset to add to the start address

   Returns the address at which data was first found
*/
DWORD CMemoryPatcher::FindAddress( LPCSTR pszWindowTitle, LPVOID pvSearch, SIZE_T sizetLength, DWORD dwStartAddress, DWORD dwEndAddress, DWORD dwInterval, DWORD dwOptionalOffset )
{
   HANDLE hProcessHandle;
   LPBYTE pbyteReadContents;
   SIZE_T sizetBytesRead;

   pbyteReadContents = (LPBYTE)new char[ sizetLength ];

   GetProcessByName( pszWindowTitle );

   if( m_ProcessID )
   {
      hProcessHandle = OpenProcess( PROCESS_ALL_ACCESS, NULL, m_ProcessID );

      if( hProcessHandle )
      {
         for( DWORD dwSearchAddress = dwStartAddress; dwSearchAddress <= dwEndAddress; dwSearchAddress += dwInterval )
         {
            ReadProcessMemory( hProcessHandle, (LPCVOID)(dwSearchAddress+dwOptionalOffset), pbyteReadContents, sizetLength, &sizetBytesRead );

            if( !memcmp( pvSearch, pbyteReadContents, sizetLength ) )
            {
               delete [] pbyteReadContents;
               return dwSearchAddress+dwOptionalOffset;
            }
         }

         CloseHandle( hProcessHandle );
      }
   }

   delete [] pbyteReadContents;
   return 0;
}
[/code]

Snippet from the implementation
[code]
<snip>
void SpoofName( int SpoofType )
{
   CMemoryPatcher MemoryPatcher;

   DWORD AddressToModify = 0;
   char Search[] = "PX3W";
   char Name[20];

   AddressToModify = MemoryPatcher.FindAddress( "Warcraft III", (LPVOID)Search, 4, 0x00100000, 0x0F000000, 0x00010000, 0x2d4 );

   if( AddressToModify )
   {
      cout << "AddressToModify: " << std::hex << AddressToModify << std::dec << endl;
      cout << "Query: What would you like to change your name to?" << endl;
      memset( static_cast<void *>(Name), 0, 20 );
      cout << "Name: ";
      cin >> Name;

      if( SpoofType == 0 )
         MemoryPatcher.SetPatchAddress( AddressToModify - 0x20 );
      else
         MemoryPatcher.SetPatchAddress( AddressToModify - 0x10 );

      MemoryPatcher.SetPatch( Name, strlen(Name) + 1 );
      MemoryPatcher.ApplyPatch( "Warcraft III" );
   }
}
<snip>
[/code]
April 6, 2004, 5:57 PM
iago
hmm, I have a similar class that works once the program is already in memory. I also have a program that takes in a window name/dll name and does the injecting for me. It's open source and I've posted it here before, contact me if you want to have a look.
April 6, 2004, 6:58 PM
Telos
Thanks after I posted I actually remembered you having posted something similar and I looked back through to find it. If you have more than what you already put up Id be interested in seeing it
April 6, 2004, 7:01 PM
iago
Nope, it's successfully worked for everything I've tried to do with it :)
April 6, 2004, 7:42 PM
Noodlez
Link to your dll injector iago?
April 7, 2004, 4:31 AM
Maddox
[quote author=iago link=board=30;threadid=6182;start=0#msg53734 date=1081277936]
hmm, I have a similar class that works once the program is already in memory. I also have a program that takes in a window name/dll name and does the injecting for me. It's open source and I've posted it here before, contact me if you want to have a look.
[/quote]

What does it do? Look for space in the process memory to insert your LoadLibrary() code, or allocate memory to the proccess with VirtualAllocEx()?
April 7, 2004, 7:58 AM
iago
[quote author=Maddox link=board=30;threadid=6182;start=0#msg53860 date=1081324686]
[quote author=iago link=board=30;threadid=6182;start=0#msg53734 date=1081277936]
hmm, I have a similar class that works once the program is already in memory. I also have a program that takes in a window name/dll name and does the injecting for me. It's open source and I've posted it here before, contact me if you want to have a look.
[/quote]

What does it do? Look for space in the process memory to insert your LoadLibrary() code, or allocate memory to the proccess with VirtualAllocEx()?
[/quote]

It uses CreateRemoteThread (which only works on Win 2k+) to run LoadLibrary in the remote address space.

http://www.valhallalegends.com/iago/Injector.rar

<Edit> Like I said before, though, it's up the the .dll to do the memory editing for itself. You can find my memory editor somewhere at the beginning of the Advanced Programming forum.

<Edit 2> or, I just noticed, you can get it at http://www.valhallalegends.com/iago/MemoryPatcher.rar
April 7, 2004, 1:05 PM

Search