Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


AOB scanner

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> General programming
View previous topic :: View next topic  
Author Message
atom0s
Moderator
Reputation: 205

Joined: 25 Jan 2006
Posts: 8587
Location: 127.0.0.1

PostPosted: Fri May 16, 2014 6:39 pm    Post subject: Reply with quote

Code:
/**
 * @brief Compares the given memory data against the given pattern using the desired mask.
 *
 * @Param lpData            Pointer to the actual memory to be compared again.
 * @Param lpPattern         Pointer to the pattern to scan the memory for.
 * @Param pszMask           String containing the mask for the pattern being compared against.
 *
 * @returN True when the pattern is found, false otherwise.
 */
static bool __stdcall MaskCompare(const unsigned char* lpData, const unsigned char* lpPattern, const char* pszMask)
{
    for (; *pszMask; ++pszMask, ++lpData, ++lpPattern)
        if (*pszMask == 'x' && *lpData != *lpPattern)
            return false;
    return (*pszMask) == NULL;
}

/**
 * @brief Locates the given pattern inside the given data.
 *
 * @Param lpData            The data to scan for our pattern within.
 * @Param nDataSize         The size of the data block to scan within.
 * @Param lpPattern         The pattern to compare the memory against.
 * @Param pszMask           String containing the mask for the pattern being compared against.
 *
 * @returN Location of where the pattern was found, 0 otherwise.
 */
static DWORD __stdcall FindPattern(const unsigned char* lpData, unsigned int nDataSize, const unsigned char* lpPattern, const char* pszMask)
{
    for (unsigned int x = 0; x < nDataSize; x++)
        if (MaskCompare(lpData + x, lpPattern, pszMask))
            return (DWORD)(lpData + x);
    return 0;
}


Usage:
Code:
FindPattern(data, data_size, pattern, mask);

_________________
- Retired.
Back to top
View user's profile Send private message Visit poster's website
atom0s
Moderator
Reputation: 205

Joined: 25 Jan 2006
Posts: 8587
Location: 127.0.0.1

PostPosted: Sat May 17, 2014 1:35 pm    Post subject: Reply with quote

Format as:
\x12\x34\x56\x78\x90\xAB\xCD

And so on. For wildcards just put whatever byte you want, I tend to use \xFF
The mask handles if the byte is used or not.

Each byte of the mask should be x or ?, x means use the byte, ? means wildcard.

Here is an example of using this to read the timer value from the game Dino Crisis:
Code:

/**
 * Dino Crisis (PC) - Timer Trainer
 * (c) 2014 atom0s [[email protected]]
 */

#include <Windows.h>
#include <iostream>
#include <TlHelp32.h>

/**
 * @brief Game Executable Names
 */
const char g_GameNames[][255] =
{
    { "DINO.exe" },
    { NULL }
};

/**
 * @brief Data structure passed to our window enumeration callback.
 */
typedef struct _WINDOW_DATA
{
    DWORD   ProcessId;
    HWND    WindowHandle;
} WINDOW_DATA;

/**
 * @brief Enumerates the running windows on the system.
 *
 * @Param hWnd      The current window handle.
 * @Param lParam    The custom data passed to this callback.
 *
 * @return True to keep searching, false otherwise.
 */
BOOL __stdcall EnumWindowsProc(HWND hWnd, LPARAM lParam)
{
    auto procId = (DWORD)0;
    auto wd = (WINDOW_DATA*)lParam;

    ::GetWindowThreadProcessId(hWnd, &procId);
    if (procId == wd->ProcessId)
    {
        wd->WindowHandle = hWnd;
        return FALSE;
    }
    return TRUE;
}

/**
 * @brief Obtains the main window hwnd of the given process id.
 *
 * @Param dwProcId          The process id of our game.
 *
 * @return The window handle if found, NULL otherwise.
 */
HWND getResidentEvilWindowHandle(DWORD dwProcId)
{
    auto wd = new WINDOW_DATA();
    wd->ProcessId = dwProcId;

    ::EnumWindows(EnumWindowsProc, (LPARAM)wd);

    auto hWnd = wd->WindowHandle;
    delete wd;

    return hWnd;
}

/**
 * @brief Obtains the process id of our target.
 * @return The process id if found, 0 otherwise.
 */
