|
|
|
@ -31,7 +31,6 @@
@@ -31,7 +31,6 @@
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
#include <Windows.h> |
|
|
|
|
#include <algorithm> |
|
|
|
|
#include <sstream> |
|
|
|
|
#include <vector> |
|
|
|
|
|
|
|
|
@ -41,16 +40,80 @@ namespace Ashita
@@ -41,16 +40,80 @@ namespace Ashita
|
|
|
|
|
{ |
|
|
|
|
public: |
|
|
|
|
/**
|
|
|
|
|
* Locates a pattern of data within a large block of memory. |
|
|
|
|
* Determines the length of data from the given offset valid to scan with. |
|
|
|
|
* |
|
|
|
|
* @param {std::vector} data - The data to scan for the pattern within. |
|
|
|
|
* @param {uintptr_t} baseAddress - The base address to add to the offset when the pattern is found. |
|
|
|
|
* @param {const char*} pattern - The pattern to scan for. |
|
|
|
|
* @param {uintptr_t} offset - The offset to add after the pattern has been found. |
|
|
|
|
* @param {uintptr_t} count - The result count to use if the pattern is found multiple times. |
|
|
|
|
* @param {std::vector} pattern - The pattern to find the length within. |
|
|
|
|
* @param {uintptr_t} offset - The offset to begin iterating at. |
|
|
|
|
* @returns {uintptr_t} The length of data from the given offset. |
|
|
|
|
*/ |
|
|
|
|
static uintptr_t FindLength(const std::vector<std::pair<uint8_t, bool>>& pattern, uintptr_t offset) |
|
|
|
|
{ |
|
|
|
|
// Ensure the offset is within the pattern range..
|
|
|
|
|
if (offset >= pattern.size()) |
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
auto len = 0; |
|
|
|
|
for (size_t x = 0; x < pattern.size(); x++) |
|
|
|
|
{ |
|
|
|
|
// Compare the data for wildcards or null characters..
|
|
|
|
|
if (pattern[x].second == false || |
|
|
|
|
pattern[x].first == 0x00) |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
len++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return len; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Finds the largest chunk of valid data within the pattern to scan for. |
|
|
|
|
* |
|
|
|
|
* @param {std::vector} pattern - The pattern to find the chunk within. |
|
|
|
|
* @param {int32_t [2]} output - The output data to store the offset and length of data to use. |
|
|
|
|
*/ |
|
|
|
|
static void FindLargestChunk(const std::vector<std::pair<uint8_t, bool>>& pattern, uintptr_t output[2]) |
|
|
|
|
{ |
|
|
|
|
auto offset = (uintptr_t)0; |
|
|
|
|
auto length = (uintptr_t)FindLength(pattern, 0); |
|
|
|
|
auto maxlen = (uintptr_t)pattern.size(); |
|
|
|
|
|
|
|
|
|
// Loop the pattern and find its largest chunk..
|
|
|
|
|
for (auto x = length; x < maxlen; x++) |
|
|
|
|
{ |
|
|
|
|
// Ensure the data is required..
|
|
|
|
|
if (pattern[x].second != true) |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
// Find the length at the given offset..
|
|
|
|
|
auto count = FindLength(pattern, x); |
|
|
|
|
if (count > length) |
|
|
|
|
{ |
|
|
|
|
offset = x; |
|
|
|
|
length = count; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Step past the current data..
|
|
|
|
|
if (count > 0) |
|
|
|
|
x += count - 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Return the largest offset and length..
|
|
|
|
|
output[0] = offset; |
|
|
|
|
output[1] = length; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Finds a pattern within the given range of data. |
|
|
|
|
* |
|
|
|
|
* @param {uintptr_t} baseAddress - The address of the data to begin searching within. |
|
|
|
|
* @param {uintptr_t} baseSize - The size of the data to search within. |
|
|
|
|
* @param {const char*} pattern - The pattern to search for. |
|
|
|
|
* @param {uintptr_t} offset - The offset from the found location to add to the pointer. |
|
|
|
|
* @param {uintptr_t} count - The result count to use if the pattern is found more than once. |
|
|
|
|
* @returns {uintptr_t} The address where the pattern was located, 0 otherwise. |
|
|
|
|
*/ |
|
|
|
|
static uintptr_t FindPattern(const std::vector<uint8_t>& data, uintptr_t baseAddress, const char* pattern, uintptr_t offset, uintptr_t count) |
|
|
|
|
static uintptr_t FindPattern(uintptr_t baseAddress, uintptr_t baseSize, const char* pattern, uintptr_t offset, uintptr_t count) |
|
|
|
|
{ |
|
|
|
|
// Ensure the incoming pattern is properly aligned..
|
|
|
|
|
if (strlen(pattern) % 2 > 0) |
|
|
|
@ -73,33 +136,69 @@ namespace Ashita
@@ -73,33 +136,69 @@ namespace Ashita
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
auto scanStart = data.begin(); |
|
|
|
|
auto result = (uintptr_t)0; |
|
|
|
|
// Find the largest chunk of valid data to scan with..
|
|
|
|
|
uintptr_t p[2] = { 0 }; |
|
|
|
|
FindLargestChunk(vpattern, p); |
|
|
|
|
|
|
|
|
|
// Prepare the required variables..
|
|
|
|
|
const auto psize = vpattern.size(); |
|
|
|
|
const auto pstart = p[0]; |
|
|
|
|
const auto plen = (intptr_t)p[1]; |
|
|
|
|
const auto pfirst = vpattern[0].first; |
|
|
|
|
|
|
|
|
|
// Build the wildcard table..
|
|
|
|
|
uint8_t wildcard[UCHAR_MAX + 1] = { 0 }; |
|
|
|
|
for (auto x = pstart; x < pstart + plen; x++) |
|
|
|
|
wildcard[(uint8_t)vpattern[x].first] = 1; |
|
|
|
|
|
|
|
|
|
const auto data = (uint8_t*)baseAddress; |
|
|
|
|
const auto size = (uint32_t)baseSize; |
|
|
|
|
|
|
|
|
|
while (true) |
|
|
|
|
std::vector<uintptr_t> matches; |
|
|
|
|
|
|
|
|
|
// Loop the data and look for the pattern..
|
|
|
|
|
for (intptr_t x = size - psize; x >= 0; x--) |
|
|
|
|
{ |
|
|
|
|
// Search for the pattern..
|
|
|
|
|
auto ret = std::search(scanStart, data.end(), vpattern.begin(), vpattern.end(), |
|
|
|
|
[&](uint8_t curr, std::pair<uint8_t, bool> currPattern) |
|
|
|
|
auto c = data[x]; |
|
|
|
|
auto w = wildcard[c]; |
|
|
|
|
auto k = 0; |
|
|
|
|
|
|
|
|
|
// Step over wildcard characters..
|
|
|
|
|
while (w == 0 && x > (intptr_t)plen) |
|
|
|
|
{ |
|
|
|
|
return (!currPattern.second) || curr == currPattern.first; |
|
|
|
|
}); |
|
|
|
|
x -= plen; |
|
|
|
|
w = wildcard[data[x]]; |
|
|
|
|
k = 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Did we find a match..
|
|
|
|
|
if (ret != data.end()) |
|
|
|
|
if (k == 1) |
|
|
|
|
{ |
|
|
|
|
// If we hit the usage count, return the result..
|
|
|
|
|
if (result == count || count == 0) |
|
|
|
|
return (std::distance(data.begin(), ret) + baseAddress) + offset; |
|
|
|
|
x++; |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Ensure the first byte matches..
|
|
|
|
|
if (c != pfirst) continue; |
|
|
|
|
|
|
|
|
|
// Increment the found count and scan again..
|
|
|
|
|
++result; |
|
|
|
|
scanStart = ++ret; |
|
|
|
|
// Validate the size..
|
|
|
|
|
if (x - pstart < 0 || x - pstart + psize > size) |
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
// Walk the pattern and match its data..
|
|
|
|
|
for (size_t y = 0; y < psize - 1; y++) |
|
|
|
|
{ |
|
|
|
|
if (y == pstart || vpattern[y].second != true) |
|
|
|
|
continue; |
|
|
|
|
if (data[x - pstart + y] != vpattern[y].first) |
|
|
|
|
break; |
|
|
|
|
if (y + 1 == psize - 1) |
|
|
|
|
matches.insert(matches.begin(), (uintptr_t)(data + (x - pstart)) + offset); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Handle the count match..
|
|
|
|
|
if (count < matches.size()) |
|
|
|
|
return matches[count]; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|