Exetools

Exetools (https://forum.exetools.com/index.php)
-   Source Code (https://forum.exetools.com/forumdisplay.php?f=46)
-   -   [C++] Pattern Scanner (https://forum.exetools.com/showthread.php?t=17379)

atom0s 02-09-2016 08:50

[C++] Pattern Scanner
 
I wrote a pattern scanner that makes use of C++11 features a while back and decided to adjust it to no longer require a mask be passed with it. Instead, the pattern is parsed for wildcards and handled accordingly.

This should be cross-platform and 64bit friendly.

PHP Code:


/**
 * Scans the given data for the pattern.
 *
 * @param {vector} data                     The data to scan within for the given pattern.
 * @param {intptr_t} baseAddress            The base address of where the scan is starting from.
 * @param {const char*} lpPattern           The pattern to scan for. (Wildcards are marked as ?? per byte.)
 * @param {intptr_t} offset                 The offset to add to the found location.
 * @param {intptr_t} resultUsage            The result offset to use when locating signatures that match multiple locations.
 * @returns {intptr_t}                      The address where the pattern was found, 0 otherwise.
 */
intptr_t FindPattern(std::vector<unsigned chardataintptr_t baseAddress, const charlpPatternintptr_t offsetintptr_t resultUsage)
{
    
// Ensure the incoming pattern is properly aligned..
    
if (strlen(lpPattern) % 0)
        return 
0;

    
// Convert the pattern to a vector of data..
    
std::vector<std::pair<unsigned charbool>> pattern;
    for (
size_t x 0strlen(lpPattern) / 2yx++)
    {
        
// Obtain the current byte..
        
std::stringstream stream(std::string(lpPattern + (2), 2));

        
// Check if this is a wildcard..
        
if (stream.str() == "??")
            
pattern.push_back(std::make_pair(00false));
        else
        {
            
auto byte strtol(stream.str().c_str(), nullptr16);
            
pattern.push_back(std::make_pair((unsigned char)bytetrue));
        }
    }

    
auto scanStart data.begin();
    
auto resultCnt 0;

    while (
true)
    {
        
// Search for the pattern..
        
auto ret std::search(scanStartdata.end(), pattern.begin(), pattern.end(),
            [&](
unsigned char currstd::pair<unsigned charboolcurrPattern)
        {
            return (!
currPattern.second) || curr == currPattern.first;
        });

        
// Did we find a match..
        
if (ret != data.end())
        {
            
// If we hit the usage count, return the result..
            
if (resultCnt == resultUsage || resultUsage == 0)
                return (
std::distance(data.begin(), ret) + baseAddress) + offset;

            
// Increment the found count and scan again..
            
++resultCnt;
            
scanStart = ++ret;
        }
        else
            break;
    }

    return 
0;


Example usage:
PHP Code:

    // Obtain the raw data of the memory to scan..
    
std::vector<unsigned charrawdata(0x004000000x00400000 0x01000000);

    
// Scan for the pattern..
    
auto result FindPattern(std::ref(rawdata), (intptr_t)0x00400000"8B0D????????8B15????????83EC18535556"20);
    if (
result == 0)
        
// Not found..
    
else
        
// Found.. 


atom0s 02-10-2016 14:41

A version in C# that I made for my Steamless project:
PHP Code:

        /// <summary>
        /// Scans the given data for the given pattern.
        /// 
        /// Notes:
        ///     Patterns are assumed to be 2 byte hex values with spaces.
        ///     Wildcards are represented by ??.
        /// </summary>
        /// <param name="data"></param>
        /// <param name="pattern"></param>
        /// <returns></returns>
        
public static uint FindPattern(byte[] datastring pattern)
        {
            try
            {
                
// Trim the pattern from extra whitespace..
                
var trimPattern pattern.Replace(" """).Trim();

                
// Convert the pattern to a byte array..
                
var patternMask = new List<bool>();
                var 
patternData Enumerable.Range(0trimPattern.Length).Where(=> == 0)
                                            .
Select(=>
                                                {
                                                    var 
bt trimPattern.Substring(x2);
                                                    
patternMask.Add(!bt.Contains('?'));
                                                    return 
bt.Contains('?') ? (byte)Convert.ToByte(bt16);
                                                }).
ToArray();

                
// Scan the given data for our pattern..
                
for (var 0data.Lengthx++)
                {
                    if (!
patternData.Where((ty) => patternMask[y] && != data[y]).Any())
                        return (
uint)x;
                }

                return 
0;
            }
            catch
            {
                return 
0;
            }
        } 

Example usage can be seen in Steamless here:
Code:

https://github.com/atom0s/Steamless

mr.exodia 02-10-2016 22:00

Here is a version I did. It supports nibble wildcards for the more fine-grained users. It also has a parallel signature scanner.

https://github.com/mrexodia/PatternFinder

atom0s 02-11-2016 05:53

Quote:

Originally Posted by mr.exodia (Post 104236)
Here is a version I did. It supports nibble wildcards for the more fine-grained users. It also has a parallel signature scanner.

https://github.com/mrexodia/PatternFinder

Just a question, but have you ever really put the nibble support to use much? I personally never found it useful in scanners and felt it just added bloat to the code for something that could just be a full wildcard byte. Just wondering what some situations are that others found it useful.

mr.exodia 02-11-2016 06:03

@atom0s: sure, I mainly use it for a more fine-grained matching on instructions with wildcard registers, for example FF D0 (call eax), for call reg you need to match FF D?, so without nibbles you would match on FF and this also matches a lot of other shit (invalid instructions, inc [reg], call [] etc). I agree that in signature matching it isn't quite useful, but if you need to find the next 'call reg' in a reliable way you need nibble matching. Same applies to 'push reg'.

Obviously if you feel it's a bloat you shouldn't use it :) I just commented so other people don't have to implement it themselves.

Greetings


All times are GMT +8. The time now is 14:39.

Powered by vBulletin® Version 3.8.8
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Always Your Best Friend: Aaron, JMI, ahmadmansoor, ZeNiX