Files
Project-Reboot-3.0/Project Reboot 3.0/hooking.h
2023-04-06 18:27:24 -04:00

303 lines
8.8 KiB
C++

#pragma once
#include <functional>
#include <MinHook/MinHook.h>
#include "memcury.h"
#include "Class.h"
inline __int64 GetFunctionIdxOrPtr2(UFunction* Function)
{
auto NativeAddr = __int64(Function->GetFunc());
auto FuncName = Function->GetName();
std::wstring ValidateWStr = (std::wstring(FuncName.begin(), FuncName.end()) + L"_Validate");
const wchar_t* ValidateWCStr = ValidateWStr.c_str();
bool bHasValidateFunc = Memcury::Scanner::FindStringRef(ValidateWCStr, false).Get();
bool bFoundValidate = !bHasValidateFunc;
__int64 RetAddr = 0;
for (int i = 0; i < 2000; i++)
{
// std::cout << std::format("CURRENT 0x{:x}\n", __int64((uint8_t*)(NativeAddr + i)) - __int64(GetModuleHandleW(0)));
if (!RetAddr && *(uint8_t*)(NativeAddr + i) == 0xC3)
{
RetAddr = NativeAddr + i;
break;
}
}
int i = 0;
__int64 functionAddyOrOffset = 0;
for (__int64 CurrentAddy = RetAddr; CurrentAddy != NativeAddr && i < 2000; CurrentAddy -= 1) // Find last call
{
// LOG_INFO(LogDev, "[{}] 0x{:x}", i, *(uint8_t*)CurrentAddy);
/* if (*(uint8_t*)CurrentAddy == 0xE8) // BAD
{
// LOG_INFO(LogDev, "CurrentAddy 0x{:x}", CurrentAddy - __int64(GetModuleHandleW(0)));
functionAddyOrOffset = (CurrentAddy + 1 + 4) + *(int*)(CurrentAddy + 1);
break;
}
else */ if ((*(uint8_t*)(CurrentAddy) == 0xFF && *(uint8_t*)(CurrentAddy + 1) == 0x90) ||
*(uint8_t*)(CurrentAddy) == 0xFF && *(uint8_t*)(CurrentAddy + 1) == 0x93)
{
auto SecondByte = *(uint8_t*)(CurrentAddy + 2);
auto ThirdByte = *(uint8_t*)(CurrentAddy + 3);
std::string bytes = GetBytes(CurrentAddy + 2, 2);
std::string last2bytes;
last2bytes += bytes[3];
last2bytes += bytes[4];
std::string neww;
if (last2bytes != "00")
neww = last2bytes;
neww += bytes[0];
neww += bytes[1];
bytes = neww;
functionAddyOrOffset = HexToDec(bytes);
break;
}
i++;
}
return functionAddyOrOffset;
}
inline __int64 GetIndexFromVirtualFunctionCall(__int64 NativeAddr)
{
std::string wtf = "";
int shots = 0;
bool bFoundFirstNumber = false;
for (__int64 z = (NativeAddr + 5); z != (NativeAddr + 1); z -= 1)
{
auto anafa = (int)(*(uint8_t*)z);
auto asfk = anafa < 10 ? "0" + std::format("{:x}", anafa) : std::format("{:x}", anafa);
// std::cout << std::format("[{}] 0x{}\n", shots, asfk);
if (*(uint8_t*)z == 0 ? bFoundFirstNumber : true)
{
wtf += asfk;
bFoundFirstNumber = true;
}
shots++;
}
std::transform(wtf.begin(), wtf.end(), wtf.begin(), ::toupper);
// LOG_INFO(LogDev, "wtf: {}", wtf);
return HexToDec(wtf);
}
inline __int64 GetFunctionIdxOrPtr(UFunction* Function)
{
if (!Function)
return 0;
auto NativeAddr = __int64(Function->GetFunc());
auto FuncName = Function->GetName();
std::wstring ValidateWStr = (std::wstring(FuncName.begin(), FuncName.end()) + L"_Validate");
const wchar_t* ValidateWCStr = ValidateWStr.c_str();
bool bHasValidateFunc = Memcury::Scanner::FindStringRef(ValidateWCStr, false).Get();
// LOG_INFO(LogDev, "[{}] bHasValidateFunc: {}", Function->GetName(), bHasValidateFunc);
// LOG_INFO(LogDev, "NativeAddr: 0x{:x}", __int64(NativeAddr) - __int64(GetModuleHandleW(0)));
bool bFoundValidate = !bHasValidateFunc;
__int64 RetAddr = 0;
for (int i = 0; i < 2000; i++)
{
// LOG_INFO(LogDev, "0x{:x}", *(uint8_t*)(NativeAddr + i));
if (Fortnite_Version >= 19) // We should NOT do this, instead, if we expect a validate and we don't find before C3, then search for 0x41 0xFF.
{
if ((*(uint8_t*)(NativeAddr + i) == 0x41 && *(uint8_t*)(NativeAddr + i + 1) == 0xFF)) // wtf s18+
{
LOG_INFO(LogDev, "Uhhhhhh report this to milxnor if u not on s19+ {}", Function->GetName());
bFoundValidate = true;
continue;
}
}
if ((*(uint8_t*)(NativeAddr + i) == 0xFF && *(uint8_t*)(NativeAddr + i + 1) == 0x90) || // call qword ptr
(*(uint8_t*)(NativeAddr + i) == 0xFF && *(uint8_t*)(NativeAddr + i + 1) == 0x93)) // call qword ptr
{
if (bFoundValidate)
{
return GetIndexFromVirtualFunctionCall(NativeAddr + i);
}
else
{
bFoundValidate = true;
continue;
}
}
if ((*(uint8_t*)(NativeAddr + i) == 0x48 && *(uint8_t*)(NativeAddr + i + 1) == 0xFF) && *(uint8_t*)(NativeAddr + i + 2) == 0xA0) // jmp qword ptr
{
if (bFoundValidate)
{
std::string wtf = "";
int shots = 0;
bool bFoundFirstNumber = false;
for (__int64 z = (NativeAddr + i + 6); z != (NativeAddr + i + 2); z -= 1)
{
auto anafa = (int)(*(uint8_t*)z);
auto asfk = anafa < 10 ? "0" + std::format("{:x}", anafa) : std::format("{:x}", anafa);
// std::cout << std::format("[{}] 0x{}\n", shots, asfk);
if (*(uint8_t*)z == 0 ? bFoundFirstNumber : true)
{
wtf += asfk;
bFoundFirstNumber = true;
}
shots++;
}
std::transform(wtf.begin(), wtf.end(), wtf.begin(), ::toupper);
// LOG_INFO(LogDev, "wtf: {}", wtf);
return HexToDec(wtf);
}
}
if (!RetAddr && *(uint8_t*)(NativeAddr + i) == 0xC3)
{
RetAddr = NativeAddr + i;
// break;
}
}
// The function isn't virtual
__int64 functionAddy = 0;
if (RetAddr)
{
// LOG_INFO(LogDev, "RetAddr 0x{:x}", RetAddr - __int64(GetModuleHandleW(0)));
int i = 0;
for (__int64 CurrentAddy = RetAddr; CurrentAddy != NativeAddr && i < 2000; CurrentAddy -= 1) // Find last call
{
// LOG_INFO(LogDev, "[{}] 0x{:x}", i, *(uint8_t*)CurrentAddy);
if (*(uint8_t*)CurrentAddy == 0xE8)
{
// LOG_INFO(LogDev, "CurrentAddy 0x{:x}", CurrentAddy - __int64(GetModuleHandleW(0)));
functionAddy = (CurrentAddy + 1 + 4) + *(int*)(CurrentAddy + 1);
break;
}
i++;
}
}
return !functionAddy ? -1 : functionAddy;
}
namespace Hooking
{
namespace MinHook
{
static bool Hook(void* Addr, void* Detour, void** Original = nullptr)
{
LOG_INFO(LogDev, "Hooking 0x{:x}", __int64(Addr) - __int64(GetModuleHandleW(0)));
auto ret1 = MH_CreateHook(Addr, Detour, Original);
auto ret2 = MH_EnableHook(Addr);
return ret1 == MH_OK && ret2 == MH_OK;
}
static bool PatchCall(void* Addr, void* Detour/*, void** Original = nullptr*/)
{
// int64_t delta = targetAddr - (instrAddr + 5);
// *(int32_t*)(instrAddr + 1) = static_cast<int32_t>(delta);
}
static bool Hook(UObject* DefaultClass, UFunction* Function, void* Detour, void** Original = nullptr, bool bUseSecondMethod = true, bool bHookExec = false) // Native hook
{
if (!Function)
return false;
if (!DefaultClass || !DefaultClass->VFTable)
{
LOG_WARN(LogHook, "DefaultClass or the vtable for function {} is null! ({})", Function->GetName(), __int64(DefaultClass));
return false;
}
auto& Exec = Function->GetFunc();
if (bHookExec)
{
LOG_INFO(LogDev, "Hooking Exec {}", Function->GetName());
if (Original)
*Original = Exec;
Exec = Detour;
return true;
}
auto AddrOrIdx = bUseSecondMethod ? GetFunctionIdxOrPtr2(Function) : GetFunctionIdxOrPtr(Function);
if (AddrOrIdx == -1)
{
LOG_ERROR(LogInit, "Failed to find anything for {}.", Function->GetName());
return false;
}
if (IsBadReadPtr((void*)AddrOrIdx))
{
auto Idx = AddrOrIdx / 8;
if (Original)
*Original = DefaultClass->VFTable[Idx];
LOG_INFO(LogDev, "Hooking {} with Idx 0x{:x}", Function->GetName(), AddrOrIdx);
VirtualSwap(DefaultClass->VFTable, Idx, Detour);
return true;
}
return Hook((PVOID)AddrOrIdx, Detour, Original);
}
static bool Unhook(void* Addr)
{
return MH_DisableHook((PVOID)Addr) == MH_OK;
}
}
}