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 


Memory Searching From Within A DLL

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> General programming
View previous topic :: View next topic  
Author Message
KryziK
Expert Cheater
Reputation: 3

Joined: 16 Aug 2009
Posts: 199

PostPosted: Wed Jan 16, 2013 1:41 am    Post subject: Memory Searching From Within A DLL Reply with quote

I need to search a process' entire memory for a specific byte pattern, and I need to do it from within a DLL.

Currently, I obtain the system's minimum and maximum application address and iterate through every address between them. However, this makes the process crash. My first thought was that the protection was causing the crash. So, I added a VirtualQuery call every iteration to check if it was PAGE_ACCESS or PAGE_NOEXECUTE (which fixed SOME crashing). However, this is obviously very slow because of so many API calls. I will fix this by using the page size to get the next page, check if it is readable, and then proceed to read from there (want to get the crashing fixed first).

However, while the current method of iterating through every address is slow, it certainly shouldn't crash when it hits some addresses. It works fine when starting from certain addresses, but not others, so I think I must be missing some sort of protection.

A few of the questions I have are:
1. I see lots of pattern searchers online, and none of them bother uerying anything. Is my assumption of needing to query valid, or am I wasting my time?
2. Is there a certain protection or special case I am missing when reading from memory that is causing this crash, or am I just perhaps doing something wrong in terms of my code?
3. I'm not quite sure how pages work, but will there be a potential for a byte pattern I'm searching for to span multiple pages (the end of one and beginning of another)? Will this mean I need to query a page ahead?

Additional information:
Starting from the process' base address gives me a few addresses where the code I am searching for is found. Some are within the main module's memory (static), and some are not. However, starting from the minimum address of 10000 causes a crash somewhere before the first result (which is around 230000).

Edit: Currently checking the following in terms of protection:
Code:
if (mbr.State != MEM_COMMIT || mbr.Protect == PAGE_NOACCESS || mbr.Protect == PAGE_EXECUTE)
    //skip
Back to top
View user's profile Send private message
Dark Byte
Site Admin
Reputation: 471

Joined: 09 May 2003
Posts: 25827
Location: The netherlands

PostPosted: Wed Jan 16, 2013 4:31 am    Post subject: Reply with quote

1: They most likely get a range pre programmed, like modulebase+size only
2: Watch out for PAGE_GUARD pages, like the top of the stack of a thread. When that gets hit a pagefault will happen that you should respond to. If you don't then when the game actually needs to grow the stack it will crash

Also, when you try to read memory that isn't allocated you will raise an access violation exception. Make sure you handle that properly

And then in the past there where memory pages marked as "No_cache", and trying to read those would BSOD you. I think that has been fixed by now, but it's recommended not to touch those

3: If your (current address % pagesize)+patternsize-1 > pagesize, then yes

_________________
Do not ask me about online cheats. I don't know any and wont help finding them.

Like my help? Join me on Patreon so i can keep helping
Back to top
View user's profile Send private message MSN Messenger
KryziK
Expert Cheater
Reputation: 3

Joined: 16 Aug 2009
Posts: 199

PostPosted: Wed Jan 16, 2013 5:36 pm    Post subject: Reply with quote

Thank you. For the most part my scans replicate CE's results (I get a few not on CE's list, and CE has a few not on my list). Not quite sure why that happens, but at the moment it doesn't really matter.

How does CE scan for an array of bytes so quickly? Even with my updated code, my scan takes probably a full second longer than CE's "instantaneous" scan. If you could point me to the specific file in the source code, I'd take a look at it. Or you could provide a brief overview!

Edit: Forgot to mention that CE's Writable, Executable, and CopyOnWrite checkboxes are all filled (not checked) to try to search as much memory as possible.
Back to top
View user's profile Send private message
Pingo
Grandmaster Cheater
Reputation: 8

Joined: 12 Jul 2007
Posts: 571

PostPosted: Thu Jan 17, 2013 6:13 am    Post subject: Reply with quote

Here a fast scan array function in C#.
From my personal tests, its just as fast as CE.
I'm not sure what language you're coding in but it might help you anyway.