DWORD getGameProcessId(void)
{
    PROCESSENTRY32 pe32{ sizeof(PROCESSENTRY32) };

    auto handle = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (handle == INVALID_HANDLE_VALUE)
        return 0;

    if (!::Process32First(handle, &pe32))
    {
        ::CloseHandle(handle);
        return 0;
    }

    do
    {
        for (auto x = 0; x < _countof(g_GameNames); x++)
        {
            if (g_GameNames[x][0] != NULL && _strnicmp(pe32.szExeFile, g_GameNames[x], strlen(g_GameNames[x])) == 0)
            {
                ::CloseHandle(handle);
                return pe32.th32ProcessID;
            }
        }
    } while (::Process32Next(handle, &pe32));

    ::CloseHandle(handle);
    return 0;
}

/**
 * @brief Obtains the process base address of the target process.
 *
 * @Param dwProcId  The process id to obtain the base address of.
 * @return The process base address if found, 0 otherwise.
 */
DWORD getGameProcessBaseAddress(DWORD dwProcId)
{
    MODULEENTRY32 me32{ sizeof(MODULEENTRY32) };

    auto handle = ::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcId);
    if (handle == INVALID_HANDLE_VALUE)
        return 0;

    if (!::Module32First(handle, &me32))
    {
        ::CloseHandle(handle);
        return 0;
    }

    ::CloseHandle(handle);
    return (DWORD)me32.modBaseAddr;
}

/**
 * @brief Obtains the process base size of the target process.
 *
 * @Param dwProcId  The process id to obtain the base address of.
 * @return The process base size if found, 0 otherwise.
 */
DWORD getGameProcessBaseSize(DWORD dwProcId)
{
    MODULEENTRY32 me32{ sizeof(MODULEENTRY32) };

    auto handle = ::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcId);
    if (handle == INVALID_HANDLE_VALUE)
        return 0;

    if (!::Module32First(handle, &me32))
    {
        ::CloseHandle(handle);
        return 0;
    }

    ::CloseHandle(handle);
    return me32.modBaseSize;
}

/**
 * @brief Compares the given memory data against the given pattern using the desired mask.
 *
 * @Param lpData            Pointer to the actual memory to be compared again.
 * @Param lpPattern         Pointer to the pattern to scan the memory for.
 * @Param pszMask           String containing the mask for the pattern being compared against.
 *
 * @return True when the pattern is found, false otherwise.
 */
static bool __stdcall MaskCompare(const unsigned char* lpData, const unsigned char* lpPattern, const char* pszMask)
{
    for (; *pszMask; ++pszMask, ++lpData, ++lpPattern)
        if (*pszMask == 'x' && *lpData != *lpPattern)
            return false;
    return (*pszMask) == NULL;
}

/**
 * @brief Locates the given pattern inside the given data.
 *
 * @Param lpData            The data to scan for our pattern within.
 * @Param nDataSize         The size of the data block to scan within.
 * @Param lpPattern         The pattern to compare the memory against.
 * @Param pszMask           String containing the mask for the pattern being compared against.
 *
 * @return Location of where the pattern was found, 0 otherwise.
 */
static DWORD __stdcall FindPattern(const unsigned char* lpData, unsigned int nDataSize, const unsigned char* lpPattern, const char* pszMask)
{
    for (unsigned int x = 0; x < nDataSize; x++)
        if (MaskCompare(lpData + x, lpPattern, pszMask))
            return (DWORD)(lpData + x);
    return 0;
}

/**
 * @brief The main application entry point.
 *
 * @Param argc  The number of arguments passed to this program.
 * @Param argv  The arguments passed to this program.
 *
 * @return Error code on succss of application.
 */
