Page 1 of 2 12 LastLast
Results 1 to 15 of 17
  1. #1
    WasserEsser's Avatar
    Join Date
    Jul 2015
    Gender
    male
    Posts
    735
    Reputation
    174
    Thanks
    677
    My Mood
    Busy

    Understanding Pattern Scanning

    This post is for people that know how to code but don't know what pattern scanning is. It's meant as an informative post and i'm more than open to critism. I'd also like you to spot any errors / mistakes / false information so i can fix them as soon as possible.

    Intro

    Since alot of people have problems understanding the concept of pattern scanning and how to implement it into their own cheats, i quickly wanted to cover the concept of pattern scanning and how to implement it. My goal of this article is to teach you the concept so you can implement it into your own code and apply it to any game.

    What is pattern scanning?

    When you write your program in C++, the code is getting compiled into machine code. The Visual C++ compiler compiles the code directly into binary, but we can use tools like OllyDbg, x64dbg or any other debugger to display it in assembly. In cheat developement we use so called offsets to access certain variables / addresses. These offsets are in most cases also used in memory to access certain data as described below. To eliminate the hassle with updating your cheat on every update by either grabbing the offsets yourself or using an offset dumper, you can implement pattern scanning. Depending on your implementation, you can provide your pattern scanning function a specific pattern which should be found inside of a range of bytes. It will scan over the bytes and find the address of where the desired offset is used, making it easy for you to copy it. This way you don't have to update your cheat whenever an offset changes, you only need to change the pattern if the code where it's used changes, which doesn't happen as often.

    What are offsets and how are they generated?


    Offsets are addresses, often used with another address, for example a player address. To understand offsets, you need to know about the size of datatypes. On a 32 bit machine, an integer if not otherwise specified is 4 bytes long. A bool is one byte long. These variables will later be layed out in memory at certain addresses. I'll show you an example by coding a small player class.


    Code:
    class CPlayer
    {
    public:
         CPlayer( int Health, int Team, int Armor, CVector Pos, bool Valid, bool Alive ) 
             : m_iHealth( Health ), m_iTeam( Team ), m_iArmor( Armor ), m_vecPosition( Pos ), m_bValidPlayer( Valid ), m_bIsAlive( Alive )
         {
     
         }
         ~CPlayer( )
         {
     
         }
    
         int m_iHealth;
         int m_iTeam;
         int m_iArmor;
    
         CVector m_vecPosition;
    
         bool m_bValidPlayer;
         bool m_bIsAlive;
    };
    If we instantiate a player object, give it dummy values and browse the memory region in cheat engine, we can rebuild our data structure.



    Here we can see our class layed out in memory, along with it's addresses. The address 18FDAC is our base address, the address of our player class. If the game wants to check if the player is valid, it might check the bool m_bIsValid inside this class. In most cases, the address of the player is saved in one of the registers. The game will most likely have an instruction like

    Code:
    mov eax, [ecx + 00000018]
    0x18 is called an offset. To access the boolean m_bIsValid, we use the address of the player + 0x18. The same principle can be applied to any pointer. Static pointers that point to our player class for example might be accessed using the base address of a certain dynamic link library + an offset. If we can find the instruction where the address is accessed, we can read out our offset. Since the instruction is also stored in memory, we can simply read the .text section. In there we can find our offset. To be able to find the address where this offset is stored, we can use pattern scanning.

    How can i implement pattern scanning?


    Let's take an actual look at a game. I'll be using Counter-Strike: Global Offensive here as it's one of the most documented games out there. First, you need to know the current offset. Get it by either looking for it with cheat engine, using an offset dumper or visiting the offset thread. We attach Cheat Engine to our game and click on "Add Address Manually".



    I'll be using the health offset for our LocalPlayer for this example. I first add a pointer to our LocalPlayer, so we know the address of our LocalPlayer.



    Rightclick, show as decimal and you got the address of the LocalPlayer. Make sure to be in a bot game. Now we can take that address and add 0xFC onto it to access our health.



    You can also use the "Pointer" checkbox, however i only use it for multi-level pointers.

    Now rightclick it and click on "Find out what accesses this address". It will attach a debugger to the process and list you every instruction accessing the address.



    As we can see in the screenshot, the game accesses the address differently in different places. Interesting for us are the instructions that access our address using the offset we want to grab. The first instruction accesses our address by moving the value of ecx + 000000FC into the eax register. This instruction is somewhere in the .text section. We want to find it and read out the offset. If youv double click on the first instruction you can see more information about this instruction together with the register states after the instruction occured and the surrounding instructions. This information is useful for us. We can see that the ecx register holds the address of our LocalPlayer, and it accesses the health by copying the value of ecx + 000000FC. But there is one problem. The surrounding assembly instructions are most likely going to cause problems if the permutation of bytes is used in multiple places. It could find the wrong instructions and therefore may result in wrong results. We want to find a pattern which will result in a single result, meaning that the permutation of bytes are only present once in the entire chunck of bytes we search for our pattern in. Let's try the fourth instruction in the list. It looks much better as it doesn't have a bunch of int3 instructions, the actual instruction and a return instruction. Now rightclick, copy the information and paste it into an editor for now.

    Close Cheat Engine and open up OllyDbg. Make sure you have the SigMaker plugin installed. Attach OllyDbg to the game and wait for it to load.



    Once it's finished loading, rightclick, click on "Go to" and click on expression.



    Now you need to copy the address which contains the address of the instruction and paste it into the "Go to expression" dialog. Important is that you do not close your game inbetween copying the address from Cheat Engine and going to the address in OllyDbg or else it will most likely have a different address.



    Once done, you can scroll up a little bit to see the the surrounding instruction bytes at that instruction.

    The instructions can be found in the middle while the hexadecimal representation can be found on the left of the instructions.



    Since hexadecimal is base 16, each byte has to have 2 characters representing them.



    Now we need to make ourself a pattern. Like mentioned above, we want to make a pattern which can only be found once in the block of memory we copy.

    If we would now rightclick, Make Sig, Test Sig and click on Scan, we would end up with 6 results. We want to increase the size of the signature to assure that we only get one result.
    We can start further above, further down, as long as we can still count the byte difference. However, we don't want a signature which is too big or else it is much more likely that we have to update our pattern in the future. The instructions could change, so try to keep the pattern as small as possible while only getting one result. Let's start 1 line above and mark until the line underneath our instruction.



    You may have already noticed that the hexadecimal representation has our offset stored inside of it. It's stored in reverse order, though if we read it out later we will end up with the right address.



    Again, the pattern scanning function is iterating through the bytes until it finds the signature matching to the pattern.



    Once it found the place where it matches, it will return us depending on your implementation an address or an index. My pattern scanning function will return you an index so you can copy the offset directly from the filled allocated memory.



    But wait, let's assume the offset changed. It's now 0x100, the pattern on the right side wouldn't match with the bytes on the left side since FC000000 would be 00010000 now. That's what so called "wildcards" are for. Wildcards will skip bytes that might differ, for example the offset, but also other addresses that might change each time. Usually, the SigMaker plugin catches those addresses and replaces them with wildcards in the pop up window, however it didn't do it for this offset, probably since it's a very small address. Usually, it would replace those might changing addresses with \x00 in the pattern (also called signature ) and replace the according 'x' in the mask with a '?'. This time we have to do it manually. Since an address is four bytes long, we want to zero out the four bytes that store the address. Depending on your implementation, you might need the mask aswell, so make sure you change it aswell. Make sure that you only get one result by clicking on scan before you use the pattern. It only found the pattern once, which means we can use this pattern.

    Since i don't use a mask for my implementation, i only have to replace the \xFC with a \x00.





    Now we can code ourself a pattern scanning function. I'll be using my CPatternScan class which will load a module's bytes into the heap and will store it until the object is destroyed. At the end of this tutorial, you should've fully understood the concept of pattern scanning, and with a bit of thinking, you should be able to create your own pattern scanning class depending on your needs.

    Code:
    class CPatternScan
    {
        CPatternScan( )
        {
            Process = nullptr;
            Data = nullptr;
            Size = nullptr;
        }
    
        const CProcess* Process;
    
        std::unique_ptr< BYTE[ ] > Data;
    
        const DWORD* Size;
    
    public:
    
        CPatternScan( CProcess* Process, char* ModuleName )
        {
            if ( Process != nullptr && ModuleName != nullptr )
            {
                this->Process = Process;
    
                Size = this->Process->GetModuleSize( ModuleName );
    
                Data = std::make_unique< BYTE[ ] >( *Size );
    
                auto BytesRead{ SIZE_T( ) };
    
                if ( !ReadProcessMemory( *this->Process->GetHandle( ), reinterpret_cast< LPCVOID >( this->Process->GetModuleBaseAddress( ModuleName ) ), Data.get( ), *Size, &BytesRead ) || BytesRead != *Size )
                {
                    memset( &Data, 0, *Size );
                }
            }
    
        ~CPatternScan( )
        {
    
        }
    
        auto FindPattern( std::vector< BYTE > Pattern ) const -> DWORD
        {
    
            Pattern.shrink_to_fit( );
    
            for ( DWORD i = 0; i < *Size; i++ )
            {
                auto DoesMatch{ true };
    
                for ( DWORD j = 0; j < Pattern.size( ); j++ )
                {
                    if ( Pattern[ j ] == 0 ) continue;
                    if ( Pattern[ j ] == Data[ i + j ] ) { DoesMatch = false; break; }
                }
    
                if ( DoesMatch ) return i;
           }
    
           return 0;
        }
    
        auto GetOffset( DWORD Offset ) const -> DWORD
        {
            auto Buffer{ DWORD( 0 ) };
    
            memcpy( &Buffer, &Data[ Offset ], sizeof( DWORD ) );
    
            return Buffer;
        }
    
        auto GetOffset( std::vector< BYTE > Pattern, DWORD Offset ) const -> DWORD
        {
            return GetOffset( FindPattern( Pattern ) + Offset );
        }
    };
    Let's take a closer look at it. Once the object is created, i create a unique_ptr which will allocate space on the heap. Once this space is allocated, i copy the bytes of the dynamic link library into the allocated space on the heap. I use a vector for my pattern, with zeros ( 0x00 ) as wildcards. Once the pattern is found, i can return the index at which the pattern is found. I could also return the address at which the pattern is located in memory to read the offset from the original process, but since i already copied the entire dynamic link library, i can also copy the offset from the allocated space.

    But wait, did we miss something? Why is this not giving me the right offset? Well, let's take a look again. The function will return us the address at which the pattern is found, this means that it will return us this position ( a relative index in my case, it could also return you an address which you can read via ReadProcessMemory ):



    If you would read the next four bytes at the address the pattern scanning function returned, you would essentially read the following:



    This is obviously not the result you want, as it's not the offset you desired. This being said, you need to add your own offset on top of the returned address / index. Since we know that hexadecimal is base 16 and therefore needs 2 characters for one byte being displayed, the box we marked is all together four bytes long. Right after these four bytes is our desired offset. This means that you need to read / copy the address the function returned + 4 bytes. This would be the address / index where the offset is stored. Let's assume you want to read out the bytes 00 00 7F 2D. To get the right address, you need to count the bytes before the bytes you want read.

    In the above case it would be 7 bytes. Take the address / index the pattern scanning function returned and add 7 bytes on to it and you should end up with the right offset.

    Let's pick another example, this time with a static pointer to our LocalPlayer. If we perform a pointer scan in cheat engine, preferably multiple times to make sure every result is always pointing at our LocalPlayer we can see multiple pointers that point to the address of our LocalPlayer. Let's try to make a pattern for the LocalPlayer pointer which we used earlier to make ourself a health offset pattern.

    We scan multiple times by rescanning over the previous results after restarting the game. This will eliminate temporary pointers and show us the pointers that seem to always pointer at our LocalPlayer.



    The first result is a valid pointer to our LocalPlayer. Since almost everyone who uses a LocalPlayer pointer uses it, so we could try and create a signature using that pointer.

    If we doubleclick, the pointer gets added to our address list. Rightclicking and clicking on "Find out what accesses this address" brings up a different dialog now. We can either find out what accesses the pointer itself ( which we want to grab ) or find out what accesses the address pointed to by this pointer. We want to grab the pointer itself, so we click on "Find out what accesses this pointer".

    But wait, there is only one instruction that accesses this pointer at this point in time and it doesn't contain the actual offset in it's instruction. How should we grab it?



    We could look for surrounding instructions by clicking on the instruction, then on "Show Dissasembly" and see how the instructions are formed and accessed, but we don't want to bother with that now, we have many other pointers that point to our LocalPlayer, so we'll just take a look at a different one.

    So let's take the next one, client.dll + 4A98144. Double click it to add it to our address list and find out what accesses this pointer. We can see alot of instructions that move registers, so we can't read out the registers without hooking the function and reading out the registers at that point of time. But we also have instructions that contian an absolute address. By clicking on it once, we can see that this absolute address is formed of client.dll + 4A98164, meaning it's a static global pointer which is always going to be at the base address of the client.dll module + 4A98164. But if we compare that offset to our offset in the pointer list, we can see that it differs by 10 bytes. How come? Let's add the pointer to our list and browse the memory region it points to. The current pointer in the list points to the address the first entry in the player class points to, so we can't browse this memory region.





    We can see alot of addresses in this memory region, and with a closer look we can spot our LocalPlayer address in there, again saved in reverse order.



    With further investigation this turns out to be the EntityList, which contains pointers to every entity in the game. client.dll + 4A98164 always points to the world, while client.dll + 4A98174 points to the first entity in the world, which in a local bot game is our own player, since the bots spawn once we are on the server and "started" the server. This is differnt in online servers, we will rarely be the first entity in the list. I'm not going to go too much into detail about the source engine since this article is about pattern scanning, however, we can see that this is not a good pointer to our LocalPlayer since we are not always at the same position in this list.

    Let's take the next pointer in our pointer list. If we find out what accesses this address, we do again see a list with a different offset, so we can't read out our offset from these instructions.



    Onto the next pointer. This time we can see alot more instructions that access this pointer, together with the same offset every time. This could mean that it's a static global pointer again, being in the same address on every game start relative to the module's base address. If we click on the first instruction and take a look at the window at the bottom we can see that the absolute address in the instruction is formed out of client.dll + 4F2B50C, exactly what we can use, so let's double click this instruction and copy the information. But hey, we got a instruction which doesn't contain a lot of valueable instructions around it, meaning that it could be found in multiple places again, so we look for a different instruction which might have better surrounding instructions. Double clicking the next one gives us better surrounding instructions, so let's copy the information and paste it into an editor again.



    Close Cheat Engine, open up OllyDbg, attach to our process and go to the copied expression. After marking different parts of the bytes, i came up with the following which will give you one result when scanning for it.



    This time, the SigMaker plugin formed the right signature and mask out of the bytes in the hexadecimal representation, so we don't have to correct the pattern.



    Now, since we have a pointer to our LocalPlayer, we can dereference it / ReadProcessMemory it and grab the base address of our LocalPlayer, add the health offset and dereference it again / ReadProcessMemory it and read out our current health.
    Last edited by WasserEsser; 03-16-2016 at 10:17 AM.

  2. The Following 37 Users Say Thank You to WasserEsser For This Useful Post:

    ***HELLSANGEL*** (06-30-2016),1C4ST4W4Y1 (04-17-2018),a26401618 (10-01-2018),affe2626 (07-10-2016),canown (07-04-2016),cironio (07-08-2017),csgocheatxddd123 (06-04-2017),CyanRed3 (11-21-2016),Delision (11-30-2016),DonkeyHorse (08-23-2017),grannycrazy (01-06-2018),HexMurder (03-15-2016),Hunter (04-04-2016),ImStyL (05-06-2016),inieuwoudt1 (02-11-2019),iTzCode (08-21-2016),jonluke (09-28-2017),Josh155 (03-16-2016),KappaMang (03-16-2016),kollingmaster (12-06-2017),lordbatt29 (02-07-2021),mariogk2 (06-14-2016),Matrix Cow (01-17-2018),MegaProphet (05-12-2016),monsterx69 (05-13-2016),NightDev (03-17-2016),RowSkidrowAnon (12-11-2018),SP1K3CSGO (04-19-2016),suppmate (04-30-2019),Sytrux (12-13-2016),The.Asian (09-26-2016),The4byssWacther (04-15-2019),TheNamless (07-10-2016),Urzeitkrebs (09-07-2016),utlmamba (07-04-2016),vidsac (09-17-2017),Yemiez (03-16-2016)

  3. #2
    HexMurder's Avatar
    Join Date
    Apr 2011
    Gender
    male
    Location
    System.Diagnostics
    Posts
    344
    Reputation
    96
    Thanks
    3,169
    Absolutley amazing thread. I have been trying to research this myself without very much success. Thanks so much man. Gonna drop a thanks on this thread as soon as i'm not on mobile .

  4. #3
    HexMurder's Avatar
    Join Date
    Apr 2011
    Gender
    male
    Location
    System.Diagnostics
    Posts
    344
    Reputation
    96
    Thanks
    3,169
    +rep . /2short.

  5. #4
    Lak33's Avatar
    Join Date
    Feb 2016
    Gender
    male
    Posts
    5
    Reputation
    10
    Thanks
    1
    My Mood
    Drunk
    your post included so much things that i cant even understand it. Another sticky post. GJ

  6. #5
    WasserEsser's Avatar
    Join Date
    Jul 2015
    Gender
    male
    Posts
    735
    Reputation
    174
    Thanks
    677
    My Mood
    Busy
    I'm currently adding more to it, which will cover some more examples.

    - - - Updated - - -

    Quote Originally Posted by Lak33 View Post
    your post included so much things that i cant even understand it. Another sticky post. GJ
    It would be good if you could elaborate and tell me the things you didn't understand, since this should be a tutorial which everyone wanting to take advantage of patern scanning should understand, so i can add an explaination for it.

  7. The Following User Says Thank You to WasserEsser For This Useful Post:

    cs2380189 (11-16-2017)

  8. #6
    iTzCode's Avatar
    Join Date
    Apr 2015
    Gender
    male
    Location
    idk.dll
    Posts
    72
    Reputation
    10
    Thanks
    29
    My Mood
    Relaxed
    Nice dude I Love you thx ♥

  9. #7
    WasserEsser's Avatar
    Join Date
    Jul 2015
    Gender
    male
    Posts
    735
    Reputation
    174
    Thanks
    677
    My Mood
    Busy
    // More things added.

  10. The Following User Says Thank You to WasserEsser For This Useful Post:

    iTzCode (05-20-2016)

  11. #8
    Yemiez's Avatar
    Join Date
    Jun 2012
    Gender
    male
    Location
    Sweden
    Posts
    2,566
    Reputation
    731
    Thanks
    16,279
    My Mood
    Devilish

    What I would recommend you change:
    • When you scan the memory looping (i < size) you should check ((i + pattern.size( )) < size) to minimize loops.
    • Instead of mashing all the code into your FindPattern function just make a bunch of inline functions (e.g comparing the pattern with the current byte).
    • Why would you manually specify the return type if you are using the auto keyword? Doesn't make any sense, the compiler should be able to deduct the type by its return value.

    Of course these are just recommendations!

    Thats all I could think of code wise, great work!


    edit:
    nvm my 3rd point, realized that it may be necessary :P
    Last edited by Yemiez; 03-16-2016 at 10:02 AM.

  12. #9
    WasserEsser's Avatar
    Join Date
    Jul 2015
    Gender
    male
    Posts
    735
    Reputation
    174
    Thanks
    677
    My Mood
    Busy
    Quote Originally Posted by Yamiez View Post

    What I would recommend you change:
    • When you scan the memory looping (i < size) you should check ((i + pattern.size( )) < size) to minimize loops.
    • Instead of mashing all the code into your FindPattern function just make a bunch of inline functions (e.g comparing the pattern with the current byte).
    • Why would you manually specify the return type if you are using the auto keyword? Doesn't make any sense, the compiler should be able to deduct the type by its return value.

    Of course these are just recommendations!

    Thats all I could think of code wise, great work!


    edit:
    nvm my 3rd point, realized that it may be necessary :P
    The first point is a good one, which i haven't thought of.

    Inlined functions may be cleaner, though i thought its not really necessary for this small function :P .

    The third point is necessary since this function is going to be part of an exported library, which means that people using it will only have a headerfile, which needs a clear return type, hence the trailing return type.
    Last edited by WasserEsser; 03-16-2016 at 10:07 AM.

  13. The Following User Says Thank You to WasserEsser For This Useful Post:

    Delision (11-30-2016)

  14. #10
    Yemiez's Avatar
    Join Date
    Jun 2012
    Gender
    male
    Location
    Sweden
    Posts
    2,566
    Reputation
    731
    Thanks
    16,279
    My Mood
    Devilish
    Quote Originally Posted by WasserEsser View Post
    The third point is necessary since this function is going to be part of an exported library, which means that people using it will only have a headerfile, which needs a clear return type, hence the trailing return type.
    If its going to be in a library I'd refrain completely from using auto when declaring functions, it would be the same as writing a normal function prototype but looks a bit worse, but of course this is just a personal preference.

    I would only use auto when writing templated functions, but I'd use decltype because its more flexible and explicit with its rules.

  15. The Following 2 Users Say Thank You to Yemiez For This Useful Post:

    Hunter (05-07-2016),WasserEsser (03-16-2016)

  16. #11
    jambertobbles's Avatar
    Join Date
    Aug 2015
    Gender
    male
    Posts
    12
    Reputation
    10
    Thanks
    19
    This is a very well made tutorial! Cheers WasserEsser!

  17. The Following User Says Thank You to jambertobbles For This Useful Post:

    WasserEsser (03-16-2016)

  18. #12
    rwby's Avatar
    Join Date
    Jul 2015
    Gender
    male
    Location
    client.dll
    Posts
    1,631
    Reputation
    142
    Thanks
    6,723
    Very nice thread WasserEsser. I went ahead and stickied this topic for you. Cheers.

  19. The Following User Says Thank You to rwby For This Useful Post:

    WasserEsser (03-17-2016)

  20. #13
    Adrenaline's Avatar
    Join Date
    Jul 2015
    Gender
    male
    Location
    Visual Studio
    Posts
    1,126
    Reputation
    29
    Thanks
    503
    My Mood
    Angelic
    Nice thread WasserEsser!

  21. #14
    RealTalk's Avatar
    Join Date
    May 2012
    Gender
    male
    Location
    Canada
    Posts
    19
    Reputation
    10
    Thanks
    0
    My Mood
    Cheerful
    Love the thread, would be amazing if you made video tutorials. As someone who's visual I love watching tuts on how to do things.


    Side note; would you permit me to add you on skype to discuss a few questions?
    Don't want to bother you, so it's cool if you don't want to.

  22. #15
    RoyGojnes's Avatar
    Join Date
    Mar 2016
    Gender
    male
    Posts
    5
    Reputation
    10
    Thanks
    0
    Very good resource, thank you.

Page 1 of 2 12 LastLast

Similar Threads

  1. Address Logger Pattern Scan Problems
    By [H]aaBX in forum Crossfire Coding Help & Discussion
    Replies: 8
    Last Post: 01-20-2014, 03:01 AM
  2. [Release] Pattern Scans
    By N3OH4X in forum Combat Arms Hack Coding / Programming / Source Code
    Replies: 19
    Last Post: 02-09-2013, 05:55 AM
  3. [Release] List of Patterns Scans
    By luizimloko in forum CrossFire Hack Coding / Programming / Source Code
    Replies: 13
    Last Post: 12-19-2012, 10:28 PM
  4. Pattern Scan
    By GoldWhite in forum Combat Arms Coding Help & Discussion
    Replies: 11
    Last Post: 11-27-2012, 11:15 AM
  5. [Help] Pattern scanning
    By pyton789 in forum Visual Basic Programming
    Replies: 27
    Last Post: 03-09-2011, 03:44 AM