mirror of
https://github.com/HolographicHat/Yae.git
synced 2025-12-15 19:08:12 +08:00
use cpp23 and 'modernize'
This commit is contained in:
@@ -60,7 +60,7 @@
|
|||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
<PreprocessorDefinitions>_DEBUG;YAEACHIEVEMENTLIB_EXPORTS;_WINDOWS;_USRDLL;WIN32_LEAN_AND_MEAN;ZYDIS_STATIC_BUILD;ZYCORE_STATIC_BUILD;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>_DEBUG;YAEACHIEVEMENTLIB_EXPORTS;_WINDOWS;_USRDLL;WIN32_LEAN_AND_MEAN;ZYDIS_STATIC_BUILD;ZYCORE_STATIC_BUILD;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ConformanceMode>false</ConformanceMode>
|
<ConformanceMode>false</ConformanceMode>
|
||||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
@@ -78,7 +78,7 @@
|
|||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<PreprocessorDefinitions>_AMD64_;NDEBUG;YAEACHIEVEMENTLIB_EXPORTS;_WINDOWS;_USRDLL;WIN32_LEAN_AND_MEAN;ZYDIS_STATIC_BUILD;ZYCORE_STATIC_BUILD;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>_AMD64_;NDEBUG;YAEACHIEVEMENTLIB_EXPORTS;_WINDOWS;_USRDLL;WIN32_LEAN_AND_MEAN;ZYDIS_STATIC_BUILD;ZYCORE_STATIC_BUILD;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ConformanceMode>false</ConformanceMode>
|
<ConformanceMode>false</ConformanceMode>
|
||||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
// ReSharper disable CppClangTidyCertErr33C
|
// ReSharper disable CppClangTidyCertErr33C
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
#include <print>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <TlHelp32.h>
|
#include <TlHelp32.h>
|
||||||
@@ -49,11 +50,11 @@ namespace Hook {
|
|||||||
const auto headLength = _byteswap_ushort(packet->HeaderLength);
|
const auto headLength = _byteswap_ushort(packet->HeaderLength);
|
||||||
const auto dataLength = _byteswap_ulong(packet->DataLength);
|
const auto dataLength = _byteswap_ulong(packet->DataLength);
|
||||||
|
|
||||||
printf("CmdId: %d\n", _byteswap_ushort(packet->CmdId));
|
std::println("CmdId: {}", _byteswap_ushort(packet->CmdId));
|
||||||
printf("DataLength: %d\n", dataLength);
|
std::println("DataLength: {}", dataLength);
|
||||||
|
|
||||||
const auto base64 = Util::Base64Encode(packet->Data + headLength, dataLength) + "\n";
|
const auto base64 = Util::Base64Encode(packet->Data + headLength, dataLength) + "\n";
|
||||||
printf("Base64: %s\n", base64.c_str());
|
std::println("Base64: {}", base64);
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
system("pause");
|
system("pause");
|
||||||
@@ -137,7 +138,7 @@ DWORD __stdcall ThreadProc(LPVOID hInstance)
|
|||||||
if (MessagePipe == INVALID_HANDLE_VALUE)
|
if (MessagePipe == INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
printf("CreateFile failed: %d\n", GetLastError());
|
std::println("CreateFile failed: {}", GetLastError());
|
||||||
#else
|
#else
|
||||||
Util::Win32ErrorDialog(1001, GetLastError());
|
Util::Win32ErrorDialog(1001, GetLastError());
|
||||||
ExitProcess(0);
|
ExitProcess(0);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
#include <print>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
@@ -40,11 +41,11 @@ namespace
|
|||||||
std::vector<ZydisDecodedOperand> Operands;
|
std::vector<ZydisDecodedOperand> Operands;
|
||||||
};
|
};
|
||||||
|
|
||||||
uintptr_t GetSection(LPCSTR name, size_t* sectionSize = nullptr)
|
std::span<uint8_t> GetSection(LPCSTR name)
|
||||||
{
|
{
|
||||||
using namespace Globals;
|
using namespace Globals;
|
||||||
if (BaseAddress == 0)
|
if (BaseAddress == 0)
|
||||||
return 0;
|
return {};
|
||||||
|
|
||||||
const auto dosHeader = (PIMAGE_DOS_HEADER)BaseAddress;
|
const auto dosHeader = (PIMAGE_DOS_HEADER)BaseAddress;
|
||||||
const auto ntHeader = (PIMAGE_NT_HEADERS)((uintptr_t)dosHeader + dosHeader->e_lfanew);
|
const auto ntHeader = (PIMAGE_NT_HEADERS)((uintptr_t)dosHeader + dosHeader->e_lfanew);
|
||||||
@@ -54,14 +55,13 @@ namespace
|
|||||||
{
|
{
|
||||||
if (strcmp((char*)sectionHeader[i].Name, name) == 0)
|
if (strcmp((char*)sectionHeader[i].Name, name) == 0)
|
||||||
{
|
{
|
||||||
if (sectionSize != nullptr) {
|
const auto sectionSize = sectionHeader[i].Misc.VirtualSize;
|
||||||
*sectionSize = sectionHeader[i].Misc.VirtualSize;
|
const auto virtualAddress = BaseAddress + sectionHeader[i].VirtualAddress;
|
||||||
}
|
return std::span(reinterpret_cast<uint8_t*>(virtualAddress), sectionSize);
|
||||||
return BaseAddress + sectionHeader[i].VirtualAddress;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -148,7 +148,7 @@ namespace
|
|||||||
for (const auto& instr : instructions)
|
for (const auto& instr : instructions)
|
||||||
{
|
{
|
||||||
if (instr.Instruction.mnemonic == ZYDIS_MNEMONIC_CALL) {
|
if (instr.Instruction.mnemonic == ZYDIS_MNEMONIC_CALL) {
|
||||||
uint32_t destination = instr.RVA + instr.Instruction.length + instr.Operands[0].imm.value.s;
|
uint32_t destination = instr.Operands[0].imm.value.s + instr.RVA + instr.Instruction.length;
|
||||||
calls.insert(destination);
|
calls.insert(destination);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -165,52 +165,50 @@ namespace
|
|||||||
|
|
||||||
void ResolveCmdId()
|
void ResolveCmdId()
|
||||||
{
|
{
|
||||||
size_t sectionSize;
|
const auto il2cppSection = GetSection("il2cpp");
|
||||||
const auto sectionAddress = GetSection("il2cpp", §ionSize);
|
|
||||||
const auto sectionEnd = sectionAddress + sectionSize;
|
|
||||||
|
|
||||||
printf("Section Address: 0x%llX\n", sectionAddress);
|
std::println("Section Address: 0x{:X}", reinterpret_cast<uintptr_t>(il2cppSection.data()));
|
||||||
printf("Section End: 0x%llX\n", sectionEnd);
|
std::println("Section End: 0x{:X}", reinterpret_cast<uintptr_t>(il2cppSection.data() + il2cppSection.size()));
|
||||||
|
|
||||||
if (sectionAddress == 0)
|
if (il2cppSection.empty())
|
||||||
return; // message box?
|
return; // message box?
|
||||||
|
|
||||||
const auto candidates = Util::PatternScanAll(sectionAddress, sectionEnd, "56 48 83 EC 20 48 89 D0 48 89 CE 80 3D ? ? ? ? 00");
|
const auto candidates = Util::PatternScanAll(il2cppSection, "56 48 83 EC 20 48 89 D0 48 89 CE 80 3D ? ? ? ? 00");
|
||||||
printf("Candidates: %llu\n", candidates.size());
|
std::println("Candidates: {}", candidates.size());
|
||||||
|
|
||||||
std::vector<std::vector<DecodedInstruction>> candidateInstructions;
|
|
||||||
std::ranges::transform(candidates, std::back_inserter(candidateInstructions), DecodeFunction);
|
|
||||||
|
|
||||||
std::vector<std::vector<DecodedInstruction>> filteredInstructions;
|
std::vector<std::vector<DecodedInstruction>> filteredInstructions;
|
||||||
std::ranges::copy_if(candidateInstructions, std::back_inserter(filteredInstructions), [](const std::vector<DecodedInstruction>& instr) {
|
std::ranges::copy_if(
|
||||||
return GetDataReferenceCount(instr) == 5 && GetCallCount(instr) == 10 && GetUniqueCallCount(instr) == 6 && GetCmpImmCount(instr) == 5;
|
candidates | std::views::transform(DecodeFunction),
|
||||||
|
std::back_inserter(filteredInstructions),
|
||||||
|
[](const std::vector<DecodedInstruction>& instr) {
|
||||||
|
return GetDataReferenceCount(instr) == 5 && GetCallCount(instr) == 10 &&
|
||||||
|
GetUniqueCallCount(instr) == 6 && GetCmpImmCount(instr) == 5;
|
||||||
});
|
});
|
||||||
|
|
||||||
// should have only one result
|
// should have only one result
|
||||||
if (filteredInstructions.size() != 1)
|
if (filteredInstructions.size() != 1)
|
||||||
{
|
{
|
||||||
printf("Filtered Instructions: %llu\n", filteredInstructions.size());
|
std::println("Filtered Instructions: {}", filteredInstructions.size());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& instructions = filteredInstructions[0];
|
const auto& instructions = filteredInstructions[0];
|
||||||
printf("RVA: 0x%08X\n", instructions.front().RVA);
|
std::println("RVA: 0x{:08X}", instructions.front().RVA);
|
||||||
|
|
||||||
// extract all the non-zero immediate values from the cmp instructions
|
// extract all the non-zero immediate values from the cmp instructions
|
||||||
std::decay_t<decltype(instructions)> cmpInstructions;
|
|
||||||
std::ranges::copy_if(instructions, std::back_inserter(cmpInstructions), [](const DecodedInstruction& instr) {
|
|
||||||
return instr.Instruction.mnemonic == ZYDIS_MNEMONIC_CMP && instr.Operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE && instr.Operands[1].imm.value.u;
|
|
||||||
});
|
|
||||||
|
|
||||||
std::vector<uint32_t> cmdIds;
|
std::vector<uint32_t> cmdIds;
|
||||||
std::ranges::transform(cmpInstructions, std::back_inserter(cmdIds), [](const DecodedInstruction& instr) {
|
std::ranges::for_each(instructions, [&cmdIds](const DecodedInstruction& instr) {
|
||||||
return instr.Operands[1].imm.value.u;
|
if (instr.Instruction.mnemonic == ZYDIS_MNEMONIC_CMP &&
|
||||||
|
instr.Operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
|
||||||
|
instr.Operands[1].imm.value.u != 0) {
|
||||||
|
cmdIds.push_back(static_cast<uint32_t>(instr.Operands[1].imm.value.u));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const auto& cmdId : cmdIds)
|
for (const auto& cmdId : cmdIds)
|
||||||
{
|
{
|
||||||
printf("CmdId: %u\n", cmdId);
|
std::println("CmdId: {}", cmdId);
|
||||||
Globals::DynamicCmdIds.insert(cmdId);
|
Globals::DynamicCmdIds.insert(static_cast<uint16_t>(cmdId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -218,9 +216,9 @@ namespace
|
|||||||
|
|
||||||
int32_t GetCallCount(uint8_t* target)
|
int32_t GetCallCount(uint8_t* target)
|
||||||
{
|
{
|
||||||
size_t sectionSize;
|
const auto il2cppSection = GetSection("il2cpp");
|
||||||
const auto sectionAddress = GetSection("il2cpp", §ionSize);
|
const auto sectionAddress = reinterpret_cast<uintptr_t>(il2cppSection.data());
|
||||||
const auto sectionEnd = sectionAddress + sectionSize;
|
const auto sectionSize = il2cppSection.size();
|
||||||
|
|
||||||
int32_t count = 0;
|
int32_t count = 0;
|
||||||
const __m128i callOpcode = _mm_set1_epi8(0xE8);
|
const __m128i callOpcode = _mm_set1_epi8(0xE8);
|
||||||
@@ -283,12 +281,10 @@ namespace
|
|||||||
|
|
||||||
uintptr_t Resolve_BitConverter_ToUInt16()
|
uintptr_t Resolve_BitConverter_ToUInt16()
|
||||||
{
|
{
|
||||||
size_t sectionSize;
|
const auto il2cppSection = GetSection("il2cpp");
|
||||||
const auto sectionAddress = GetSection("il2cpp", §ionSize);
|
|
||||||
const auto sectionEnd = sectionAddress + sectionSize;
|
|
||||||
|
|
||||||
printf("Section Address: 0x%llX\n", sectionAddress);
|
std::print("Section Address: 0x{:X}", reinterpret_cast<uintptr_t>(il2cppSection.data()));
|
||||||
printf("Section End: 0x%llX\n", sectionEnd);
|
std::println("Section End: 0x{:X}", reinterpret_cast<uintptr_t>(il2cppSection.data() + il2cppSection.size()));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
mov ecx, 0Fh
|
mov ecx, 0Fh
|
||||||
@@ -299,8 +295,8 @@ namespace
|
|||||||
mov ecx, 5
|
mov ecx, 5
|
||||||
call ThrowHelper.ThrowArgumentException
|
call ThrowHelper.ThrowArgumentException
|
||||||
*/
|
*/
|
||||||
auto candidates = Util::PatternScanAll(sectionAddress, sectionEnd, "B9 0F 00 00 00 E8 ? ? ? ? B9 0E 00 00 00 BA 16 00 00 00 E8 ? ? ? ? B9 05 00 00 00 E8 ? ? ? ?");
|
auto candidates = Util::PatternScanAll(il2cppSection, "B9 0F 00 00 00 E8 ? ? ? ? B9 0E 00 00 00 BA 16 00 00 00 E8 ? ? ? ? B9 05 00 00 00 E8 ? ? ? ?");
|
||||||
printf("Candidates: %llu\n", candidates.size());
|
std::println("Candidates: {}", candidates.size());
|
||||||
|
|
||||||
std::vector<uintptr_t> filteredEntries;
|
std::vector<uintptr_t> filteredEntries;
|
||||||
std::ranges::copy_if(candidates, std::back_inserter(filteredEntries), [](uintptr_t& entry) {
|
std::ranges::copy_if(candidates, std::back_inserter(filteredEntries), [](uintptr_t& entry) {
|
||||||
@@ -310,10 +306,10 @@ namespace
|
|||||||
|
|
||||||
for (const auto& entry : filteredEntries)
|
for (const auto& entry : filteredEntries)
|
||||||
{
|
{
|
||||||
printf("Entry: 0x%llX\n", entry);
|
std::println("Entry: 0x{:X}", entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Looking for call counts...\n");
|
std::println("Looking for call counts...");
|
||||||
std::mutex mutex;
|
std::mutex mutex;
|
||||||
std::unordered_map<uintptr_t, int32_t> callCounts;
|
std::unordered_map<uintptr_t, int32_t> callCounts;
|
||||||
// find the call counts to candidate functions
|
// find the call counts to candidate functions
|
||||||
@@ -333,7 +329,7 @@ namespace
|
|||||||
uintptr_t targetEntry = 0;
|
uintptr_t targetEntry = 0;
|
||||||
for (const auto& [entry, count] : callCounts)
|
for (const auto& [entry, count] : callCounts)
|
||||||
{
|
{
|
||||||
printf("Entry: 0x%llX, RVA: 0x%08llX, Count: %d\n", entry, entry - Globals::BaseAddress, count);
|
std::println("Entry: 0x{:X}, RVA: 0x{:08X}, Count: {}", entry, entry - Globals::BaseAddress, count);
|
||||||
if (count == 5) {
|
if (count == 5) {
|
||||||
targetEntry = entry;
|
targetEntry = entry;
|
||||||
}
|
}
|
||||||
@@ -380,7 +376,7 @@ void InitIL2CPP()
|
|||||||
resolveFuncFuture.get();
|
resolveFuncFuture.get();
|
||||||
resolveCmdIdFuture.get();
|
resolveCmdIdFuture.get();
|
||||||
|
|
||||||
printf("BaseAddress: 0x%llX\n", BaseAddress);
|
std::println("BaseAddress: 0x{:X}", BaseAddress);
|
||||||
printf("IsCNREL: %d\n", IsCNREL);
|
std::println("IsCNREL: {:d}", IsCNREL);
|
||||||
printf("BitConverter_ToUInt16: 0x%llX\n", Offset.BitConverter_ToUInt16);
|
std::println("BitConverter_ToUInt16: 0x{:X}", Offset.BitConverter_ToUInt16);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class Array
|
class Array
|
||||||
@@ -16,6 +17,10 @@ public:
|
|||||||
T* data() {
|
T* data() {
|
||||||
return vector;
|
return vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::span<T> AsSpan() {
|
||||||
|
return { vector, max_length };
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(alignof(Array<uint8_t>) == 8, "Array alignment is incorrect");
|
static_assert(alignof(Array<uint8_t>) == 8, "Array alignment is incorrect");
|
||||||
@@ -29,6 +34,10 @@ struct PacketMeta
|
|||||||
uint16_t HeaderLength;
|
uint16_t HeaderLength;
|
||||||
uint32_t DataLength;
|
uint32_t DataLength;
|
||||||
uint8_t Data[1];
|
uint8_t Data[1];
|
||||||
|
|
||||||
|
std::span<uint8_t> AsSpan() {
|
||||||
|
return {Data, DataLength};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
|||||||
132
lib/src/util.cpp
132
lib/src/util.cpp
@@ -1,5 +1,9 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
#include <array>
|
||||||
|
#include <ranges>
|
||||||
|
#include <intrin.h>
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
@@ -11,12 +15,12 @@
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
struct HandleData {
|
struct HandleData {
|
||||||
DWORD pid;
|
DWORD Pid;
|
||||||
HWND hwnd;
|
HWND Hwnd;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool IsMainWindow(HWND handle) {
|
bool IsMainWindow(HWND handle) {
|
||||||
return GetWindow(handle, GW_OWNER) == (HWND)0 && IsWindowVisible(handle) == TRUE;
|
return GetWindow(handle, GW_OWNER) == nullptr && IsWindowVisible(handle) == TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsUnityWindow(HWND handle) {
|
bool IsUnityWindow(HWND handle) {
|
||||||
@@ -29,16 +33,16 @@ namespace
|
|||||||
HandleData& data = *(HandleData*)lParam;
|
HandleData& data = *(HandleData*)lParam;
|
||||||
DWORD pid = 0;
|
DWORD pid = 0;
|
||||||
GetWindowThreadProcessId(handle, &pid);
|
GetWindowThreadProcessId(handle, &pid);
|
||||||
if (data.pid != pid || !IsMainWindow(handle) || !IsUnityWindow(handle))
|
if (data.Pid != pid || !IsMainWindow(handle) || !IsUnityWindow(handle))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
data.hwnd = handle;
|
data.Hwnd = handle;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<std::vector<uint8_t>, std::vector<bool>> PatternToBytes(const char* pattern)
|
std::tuple<std::vector<uint8_t>, std::string> PatternToBytes(const char* pattern)
|
||||||
{
|
{
|
||||||
std::vector<uint8_t> bytes;
|
std::vector<uint8_t> bytes;
|
||||||
std::vector<bool> maskBytes;
|
std::string mask;
|
||||||
|
|
||||||
const auto start = const_cast<char*>(pattern);
|
const auto start = const_cast<char*>(pattern);
|
||||||
const auto end = const_cast<char*>(pattern) + strlen(pattern);
|
const auto end = const_cast<char*>(pattern) + strlen(pattern);
|
||||||
@@ -49,14 +53,14 @@ namespace
|
|||||||
if (*current == '?')
|
if (*current == '?')
|
||||||
++current;
|
++current;
|
||||||
bytes.push_back(-1);
|
bytes.push_back(-1);
|
||||||
maskBytes.push_back(false);
|
mask.push_back('?');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
bytes.push_back(strtoul(current, ¤t, 16));
|
bytes.push_back(strtoul(current, ¤t, 16));
|
||||||
maskBytes.push_back(true);
|
mask.push_back('x');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return { bytes, maskBytes };
|
return { bytes, mask };
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -69,17 +73,25 @@ namespace Util
|
|||||||
{
|
{
|
||||||
HWND FindMainWindowByPID(DWORD pid)
|
HWND FindMainWindowByPID(DWORD pid)
|
||||||
{
|
{
|
||||||
HandleData data = { pid, 0 };
|
HandleData data = {
|
||||||
|
.Pid = pid,
|
||||||
|
.Hwnd = nullptr
|
||||||
|
};
|
||||||
EnumWindows(EnumWindowsCallback, (LPARAM)&data);
|
EnumWindows(EnumWindowsCallback, (LPARAM)&data);
|
||||||
return data.hwnd;
|
return data.Hwnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Base64Encode(BYTE const* buf, unsigned int bufLen)
|
std::string Base64Encode(std::span<uint8_t> data)
|
||||||
|
{
|
||||||
|
return Base64Encode(data.data(), data.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Base64Encode(uint8_t const* buf, size_t bufLen)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
BYTE char_array_3[3];
|
uint8_t char_array_3[3];
|
||||||
BYTE char_array_4[4];
|
uint8_t char_array_4[4];
|
||||||
while (bufLen--) {
|
while (bufLen--) {
|
||||||
char_array_3[i++] = *buf++;
|
char_array_3[i++] = *buf++;
|
||||||
if (i == 3) {
|
if (i == 3) {
|
||||||
@@ -126,51 +138,67 @@ namespace Util
|
|||||||
ErrorDialog("YaeAchievement", msg.c_str());
|
ErrorDialog("YaeAchievement", msg.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t PatternScan(uintptr_t start, uintptr_t end, const char* pattern)
|
std::vector<uintptr_t> PatternScanAll(std::span<uint8_t> bytes, const char* pattern)
|
||||||
{
|
|
||||||
const auto [patternBytes, patternMask] = PatternToBytes(pattern);
|
|
||||||
const auto scanBytes = reinterpret_cast<uint8_t*>(start);
|
|
||||||
|
|
||||||
const auto patternSize = patternBytes.size();
|
|
||||||
const auto pBytes = patternBytes.data();
|
|
||||||
|
|
||||||
for (auto i = 0ul; i < end - start - patternSize; ++i) {
|
|
||||||
bool found = true;
|
|
||||||
for (auto j = 0ul; j < patternSize; ++j) {
|
|
||||||
if (scanBytes[i + j] != pBytes[j] && patternMask[j]) {
|
|
||||||
found = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (found) {
|
|
||||||
return reinterpret_cast<uintptr_t>(&scanBytes[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<uintptr_t> PatternScanAll(uintptr_t start, uintptr_t end, const char* pattern)
|
|
||||||
{
|
{
|
||||||
std::vector<uintptr_t> results;
|
std::vector<uintptr_t> results;
|
||||||
const auto [patternBytes, patternMask] = PatternToBytes(pattern);
|
const auto [patternBytes, patternMask] = PatternToBytes(pattern);
|
||||||
const auto scanBytes = reinterpret_cast<uint8_t*>(start);
|
constexpr std::size_t chunkSize = 16;
|
||||||
|
|
||||||
const auto patternSize = patternBytes.size();
|
const auto maskCount = static_cast<std::size_t>(std::ceil(patternMask.size() / chunkSize));
|
||||||
const auto pBytes = patternBytes.data();
|
std::array<int32_t, 32> masks{};
|
||||||
|
|
||||||
for (auto i = 0ul; i < end - start - patternSize; ++i) {
|
auto chunks = patternMask | std::views::chunk(chunkSize);
|
||||||
bool found = true;
|
for (std::size_t i = 0; auto chunk : chunks) {
|
||||||
for (auto j = 0ul; j < patternSize; ++j) {
|
int32_t mask = 0;
|
||||||
if (scanBytes[i + j] != pBytes[j] && patternMask[j]) {
|
for (std::size_t j = 0; j < chunk.size(); ++j) {
|
||||||
found = false;
|
if (chunk[j] == 'x') {
|
||||||
break;
|
mask |= 1 << j;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (found) {
|
masks[i++] = mask;
|
||||||
results.push_back(reinterpret_cast<uintptr_t>(&scanBytes[i]));
|
}
|
||||||
i += patternSize - 1;
|
|
||||||
|
__m128i xmm1 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(patternBytes.data()));
|
||||||
|
__m128i xmm2, xmm3, mask;
|
||||||
|
|
||||||
|
auto pData = bytes.data();
|
||||||
|
const auto end = pData + bytes.size() - patternMask.size();
|
||||||
|
|
||||||
|
while (pData < end)
|
||||||
|
{
|
||||||
|
_mm_prefetch(reinterpret_cast<const char*>(pData + 64), _MM_HINT_NTA);
|
||||||
|
|
||||||
|
if (patternBytes[0] == pData[0])
|
||||||
|
{
|
||||||
|
xmm2 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(pData));
|
||||||
|
mask = _mm_cmpeq_epi8(xmm1, xmm2);
|
||||||
|
|
||||||
|
if ((_mm_movemask_epi8(mask) & masks[0]) == masks[0])
|
||||||
|
{
|
||||||
|
bool found = true;
|
||||||
|
for (int i = 1; i < maskCount; ++i)
|
||||||
|
{
|
||||||
|
xmm2 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(pData + i * chunkSize));
|
||||||
|
xmm3 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(patternBytes.data() + i * chunkSize));
|
||||||
|
mask = _mm_cmpeq_epi8(xmm2, xmm3);
|
||||||
|
if ((_mm_movemask_epi8(mask) & masks[i]) != masks[i])
|
||||||
|
{
|
||||||
|
found = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (found) {
|
||||||
|
results.push_back(reinterpret_cast<uintptr_t>(pData));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
++pData;
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
|
|||||||
@@ -3,16 +3,17 @@
|
|||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
namespace Util
|
namespace Util
|
||||||
{
|
{
|
||||||
HWND FindMainWindowByPID(DWORD pid);
|
HWND FindMainWindowByPID(DWORD pid);
|
||||||
std::string Base64Encode(BYTE const* buf, unsigned int bufLen);
|
std::string Base64Encode(std::span<uint8_t> data);
|
||||||
|
std::string Base64Encode(uint8_t const* buf, size_t bufLen);
|
||||||
|
|
||||||
void ErrorDialog(LPCSTR title, LPCSTR msg);
|
void ErrorDialog(LPCSTR title, LPCSTR msg);
|
||||||
void ErrorDialog(LPCSTR msg);
|
void ErrorDialog(LPCSTR msg);
|
||||||
void Win32ErrorDialog(DWORD code, DWORD winerrcode);
|
void Win32ErrorDialog(DWORD code, DWORD winerrcode);
|
||||||
|
|
||||||
uintptr_t PatternScan(uintptr_t start, uintptr_t end, const char* pattern);
|
std::vector<uintptr_t> PatternScanAll(std::span<uint8_t> bytes, const char* pattern);
|
||||||
std::vector<uintptr_t> PatternScanAll(uintptr_t start, uintptr_t end, const char* pattern);
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user