|
|
@ -36,73 +36,27 @@ |
|
|
|
|
|
|
|
|
|
|
|
namespace Ashita |
|
|
|
namespace Ashita |
|
|
|
{ |
|
|
|
{ |
|
|
|
class Memory |
|
|
|
/**
|
|
|
|
|
|
|
|
* Iteratable object to reduce the overhead of using a vector. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
template<typename T> |
|
|
|
|
|
|
|
struct scannableiterator_t |
|
|
|
{ |
|
|
|
{ |
|
|
|
public: |
|
|
|
uintptr_t m_BaseAddress; |
|
|
|
/**
|
|
|
|
uintptr_t m_BaseSize; |
|
|
|
* Determines the length of data from the given offset valid to scan with. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @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..
|
|
|
|
scannableiterator_t(uintptr_t base, uintptr_t size) |
|
|
|
auto count = FindLength(pattern, x); |
|
|
|
: m_BaseAddress(base), m_BaseSize(size) |
|
|
|
if (count > length) |
|
|
|
{ } |
|
|
|
{ |
|
|
|
scannableiterator_t(const scannableiterator_t&) = delete; |
|
|
|
offset = x; |
|
|
|
|
|
|
|
length = count; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Step past the current data..
|
|
|
|
|
|
|
|
if (count > 0) |
|
|
|
|
|
|
|
x += count - 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Return the largest offset and length..
|
|
|
|
T* begin(void) { return (T*)this->m_BaseAddress; } |
|
|
|
output[0] = offset; |
|
|
|
T* end(void) { return (T*)(this->m_BaseAddress + this->m_BaseSize); } |
|
|
|
output[1] = length; |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Memory |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
public: |
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Finds a pattern within the given range of data. |
|
|
|
* Finds a pattern within the given range of data. |
|
|
|
* |
|
|
|
* |
|
|
@ -136,69 +90,35 @@ namespace Ashita |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Find the largest chunk of valid data to scan with..
|
|
|
|
// Create a scanner object to use with the STL functions..
|
|
|
|
uintptr_t p[2] = { 0 }; |
|
|
|
scannableiterator_t<uint8_t> data(baseAddress, baseSize); |
|
|
|
FindLargestChunk(vpattern, p); |
|
|
|
auto scanStart = data.begin(); |
|
|
|
|
|
|
|
auto result = (uintptr_t)0; |
|
|
|
// 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; |
|
|
|
while (true) |
|
|
|
const auto size = (uint32_t)baseSize; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<uintptr_t> matches; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Loop the data and look for the pattern..
|
|
|
|
|
|
|
|
for (intptr_t x = size - psize; x >= 0; x--) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
auto c = data[x]; |
|
|
|
// Search for the pattern..
|
|
|
|
auto w = wildcard[c]; |
|
|
|
auto ret = std::search(scanStart, data.end(), vpattern.begin(), vpattern.end(), |
|
|
|
auto k = 0; |
|
|
|
[&](uint8_t curr, std::pair<uint8_t, bool> currPattern) |
|
|
|
|
|
|
|
|
|
|
|
// Step over wildcard characters..
|
|
|
|
|
|
|
|
while (w == 0 && x > (intptr_t)plen) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
x -= plen; |
|
|
|
return (!currPattern.second) || curr == currPattern.first; |
|
|
|
w = wildcard[data[x]]; |
|
|
|
}); |
|
|
|
k = 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (k == 1) |
|
|
|
// Did we find a match..
|
|
|
|
|
|
|
|
if (ret != data.end()) |
|
|
|
{ |
|
|
|
{ |
|
|
|
x++; |
|
|
|
// If we hit the usage count, return the result..
|
|
|
|
continue; |
|
|
|
if (result == count || count == 0) |
|
|
|
} |
|
|
|
return (std::distance(data.begin(), ret) + baseAddress) + offset; |
|
|
|
|
|
|
|
|
|
|
|
// Ensure the first byte matches..
|
|
|
|
// Increment the found count and scan again..
|
|
|
|
if (c != pfirst) continue; |
|
|
|
++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; y++) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (y == pstart || vpattern[y].second != true) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
if (data[x - pstart + y] != vpattern[y].first) |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
if (y + 1 == psize) |
|
|
|
|
|
|
|
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; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|