I use this in my memory class for aobscanning. At one point i even made a simple memory scanner, worked well.
Code:
        public int SearchBytes(byte[] SearchIn, byte[] SearchFor)
        {
            int[] sBytes = new int[256];
            int Len = SearchFor.Length - 1, P = 0;

            for (int i = 256; i-- > 0; )
                sBytes[i] = SearchFor.Length;

            for (int i = SearchFor.Length - 1; i-- > 0; )
                sBytes[SearchFor[i]] = Len - i;

            while (P <= SearchIn.Length - SearchFor.Length)
            {
                for (int i = Len; SearchIn[P + i] == SearchFor[i]; i--)
                    if (i == 0) return P;
                P += sBytes[SearchIn[P + Len]];
            }
            return -1;
        }


Based off this
http://en.wikipedia.org/wiki/Boyer%E2%80%93Moore%E2%80%93Horspool_algorithm

_________________
Back to top
View user's profile Send private message
KryziK
Expert Cheater
Reputation: 3

Joined: 16 Aug 2009
Posts: 199

PostPosted: Thu Jan 17, 2013 11:36 am    Post subject: Reply with quote

Pingo wrote:
Here a fast scan array function in C#.
From my personal tests, its just as fast as CE.
I'm not sure what language you're coding in but it might help you anyway.

I use this in my memory class for aobscanning. At one point i even made a simple memory scanner, worked well.
Code:
        public int SearchBytes(byte[] SearchIn, byte[] SearchFor)
        {
            int[] sBytes = new int[256];
            int Len = SearchFor.Length - 1, P = 0;

            for (int i = 256; i-- > 0; )
                sBytes[i] = SearchFor.Length;

            for (int i = SearchFor.Length - 1; i-- > 0; )
                sBytes[SearchFor[i]] = Len - i;

            while (P <= SearchIn.Length - SearchFor.Length)
            {
                for (int i = Len; SearchIn[P + i] == SearchFor[i]; i--)
                    if (i == 0) return P;
                P += sBytes[SearchIn[P + Len]];
            }
            return -1;
        }


Based off this
http://en.wikipedia.org/wiki/Boyer%E2%80%93Moore%E2%80%93Horspool_algorithm


I'm searching a process' memory from a DLL injected within that process (C++). Because of this, I don't have any arrays holding the bytes, I am directly accessing the memory locations. Thank you for your help, though! I have something similar to your code written in C#.
Back to top
View user's profile Send private message
Pingo
Grandmaster Cheater
Reputation: 8

Joined: 12 Jul 2007
Posts: 571

PostPosted: Thu Jan 17, 2013 2:08 pm    Post subject: Reply with quote

Yea no prob, thought id post it just incase.

I also use it in my C# dlls.
I'v had very little experience with C++, wish i could help more but i can't.

_________________
Back to top
View user's profile Send private message
atom0s
Moderator
Reputation: 205

Joined: 25 Jan 2006
Posts: 8587
Location: 127.0.0.1

PostPosted: Fri Jan 18, 2013 6:17 am    Post subject: Reply with quote

The most common method of byte scanning in C++ (injected) is similar to this:
Code:

bool __stdcall MaskCompare( const unsigned char* lpDataPtr, const unsigned char* lpPattern, const char* pszMask )
{
   for (; *pszMask; ++pszMask, ++lpDataPtr, ++lpPattern)
   {
      if (*pszMask == 'x' && *lpDataPtr != *lpPattern)
         return false;
   }
   return (*pszMask) == NULL;
}

DWORD __stdcall FindPattern( const unsigned char* lpPattern, const char* pszMask )
{
   MODULEINFO mod = { 0 };
   if (!GetModuleInformation( GetCurrentProcess(), GetModuleHandle( "ModuleToScanWithin.dll" ), &mod, sizeof( MODULEINFO ) ))
      return 0;

   for (DWORD x = 0; x < mod.SizeOfImage; x++)
   {
      if (MaskCompare( reinterpret_cast< unsigned char* >( (DWORD)mod.lpBaseOfDll + x ), lpPattern, pszMask ))
         return ( (DWORD)mod.lpBaseOfDll + x );
   }
   return 0;
}


Adjust as needed etc.

_________________
- Retired.
Back to top
View user's profile Send private message Visit poster's website
KryziK
Expert Cheater
Reputation: 3

Joined: 16 Aug 2009
Posts: 199

PostPosted: Fri Jan 18, 2013 2:03 pm    Post subject: Reply with quote

Thanks, Wiccaan. Unfortunately, since I am not worried about whether the pattern is in a module or not, I don't want to slow down my search code by bothering with obtaining any module information. My MaskCompare code is basically the same, however.

