Source Code Pattern Scanning

Hexui Undetected CSGO Cheats Sinkicheat PUBG Cheat

Solaire

Respected Hacker
Dank Tier VIP
Dec 15, 2013
1,051
16,353
62
I was rolling the concept around in my head this morning and decided to see if I could write a pattern scan funct from scratch. This is the result. It's heavily commented, so hopefully it'll help anyone new to pattern scanning understand how it works.

C++:
#include <Windows.h>
#include <stdio.h>

int PatternScan(char * arr, int size, char * pattern, char * mask, int len) {
    // The index at which the pattern is found
    int index = -1;

    // Scan for the pattern in the byte array. We do size - len so that we don't
    // go out of the bounds of the array we're scanning
    for (int i = 0; i < size - len; i++) {
        // False until the pattern is found
        bool found = false;

        // If the byte we're at is equal to the start of our pattern
        if (arr[i] == pattern[0]) {
            // Loop through the current spot and see if it's the pattern
            for (int j = 0; j < len; j++) {
                // If the bytes are the same at the index, or the byte is a wildcard, set found to true and continue
                if ((arr[i + j] == pattern[j]) || (mask[j] == '?')) {
                    found = true;
                    continue;
                }
                
                // Otherwise set found to false and break;
                else {
                    found = false;
                    break;
                }
            }
        }

        // Set index to i and break from the loop if the pattern is found
        if (found) {
            index = i;
            break;
        }
    }

    return index;
}

int main() {
    // Our array of bytes and its size
    char * arr = "\xFF\x24\x1E\xEF\xA7\x99\x90\x4E\xA4\x1E\x99\x4E\x3C\xAB\xB7\x12\x83\x3E\x75";
    int arrSize = 19;

    // Our pattern and mask, and its length
    char * pattern = "\x1E\x99\x4F\x3C\xAC";
    char * mask = "xx?x?";
    int len = 5;

    // Scan for the pattern
    int index = PatternScan(arr, arrSize, pattern, mask, len);

    // Make sure the pattern was found
    if (index != -1) {
        // Print out our findings
        printf("Index: %d\n", index);
        printf("Bytes at arr[index]: ");
        for (int i = 0; i < len; i++) {
            printf("\\x%X", (char)arr[index + i]);
        }
    }

    getchar();

    return 0;
}

This code is for the most part a concept. You'll have to figure out how to implement it yourself if you want to use it on a game, though that should be fairly simple.
 
Last edited:

Broihon

edgy 12 y/o
Escobar Tier VIP
Fleep Tier Donator
Dec 22, 2013
1,745
40,528
316
C++:
bool bCompare(const char * szMask, const BYTE * pPattern, const BYTE * pSource)
{
	for (;*szMask;++szMask, ++pPattern, ++pSource)
	{
		if (*szMask == 'x' && *pPattern != *pSource)
			return false;
	}
	return true;
}

const void * FindPattern(const void * StartAddress, DWORD RegionSize, const BYTE * pPattern, const char * szMask, UINT Alignment = 4, UINT Skip = 0)
{
	UINT Count = 0;
	const BYTE* CurrAddress = reinterpret_cast<const BYTE*>(StartAddress);
	for (;reinterpret_cast<const BYTE*>(StartAddress) + RegionSize >= CurrAddress; CurrAddress += Alignment)
	{
		if (bCompare(szMask, pPattern, CurrAddress))
		{
			if (Count == Skip)
				return CurrAddress;
			Count++;
		}
	}
	return nullptr;
}
Just leaving this here if you don't mind :3
 

Solaire

Respected Hacker
Dank Tier VIP
Dec 15, 2013
1,051
16,353
62
Вroihon;40170 said:
C++:
bool bCompare(const char * szMask, const BYTE * pPattern, const BYTE * pSource)
{
    for (;*szMask;++szMask, ++pPattern, ++pSource)
    {
        if (*szMask == 'x' && *pPattern != *pSource)
            return false;
    }
    return true;
}

const void * FindPattern(const void * StartAddress, DWORD RegionSize, const BYTE * pPattern, const char * szMask, UINT Alignment = 4, UINT Skip = 0)
{
    UINT Count = 0;
    const BYTE* CurrAddress = reinterpret_cast<const BYTE*>(StartAddress);
    for (;reinterpret_cast<const BYTE*>(StartAddress) + RegionSize >= CurrAddress; CurrAddress += Alignment)
    {
        if (bCompare(szMask, pPattern, CurrAddress))
        {
            if (Count == Skip)
                return CurrAddress;
            Count++;
        }
    }
    return nullptr;
}
Just leaving this here if you don't mind :3
Yes, yes, we get it, your codenz are much better :p
 

