Automated Pointer Search

Share Your Own Code Samples With the World

Moderators: g3nuin3, SpeedWing, WhiteHat, mezzo

Automated Pointer Search

Postby CoMPMStR » Sat Oct 17, 2009 1:51 am

This is something I recently developed (thanks to the help of L. Spiro) that can assist in the tedious task of pointer searching. Now I want to first say that this isn't some magic script that will automatically find the correct pointer, but it does help by mass searching much faster than any person can, depending on the game and search range of course. ;)

First of all the script makes full use of recursion, which means that it will search until there's nothing left to find (or you cancel it). It's also threaded so during the search MHS won't lock up or freeze. You can also choose to save to a file or print to the immediate window, although saving to a file is probably quicker especially with some of the more lenghty searches. You can even specify to overwrite the file each time, or append to it. :D

Some other useful features is the ability to specify how to evaluate the pointer offsets, on a per offset basis. You can choose whether to search for the exact offset distance or any offset less than or equal to the one specified, it's easier than it sounds. On top of that you can optionally choose to evaluate the current pointer address against a specified address and offset, current pointer address means the current pointer being evaluated and NOT the initial base address, using a few different methods.

It's also possible to search for multiple pointers without recompiling the script each time, by specifying so using the Hotkey params. Param 2 is used for the initial base address while Param 3 is used to specify saving to a file. Everything is explained in-depth in the comments.

So, without further ado... the script:

Code: Select all
// Resizable arrays to store pointer results and distances.
// Also a fixed-length array for less than (<=) distances (can be changed if you require more than 256 offsets, which I doubt).
DWORD * dwCompareAddys; DWORD * dwCompareDists; DWORD dwAltOffset[256] = {0};
// Some other used global variables. Changing any of the values does nothing toward the outcome of the search.
BOOL bCancelSearch = false; BOOL bCancelConfirmed = false;
DWORD dwTotalResults = 0; DWORD dwMaxResults = 0; unsigned long ulDispTimer = 0;
// Used to display the time.
BOOL bShowElapsedTime = true;
struct sTimeFormat
{
   int iHours;
   int iMinutes;
   int iSeconds;
   int iMSeconds;
};

// Set this to true to search for ONLY static addresses.
BOOL bOnlyStatic = false;
// This determines whether the script will pause when a static address is found (a MessageBox is displayed).
BOOL bPauseOnStatic = true;

// File saving globals.
FILE * pFile;
// Set to true to save to the specified file, otherwise it will print to the debug window.
BOOL bSaveToFile = true;
// Set to true to append to the saved file rather than overwriting with a new file each time.
BOOL bAppend = false;
// The specified file path to save the complex address results. You can change it if you prefer.
char * cFilename = "c:\\ptr_results.txt";

// Search ranges to use during the search process, can be adjusted if necessary.
LPVOID lpvBeginAddy = (LPVOID)0x00400000;
LPVOID lpvEndAddy = (LPVOID)0x20000000;

// Set up the initial address on which to do the pointer search, then the offsets.
// The offsets are set in reverse order, for example: '[[0x5AFCDE]+0x34]+8' would be 'DWORD dwPtrOffsets[] = {8, 0x34};'.
LPVOID lpvInitialAddy = (LPVOID)0x04C66738; // Base address - This is your ammo or money address on which you begin the pointer search.
DWORD dwPtrOffsets[] = {0x8, 0x4, 0xC, 0x8, 0x4, 0x0, 0x18}; // Offsets - The complex address would be: ...
                                              // [[[[[[[0x1000FD08]+0x18]+0x0]+0x4]+0x8]+0xC]+0x4]+0x8.
BOOL bExactMatch[] = {true, true, true, true, true, true, true}; // This array determines how the offset distance check is performed.
                                    // Each element corresponds to it's matching dwPtrOffsets element during evaluation.
                                    // Set to 'true' to set exact comparison (==) while 'false' will be less than or equal (<=).
                                    // Both the dwPtrOffsets array and bExactMatch array SHOULD have the same number of elements.

// Optionally you can check the current pointer (not initial base address) being evaluated against a specified address and offset.
// The offset specifies as such: dwCheckAddress - dwCheckOffset; and bExactCheck specifies how to evaluate the pointer.
// bExactCheck should be one of the enum specified below. Each time a match is found, the search will prompt a MessageBox.
BOOL bCheckPointerAddress = false;
DWORD dwCheckAddress = 0x17E86D0;
DWORD dwCheckOffset = 0x1000;
DWORD bExactCheck = Range;

