• Welcome to Valhalla Legends Archive.
 

Memory Patcher

Started by Telos, April 06, 2004, 12:57 PM

Previous topic - Next topic

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


// 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



// 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;
}


Snippet from the implementation

<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>

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.
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*


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

iago

Nope, it's successfully worked for everything I've tried to do with it :)
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*


Noodlez

Link to your dll injector iago?

Maddox

Quote from: iago on April 06, 2004, 01:58 PM
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.

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

iago

#6
Quote from: Maddox on April 07, 2004, 02:58 AM
Quote from: iago on April 06, 2004, 01:58 PM
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.

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

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
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*