Broihon

edgy 12 y/o
Escobar Tier VIP
Fleep Tier Donator
Dec 22, 2013
1,745
40,528
316
Yes, yes, we get it, your codenz are much better :p
Actually that's not what I wanted to point out. I just think that this thread is a good place to sure different versions of the same function ^^ Also my version is not coded from scratch. For example I'm still not happy with the extra function bCompare.
 

mambda

headass
Escobar Tier VIP
Trump Tier Donator
Jun 25, 2014
2,297
37,938
269
i prefer pattern scans where you dont have to include a mask, so the pattern is the mask itself

i.e.

FindPattern(module, "83 45 23 ? ? 32 86 ? 50", sizeOfModuleHere);

then you can straight copy it out of IDA or Cheat engine or whatever you like
 

Solaire

Respected Hacker
Dank Tier VIP
Dec 15, 2013
1,051
16,353
62
Вroihon;40172 said:
Actually that's not what I wanted to point out. I just think that this thread is a good place to sure different versions of the same function ^^ Also my version is not coded from scratch. For example I'm still not happy with the extra function bCompare.
Heh no worries, just messing around :p

i prefer pattern scans where you dont have to include a mask, so the pattern is the mask itself

i.e.

FindPattern(module, "83 45 23 ? ? 32 86 ? 50", sizeOfModuleHere);

then you can straight copy it out of IDA or Cheat engine or whatever you like
Nice! I'll have to see if I can implement that and throw it in here :D
 

Solaire

Respected Hacker
Dank Tier VIP
Dec 15, 2013
1,051
16,353
62
@mambda

C++:
int GetLen(char * byteArray) {
    return (strlen(byteArray) + 1) / 3;
}

void ToPatAndMask(char * byteArray, char * pattern, char * mask) {
    // Get the first byte in the string
    char * byte = strtok(byteArray, " ");

    int i = 0;
    while (byte) {
        // If the byte is a wild card, set the mask index to '?', get the next byte, and continue
        if (byte[0] == '?') {
            byte = strtok(NULL, " ");
            pattern[i] = 0;
            mask[i] = '?';
            i++;
            continue;
        }

        // Convert the string byte to a regular hex integer
        pattern[i] = strtol((const char *)byte, NULL, 16);
        mask[i] = 'x';

        // Get the next byte
        byte = strtok(NULL, " ");
        i++;
    }

    // Make sure the mask is NULL terminated
    mask[i] = 0;
}

int PatternScan(char * arr, int size, char * mixedPattern) {
    // Get the length of the pattern and allocate memory for the new pattern and mask
    int len = GetLen(mixedPattern);
    char * pattern = new char[len];
    char * mask = new char[len + 1];

    // Get the pattern and mask from the mixed pattern
    ToPatAndMask(mixedPattern, pattern, mask);

    // The index at which the pattern is found
    int index = -1;

    // Scan for the pattern in the byte array. We do size - len so that we don't
    // go out of the bounds of the array we're scanning
    for (int i = 0; i < size - len; i++) {
        // False until the pattern is found
        bool found = false;

        // If the byte we're at is equal to the start of our pattern
        if (arr[i] == pattern[0]) {
            // Loop through the current spot and see if it's the pattern
            for (int j = 0; j < len; j++) {
                // If the bytes are the same at the index, or the byte is a wildcard, set found to true and continue
                if ((arr[i + j] == pattern[j]) || (mask[j] == '?')) {
                    found = true;
                    continue;
                }

                // Otherwise set found to false and break;
                else {
                    found = false;
                    break;
                }
            }
        }

        // Set index to i and break from the loop if the pattern is found
        if (found) {
            index = i;
            break;
        }
    }

    // Clean up and return the index
    delete[] pattern;
    delete[] mask;
    return index;
}
There's just one small (Actually, quite big) problem with it. When delete[] pattern and delete[]mask are called, program flow goes into what looks like an infinite loop. You can remove those two lines, but that leaves a small memory leak. Anywho, I ended up just converting the string into the two char arrays heh. I'm sure there is a better and cleaner way tbh. You also have to send in wildcards as "??" instead of just one "?".