int __cdecl main(int argc, char* argv[])
{
    std::cout << "===============================================" << std::endl;
    std::cout << "Dino Crisis (PC) Game Timer" << std::endl;
    std::cout << "by atom0s (c) 2014 [[email protected]]" << std::endl;
    std::cout << "===============================================" << std::endl << std::endl;

    // Get the process id..
    auto procId = getGameProcessId();
    if (procId == 0)
        return -1;
    std::cout << "[*] Found game process!" << std::endl;

    // Get the process base address..
    auto procBase = getGameProcessBaseAddress(procId);
    if (procBase == 0)
        return -1;
    std::cout << "[*] Found game process base!" << std::endl;

    // Get the process base size..
    auto procSize = getGameProcessBaseSize(procId);
    if (procSize == 0)
        return -1;
    std::cout << "[*] Obtained process base size!" << std::endl;

    // Get the window handle..
    auto procHwnd = getResidentEvilWindowHandle(procId);

    // Open the process for reading..
    auto handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_READ, FALSE, procId);
    if (handle == INVALID_HANDLE_VALUE)
        return -1;
    std::cout << "[*] Obtained process handle for memory reading!" << std::endl;

    // Dump the process memory..
    auto procDump = new unsigned char[procSize + 1];
    ::ReadProcessMemory(handle, (LPCVOID)procBase, procDump, procSize, NULL);

    // Scan for our signature..
    auto timerPtr = FindPattern(procDump, procSize, (BYTE*)"\x8B\x15\xFF\xFF\xFF\xFF\x8D\x84\x0A\xFF\xFF\xFF\xFF\x89\x45\xD4\x8B\x4D\xD4\x8B\x11\x8B\x82\xFF\xFF\xFF\xFF\x89\x45\xE0\x8B\x45\xE0", "xx????xxx????xxxxxxxxxx????xxxxxx");
    if (timerPtr == NULL)
    {
        ::CloseHandle(handle);
        return 0;
    }

    // Readjust the offsets..
    timerPtr -= (DWORD)procDump;
    std::cout << "[*] Found signatures for timer offsets!" << std::endl << std::endl;
    std::cout << "[*] Game time should now be rendering on the game window!" << std::endl;
    std::cout << "[*] Hold shift and press escape to close this application!" << std::endl;

    // Loop until we want to escape..
    while (true)
    {
        // Allow escape to leave the loop and close the app..
        if ((::GetAsyncKeyState(VK_ESCAPE) & 1) && ::GetAsyncKeyState(VK_SHIFT))
            break;

        // Obtain the main timer value..
        DWORD dwTimerValue1 = 0;
        DWORD dwTimerValue2 = 0;
        ::ReadProcessMemory(handle, (LPCVOID)(procBase + timerPtr + 2), &dwTimerValue1, 4, NULL);
        ::ReadProcessMemory(handle, (LPCVOID)(procBase + timerPtr + 23), &dwTimerValue2, 4, NULL);
        ::ReadProcessMemory(handle, (LPCVOID)(dwTimerValue1), &dwTimerValue1, 4, NULL);
        ::ReadProcessMemory(handle, (LPCVOID)(dwTimerValue1), &dwTimerValue1, 4, NULL);
        ::ReadProcessMemory(handle, (LPCVOID)(dwTimerValue1 + dwTimerValue2), &dwTimerValue1, 4, NULL);

        // Convert the time into a timestamp..
        auto timer = dwTimerValue1;
        timer /= 60;

        auto hour = (int)floor(timer / (60 * 60));
        auto mins = (int)floor(timer / 60 - hour * 60);
        auto secs = (int)floor(timer - (mins + hour * 60) * 60);

        char szBuffer[1024] = { 0 };
        sprintf_s(szBuffer, "%02i:%02i:%02i\r\n", hour, mins, secs);

        // Get the window dc..
        auto dc = ::GetDC(procHwnd);

        // Get the default UI font..
        LOGFONT logfont = { 0 };
        auto font = ::GetStockObject(DEFAULT_GUI_FONT);
        ::GetObject(font, sizeof(LOGFONT), &logfont);

        // Adjust the font size..
        logfont.lfHeight = -MulDiv(15, ::GetDeviceCaps(dc, LOGPIXELSY), 72);

        // Create the new font..
        font = ::CreateFontIndirect(&logfont);

        // Change the dc font..
        auto oldfont = ::SelectObject(dc, font);

        // Draw our text..
        RECT rectText = { 5, 5, 0, 0 };
        ::SetTextColor(dc, 0x0000FF);
        ::SetBkMode(dc, TRANSPARENT);
        ::DrawText(dc, szBuffer, strlen(szBuffer), &rectText, DT_CALCRECT);
        ::DrawText(dc, szBuffer, strlen(szBuffer), &rectText, 0);

        // Cleanup the font..
        ::SelectObject(dc, oldfont);
        ::DeleteObject(font);
        ::DeleteDC(dc);

        ::Sleep(1);
    }

    // Cleanup..
    ::CloseHandle(handle);
    return ERROR_SUCCESS;
}

_________________
- Retired.
Back to top
View user's profile Send private message Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> General programming All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites