Page 1 of 1

[HELP - C++] Failed using PAGE_READWRITE on Memory Scanner

PostPosted: Wed Sep 29, 2010 9:15 pm
by TheJAF
I try to using a HadFuny Memory Scanner source code, worked like a charms when I compile to be an executable. But, when I modify and compile to be a DLL (injection), the process that has been injected using RAM resource so high (any program windows is not responding, but the cursor still moveable).

here the source:

memscan.h
Code: Select all
// Filename: MemoryScan.cpp
// Author: HadFuny
// Date: 28-05-2010
// Copyright HadFuny 2010

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

#define IS_IN_SEARCH(mb,offset) (mb->searchmask[(offset) / 8] & ( 1 << ((offset) % 8)))
#define REMOVE_FROM_SEARCH(mb,offset) mb->searchmask[(offset) / 8] &= ~(1<<((offset) % 8));

typedef struct _MEMBLOCK
{
    HANDLE hProc;
    unsigned char *addr;
    int size;
    unsigned char *buffer;

    unsigned char *searchmask;
    int matches;
    int data_size;

    struct _MEMBLOCK *next;
} MEMBLOCK;

typedef enum
{
    COND_UNCONDITIONAL,
    COND_EQUALS,

    COND_INCREASED,
    COND_DECREASED,
} SEARCH_CONDITION;

// added for debugging
void __cdecl odprintf(const char *format, ...)
{
   char    buf[4096], *p = buf;
   va_list args;
   int     n;

    va_start(args, format);
    n = _vsnprintf(p, sizeof buf - 3, format, args); // buf-3 is room for CR/LF/NUL
    va_end(args);

    p += (n < 0) ? sizeof buf - 3 : n;

    while ( p > buf  &&  isspace(p[-1]) )
            *--p = '\0';

    *p++ = '\r';
    *p++ = '\n';
    *p   = '\0';

    OutputDebugString(buf);
}
// added for debugging

MEMBLOCK* create_memblock (HANDLE hProc, MEMORY_BASIC_INFORMATION *meminfo, int data_size)
{
    MEMBLOCK *mb = (MEMBLOCK*)malloc(sizeof(MEMBLOCK));

    if (mb)
    {
        mb->hProc = hProc;
        mb->addr = (unsigned char*)meminfo->BaseAddress;
        mb->size = meminfo->RegionSize;
        mb->buffer = (unsigned char*)malloc (meminfo->RegionSize);
        mb->searchmask = (unsigned char*)malloc (meminfo->RegionSize/8);
        memset (mb->searchmask, 0xff, meminfo->RegionSize/8);
        mb->matches = meminfo->RegionSize;
        mb->data_size = data_size;
        mb->next = NULL;
    }

    return mb;
}

void free_memblock (MEMBLOCK *mb)
{
    if (mb)
    {
        if (mb->buffer)
        {
            free (mb->buffer);
        }

        if (mb->searchmask)
        {
            free (mb->searchmask);
        }

        free (mb);
    }
}


void update_memblock (MEMBLOCK *mb, SEARCH_CONDITION condition, unsigned int val)
{
    static unsigned char tempbuf[128*1024];
    unsigned int bytes_left;
    unsigned int total_read;
    unsigned int bytes_to_read;
    unsigned int bytes_read;

    if (mb->matches > 0)
    {
        bytes_left = mb->size;
        total_read = 0;
        mb->matches = 0;
   
        while (bytes_left)
        {
            bytes_to_read = (bytes_left > sizeof(tempbuf)) ? sizeof(tempbuf) : bytes_left;
            ReadProcessMemory (mb->hProc, mb->addr + total_read, tempbuf, bytes_to_read, (DWORD*)&bytes_read);
            if (bytes_read != bytes_to_read) break;
   
            if (condition == COND_UNCONDITIONAL)
            {
                memset (mb->searchmask + (total_read/8), 0xff, bytes_read/8);
                mb->matches += bytes_read;
            }
            else
            {
                unsigned int offset;
   
                for (offset = 0; offset < bytes_read; offset += mb->data_size)
                {
                    if (IS_IN_SEARCH(mb,(total_read+offset)))
                    {
                        BOOL is_match = FALSE;
                        unsigned int temp_val;
                        unsigned int prev_val = 0;
   
                        switch (mb->data_size)
                        {
                            case 1:
                                temp_val = tempbuf[offset];
                                prev_val = *((unsigned char*)&mb->buffer[total_read+offset]);
                                break;
                            case 2:
                                temp_val = *((unsigned short*)&tempbuf[offset]);
                                prev_val = *((unsigned short*)&mb->buffer[total_read+offset]);
                                break;
                            case 4:
                            default:
                                temp_val = *((unsigned int*)&tempbuf[offset]);
                                prev_val = *((unsigned int*)&mb->buffer[total_read+offset]);
                                break;
                        }
   
                        switch (condition)
                        {
                            case COND_EQUALS:
                                is_match = (temp_val == val);
                                break;
                            case COND_INCREASED:
                                is_match = (temp_val > prev_val);
                                break;
                            case COND_DECREASED:
                                is_match = (temp_val < prev_val);
                                break;
                            default:
                                break;
                        }
   
                        if (is_match)
                        {
                            mb->matches++;
                        }
                        else
                        {
                            REMOVE_FROM_SEARCH(mb,(total_read+offset));
                        }
                    }
                }
            }
   
            memcpy (mb->buffer + total_read, tempbuf, bytes_read);
   
            bytes_left -= bytes_read;
            total_read += bytes_read;
        }
   
        mb->size = total_read;
    }
}