Would it be better to not bother with gathering module information and just query every page/set of pages, or use the module information to help me replace VirtualQuery while within those modules, and then only query the memory between them?
Back to top
View user's profile Send private message
atom0s
Moderator
Reputation: 205

Joined: 25 Jan 2006
Posts: 8587
Location: 127.0.0.1

PostPosted: Sat Jan 19, 2013 4:01 am    Post subject: Reply with quote

KryziK wrote:
Thanks, Wiccaan. Unfortunately, since I am not worried about whether the pattern is in a module or not, I don't want to slow down my search code by bothering with obtaining any module information. My MaskCompare code is basically the same, however.

Would it be better to not bother with gathering module information and just query every page/set of pages, or use the module information to help me replace VirtualQuery while within those modules, and then only query the memory between them?


Depends on the situation. If you know the data your are scanning for is going to be in a specific modules memory space it'll be faster to just use that space only in the scan.

If you are unsure where its going to be, just loop each page that has proper access and scan that way. Keep in mind what DB said above about page permissions though to ensure you don't crash.

_________________
- Retired.
Back to top
View user's profile Send private message Visit poster's website
KryziK
Expert Cheater
Reputation: 3

Joined: 16 Aug 2009
Posts: 199

PostPosted: Sat Jan 19, 2013 12:49 pm    Post subject: Reply with quote

I may write two separate functions so that either can be used, but for now I am just trying to search all of memory. Currently I loop through each page, incrementing by the system info's pagesize. Then, if the page is readable (by checking the struct given by VirtualQuery for MEM_COMMIT, PAGE_NOACCESS, PAGE_GUARD, PAGE_EXECUTE, and PAGE_NOCACHE), I loop through each byte from the base address of the page to the pagesize - pattern length. For each byte there, I also loop through each byte of the pattern, so it's similar to the mask comparing function. At the moment, the scan takes a full second or two, yet CE's scan, even though it's external, appears to complete instantly.
Back to top
View user's profile Send private message
Dark Byte
Site Admin
Reputation: 471

Joined: 09 May 2003
Posts: 25827
Location: The netherlands

PostPosted: Sat Jan 19, 2013 2:34 pm    Post subject: Reply with quote

VirtualQuery returns more than 1 page, so you can cache that

or if you put every read between a try/except it will slow down a lot as well (you MUST use exception handling through, as the game might free a memory block you're currently reading)

also, try increasing the priority of your thread to higher than the other threads of the game, else you only get a fraction of the cpu power assigned to that process

_________________
Do not ask me about online cheats. I don't know any and wont help finding them.

Like my help? Join me on Patreon so i can keep helping
Back to top
View user's profile Send private message MSN Messenger
KryziK
Expert Cheater
Reputation: 3

Joined: 16 Aug 2009
Posts: 199

PostPosted: Sat Jan 19, 2013 2:38 pm    Post subject: Reply with quote

Dark Byte wrote:
VirtualQuery returns more than 1 page, so you can cache that

or if you put every read between a try/except it will slow down a lot as well (you MUST use exception handling through, as the game might free a memory block you're currently reading)

also, try increasing the priority of your thread to higher than the other threads of the game, else you only get a fraction of the cpu power assigned to that process


Thanks. I actually do read until the end of pages of the same type and account for the difference in my for loop of pages. I don't have any try/except statements, and currently I don't have any exception handling, but I haven't needed them yet. I was planning on making everything "stable" once I got it working quickly. I will take a look at the thread priority. Thanks again to all of you.
Back to top
View user's profile Send private message
Dark Byte
Site Admin
Reputation: 471

Joined: 09 May 2003
Posts: 25827
Location: The netherlands

PostPosted: Sat Jan 19, 2013 10:09 pm    Post subject: Reply with quote

Just wondering how many results you get?
If more than 100 make sure you do not convert the addresses to text, and certainly not add them to a gui object during the scan. (gui updates are horribly slow)

_________________
Do not ask me about online cheats. I don't know any and wont help finding them.

Like my help? Join me on Patreon so i can keep helping
Back to top
View user's profile Send private message MSN Messenger
KryziK
Expert Cheater
Reputation: 3

Joined: 16 Aug 2009
Posts: 199

PostPosted: Sat Jan 19, 2013 10:21 pm    Post subject: Reply with quote

I get almost the same as CE, which is ~150. The total number of results is the only thing printed to the command prompt. Even if I print the addresses, it completes in just about the same amount of time as without.
Back to top
View user's profile Send private message
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