mirror of
https://github.com/HolographicHat/Yae.git
synced 2026-03-28 07:19:48 +08:00
refactor
This commit is contained in:
@@ -20,9 +20,9 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
@@ -30,7 +30,6 @@
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<EnableASAN>false</EnableASAN>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
@@ -45,31 +44,28 @@
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)build\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>build\$(Platform)\$(Configuration)\</IntDir>
|
||||
<TargetName>YaeLib</TargetName>
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)build\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>build\$(Platform)\$(Configuration)\</IntDir>
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;YAEACHIEVEMENTLIB_EXPORTS;_WINDOWS;_USRDLL;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<ConformanceMode>false</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<LanguageStandard_C>stdc17</LanguageStandard_C>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<SubSystem>NotSet</SubSystem>
|
||||
<GenerateDebugInformation>DebugFull</GenerateDebugInformation>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>copy $(TargetPath) $(ProjectDir)..\bin\Debug\net6.0</Command>
|
||||
@@ -80,29 +76,25 @@
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_AMD64_;NDEBUG;YAEACHIEVEMENTLIB_EXPORTS;_WINDOWS;_USRDLL;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<ConformanceMode>false</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<LanguageStandard_C>stdc17</LanguageStandard_C>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<SubSystem>NotSet</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<GenerateDebugInformation>DebugFull</GenerateDebugInformation>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>copy $(TargetPath) $(ProjectDir)..\bin\Debug\net8.0-windows\win-x64\YaeAchievementLib.dll /y</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src\globals.h" />
|
||||
<ClInclude Include="src\il2cpp-types.h" />
|
||||
<ClInclude Include="src\il2cpp-init.h" />
|
||||
<ClInclude Include="src\util.h" />
|
||||
|
||||
@@ -1,87 +1,174 @@
|
||||
// ReSharper disable CppCStyleCast
|
||||
// ReSharper disable CppInconsistentNaming
|
||||
// ReSharper disable CppClangTidyModernizeUseStdPrint
|
||||
// ReSharper disable CppClangTidyClangDiagnosticCastAlign
|
||||
// ReSharper disable CppClangTidyHicppMultiwayPathsCovered
|
||||
// ReSharper disable CppDefaultCaseNotHandledInSwitchStatement
|
||||
// ReSharper disable CppClangTidyClangDiagnosticCastFunctionTypeStrict
|
||||
|
||||
// ReSharper disable CppClangTidyCertErr33C
|
||||
#include <Windows.h>
|
||||
#include <string>
|
||||
#include <TlHelp32.h>
|
||||
|
||||
#include "globals.h"
|
||||
#include "util.h"
|
||||
#include "il2cpp-init.h"
|
||||
#include "il2cpp-types.h"
|
||||
|
||||
using Genshin::ByteArray;
|
||||
|
||||
HWND unityWnd = nullptr;
|
||||
HANDLE hPipe = nullptr;
|
||||
|
||||
void* baClass;
|
||||
std::string checksum;
|
||||
CRITICAL_SECTION CriticalSection;
|
||||
void SetBreakpoint(HANDLE thread, uintptr_t address, bool enable, uint8_t index = 0);
|
||||
|
||||
namespace Hook {
|
||||
|
||||
ByteArray* UnityEngine_RecordUserData(const INT type) {
|
||||
/*if (type == 0) {
|
||||
const auto len = checksum.length();
|
||||
const auto arr = Genshin::il2cpp_array_new_specific(baClass, len);
|
||||
memcpy(&arr->vector[0], checksum.data(), len);
|
||||
return arr;
|
||||
}
|
||||
return Genshin::il2cpp_array_new_specific(baClass, 0);*/
|
||||
return {};
|
||||
}
|
||||
|
||||
uint16_t BitConverter_ToUInt16(ByteArray* val, const int startIndex) {
|
||||
/*const auto ret = CALL_ORIGIN(BitConverter_ToUInt16, val, startIndex);
|
||||
if (ret == 0xAB89 && ReadMapped<UINT16>(val->vector, 2) == 24082) {
|
||||
const auto headLength = ReadMapped<UINT16>(val->vector, 4);
|
||||
const auto dataLength = ReadMapped<UINT32>(val->vector, 6);
|
||||
const auto cStr = base64_encode(val->vector + 10 + headLength, dataLength) + "\n";
|
||||
WriteFile(hPipe, cStr.c_str(), (DWORD) cStr.length(), nullptr, nullptr);
|
||||
CloseHandle(hPipe);
|
||||
|
||||
uint16_t __fastcall BitConverter_ToUInt16(Array<uint8_t>* val, const int startIndex)
|
||||
{
|
||||
using namespace Globals;
|
||||
const auto ToUInt16 = reinterpret_cast<decltype(&BitConverter_ToUInt16)>(Offset.BitConverter_ToUInt16);
|
||||
|
||||
EnterCriticalSection(&CriticalSection);
|
||||
SetBreakpoint((HANDLE)-2, 0, false);
|
||||
const auto ret = ToUInt16(val, startIndex);
|
||||
SetBreakpoint((HANDLE)-2, Offset.BitConverter_ToUInt16, true);
|
||||
LeaveCriticalSection(&CriticalSection);
|
||||
|
||||
const auto packet = reinterpret_cast<PacketMeta*>(val->data());
|
||||
|
||||
using namespace Globals;
|
||||
if (ret == 0xAB89 && _byteswap_ushort(packet->CmdId) == CmdId)
|
||||
{
|
||||
const auto headLength = _byteswap_ushort(packet->HeaderLength);
|
||||
const auto dataLength = _byteswap_ulong(packet->DataLength);
|
||||
|
||||
const auto base64 = Util::Base64Encode(packet->Data + headLength, dataLength) + "\n";
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("Base64: %s\n", base64.c_str());
|
||||
system("pause");
|
||||
#endif
|
||||
|
||||
WriteFile(MessagePipe, base64.c_str(), (DWORD)base64.length(), nullptr, nullptr);
|
||||
CloseHandle(MessagePipe);
|
||||
ExitProcess(0);
|
||||
}
|
||||
return ret;*/
|
||||
return {};
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
void Run(HMODULE* phModule) {
|
||||
//AllocConsole();
|
||||
//freopen_s((FILE**)stdout, "CONOUT$", "w", stdout);
|
||||
while ((unityWnd = FindMainWindowByPID(GetCurrentProcessId())) == nullptr) {
|
||||
Sleep(1000);
|
||||
LONG __stdcall VectoredExceptionHandler(PEXCEPTION_POINTERS ep)
|
||||
{
|
||||
using namespace Globals;
|
||||
const auto exceptionRecord = ep->ExceptionRecord;
|
||||
const auto contextRecord = ep->ContextRecord;
|
||||
|
||||
if (exceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP)
|
||||
{
|
||||
if (exceptionRecord->ExceptionAddress != reinterpret_cast<void*>(Offset.BitConverter_ToUInt16)) {
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
contextRecord->Rip = reinterpret_cast<DWORD64>(Hook::BitConverter_ToUInt16);
|
||||
contextRecord->EFlags &= ~0x100; // clear the trap flag
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
Sleep(5000);
|
||||
DisableVMProtect();
|
||||
InitIL2CPP();
|
||||
/*for (int i = 0; i < 3; i++) {
|
||||
const auto result = Genshin::RecordUserData(i);
|
||||
checksum += string(reinterpret_cast<char*>(&result->vector[0]), result->max_length);
|
||||
baClass = result->klass;
|
||||
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
void SetBreakpoint(HANDLE thread, uintptr_t address, bool enable, uint8_t index)
|
||||
{
|
||||
using namespace Globals;
|
||||
|
||||
if (index > 3) {
|
||||
return;
|
||||
}
|
||||
HookManager::install(Genshin::RecordUserData, Hook::UnityEngine_RecordUserData);
|
||||
HookManager::install(Genshin::BitConverter_ToUInt16, Hook::BitConverter_ToUInt16);*/
|
||||
hPipe = CreateFile(R"(\\.\pipe\YaeAchievementPipe)", GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (hPipe == INVALID_HANDLE_VALUE) {
|
||||
Win32ErrorDialog(1001);
|
||||
|
||||
if (!BaseAddress || Offset.BitConverter_ToUInt16 <= BaseAddress) {
|
||||
// not initialized yet
|
||||
return;
|
||||
}
|
||||
|
||||
CONTEXT ctx{};
|
||||
ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
|
||||
GetThreadContext(thread, &ctx);
|
||||
|
||||
DWORD64* dr = &ctx.Dr0;
|
||||
dr[index] = enable ? address : 0;
|
||||
|
||||
const auto mask = 1ull << (index * 2);
|
||||
ctx.Dr7 |= mask;
|
||||
|
||||
SetThreadContext(thread, &ctx);
|
||||
}
|
||||
|
||||
DWORD __stdcall ThreadProc(LPVOID hInstance)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
AllocConsole();
|
||||
freopen_s((FILE**)stdout, "CONOUT$", "w", stdout);
|
||||
#endif
|
||||
InitializeCriticalSection(&CriticalSection);
|
||||
|
||||
const auto hInitThread = CreateThread(nullptr, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(InitIL2CPP), nullptr, 0,
|
||||
nullptr);
|
||||
|
||||
using namespace Globals;
|
||||
const auto pid = GetCurrentProcessId();
|
||||
|
||||
while ((GameWindow = Util::FindMainWindowByPID(pid)) == nullptr) {
|
||||
SwitchToThread();
|
||||
}
|
||||
|
||||
if (!hInitThread) {
|
||||
InitIL2CPP();
|
||||
}
|
||||
else {
|
||||
WaitForSingleObject(hInitThread, INFINITE);
|
||||
CloseHandle(hInitThread);
|
||||
}
|
||||
|
||||
MessagePipe = CreateFileA(R"(\\.\pipe\YaeAchievementPipe)", GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (MessagePipe == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
Util::ErrorDialog("Failed to open pipe");
|
||||
#else
|
||||
Util::Win32ErrorDialog(1001, GetLastError());
|
||||
ExitProcess(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
AddVectoredExceptionHandler(1, VectoredExceptionHandler);
|
||||
while (true)
|
||||
{
|
||||
THREADENTRY32 te32{};
|
||||
te32.dwSize = sizeof(THREADENTRY32);
|
||||
const auto hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
|
||||
for (Thread32First(hSnapshot, &te32); Thread32Next(hSnapshot, &te32);)
|
||||
{
|
||||
if (te32.th32OwnerProcessID != pid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (const auto hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, te32.th32ThreadID))
|
||||
{
|
||||
EnterCriticalSection(&CriticalSection);
|
||||
SetBreakpoint(hThread, Offset.BitConverter_ToUInt16, true);
|
||||
CloseHandle(hThread);
|
||||
LeaveCriticalSection(&CriticalSection);
|
||||
}
|
||||
}
|
||||
CloseHandle(hSnapshot);
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// DLL entry point
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ulReasonForCall, LPVOID lpReserved) {
|
||||
switch (ulReasonForCall) {
|
||||
case DLL_PROCESS_ATTACH:
|
||||
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Run, new HMODULE(hModule), 0, NULL);
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
BOOL __stdcall DllMain(HMODULE hInstance, DWORD fdwReason, LPVOID lpReserved)
|
||||
{
|
||||
|
||||
if (fdwReason == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
if (const auto hThread = CreateThread(nullptr, 0, ThreadProc, hInstance, 0, nullptr)) {
|
||||
CloseHandle(hThread);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
28
lib/src/globals.h
Normal file
28
lib/src/globals.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
|
||||
#define PROPERTY2(type, name, cn, os) \
|
||||
type name##_cn = cn; \
|
||||
type name##_os = os; \
|
||||
type get_##name() { return Globals::IsCNREL ? name##_cn : name##_os; } \
|
||||
void set_##name(type value) { if (Globals::IsCNREL) name##_cn = value; else name##_os = value; } \
|
||||
__declspec(property(get = get_##name, put = set_##name)) type name;
|
||||
|
||||
namespace Globals
|
||||
{
|
||||
inline HWND GameWindow = nullptr;
|
||||
inline HANDLE MessagePipe = nullptr;
|
||||
inline bool IsCNREL = true;
|
||||
inline uintptr_t BaseAddress = 0;
|
||||
|
||||
// 5.1.0 - 24082
|
||||
inline uint16_t CmdId = 24082; // use non-zero to override dynamic search
|
||||
|
||||
class Offsets
|
||||
{
|
||||
public:
|
||||
PROPERTY2(uintptr_t, BitConverter_ToUInt16, 0x0F826CF0, 0x0F825F10); // use non-zero to override dynamic search
|
||||
};
|
||||
|
||||
inline Offsets Offset;
|
||||
}
|
||||
@@ -1,12 +1,32 @@
|
||||
// ReSharper disable CppCStyleCast
|
||||
// ReSharper disable CppInconsistentNaming
|
||||
// ReSharper disable CppClangTidyBugproneMacroParentheses
|
||||
// ReSharper disable CppClangTidyClangDiagnosticCastAlign
|
||||
|
||||
#include <Windows.h>
|
||||
#include <string>
|
||||
#include "globals.h"
|
||||
|
||||
void InitIL2CPP()
|
||||
{
|
||||
|
||||
std::string buffer;
|
||||
buffer.resize(MAX_PATH);
|
||||
ZeroMemory(buffer.data(), MAX_PATH);
|
||||
const auto pathLength = GetModuleFileNameA(nullptr, buffer.data(), MAX_PATH);
|
||||
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
buffer.resize(pathLength);
|
||||
ZeroMemory(buffer.data(), pathLength);
|
||||
GetModuleFileNameA(nullptr, buffer.data(), pathLength);
|
||||
}
|
||||
buffer.shrink_to_fit();
|
||||
|
||||
using namespace Globals;
|
||||
IsCNREL = buffer.find("YuanShen.exe") != std::string::npos;
|
||||
BaseAddress = (uintptr_t)GetModuleHandleA(nullptr);
|
||||
|
||||
if (Offset.BitConverter_ToUInt16 != 0) {
|
||||
Offset.BitConverter_ToUInt16 += BaseAddress;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("BaseAddress: 0x%llX\n", BaseAddress);
|
||||
printf("IsCNREL: %d\n", IsCNREL);
|
||||
printf("BitConverter_ToUInt16: 0x%llX\n", Offset.BitConverter_ToUInt16);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,15 +1,38 @@
|
||||
// ReSharper disable CppClangTidyClangDiagnosticReservedIdentifier
|
||||
// ReSharper disable CppClangTidyBugproneReservedIdentifier
|
||||
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
namespace Genshin {
|
||||
template <typename T>
|
||||
class Array
|
||||
{
|
||||
public:
|
||||
void* klass;
|
||||
void* monitor;
|
||||
void* bounds;
|
||||
size_t max_length;
|
||||
T vector[1];
|
||||
|
||||
struct ByteArray {
|
||||
void* klass;
|
||||
void* monitor;
|
||||
void* bounds;
|
||||
uint64_t max_length;
|
||||
uint8_t vector[32];
|
||||
};
|
||||
}
|
||||
Array() = delete;
|
||||
|
||||
T* data() {
|
||||
return vector;
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(alignof(Array<uint8_t>) == 8, "Array alignment is incorrect");
|
||||
static_assert(offsetof(Array<uint8_t>, vector) == 32, "vector offset is incorrect");
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct PacketMeta
|
||||
{
|
||||
uint16_t HeadMagic;
|
||||
uint16_t CmdId;
|
||||
uint16_t HeaderLength;
|
||||
uint32_t DataLength;
|
||||
uint8_t Data[1];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
static_assert(offsetof(PacketMeta, CmdId) == 2, "CmdId offset is incorrect");
|
||||
static_assert(offsetof(PacketMeta, HeaderLength) == 4, "HeadLength offset is incorrect");
|
||||
static_assert(offsetof(PacketMeta, DataLength) == 6, "DataLength offset is incorrect");
|
||||
static_assert(offsetof(PacketMeta, Data) == 10, "Data offset is incorrect");
|
||||
168
lib/src/util.cpp
168
lib/src/util.cpp
@@ -1,95 +1,99 @@
|
||||
#include <Windows.h>
|
||||
#include <string>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
VOID DisableVMProtect() {
|
||||
DWORD oldProtect = 0;
|
||||
auto ntdll = GetModuleHandleA("ntdll.dll");
|
||||
auto pNtProtectVirtualMemory = GetProcAddress(ntdll, "NtProtectVirtualMemory");
|
||||
auto pNtQuerySection = GetProcAddress(ntdll, "NtQuerySection");
|
||||
DWORD old;
|
||||
VirtualProtect(pNtProtectVirtualMemory, 1, PAGE_EXECUTE_READWRITE, &old);
|
||||
*(uintptr_t*)pNtProtectVirtualMemory = *(uintptr_t*)pNtQuerySection & ~(0xFFui64 << 32) | (uintptr_t)(*(uint32_t*)((uintptr_t)pNtQuerySection + 4) - 1) << 32;
|
||||
VirtualProtect(pNtProtectVirtualMemory, 1, old, &old);
|
||||
}
|
||||
|
||||
#pragma region ByteUtils
|
||||
|
||||
bool IsLittleEndian() {
|
||||
UINT i = 1;
|
||||
char* c = (char*)&i;
|
||||
return *c;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
#include "globals.h"
|
||||
|
||||
#pragma region FindMainWindowByPID
|
||||
|
||||
struct HandleData {
|
||||
DWORD pid;
|
||||
HWND hwnd;
|
||||
};
|
||||
namespace
|
||||
{
|
||||
struct HandleData {
|
||||
DWORD pid;
|
||||
HWND hwnd;
|
||||
};
|
||||
|
||||
BOOL IsMainWindow(HWND handle) {
|
||||
return GetWindow(handle, GW_OWNER) == (HWND)0 && IsWindowVisible(handle) == TRUE;
|
||||
}
|
||||
bool IsMainWindow(HWND handle) {
|
||||
return GetWindow(handle, GW_OWNER) == (HWND)0 && IsWindowVisible(handle) == TRUE;
|
||||
}
|
||||
|
||||
BOOL IsUnityWindow(HWND handle) {
|
||||
TCHAR name[256];
|
||||
GetClassName(handle, name, 256);
|
||||
return _strcmpi(name, "UnityWndClass") == 0;
|
||||
}
|
||||
bool IsUnityWindow(HWND handle) {
|
||||
char szName[256]{};
|
||||
GetClassNameA(handle, szName, 256);
|
||||
return _stricmp(szName, "UnityWndClass") == 0;
|
||||
}
|
||||
|
||||
BOOL CALLBACK EnumWindowsCallback(HWND handle, LPARAM lParam) {
|
||||
HandleData& data = *(HandleData*)lParam;
|
||||
DWORD pid = 0;
|
||||
GetWindowThreadProcessId(handle, &pid);
|
||||
if (data.pid != pid || !IsMainWindow(handle) || !IsUnityWindow(handle))
|
||||
return TRUE;
|
||||
data.hwnd = handle;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
HWND FindMainWindowByPID(DWORD pid) {
|
||||
HandleData data = { pid, 0 };
|
||||
EnumWindows(EnumWindowsCallback, (LPARAM)&data);
|
||||
return data.hwnd;
|
||||
BOOL CALLBACK EnumWindowsCallback(HWND handle, LPARAM lParam) {
|
||||
HandleData& data = *(HandleData*)lParam;
|
||||
DWORD pid = 0;
|
||||
GetWindowThreadProcessId(handle, &pid);
|
||||
if (data.pid != pid || !IsMainWindow(handle) || !IsUnityWindow(handle))
|
||||
return TRUE;
|
||||
data.hwnd = handle;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
static constexpr LPCSTR base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
std::string base64_encode(BYTE const* buf, unsigned int bufLen) {
|
||||
std::string ret;
|
||||
int i = 0;
|
||||
BYTE char_array_3[3];
|
||||
BYTE char_array_4[4];
|
||||
while (bufLen--) {
|
||||
char_array_3[i++] = *buf++;
|
||||
if (i == 3) {
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
for (i = 0; (i < 4); i++)
|
||||
ret += base64_chars[char_array_4[i]];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
if (i) {
|
||||
int j;
|
||||
for (j = i; j < 3; j++)
|
||||
char_array_3[j] = '\0';
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
for (j = 0; j < i + 1; j++)
|
||||
ret += base64_chars[char_array_4[j]];
|
||||
while (i++ < 3)
|
||||
ret += '=';
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
namespace Util
|
||||
{
|
||||
HWND FindMainWindowByPID(DWORD pid)
|
||||
{
|
||||
HandleData data = { pid, 0 };
|
||||
EnumWindows(EnumWindowsCallback, (LPARAM)&data);
|
||||
return data.hwnd;
|
||||
}
|
||||
|
||||
std::string Base64Encode(BYTE const* buf, unsigned int bufLen)
|
||||
{
|
||||
std::string ret;
|
||||
int i = 0;
|
||||
BYTE char_array_3[3];
|
||||
BYTE char_array_4[4];
|
||||
while (bufLen--) {
|
||||
char_array_3[i++] = *buf++;
|
||||
if (i == 3) {
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
for (i = 0; (i < 4); i++)
|
||||
ret += base64_chars[char_array_4[i]];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
if (i) {
|
||||
int j;
|
||||
for (j = i; j < 3; j++)
|
||||
char_array_3[j] = '\0';
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
for (j = 0; j < i + 1; j++)
|
||||
ret += base64_chars[char_array_4[j]];
|
||||
while (i++ < 3)
|
||||
ret += '=';
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ErrorDialog(LPCSTR title, LPCSTR msg)
|
||||
{
|
||||
MessageBoxA(Globals::GameWindow, msg, title, MB_OK | MB_ICONERROR | MB_SYSTEMMODAL);
|
||||
}
|
||||
|
||||
void ErrorDialog(LPCSTR msg)
|
||||
{
|
||||
ErrorDialog("YaeAchievement", msg);
|
||||
}
|
||||
|
||||
void Win32ErrorDialog(DWORD code, DWORD winerrcode)
|
||||
{
|
||||
const std::string msg = "CRITICAL ERROR!\nError code: " + std::to_string(winerrcode) + "-" + std::to_string(code) +
|
||||
"\n\nPlease take the screenshot and contact developer by GitHub Issue to solve this problem\nNOT MIHOYO/COGNOSPHERE CUSTOMER SERVICE!";
|
||||
|
||||
ErrorDialog("YaeAchievement", msg.c_str());
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,17 @@
|
||||
// ReSharper disable CppClangTidyClangDiagnosticLanguageExtensionToken
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
#include <type_traits>
|
||||
|
||||
using std::string;
|
||||
|
||||
VOID DisableVMProtect();
|
||||
bool IsLittleEndian();
|
||||
HWND FindMainWindowByPID(DWORD pid);
|
||||
std::string base64_encode(BYTE const* buf, unsigned int bufLen);
|
||||
namespace Util
|
||||
{
|
||||
HWND FindMainWindowByPID(DWORD pid);
|
||||
std::string Base64Encode(BYTE const* buf, unsigned int bufLen);
|
||||
|
||||
#define ErrorDialogT(title, msg) MessageBox(unityWnd, msg, title, MB_OK | MB_ICONERROR | MB_SYSTEMMODAL)
|
||||
#define ErrorDialog(msg) ErrorDialogT("YaeAchievement", msg)
|
||||
#define Win32ErrorDialog(code) ErrorDialogT("YaeAchievement", ("CRITICAL ERROR!\nError code: " + std::to_string(GetLastError()) + "-"#code"\n\nPlease take the screenshot and contact developer by GitHub Issue to solve this problem\nNOT MIHOYO/COGNOSPHERE CUSTOMER SERVICE!").c_str())
|
||||
void ErrorDialog(LPCSTR title, LPCSTR msg);
|
||||
void ErrorDialog(LPCSTR msg);
|
||||
void Win32ErrorDialog(DWORD code, DWORD winerrcode);
|
||||
|
||||
template<class T>
|
||||
static T ReadMapped(void* data, int offset, bool littleEndian = false) {
|
||||
char* cData = (char*)data;
|
||||
T result = {};
|
||||
if (IsLittleEndian() != littleEndian) {
|
||||
for (int i = 0; i < sizeof(T); i++)
|
||||
((char*)&result)[i] = cData[offset + sizeof(T) - i - 1];
|
||||
return result;
|
||||
}
|
||||
memcpy(&result, cData + offset, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user