// The enum should be used in conjunction ONLY with the bExactCheck variable.
// Exact means the evaluation will be (PointerAddress == dwCheckAddress - dwCheckOffset);
// Range means the evaluation will be (PointerAddress >= dwCheckAddress - dwCheckOffset && PointerAddress <= dwCheckAddress);
// Less means the evaluation will be (PointerAddress <= dwCheckAddress); [dwCheckOffset has no effect.]
// Greater means the evaluation will be (PointerAddress >= dwCheckAddress - dwCheckOffset);
enum { Exact, Range, Less, Greater };

// Hotkey index used to cancel the search, set in Tools->Hotkeys.
VOID On_HK_1(DWORD dw1, DWORD dw2) { bCancelSearch = true; }

// Hotkey index used to activate the search, set in Tools->Hotkeys.
VOID On_HK_0(DWORD dw1, DWORD dw2)
{
   // First parameter allows setting the address...
   if (dw1 > 0) { lpvInitialAddy = (LPVOID)dw1; }
   // ... and the second parameter allows setting the save to file option. [1=save, 2=print]
   if (dw2 > 0)
   {
      if (dw2 <= 1)
         bSaveToFile = true;
      else if (dw2 >= 2)
         bSaveToFile = false;
   }
   
   // If the option is set, initialize the FILE variable, otherwise clear the immediate window.
   if (bSaveToFile)
   {
      char * cWrite = "w";
      if (bAppend) { cWrite = "a"; }
      pFile = FOpen(cFilename, cWrite);
      FPrintF(pFile, "\n------------------------------------------------------------------------------------\nBeginning Pointer Search (0x%X)\n------------------------------------------------------------------------------------\n\n", (DWORD)lpvInitialAddy);
   }
   else
   {
      Clear();
      PrintF("------------------------------------------------------------------------------------Beginning Pointer Search (0x%X)", (DWORD)lpvInitialAddy);
   }
   
   // Create a new thread for the pointer search, so it doesn't bog down MHS during the process.
   HANDLE hPtrSearch = CreateThread("SearchThread", 0);
   
   if (!hPtrSearch)
        PrintF("Failed to create the search thread successfully.");
    else
      CloseHandle(hPtrSearch);
}

DWORD SearchThread(DWORD dwParm)
{   
    // Initialize and begin the search.
    bCancelSearch = false; bCancelConfirmed = false;
   dwTotalResults = 0; dwMaxResults = 0; ulDispTimer = Time();
   BOOL fp = FindPointers(lpvInitialAddy, dwPtrOffsets, 0);
   
   // Finally close the FILE variable ...
   if (bSaveToFile) { FClose(pFile); pFile = NULL; }
   
   // ... Then display the confirmation or failure message ...
   if (fp)
      MessageBox(MBS_OK, "Pointer Search Complete!", "The search process has completed successfully!\n\nReturned with %d result(s)!", dwTotalResults);
   else
      MessageBox(MBS_OK, "Pointer Search Failed!", "The search process has failed at some point, or some parameters may be incorrect.");
      
   // ... And clear the immediate window.
   if (bSaveToFile) { Clear(); }
}

// Search for a pointer - Do NOT change any code below this point unless you know what you're doing!!!
BOOL FindPointers(LPVOID lpvFinalAddy, DWORD dwOffsets[], DWORD dwCurrentOffset)
{
   if (bCancelSearch)
      if (TryScriptCancel())
         return true;
   
   DWORD ptrOffsetSize = sizeof(dwPtrOffsets) / sizeof(DWORD);
   DWORD ptrEvalSize = sizeof(bExactMatch) / sizeof(BOOL);
   if (ptrOffsetSize != ptrEvalSize) { return false; }
   if (dwCurrentOffset >= ptrOffsetSize) { return true; }
   
    // The structure holds all the information we will pass to the function.
    MHS_API_SEARCH_PARMS pSearch;

    // Firstly, we are doing a pointer search.
    pSearch.dwType = LS_POINTER;

    // Cover the search range.
    pSearch.lpvStart = lpvBeginAddy; pSearch.lpvEnd = lpvEndAddy;

    // We will search for a range of pointers.
    pSearch.TypeParms.pParms.dwSubType = ST_RANGE;

    // We don't need the Same as Original sub search.
    pSearch.TypeParms.pParms.bEnableSame = false;

    // We are not interested in only static pointers.
    pSearch.TypeParms.pParms.bStatic = bOnlyStatic;

    // Save the offset from the value passed to us.
    // This should always be done in Pointer Searches.
    // This allows us to see how far away pointers are from this address in the address list.
    pSearch.TypeParms.pParms.lpvSaveOffset = lpvFinalAddy;
    pSearch.TypeParms.pParms.atValue.UInt = (DWORD)lpvFinalAddy - dwOffsets[dwCurrentOffset];

    // Set the high value to the actual address specified.
    pSearch.TypeParms.pParms.atTo.UInt = (DWORD)lpvFinalAddy;

    // Now search.
    if (RAMSearch(&pSearch))
      return ComparePointer(lpvFinalAddy, dwOffsets, dwCurrentOffset);
   else
      return false;
}