Example call:
C++:
    char bytes[] = "\x12\x6E\x53\x27\x38\xE4\x52\x72\x24\x7B\xAB\x42\xF8\xE5\x8B";
    char mixedPattern[] = "38 E4 ?? 72 24 7B AB ?? F8";
    int index = PatternScan(bytes, 15, mixedPattern);
    printf("%d", index);
tl;dr This is essentially the same code, I just convert the mixedPattern array into two different char arrays.

EDIT:
Fixed the above code, I was writing to restricted memory with mask, just had to change it to char * mask = new char[len + 1];
 
Last edited:

Broihon

edgy 12 y/o
Escobar Tier VIP
Fleep Tier Donator
Dec 22, 2013
1,745
40,528
316
C++:
#include <Windows.h>
#include <iostream>

size_t PatternStringToMask(char * szPattern, BYTE * pPatternOut, char * szMaskOut, UINT MaxCount)
{
	size_t Len = lstrlenA(szPattern);
	size_t Ret = 0;
	for (UINT i = 0;i <= Len - 1 && Ret < MaxCount ;++i)
	{
		switch (szPattern[i])
		{
		case '?':
			szMaskOut[Ret] = '?';
			pPatternOut[Ret] = 0;
			Ret++;
			if (szPattern[i + 1] == '?')
				i++;
			break;

		default:
			BYTE HighPart, LowPart;
			if (szPattern[i] >= '0' && szPattern[i] <= 'f')
			{
				szMaskOut[Ret] = 'x';
				HighPart = szPattern[i] - 0x30;
				if (HighPart > 0x30)
					HighPart -= 0x27;
				else if(HighPart > 0x10)
					HighPart -= 0x7;
				pPatternOut[Ret] = HighPart;
				Ret++;
			}
			if (szPattern[i + 1] >= '0' && szPattern[i + 1] <= 'f')
			{
				i++;
				LowPart = szPattern[i] - 0x30;
				if (LowPart > 0x30)
					LowPart -= 0x27;
				else if (LowPart > 0x10)
					LowPart -= 0x7;
				pPatternOut[Ret - 1] <<= 4;
				pPatternOut[Ret - 1] += LowPart;
			}		
			break;
		}
	}
	return Ret;
}

int main()
{
	char* Lel = "Ab cD eF ?? 1A ? 2 0A A\0";
	BYTE pOut[50] = { 0 };
	char szOut[50] = { 0 };
	size_t ret = PatternStringToMask(Lel, pOut, szOut, 50);
	std::cout << ret << "\n" << szOut << std::endl;
	for (UINT i = 0; i != ret; ++i)
	{
		std::cout << std::hex << (DWORD)pOut[i] << " ";
	}
	Sleep(-1);
	return 0;
}
 
Last edited:

bitm0de

Newbie
Full Member
Feb 28, 2016
19
358
2
All of the above solutions are going to be slower than molasses because they are all naive byte by byte comparisons with no punch. Why not make use of the STL and functions like std::search with a vector to hold the data? You could dump chunks of memory into an internal byte array then implement a threaded scan with std::async and std::shared_future (C++11 features).
 

Broihon

edgy 12 y/o
Escobar Tier VIP
Fleep Tier Donator
Dec 22, 2013
1,745
40,528
316
All of the above solutions are going to be slower than molasses because they are all naive byte by byte comparisons with no punch. Why not make use of the STL and functions like std::search with a vector to hold the data? You could dump chunks of memory into an internal byte array then implement a threaded scan with std::async and std::shared_future (C++11 features).
Won't be faster nor as dynamic as byte by byte scanning (wildcards/alignment).
 

bitm0de

Newbie
Full Member
Feb 28, 2016
19
358
2
Вroihon;40651 said:
Won't be faster nor as dynamic as byte by byte scanning (wildcards/alignment).
Asynchronous memory scanning won't be as fast as a byte by byte comparison? And not as dynamic? You should know that you can easily achieve wildcards and surpass any alignment issues with the method I've suggested, so you're still wrong on that idea. I'm curious why you'd think that it would not be any faster -- mind providing your explanation?

Additionally, my suggestion would allow for multiple patterns to be scanned at the same time too.
 
Last edited:

Broihon