MEMBLOCK* create_scan (unsigned int pid, int data_size)
{
    MEMBLOCK *mb_list = NULL;
    MEMORY_BASIC_INFORMATION meminfo;
    unsigned char *addr = 0;

    HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS|PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE|PROCESS_QUERY_INFORMATION, FALSE, pid);

    if (hProc)
    {
        while (1)
        {
            if (VirtualQueryEx(hProc, addr, &meminfo, sizeof(meminfo)) == 0)
            {
                break;
            }
         
         #define WRITABLE (PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)
           
         if ((meminfo.State & MEM_COMMIT) && (meminfo.Protect & WRITABLE))
            {
                MEMBLOCK *mb = create_memblock (hProc, &meminfo, data_size);
                if (mb)
                {
                    mb->next = mb_list;
                    mb_list = mb;
                }
            }
            addr = (unsigned char*)meminfo.BaseAddress + meminfo.RegionSize;
        }
    }

    return mb_list;
}


void free_scan(MEMBLOCK *mb_list)
{
    CloseHandle (mb_list->hProc);

    while (mb_list)
    {
        MEMBLOCK *mb = mb_list;
        mb_list = mb_list->next;
        free_memblock (mb);
    }
}

void update_scan (MEMBLOCK *mb_list, SEARCH_CONDITION condition, unsigned int val)
{
    MEMBLOCK *mb = mb_list;
    while (mb)
    {
        update_memblock (mb, condition, val);
        mb = mb->next;
    }
}


void dump_scan_info(MEMBLOCK *mb_list)
{
    MEMBLOCK *mb = mb_list;

    while (mb)
    {
        int i;
        odprintf("0x%08x %d", mb->addr, mb->size);

        for (i = 0; i < mb->size; i++)
        {
            printf ("%02x", mb->buffer[i]);
        }

        mb = mb->next;
    }
}


void poke (HANDLE hProc, int data_size, unsigned int addr, unsigned int val)
{
    if (WriteProcessMemory (hProc, (void*)addr, &val, data_size, NULL) == 0)
    {
        odprintf("poke failed");
    }
}

unsigned int peek(HANDLE hProc, int data_size, unsigned int addr)
{
    unsigned int val = 0;

    if (ReadProcessMemory (hProc, (void*)addr, &val, data_size, NULL) == 0)
    {
        odprintf("peek failed");
    }

    return val;
}


void print_matches (MEMBLOCK *mb_list)
{
    unsigned int offset;
    MEMBLOCK *mb = mb_list;

    while (mb)
    {
        for (offset = 0; offset < mb->size; offset += mb->data_size)
        {
            if (IS_IN_SEARCH(mb,offset))
            {
                unsigned int val = peek (mb->hProc, mb->data_size, (unsigned int)mb->addr + offset);
                odprintf("0x%08x: 0x%08x (%d)", mb->addr + offset, val, val);
            }
        }

        mb = mb->next;
    }
}


int get_match_count (MEMBLOCK *mb_list)
{
    MEMBLOCK *mb = mb_list;
    int count = 0;

    while (mb)
    {
        count += mb->matches;
        mb = mb->next;
    }

    return count;
}

unsigned int str2int (char *s)
{
    int base = 10;

    if (s[0] == '0' && s[1] == 'x')
    {
        base = 16;
        s += 2;
    }

    return strtoul (s, NULL, base);
}



dllmain.cpp
Code: Select all
#include <windows.h>
#include <stdio.h>
#include "memscan.h"

#define SCAN_VALUE_SIZE      4      // 4 bytes
#define   SCAN_VALUE_START   100      // the value

MEMBLOCK *StartNewScan(void)
{
   DWORD dwProcessID = GetCurrentProcessId();

   MEMBLOCK *scan = NULL;
   scan = create_scan(dwProcessID, SCAN_VALUE_SIZE);

   if(!scan)
   {
      odprintf("[StartNewScan()] SCAN: FALSE | Breaking...");
      return FALSE;
   }

   odprintf("[StartNewScan()] SCAN: TRUE | Continue...");

   update_scan(scan, COND_EQUALS, SCAN_VALUE_START);

   odprintf("[StartNewScan()] %d matches found!", get_match_count(scan));

   return scan;
}