BOOL ComparePointer(LPVOID lpvPointerAddress, DWORD dwOffsets[], DWORD dwCurrentOffset)
{
   if (!LockScanForRead()) { return false; }
   DWORD dwCompareCount = 0; DWORD scanTotal = GetScanTotal();
   
   for (int i = 0; i < scanTotal; i++)
   {
      DWORD retValue; LPVOID retAddress;
      if (GetScanValue(i, &retAddress, &retValue))
      {
         BOOL evalOffsets = false;
         DWORD retDistance = (DWORD)lpvPointerAddress - retValue;
         
         if (bExactMatch[dwCurrentOffset])
            evalOffsets = retDistance == dwOffsets[dwCurrentOffset];
         else
            evalOffsets = retDistance <= dwOffsets[dwCurrentOffset];
            
         if (evalOffsets)
         {
            dwCompareAddys = ReAlloc(dwCompareAddys, ++dwCompareCount * sizeof(DWORD));
            if (dwCompareAddys != NULL)
               dwCompareAddys[dwCompareCount - 1] = retAddress;
               
            dwCompareDists = ReAlloc(dwCompareDists, dwCompareCount * sizeof(DWORD));
            if (dwCompareDists != NULL)
               dwCompareDists[dwCompareCount - 1] = retDistance;
         }
      }
   }
   
   if (scanTotal > 0)
   {
      DWORD * displayPtrs = Malloc(dwCompareCount * sizeof(DWORD));
      MemCpy(displayPtrs, dwCompareAddys, dwCompareCount * sizeof(DWORD));
      Free(dwCompareAddys); dwCompareAddys = NULL;
      
      DWORD * displayDsts = Malloc(dwCompareCount * sizeof(DWORD));
      MemCpy(displayDsts, dwCompareDists, dwCompareCount * sizeof(DWORD));
      Free(dwCompareDists); dwCompareDists = NULL;
      
      if (displayPtrs != NULL && displayDsts != NULL)
         DisplayPointers(displayPtrs, displayDsts, dwCompareCount, dwOffsets, ++dwCurrentOffset);
         
      Free(displayPtrs); displayPtrs = NULL; Free(displayDsts); displayDsts = NULL;
   } return UnlockScanForRead();
}

VOID DisplayPointers(DWORD * dwPointers, DWORD * dwDistances, DWORD dwMaxPtrs, DWORD dwOffsets[], DWORD dwCurrentOffset)
{
   dwMaxResults += dwMaxPtrs;
   for (int i = 0; i < dwMaxPtrs; i++)
   { dwTotalResults++;
      if (bSaveToFile)
      {
         Clear(); PrintF("Total Pointers Found / Remaining: %d / %d", dwTotalResults, dwMaxResults - dwTotalResults);
      } dwAltOffset[dwCurrentOffset - 1] = dwDistances[i];
      
      char pcBuff[256] = {0};
      for (int c = 0; c < dwCurrentOffset; c++)
         pcBuff[c] = '[';
      
      SPrintF(&pcBuff[dwCurrentOffset], "0x%X", dwPointers[i]);
      
      for (int c = dwCurrentOffset - 1; c > -1; c--)
      {
         char pcOffset[256] = {0};
         SPrintF(&pcOffset, "]+0x%X", dwAltOffset[c]);
         StrCat(&pcBuff, &pcOffset); pcOffset = NULL;
      }
      
      if (isAddressStatic(dwPointers[i]))
         StrCat(&pcBuff, " - (Static)");
      
      if (bSaveToFile)
         FPrintF(pFile, "Complex Address #%d: %s\n", dwTotalResults, pcBuff);
      else
         PrintF("Complex Address #%d: %s", dwTotalResults, pcBuff);
      
      if (bShowElapsedTime)
      {
         unsigned long ulCurTime = Time();
         sTimeFormat sTime;
         ZeroMemory(&sTime, sizeof(sTimeFormat));
         FormatTimer(ulCurTime - ulDispTimer, &sTime);
         PrintF("Total Time Elapsed: %d:%d:%d.%d", sTime.iHours, sTime.iMinutes, sTime.iSeconds, sTime.iMSeconds);
      }
      
      if (bPauseOnStatic)
         if (isAddressStatic(dwPointers[i]))
            goto PAUSEROUTE;
      
      if (bCheckPointerAddress)
      { BOOL evalAddress = false;
         if (bExactCheck == Exact)
            evalAddress = dwPointers[i] == dwCheckAddress - dwCheckOffset;
         else if (bExactCheck == Range)
            evalAddress = dwPointers[i] >= dwCheckAddress - dwCheckOffset && dwPointers[i] <= dwCheckAddress;
         else if (bExactCheck == Less)
            evalAddress = dwPointers[i] <= dwCheckAddress;
         else if (bExactCheck == Greater)
            evalAddress = dwPointers[i] >= dwCheckAddress - dwCheckOffset;
            
         if (evalAddress)
         {
PAUSEROUTE:
            INT iAnswer = MessageBox(MBS_OK | MBS_CANCEL, "Pointer Address Checked!", "The search process has found an address match!\n\n%s\n\nClick OK to continue the search or CANCEL to abort.", pcBuff);
            if (iAnswer == MBS_CANCEL)
               bCancelSearch = true;
         }
      }
      
      pcBuff = NULL; FindPointers((LPVOID)dwPointers[i], dwOffsets, dwCurrentOffset);
   }
}