edgy 12 y/o
Escobar Tier VIP
Fleep Tier Donator
Dec 22, 2013
1,745
40,528
316
Asynchronous memory scanning won't be as fast as a byte by byte comparison? And not as dynamic? You should know that you can easily achieve wildcards and surpass any alignment issues with the method I've suggested, so you're still wrong on that idea. I'm curious why you'd think that it would not be any faster -- mind providing your explanation?

Additionally, my suggestion would allow for multiple patterns to be scanned at the same time too.
Looking forward to your pattern scanner then. Ain't gonna read up on the whole std namespace when the current patternscanner functions can easily scan through 500kiB of data within >0.1ms. I'm not saying it's the fastest way to do it. I'm saying it's the most convenient for our purposes.
Go ahead and show me the true power of std::search and std::shared_future. Enlighten me instead of playing the arrogant uber coder.
 

bitm0de

Newbie
Full Member
Feb 28, 2016
19
358
2
Fair enough.

C++:
static DWORD WINAPI search_pattern(std::vector<BYTE> mem, DWORD base_address, const BYTE *pattern, const char *pattern_mask, DWORD offset, DWORD match_offset)
{
   /* initialize vector pattern */
   std::vector<std::pair<BYTE, BOOL>> pat;
   std::size_t len = strlen(pattern_mask);
   for (std::size_t x = 0; x < len; ++x)
      pat.push_back({ pattern[x], pattern_mask[x] != '*'} );

   /* matches count for multiple results */
   DWORD matches = 0;
   auto iterBegin = mem.begin();
   auto iterEnd = iterBegin;

   /* begin searching for pattern in memory chunk vector */
   while ((iterEnd = std::search(iterBegin, mem.end(), pat.begin(), pat.end(),
               [&](BYTE b, std::pair<BYTE, BOOL> bmask)
               { return (!bmask.second) || b == bmask.first; }
               )) != mem.end())
   {
      /* if match count reached return the result */
      if (matches == match_offset)
         return (std::distance(mem.begin(), iterEnd) + base_address) + offset;

      /* increment number of pattern occurrences found and update iterator scan start offset */
      ++matches;
      iterBegin = iterEnd + 1;
   }

   return 0;
}
Call it with std::async() and you'll get your std::future as the result, use that however you want. Now assuming you can accurately break pieces of memory chunks up, you can scan multiple memory regions asynchronously, and have the addresses calculated for you too for multiple signature scans. This would especially demonstrate its usefulness for larger hacks where you have more than just a single signature to be concerned with. You could store the results in an std::unordered_map if you need to associate the results by some unique key for what they represent, or in a std::vector.
 
Last edited:

Rake

Cesspool Admin
Administrator
Jan 21, 2014
12,089
78,998
2,372
I was trying to make something really simple to take "EF 04 8B 1F 89 83 ?? ?? ?? ?? C7 07 8A" as input but I came up with this as an alternative, not my best work, how can I make it better without using a mask

C++:
byte* FindPattern(byte pattern[], int length, byte* begin, byte* end)
{
	int i = 0;

	for (byte* current = begin; current < end; current++)
	{
		//if pattern matches 100%
		if (i == length)
		{
			return (current - length);
		}

		//if wildcard or matching pattern
		if (pattern[i] == 0xff || *current == pattern[i])
		{
			i++;
			continue;
		}

		//if no match
		else
		{
			//reset pattern & advance to next byte
			i = 0;
			continue;
		}
	}
	return 0;
}


//Call:
//0xff is the wildcard
byte* CG = FindPattern((byte*)"\xEF\04\x8B\x1F\x89\x83\xff\xff\xff\xff\xC7\x07\x8A", 13, codeBase, codeEnd);
 

Liduen

Hacker
Dank Tier VIP
May 19, 2013
702
8,478
33
Rake

C++:
byte* findPattern(byte pattern[], int length, byte* begin, byte* end)
{
    int i = 0;
    for (byte* current = begin; current < end; current++)
    {
        //if pattern matches 100%
        if (i == length) return (current - length);
 
        //if wildcard or matching pattern
        if (pattern[i] == 0xff || *current == pattern[i]) i++;
        else i = 0; //if no match reset pattern
    }
    return 0;
}
Actually this is a pretty clever way to do it.
Don't know if that 0xFF check is safe though. It could cause problems.
 
Last edited:

Rake