void DoScanning(void)
{
   MEMBLOCK *scan;

   scan = StartNewScan();

   if(scan)
   {
      odprintf("[DoScanning()] SCAN: TRUE | Continue to search...");
      while(true)
      {
         if(GetAsyncKeyState(VK_F10)&1)
         {
            update_scan(scan, COND_DECREASED, 0);
            odprintf("[DoScanning()] Decreased value: %d matches found!", get_match_count(scan));
         }

         if(GetAsyncKeyState(VK_F11)&1)
         {
            odprintf("[DoScanning()] Print matched output:");
            print_matches(scan);
         }

         if(GetAsyncKeyState(VK_F12)&1)
         {
            odprintf("[DoScanning()] Dumping scan info:");
            dump_scan_info(scan);
         }

         Sleep(10);
      }
   }
   else
   {
      odprintf("[DoScanning()] SCAN: FALSE | Leaving...");
   }

}

BOOL WINAPI Loop(LPVOID lpVoid)
{
   while(true)
   {
      if(GetAsyncKeyState(VK_F9)&1) DoScanning();
      
      Sleep(1);
   }

   return TRUE;
}

BOOL WINAPI DllMain(HMODULE hDll, DWORD dwReason, LPVOID lpReserved)
{
   DisableThreadLibraryCalls(hDll);
   
   if(dwReason == DLL_PROCESS_ATTACH)
   {
      odprintf("[DllMain()] DLL_PROCESS_ATTACH");
      CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)Loop, NULL, NULL, NULL);
   }
   else if(dwReason == DLL_PROCESS_DETACH)
   {
      odprintf("[DllMain()] DLL_PROCESS_DETACH");
   }

   return TRUE;
}


please look at this line (memscan.h - create_scan()):
Code: Select all
#define WRITABLE (PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)

if I use PAGE_READWRITE argument, the program that has been injected not responding (high RAM).

but if I don't use PAGE_READWRITE argument, then show some results, but not the actual search result.

What's wrong with that? I hope there is someone who can help me.

Thanks in advance!

PS: I try to injecting Cheat Engine Tutorial (Tutorial.exe) part I for the sample (looking for a value of 100, and will be decreased)

Re: [HELP - C++] Failed using PAGE_READWRITE on Memory Scanner

PostPosted: Thu Sep 30, 2010 5:28 pm
by TheJAF
anyone? L. Spiro?

:( :(

Re: [HELP - C++] Failed using PAGE_READWRITE on Memory Scanner

PostPosted: Fri Oct 01, 2010 12:19 pm
by L. Spiro
First, that is not C++, it is C, and C sucks.

The only way I am going to know what is wrong with their scanner is by compiling and debugging it myself, which I certainly do not have the time to do.
You don’t know what is wrong with it because you didn’t write it.
Why not make your own scanner, using this one as a loose base.
All you need to do is study the API functions it is calling (the ones with capital letters that are part of the Windows API: VirtualQueryEx(), ReadProcessMemory(), etc.)
Apparently the author of this code also did not know what he or she was doing, since he or she wrote a remote scanner for local usage. Why would he or she open his or her own process? Why would he or she ReadProcessMemory() from his or her own process? Why are the functions defined in the header? Headers are for declarations, translation units (.C or .CPP) are for definitions.


High RAM consumption? There is probably a leak somewhere. A likely issue when using C since you don’t have destructors called at key locations that would take the burden off you when trying to remember every single spot where you would need to delete something you allocated.
High CPU usage? Probably. He or she only sleeps for 1 millisecond. Try 5 or 30.


Additionally, his post says it should be undetected, but that is a lie, since he is using API calls such as ReadProcessMemory(), which is always blocked by nProtect GameGuard and other anti-cheats.
Again, he wrote a remote scanner that works locally, which is no more useful than any remote scanner working remotely. Why ReadProcessMemory() when memcpy() would work faster AND is undetectable? Why even copy memory at all? You are local to the process, so all you need is to set a pointer to the address you want to check and do your check. 50 times faster and 1,000,000 time less detectable.


Why is it slow? Because it needs to be rewritten.


L. Spiro

Re: [HELP - C++] Failed using PAGE_READWRITE on Memory Scanner

PostPosted: Fri Oct 01, 2010 2:11 pm
by TheJAF
thanks for the quick respond, L. Spiro.

Why are the functions defined in the header? Headers are for declarations, translation units (.C or .CPP) are for definitions.


really my mistake, I just make it simple with my little bit dev/API knowledges. :oops:

Why not make your own scanner, using this one as a loose base.


I'll try, ready for study the API functions.

Thanks, L. Spiro!