void FormatTimer(unsigned long ulTimer, sTimeFormat * sFormat)
{
   int iSec = ulTimer / 1000;
   int iMin = 0;
   while (iSec >= 60)
   {
      iMin++;
      iSec -= 60;
   }
   int iHour = 0;
   while (iMin >= 60)
   {
      iHour++;
      iMin -= 60;
   }
   sFormat->iHours = iHour;
   sFormat->iMinutes = iMin;
   sFormat->iSeconds = iSec;
   sFormat->iMSeconds = (int)Mod(ulTimer, 1000);
}

BOOL isAddressStatic(DWORD dwAddress)
{
   MODULEENTRY32 me32;
    ZeroMemory(&me32, sizeof(MODULEENTRY32));
    me32.dwSize = sizeof(MODULEENTRY32);
   return FindModuleByRange(dwAddress, &me32);
}

BOOL TryScriptCancel()
{
   if (!bCancelConfirmed)
   {
      INT iAnswer = MessageBox(MBS_YES | MBS_NO, "Cancel Pointer Search?", "Are you sure you want to cancel the current pointer search in progress?\n\nClick YES to abort or NO to continue the search.");
      if (iAnswer == MBS_YES)
      {
         bCancelConfirmed = true;
         return true;
      }
      else
         bCancelSearch = false;
   }
   else
      return true;
}


Let me know if there's anything that needs elaboration or improvement. :!:
Image

______________________________________________________
My Utilities:
CT <-> LSSAVE Converter
LSS Visual Dialog Designer
.NET Trainer Helper Library

~Whether you think you can or you think you can't, you're right.

L. Spiro wrote:In my left hand is a red pill. If you take it I will show you the truth. I lost my right hand in the war, so I’m afraid you’re stuck with the red pill.
User avatar
CoMPMStR
(P)ot (I)n (M)y (P)ipe
 
Posts: 451
Joined: Thu Mar 06, 2008 7:50 am
Location: Best Place

Postby toffey » Sat Oct 17, 2009 7:15 am

Wow, great work. I'll have to check this out when I get some free time.
User avatar
toffey
Hack-Master Hex
 
Posts: 689
Joined: Fri Sep 05, 2008 5:39 pm
Location: California, USA

Re: Automated Pointer Search

Postby SztringzS » Sat Oct 17, 2009 7:56 am

CoMPMStR wrote:Do not include long quotes in your message just to follow up with half a sentence.


wow, impressive =)
Kind of ironic huh? Cracking a patcher. Maybe if I get some free time, I'll patch this patcher and then make a patcher with this patcher to patch your patcher!

check out my colorful Thread ! - http://memoryhacking.com/forums/viewtopic.php?f=43&t=6382

Image
SztringzS
I Know My Poop
 
Posts: 467
Joined: Tue Jul 28, 2009 8:40 am
Location: Pluto :D


Return to Code Submissions

Who is online

Users browsing this forum: No registered users and 0 guests

cron