Cesspool Admin
Administrator
Jan 21, 2014
12,089
78,998
2,372
Rake
Actually this is a pretty clever way to do it.
Don't know if that 0xFF check is safe though. It could cause problems.
I was thinking about this last night tho, my code only tests if the pattern is a wildcard, if it is, it skips testing the actual byte in memory. So it will never compare the 0xff against the memory, therefore no problems.

Only problem is if your pattern you found contains 0xff, it will just skip over it. Not likely to find 0xff as an instruction but definately an opperand could contain the byte 0xff.
 

Liduen

Hacker
Dank Tier VIP
May 19, 2013
702
8,478
33
Rake;40929 said:
[...] Not likely to find 0xff as an instruction but definately an opperand could contain the byte 0xff.
That is what I was aiming at.
 

Broihon

edgy 12 y/o
Escobar Tier VIP
Fleep Tier Donator
Dec 22, 2013
1,745
40,528
316
I thought about this again and it's actually a nice idea and the risk can be minimizied by pointing out that wildcards are mostly used for relative 4/8 byte addresses (eg. in relative call/jmp instructions).
So my idea is not use a single byte as wildcards but a whole dword (or qword) like 0xDEADBEEF:

C++:
BYTE * FindPattern(BYTE * pPattern, UINT Len, BYTE * pStart, BYTE * pEnd)
{
	UINT Index = 0;
	for (; pStart < pEnd; ++pStart)
	{
		if (Index == Len) 
			return (pStart - Len);

		if (*reinterpret_cast<DWORD*>(pPattern + Index) == 0xEFBEADDE)
		{
			Index += 4;
			pStart += 3;
		} 
		else if (*pStart == pPattern[Index])
			Index++;
		else 
			Index = 0;
	}
	return 0;
}

//EXAMPLE
BYTE ToFind[] = { 0x00, 0x01, 0x13, 0x37, 0x88, 0x99, 0x13, 0x37, 0xAB, 0xBC, 0xCD, 0xEF, 0x12, 0x88 };
int main()
{	
	std::cout << std::hex << (DWORD)FindPattern((BYTE*)"\x88\x99\x13\x37\xDE\xAD\xBE\xEF\x12", 9, ToFind, ToFind + sizeof(ToFind)) << std::endl;
	std::cout << std::hex << (DWORD)&ToFind << std::endl;
	Sleep(-1);
}
 

Rake

Cesspool Admin
Administrator
Jan 21, 2014
12,089
78,998
2,372
Pretty similar to Solaire's but this works for pattern+mask combo patterns like this: "29 7b ?? 8b c7"

C++:
void ParsePattern(char* combo, char* pattern, char* mask)
{
	unsigned int patternLen = (strlen(combo) + 1) / 3;

	for (unsigned int i = 0; i < strlen(combo); i++)
	{
		if (combo[i] == ' ')
		{
			continue;
		}

		else if (combo[i] == '?')
		{
			mask[(i + 1) / 3] = '?';
			i += 2;
		}

		else
		{
			char byte = (char)strtol(&combo[i], 0, 16);
			pattern[(i + 1) / 3] = byte;
			mask[(i + 1) / 3] = 'x';
			i += 2;
		}
	}
	pattern[patternLen] = '\0';
	mask[patternLen] = '\0';
}


void* PatternScanExCombo(HANDLE hProcess, wchar_t* module, char* combopattern)
{
	unsigned int patternLen = ((strlen(combopattern) + 1) / 3) + 1;
	char* pattern = new char[patternLen];
	char* mask = new char[patternLen];

	ParsePattern(combopattern, pattern, mask);

	void* match = PatternScanExModule(hProcess, module, pattern, mask);

	delete[] pattern;
	delete[] mask;
	return match;
}
 
Attention! Before you post:

Read the How to Ask Questions Guide
99% of questions are answered in the Beginner's Guide, do it before asking a question.

No Hack Requests. Post in the correct section.  Search the forum first. Read the rules.

How to make a good post:

  • Fill out the form correctly
  • Tell us the game name & coding language
  • Post everything we need to know to help you
  • Ask specific questions, be descriptive
  • Post errors, line numbers & screenshots
  • Post code snippets using code tags
  • If it's a large project, zip it up and attach it

If you do not comply, your post may be deleted.  We want to help, please make a good post and we will do our best to help you.

Community Mods