VS 2019 compilation ok
This commit is contained in:
parent
2f02d74d26
commit
d130815f0d
@ -2,6 +2,7 @@
|
|||||||
#include <Utility/InitFunction.h>
|
#include <Utility/InitFunction.h>
|
||||||
#include "Global.h"
|
#include "Global.h"
|
||||||
#include "Utility/GameDetect.h"
|
#include "Utility/GameDetect.h"
|
||||||
|
#include "Utility/Hooking.Patterns.h"
|
||||||
|
|
||||||
#pragma optimize("", off)
|
#pragma optimize("", off)
|
||||||
void *__cdecl memcpy_0(void *a1, const void *a2, size_t a3)
|
void *__cdecl memcpy_0(void *a1, const void *a2, size_t a3)
|
||||||
@ -190,9 +191,51 @@ void init_windowHooks(windowHooks* data)
|
|||||||
}
|
}
|
||||||
/* END WINDOW HOOKS */
|
/* END WINDOW HOOKS */
|
||||||
|
|
||||||
|
void InitializeHints()
|
||||||
|
{
|
||||||
|
static std::string modPath;
|
||||||
|
|
||||||
|
if (modPath.empty())
|
||||||
|
{
|
||||||
|
char exeName[512];
|
||||||
|
GetModuleFileNameA(GetModuleHandle(NULL), exeName, sizeof(exeName));
|
||||||
|
|
||||||
|
char* exeBaseName = strrchr(exeName, '\\');
|
||||||
|
exeBaseName[0] = L'\0';
|
||||||
|
|
||||||
|
modPath = exeName;
|
||||||
|
modPath += "\\";
|
||||||
|
|
||||||
|
GetFullPathNameA(modPath.c_str(), sizeof(exeName), exeName, nullptr);
|
||||||
|
|
||||||
|
modPath = exeName;
|
||||||
|
modPath += "\\";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string hintsFile = modPath + "hints.dat";
|
||||||
|
FILE* hints = fopen(hintsFile.c_str(), "rb");
|
||||||
|
|
||||||
|
if (hints)
|
||||||
|
{
|
||||||
|
while (!feof(hints))
|
||||||
|
{
|
||||||
|
uint64_t hash;
|
||||||
|
uintptr_t hint;
|
||||||
|
|
||||||
|
fread(&hash, 1, sizeof(hash), hints);
|
||||||
|
fread(&hint, 1, sizeof(hint), hints);
|
||||||
|
|
||||||
|
hook::pattern::hint(hash, hint);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(hints);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static InitFunction globalFunc([]()
|
static InitFunction globalFunc([]()
|
||||||
{
|
{
|
||||||
|
InitializeHints();
|
||||||
CreateThread(NULL, 0, QuitGameThread, NULL, 0, NULL);
|
CreateThread(NULL, 0, QuitGameThread, NULL, 0, NULL);
|
||||||
}, GameID::Global);
|
}, GameID::Global);
|
||||||
#pragma optimize("", on)
|
#pragma optimize("", on)
|
@ -1,350 +1,361 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of the CitizenFX project - http://citizen.re/
|
* This file is part of the CitizenFX project - http://citizen.re/
|
||||||
*
|
*
|
||||||
* See LICENSE and MENTIONS in the root of the source tree for information
|
* See LICENSE and MENTIONS in the root of the source tree for information
|
||||||
* regarding licensing.
|
* regarding licensing.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Hooking.Patterns.h"
|
#include "StdInc.h"
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#ifdef min
|
||||||
|
#undef min
|
||||||
#include <windows.h>
|
#endif
|
||||||
#include <algorithm>
|
|
||||||
|
#ifdef max
|
||||||
#if PATTERNS_USE_HINTS
|
#undef max
|
||||||
#include <map>
|
#endif
|
||||||
#endif
|
|
||||||
|
#include "Hooking.Patterns.h"
|
||||||
#if PATTERNS_USE_HINTS
|
|
||||||
|
#include <algorithm>
|
||||||
// from boost someplace
|
#include <string_view>
|
||||||
template <std::uint64_t FnvPrime, std::uint64_t OffsetBasis>
|
|
||||||
struct basic_fnv_1
|
#if PATTERNS_USE_HINTS
|
||||||
{
|
#include <map>
|
||||||
std::uint64_t operator()(const char *text) const
|
|
||||||
{
|
static void Citizen_PatternSaveHint(uint64_t hash, uintptr_t hint)
|
||||||
std::uint64_t hash = OffsetBasis;
|
{
|
||||||
|
static std::string modPath;
|
||||||
while (*text != 0)
|
|
||||||
{
|
if (modPath.empty())
|
||||||
hash *= FnvPrime;
|
{
|
||||||
hash ^= *(uint8_t *)text;
|
char exeName[512];
|
||||||
|
GetModuleFileNameA(GetModuleHandle(NULL), exeName, sizeof(exeName));
|
||||||
++text;
|
|
||||||
}
|
char* exeBaseName = strrchr(exeName, '\\');
|
||||||
|
exeBaseName[0] = L'\0';
|
||||||
return hash;
|
|
||||||
}
|
modPath = exeName;
|
||||||
};
|
modPath += "\\";
|
||||||
|
|
||||||
const std::uint64_t fnv_prime = 1099511628211u;
|
GetFullPathNameA(modPath.c_str(), sizeof(exeName), exeName, nullptr);
|
||||||
const std::uint64_t fnv_offset_basis = 14695981039346656037u;
|
|
||||||
|
modPath = exeName;
|
||||||
typedef basic_fnv_1<fnv_prime, fnv_offset_basis> fnv_1;
|
modPath += "\\";
|
||||||
|
}
|
||||||
#endif
|
|
||||||
|
std::string hintsFile = modPath + "hints.dat";
|
||||||
namespace hook
|
|
||||||
{
|
FILE* hints = fopen(hintsFile.c_str(), "ab");
|
||||||
ptrdiff_t baseAddressDifference;
|
|
||||||
|
if (hints)
|
||||||
// sets the base to the process main base
|
{
|
||||||
void set_base()
|
fwrite(&hash, 1, sizeof(hash), hints);
|
||||||
{
|
fwrite(&hint, 1, sizeof(hint), hints);
|
||||||
set_base((uintptr_t)GetModuleHandle(nullptr));
|
|
||||||
}
|
fclose(hints);
|
||||||
|
}
|
||||||
|
}
|
||||||
#if PATTERNS_USE_HINTS
|
#endif
|
||||||
static std::multimap<uint64_t, uintptr_t> g_hints;
|
|
||||||
#endif
|
|
||||||
|
#if PATTERNS_USE_HINTS
|
||||||
static void TransformPattern(const char *pattern, std::vector<uint8_t>& data, std::vector<uint8_t>& mask)
|
|
||||||
{
|
// from boost someplace
|
||||||
auto tol = [](char ch) -> uint8_t
|
template <std::uint64_t FnvPrime, std::uint64_t OffsetBasis>
|
||||||
{
|
struct basic_fnv_1
|
||||||
if (ch >= 'A' && ch <= 'F') return uint8_t(ch - 'A' + 10);
|
{
|
||||||
if (ch >= 'a' && ch <= 'f') return uint8_t(ch - 'a' + 10);
|
std::uint64_t operator()(std::string_view text) const
|
||||||
return uint8_t(ch - '0');
|
{
|
||||||
};
|
std::uint64_t hash = OffsetBasis;
|
||||||
|
for (auto it : text)
|
||||||
auto is_digit = [](char ch) -> bool
|
{
|
||||||
{
|
hash *= FnvPrime;
|
||||||
return (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f') || (ch >= '0' && ch <= '9');
|
hash ^= it;
|
||||||
};
|
}
|
||||||
|
|
||||||
char temp_string[2]{ 0, 0 };
|
return hash;
|
||||||
|
}
|
||||||
data.clear();
|
};
|
||||||
mask.clear();
|
|
||||||
|
const std::uint64_t fnv_prime = 1099511628211u;
|
||||||
if (!pattern)
|
const std::uint64_t fnv_offset_basis = 14695981039346656037u;
|
||||||
{
|
|
||||||
return;
|
typedef basic_fnv_1<fnv_prime, fnv_offset_basis> fnv_1;
|
||||||
}
|
|
||||||
|
#endif
|
||||||
const char *patit = pattern;
|
|
||||||
const char *patend = (pattern + strlen(pattern) + 1);
|
namespace hook
|
||||||
|
{
|
||||||
while (patit != patend)
|
inline std::multimap<uint64_t, uintptr_t>& GetHints()
|
||||||
{
|
{
|
||||||
char ch = *patit;
|
static std::multimap<uint64_t, uintptr_t> hints;
|
||||||
|
return hints;
|
||||||
if (ch == ' ' || ch == 0)
|
}
|
||||||
{
|
|
||||||
if (!temp_string[0] && !temp_string[1]) //Continous delimiter
|
static void TransformPattern(std::string_view pattern, std::string& data, std::string& mask)
|
||||||
{
|
{
|
||||||
|
uint8_t tempDigit = 0;
|
||||||
}
|
bool tempFlag = false;
|
||||||
else if (temp_string[0] == '?' && (temp_string[1] == '?' || temp_string[1] == 0)) //??
|
|
||||||
{
|
auto tol = [](char ch) -> uint8_t
|
||||||
data.push_back(0);
|
{
|
||||||
mask.push_back(0u);
|
if (ch >= 'A' && ch <= 'F') return uint8_t(ch - 'A' + 10);
|
||||||
}
|
if (ch >= 'a' && ch <= 'f') return uint8_t(ch - 'a' + 10);
|
||||||
else if (temp_string[0] == '?' && is_digit(temp_string[1])) //?x
|
return uint8_t(ch - '0');
|
||||||
{
|
};
|
||||||
data.push_back(tol(temp_string[1]));
|
|
||||||
mask.push_back(0x0Fu);
|
for (auto ch : pattern)
|
||||||
}
|
{
|
||||||
else if (temp_string[1] == '?' && is_digit(temp_string[0])) //x?
|
if (ch == ' ')
|
||||||
{
|
{
|
||||||
data.push_back(tol(temp_string[0]) << 4);
|
continue;
|
||||||
mask.push_back(0xF0u);
|
}
|
||||||
}
|
else if (ch == '?')
|
||||||
else if (is_digit(temp_string[0]) && is_digit(temp_string[1])) //xx
|
{
|
||||||
{
|
data.push_back(0);
|
||||||
data.push_back((tol(temp_string[0]) << 4) | tol(temp_string[1]));
|
mask.push_back('?');
|
||||||
mask.push_back(0xFFu);
|
}
|
||||||
}
|
else if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f'))
|
||||||
else
|
{
|
||||||
{
|
uint8_t thisDigit = tol(ch);
|
||||||
data.clear();
|
|
||||||
mask.clear();
|
if (!tempFlag)
|
||||||
return;
|
{
|
||||||
}
|
tempDigit = thisDigit << 4;
|
||||||
|
tempFlag = true;
|
||||||
temp_string[0] = 0;
|
}
|
||||||
temp_string[1] = 0;
|
else
|
||||||
}
|
{
|
||||||
else
|
tempDigit |= thisDigit;
|
||||||
{
|
tempFlag = false;
|
||||||
if (temp_string[0] == 0)
|
|
||||||
{
|
data.push_back(tempDigit);
|
||||||
temp_string[0] = ch;
|
mask.push_back('x');
|
||||||
}
|
}
|
||||||
else if (temp_string[1] == 0)
|
}
|
||||||
{
|
}
|
||||||
temp_string[1] = ch;
|
}
|
||||||
}
|
|
||||||
else
|
class executable_meta
|
||||||
{
|
{
|
||||||
data.clear();
|
private:
|
||||||
mask.clear();
|
uintptr_t m_begin;
|
||||||
return;
|
uintptr_t m_end;
|
||||||
}
|
|
||||||
}
|
public:
|
||||||
|
template<typename TReturn, typename TOffset>
|
||||||
++patit;
|
TReturn* getRVA(TOffset rva)
|
||||||
}
|
{
|
||||||
}
|
return (TReturn*)(m_begin + rva);
|
||||||
|
}
|
||||||
class executable_meta
|
|
||||||
{
|
explicit executable_meta(void* module)
|
||||||
private:
|
: m_begin((uintptr_t)module)
|
||||||
uintptr_t m_begin;
|
{
|
||||||
uintptr_t m_end;
|
PIMAGE_DOS_HEADER dosHeader = getRVA<IMAGE_DOS_HEADER>(0);
|
||||||
|
PIMAGE_NT_HEADERS ntHeader = getRVA<IMAGE_NT_HEADERS>(dosHeader->e_lfanew);
|
||||||
public:
|
|
||||||
template<typename TReturn, typename TOffset>
|
m_end = m_begin + ntHeader->OptionalHeader.SizeOfImage;
|
||||||
TReturn* getRVA(TOffset rva)
|
}
|
||||||
{
|
|
||||||
return (TReturn*)(m_begin + rva);
|
executable_meta(uintptr_t begin, uintptr_t end)
|
||||||
}
|
: m_begin(begin), m_end(end)
|
||||||
|
{
|
||||||
explicit executable_meta(void* module)
|
}
|
||||||
: m_begin((uintptr_t)module), m_end(0)
|
|
||||||
{
|
inline uintptr_t begin() const { return m_begin; }
|
||||||
static auto getSection = [](const PIMAGE_NT_HEADERS nt_headers, unsigned section) -> PIMAGE_SECTION_HEADER
|
inline uintptr_t end() const { return m_end; }
|
||||||
{
|
};
|
||||||
return reinterpret_cast<PIMAGE_SECTION_HEADER>(
|
|
||||||
(UCHAR*)nt_headers->OptionalHeader.DataDirectory +
|
void pattern::Initialize(const char* pattern, size_t length)
|
||||||
nt_headers->OptionalHeader.NumberOfRvaAndSizes * sizeof(IMAGE_DATA_DIRECTORY) +
|
{
|
||||||
section * sizeof(IMAGE_SECTION_HEADER));
|
// get the hash for the base pattern
|
||||||
};
|
#if PATTERNS_USE_HINTS
|
||||||
|
m_hash = fnv_1()(std::string_view(pattern, length));
|
||||||
PIMAGE_DOS_HEADER dosHeader = getRVA<IMAGE_DOS_HEADER>(0);
|
#endif
|
||||||
PIMAGE_NT_HEADERS ntHeader = getRVA<IMAGE_NT_HEADERS>(dosHeader->e_lfanew);
|
|
||||||
|
// transform the base pattern from IDA format to canonical format
|
||||||
for (int i = 0; i < ntHeader->FileHeader.NumberOfSections; i++)
|
TransformPattern(std::string_view(pattern, length), m_bytes, m_mask);
|
||||||
{
|
|
||||||
auto sec = getSection(ntHeader, i);
|
#if PATTERNS_USE_HINTS
|
||||||
auto secSize = sec->SizeOfRawData != 0 ? sec->SizeOfRawData : sec->Misc.VirtualSize;
|
// if there's hints, try those first
|
||||||
//if (sec->Characteristics & IMAGE_SCN_MEM_EXECUTE)
|
if (m_module == GetModuleHandle(nullptr))
|
||||||
m_end = m_begin + sec->VirtualAddress + secSize;
|
{
|
||||||
|
auto range = GetHints().equal_range(m_hash);
|
||||||
if ((i == ntHeader->FileHeader.NumberOfSections - 1) && m_end == 0)
|
|
||||||
m_end = m_begin + sec->PointerToRawData + secSize;
|
if (range.first != range.second)
|
||||||
}
|
{
|
||||||
}
|
std::for_each(range.first, range.second, [&](const std::pair<uint64_t, uintptr_t>& hint)
|
||||||
|
{
|
||||||
executable_meta(uintptr_t begin, uintptr_t end)
|
ConsiderMatch(hint.second);
|
||||||
: m_begin(begin), m_end(end)
|
});
|
||||||
{
|
|
||||||
}
|
// if the hints succeeded, we don't need to do anything more
|
||||||
|
if (!m_matches.empty())
|
||||||
inline uintptr_t begin() const { return m_begin; }
|
{
|
||||||
inline uintptr_t end() const { return m_end; }
|
m_matched = true;
|
||||||
};
|
return;
|
||||||
|
}
|
||||||
void pattern::Initialize(const char* pattern)
|
}
|
||||||
{
|
}
|
||||||
// get the hash for the base pattern
|
#endif
|
||||||
#if PATTERNS_USE_HINTS
|
}
|
||||||
m_hash = fnv_1()(pattern);
|
|
||||||
#endif
|
void pattern::EnsureMatches(uint32_t maxCount)
|
||||||
|
{
|
||||||
// transform the base pattern from IDA format to canonical format
|
if (m_matched)
|
||||||
TransformPattern(pattern, m_bytes, m_mask);
|
{
|
||||||
|
return;
|
||||||
m_size = m_mask.size();
|
}
|
||||||
|
|
||||||
#if PATTERNS_USE_HINTS
|
// scan the executable for code
|
||||||
// if there's hints, try those first
|
executable_meta executable = m_rangeStart != 0 && m_rangeEnd != 0 ? executable_meta(m_rangeStart, m_rangeEnd) : executable_meta(m_module);
|
||||||
if (m_module == GetModuleHandle(nullptr))
|
|
||||||
{
|
auto matchSuccess = [&](uintptr_t address)
|
||||||
auto range = g_hints.equal_range(m_hash);
|
{
|
||||||
|
#if PATTERNS_USE_HINTS
|
||||||
if (range.first != range.second)
|
GetHints().emplace(m_hash, address);
|
||||||
{
|
Citizen_PatternSaveHint(m_hash, address);
|
||||||
std::for_each(range.first, range.second, [&] (const std::pair<uint64_t, uintptr_t>& hint)
|
#else
|
||||||
{
|
(void)address;
|
||||||
ConsiderMatch(hint.second);
|
#endif
|
||||||
});
|
|
||||||
|
return (m_matches.size() == maxCount);
|
||||||
// if the hints succeeded, we don't need to do anything more
|
};
|
||||||
if (!m_matches.empty())
|
|
||||||
{
|
const uint8_t* pattern = reinterpret_cast<const uint8_t*>(m_bytes.c_str());
|
||||||
m_matched = true;
|
const char* mask = m_mask.c_str();
|
||||||
return;
|
size_t maskSize = m_mask.size();
|
||||||
}
|
size_t lastWild = m_mask.find_last_of('?');
|
||||||
}
|
|
||||||
}
|
ptrdiff_t Last[256];
|
||||||
#endif
|
|
||||||
}
|
std::fill(std::begin(Last), std::end(Last), lastWild == std::string::npos ? -1 : static_cast<ptrdiff_t>(lastWild));
|
||||||
|
|
||||||
void pattern::EnsureMatches(uint32_t maxCount)
|
for (ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(maskSize); ++i)
|
||||||
{
|
{
|
||||||
if (m_matched)
|
if (Last[pattern[i]] < i)
|
||||||
return;
|
{
|
||||||
|
Last[pattern[i]] = i;
|
||||||
if (!m_rangeStart && !m_rangeEnd && !m_module)
|
}
|
||||||
return;
|
}
|
||||||
|
|
||||||
// scan the executable for code
|
for (uintptr_t i = executable.begin(), end = executable.end() - maskSize; i <= end;)
|
||||||
executable_meta executable = m_rangeStart != 0 && m_rangeEnd != 0 ? executable_meta(m_rangeStart, m_rangeEnd) : executable_meta(m_module);
|
{
|
||||||
|
uint8_t* ptr = reinterpret_cast<uint8_t*>(i);
|
||||||
auto matchSuccess = [&] (uintptr_t address)
|
ptrdiff_t j = maskSize - 1;
|
||||||
{
|
|
||||||
#if PATTERNS_USE_HINTS
|
while ((j >= 0) && (mask[j] == '?' || pattern[j] == ptr[j])) j--;
|
||||||
g_hints.emplace(m_hash, address);
|
|
||||||
#else
|
if (j < 0)
|
||||||
(void)address;
|
{
|
||||||
#endif
|
m_matches.emplace_back(ptr);
|
||||||
|
|
||||||
return (m_matches.size() == maxCount);
|
if (matchSuccess(i))
|
||||||
};
|
{
|
||||||
|
break;
|
||||||
ptrdiff_t BadCharacter[256];
|
}
|
||||||
|
i++;
|
||||||
std::ptrdiff_t index;
|
}
|
||||||
|
else i += std::max((ptrdiff_t)1, j - Last[ptr[j]]);
|
||||||
const std::uint8_t *pbytes = m_bytes.data();
|
}
|
||||||
const std::uint8_t *pmask = m_mask.data();
|
|
||||||
|
m_matched = true;
|
||||||
for (std::uint32_t bc = 0; bc < 256; ++bc)
|
}
|
||||||
{
|
|
||||||
for (index = m_size - 1; index >= 0; --index)
|
bool pattern::ConsiderMatch(uintptr_t offset)
|
||||||
{
|
{
|
||||||
if ((pbytes[index] & pmask[index]) == (bc & pmask[index]))
|
const char* pattern = m_bytes.c_str();
|
||||||
{
|
const char* mask = m_mask.c_str();
|
||||||
break;
|
|
||||||
}
|
char* ptr = reinterpret_cast<char*>(offset);
|
||||||
}
|
|
||||||
|
for (size_t i = 0, j = m_mask.size(); i < j; i++)
|
||||||
BadCharacter[bc] = index;
|
{
|
||||||
}
|
if (mask[i] == '?')
|
||||||
|
{
|
||||||
__try
|
continue;
|
||||||
{
|
}
|
||||||
for (uintptr_t i = executable.begin(), end = executable.end() - m_size; i <= end;)
|
|
||||||
{
|
if (pattern[i] != ptr[i])
|
||||||
uint8_t* ptr = reinterpret_cast<uint8_t*>(i);
|
{
|
||||||
|
return false;
|
||||||
for (index = m_size - 1; index >= 0; --index)
|
}
|
||||||
{
|
}
|
||||||
if ((pbytes[index] & pmask[index]) != (ptr[index] & pmask[index]))
|
|
||||||
{
|
m_matches.emplace_back(ptr);
|
||||||
break;
|
|
||||||
}
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index == -1)
|
#if PATTERNS_USE_HINTS
|
||||||
{
|
|
||||||
m_matches.emplace_back(ptr);
|
void InitializeHints()
|
||||||
|
{
|
||||||
if (matchSuccess(i))
|
static std::string modPath;
|
||||||
{
|
|
||||||
break;
|
if (modPath.empty())
|
||||||
}
|
{
|
||||||
|
char exeName[512];
|
||||||
i += m_size;
|
GetModuleFileNameA(GetModuleHandle(NULL), exeName, sizeof(exeName));
|
||||||
}
|
|
||||||
else
|
char* exeBaseName = strrchr(exeName, '\\');
|
||||||
{
|
exeBaseName[0] = L'\0';
|
||||||
i += max(index - BadCharacter[ptr[index]], 1);
|
|
||||||
}
|
modPath = exeName;
|
||||||
}
|
modPath += "\\";
|
||||||
}
|
|
||||||
__except ((GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
|
GetFullPathNameA(modPath.c_str(), sizeof(exeName), exeName, nullptr);
|
||||||
{ }
|
|
||||||
m_matched = true;
|
modPath = exeName;
|
||||||
}
|
modPath += "\\";
|
||||||
|
}
|
||||||
bool pattern::ConsiderMatch(uintptr_t offset)
|
|
||||||
{
|
std::string hintsFile = modPath + "hints.dat";
|
||||||
const uint8_t* pattern = m_bytes.data();
|
FILE* hints = fopen(hintsFile.c_str(), "rb");
|
||||||
const uint8_t* mask = m_mask.data();
|
|
||||||
|
if (hints)
|
||||||
char* ptr = reinterpret_cast<char*>(offset);
|
{
|
||||||
|
while (!feof(hints))
|
||||||
for (size_t i = 0; i < m_size; i++)
|
{
|
||||||
{
|
uint64_t hash;
|
||||||
if ((pattern[i] & mask[i]) != (ptr[i] & mask[i]))
|
uintptr_t hint;
|
||||||
{
|
|
||||||
return false;
|
fread(&hash, 1, sizeof(hash), hints);
|
||||||
}
|
fread(&hint, 1, sizeof(hint), hints);
|
||||||
}
|
|
||||||
|
hook::pattern::hint(hash, hint);
|
||||||
m_matches.emplace_back(ptr);
|
}
|
||||||
|
|
||||||
return true;
|
fclose(hints);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#if PATTERNS_USE_HINTS
|
|
||||||
void pattern::hint(uint64_t hash, uintptr_t address)
|
|
||||||
{
|
|
||||||
auto range = g_hints.equal_range(hash);
|
|
||||||
|
|
||||||
for (auto it = range.first; it != range.second; it++)
|
|
||||||
{
|
|
||||||
if (it->second == address)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
void pattern::hint(uint64_t hash, uintptr_t address)
|
||||||
g_hints.emplace(hash, address);
|
{
|
||||||
}
|
auto range = GetHints().equal_range(hash);
|
||||||
#endif
|
|
||||||
}
|
for (auto it = range.first; it != range.second; it++)
|
||||||
|
{
|
||||||
|
if (it->second == address)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GetHints().emplace(hash, address);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
@ -1,242 +1,201 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of the CitizenFX project - http://citizen.re/
|
* This file is part of the CitizenFX project - http://citizen.re/
|
||||||
*
|
*
|
||||||
* See LICENSE and MENTIONS in the root of the source tree for information
|
* See LICENSE and MENTIONS in the root of the source tree for information
|
||||||
* regarding licensing.
|
* regarding licensing.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define PATTERNS_USE_HINTS 0
|
#include <cassert>
|
||||||
|
#include <vector>
|
||||||
#include <cassert>
|
|
||||||
#include <vector>
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4201)
|
||||||
namespace hook
|
|
||||||
{
|
#define PATTERNS_USE_HINTS 1
|
||||||
extern ptrdiff_t baseAddressDifference;
|
|
||||||
|
namespace hook
|
||||||
// sets the base address difference based on an obtained pointer
|
{
|
||||||
inline void set_base(uintptr_t address)
|
class pattern_match
|
||||||
{
|
{
|
||||||
#ifdef _M_IX86
|
private:
|
||||||
uintptr_t addressDiff = (address - 0x400000);
|
void* m_pointer;
|
||||||
#elif defined(_M_AMD64)
|
|
||||||
uintptr_t addressDiff = (address - 0x140000000);
|
public:
|
||||||
#endif
|
inline pattern_match(void* pointer)
|
||||||
|
: m_pointer(pointer)
|
||||||
// pointer-style cast to ensure unsigned overflow ends up copied directly into a signed value
|
{
|
||||||
baseAddressDifference = *(ptrdiff_t*)&addressDiff;
|
}
|
||||||
}
|
|
||||||
|
template<typename T>
|
||||||
// sets the base to the process main base
|
T* get(ptrdiff_t offset = 0) const
|
||||||
void set_base();
|
{
|
||||||
|
char* ptr = reinterpret_cast<char*>(m_pointer);
|
||||||
template<typename T>
|
return reinterpret_cast<T*>(ptr + offset);
|
||||||
inline T* getRVA(uintptr_t rva)
|
}
|
||||||
{
|
};
|
||||||
set_base();
|
|
||||||
#ifdef _M_IX86
|
class pattern
|
||||||
return (T*)(baseAddressDifference + 0x400000 + rva);
|
{
|
||||||
#elif defined(_M_AMD64)
|
private:
|
||||||
return (T*)(baseAddressDifference + 0x140000000 + rva);
|
std::string m_bytes;
|
||||||
#endif
|
std::string m_mask;
|
||||||
}
|
|
||||||
|
#if PATTERNS_USE_HINTS
|
||||||
class pattern_match
|
uint64_t m_hash;
|
||||||
{
|
#endif
|
||||||
private:
|
|
||||||
void* m_pointer;
|
std::vector<pattern_match> m_matches;
|
||||||
|
|
||||||
public:
|
bool m_matched;
|
||||||
inline pattern_match(void* pointer)
|
|
||||||
: m_pointer(pointer)
|
union
|
||||||
{
|
{
|
||||||
}
|
void* m_module;
|
||||||
|
struct
|
||||||
template<typename T>
|
{
|
||||||
T* get(ptrdiff_t offset = 0) const
|
uintptr_t m_rangeStart;
|
||||||
{
|
uintptr_t m_rangeEnd;
|
||||||
char* ptr = reinterpret_cast<char*>(m_pointer);
|
};
|
||||||
return reinterpret_cast<T*>(ptr + offset);
|
};
|
||||||
}
|
|
||||||
};
|
protected:
|
||||||
|
inline pattern(void* module)
|
||||||
class pattern
|
: m_rangeStart((uintptr_t)module), m_matched(false), m_rangeEnd(0)
|
||||||
{
|
{
|
||||||
private:
|
}
|
||||||
std::vector<uint8_t> m_bytes;
|
|
||||||
std::vector<uint8_t> m_mask;
|
inline pattern(uintptr_t begin, uintptr_t end)
|
||||||
|
: m_rangeStart(begin), m_rangeEnd(end), m_matched(false)
|
||||||
#if PATTERNS_USE_HINTS
|
{
|
||||||
uint64_t m_hash;
|
}
|
||||||
#endif
|
|
||||||
|
void Initialize(const char* pattern, size_t length);
|
||||||
size_t m_size;
|
|
||||||
|
private:
|
||||||
std::vector<pattern_match> m_matches;
|
bool ConsiderMatch(uintptr_t offset);
|
||||||
|
|
||||||
bool m_matched;
|
void EnsureMatches(uint32_t maxCount);
|
||||||
|
|
||||||
union
|
inline pattern_match _get_internal(size_t index) const
|
||||||
{
|
{
|
||||||
void* m_module;
|
return m_matches[index];
|
||||||
struct
|
}
|
||||||
{
|
|
||||||
uintptr_t m_rangeStart;
|
public:
|
||||||
uintptr_t m_rangeEnd;
|
template<size_t Len>
|
||||||
};
|
pattern(const char(&pattern)[Len])
|
||||||
};
|
: pattern(GetModuleHandle(NULL))
|
||||||
|
{
|
||||||
protected:
|
Initialize(pattern, Len);
|
||||||
inline pattern(void* module)
|
}
|
||||||
: m_module(module), m_rangeEnd(0), m_matched(false)
|
|
||||||
{
|
inline pattern& count(uint32_t expected) &
|
||||||
}
|
{
|
||||||
|
EnsureMatches(expected);
|
||||||
inline pattern(uintptr_t begin, uintptr_t end)
|
assert(m_matches.size() == expected);
|
||||||
: m_rangeStart(begin), m_rangeEnd(end), m_matched(false)
|
return *this;
|
||||||
{
|
}
|
||||||
}
|
|
||||||
|
inline pattern& count_hint(uint32_t expected) &
|
||||||
void Initialize(const char* pattern);
|
{
|
||||||
|
EnsureMatches(expected);
|
||||||
private:
|
return *this;
|
||||||
bool ConsiderMatch(uintptr_t offset);
|
}
|
||||||
|
|
||||||
void EnsureMatches(uint32_t maxCount);
|
inline pattern& clear() &
|
||||||
|
{
|
||||||
inline const pattern_match& _get_internal(size_t index)
|
m_matches.clear();
|
||||||
{
|
m_matched = false;
|
||||||
return m_matches[index];
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
inline pattern&& count(uint32_t expected) &&
|
||||||
pattern()
|
{
|
||||||
: m_matched(true)
|
EnsureMatches(expected);
|
||||||
{
|
assert(m_matches.size() == expected);
|
||||||
}
|
return std::move(*this);
|
||||||
|
}
|
||||||
pattern(const char *pattern)
|
|
||||||
: pattern(getRVA<void>(0))
|
inline pattern&& count_hint(uint32_t expected) &&
|
||||||
{
|
{
|
||||||
Initialize(pattern);
|
EnsureMatches(expected);
|
||||||
}
|
return std::move(*this);
|
||||||
|
}
|
||||||
pattern(std::string& pattern)
|
|
||||||
: pattern(getRVA<void>(0))
|
inline pattern&& clear() &&
|
||||||
{
|
{
|
||||||
Initialize(pattern.c_str());
|
m_matches.clear();
|
||||||
}
|
m_matched = false;
|
||||||
|
return std::move(*this);
|
||||||
inline pattern& count(uint32_t expected)
|
}
|
||||||
{
|
|
||||||
EnsureMatches(expected);
|
inline size_t size()
|
||||||
assert(m_matches.size() == expected);
|
{
|
||||||
return *this;
|
EnsureMatches(UINT32_MAX);
|
||||||
}
|
return m_matches.size();
|
||||||
|
}
|
||||||
inline pattern& count_hint(uint32_t expected)
|
|
||||||
{
|
inline bool empty()
|
||||||
EnsureMatches(expected);
|
{
|
||||||
return *this;
|
return size() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline pattern& clear(void* module = nullptr)
|
inline pattern_match get(size_t index)
|
||||||
{
|
{
|
||||||
if (module)
|
EnsureMatches(UINT32_MAX);
|
||||||
m_module = module;
|
return _get_internal(index);
|
||||||
m_matches.clear();
|
}
|
||||||
m_matched = false;
|
|
||||||
return *this;
|
inline pattern_match get_one()
|
||||||
}
|
{
|
||||||
|
return std::forward<pattern>(*this).count(1)._get_internal(0);
|
||||||
inline size_t size()
|
}
|
||||||
{
|
|
||||||
EnsureMatches(UINT32_MAX);
|
template<typename T = void>
|
||||||
return m_matches.size();
|
inline auto get_first(ptrdiff_t offset = 0)
|
||||||
}
|
{
|
||||||
|
return get_one().get<T>(offset);
|
||||||
inline bool empty()
|
}
|
||||||
{
|
|
||||||
return size() == 0;
|
public:
|
||||||
}
|
#if PATTERNS_USE_HINTS
|
||||||
|
// define a hint
|
||||||
inline const pattern_match& get(size_t index)
|
static void hint(uint64_t hash, uintptr_t address);
|
||||||
{
|
#endif
|
||||||
EnsureMatches(UINT32_MAX);
|
};
|
||||||
return _get_internal(index);
|
|
||||||
}
|
class module_pattern
|
||||||
|
: public pattern
|
||||||
inline const pattern_match& get_one()
|
{
|
||||||
{
|
public:
|
||||||
return count(1)._get_internal(0);
|
template<size_t Len>
|
||||||
}
|
module_pattern(void* module, const char(&pattern)[Len])
|
||||||
|
: pattern(module)
|
||||||
template<typename T = void>
|
{
|
||||||
inline auto get_first(ptrdiff_t offset = 0)
|
Initialize(pattern, Len);
|
||||||
{
|
}
|
||||||
return get_one().get<T>(offset);
|
};
|
||||||
}
|
|
||||||
|
class range_pattern
|
||||||
template <typename Fn>
|
: public pattern
|
||||||
pattern &for_each_result(Fn Pr)
|
{
|
||||||
{
|
public:
|
||||||
EnsureMatches(UINT32_MAX);
|
template<size_t Len>
|
||||||
|
range_pattern(uintptr_t begin, uintptr_t end, const char(&pattern)[Len])
|
||||||
for (auto &result : this->m_matches)
|
: pattern(begin, end)
|
||||||
{
|
{
|
||||||
Pr(result);
|
Initialize(pattern, Len);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
template<typename T = void, size_t Len>
|
||||||
public:
|
auto get_pattern(const char(&pattern_string)[Len], ptrdiff_t offset = 0)
|
||||||
#if PATTERNS_USE_HINTS
|
{
|
||||||
// define a hint
|
return pattern(pattern_string).get_first<T>(offset);
|
||||||
static void hint(uint64_t hash, uintptr_t address);
|
}
|
||||||
#endif
|
}
|
||||||
};
|
|
||||||
|
#pragma warning(pop)
|
||||||
class module_pattern
|
|
||||||
: public pattern
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
module_pattern(void* module, const char *pattern)
|
|
||||||
: pattern(module)
|
|
||||||
{
|
|
||||||
Initialize(pattern);
|
|
||||||
}
|
|
||||||
|
|
||||||
module_pattern(void* module, std::string& pattern)
|
|
||||||
: pattern(module)
|
|
||||||
{
|
|
||||||
Initialize(pattern.c_str());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class range_pattern
|
|
||||||
: public pattern
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
range_pattern(uintptr_t begin, uintptr_t end, const char *pattern)
|
|
||||||
: pattern(begin, end)
|
|
||||||
{
|
|
||||||
Initialize(pattern);
|
|
||||||
}
|
|
||||||
|
|
||||||
range_pattern(uintptr_t begin, uintptr_t end, std::string& pattern)
|
|
||||||
: pattern(begin, end)
|
|
||||||
{
|
|
||||||
Initialize(pattern.c_str());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
template<typename T = void>
|
|
||||||
auto get_pattern(const char *pattern_string, ptrdiff_t offset = 0)
|
|
||||||
{
|
|
||||||
return pattern(pattern_string).get_first<T>(offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -23,8 +23,8 @@ project "iDmacDrv"
|
|||||||
|
|
||||||
filter "platforms:x86"
|
filter "platforms:x86"
|
||||||
targetsuffix "32"
|
targetsuffix "32"
|
||||||
linkoptions { "/DEF:iDmacDrv/src/Source32.def" }
|
linkoptions { "/DEF:$(ProjectDir)/src/Source32.def" }
|
||||||
|
|
||||||
filter "platforms:x64"
|
filter "platforms:x64"
|
||||||
targetsuffix "64"
|
targetsuffix "64"
|
||||||
linkoptions { "/DEF:iDmacDrv/src/Source64.def" }
|
linkoptions { "/DEF:$(ProjectDir)/src/Source64.def" }
|
@ -1,2 +1 @@
|
|||||||
premake5 vs2017
|
premake5 vs2019
|
||||||
pause
|
|
BIN
premake5.exe
BIN
premake5.exe
Binary file not shown.
@ -4,7 +4,7 @@ workspace "OpenParrot"
|
|||||||
|
|
||||||
flags { "StaticRuntime", "No64BitChecks" }
|
flags { "StaticRuntime", "No64BitChecks" }
|
||||||
|
|
||||||
systemversion "10.0.16299.0"
|
systemversion "latest"
|
||||||
|
|
||||||
symbols "On"
|
symbols "On"
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user