Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
Yamashi committed Aug 23, 2021
2 parents 501e769 + 80b26d1 commit 3d1c23d
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 113 deletions.
10 changes: 5 additions & 5 deletions src/reverse/RTTIHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ struct RTTIHelper
sol::object GetProperty(RED4ext::CClass* apClass, RED4ext::ScriptInstance apHandle, const std::string& acPropName, bool& aSuccess) const;
void SetProperty(RED4ext::CClass* apClass, RED4ext::ScriptInstance apHandle, const std::string& acPropName, sol::object aPropValue, bool& aSuccess) const;

RED4ext::CBaseFunction* FindFunction(const uint64_t acFullNameHash) const;
RED4ext::CBaseFunction* FindFunction(RED4ext::CClass* apClass, const uint64_t acFullNameHash) const;
std::map<uint64_t, RED4ext::CBaseFunction*> FindFunctions(const uint64_t acShortNameHash) const;
std::map<uint64_t, RED4ext::CBaseFunction*> FindFunctions(RED4ext::CClass* apClass, const uint64_t acShortNameHash, bool aIsMember) const;

static void Initialize(const LockableState& acLua);
static void Shutdown();
static RTTIHelper& Get();
Expand All @@ -46,11 +51,6 @@ struct RTTIHelper
void AddResolvedFunction(const uint64_t acFuncHash, sol::function& acFunc);
void AddResolvedFunction(const uint64_t acClassHash, const uint64_t acFuncHash, sol::function& acFunc, bool aIsMember);

RED4ext::CBaseFunction* FindFunction(const uint64_t acFullNameHash) const;
RED4ext::CBaseFunction* FindFunction(RED4ext::CClass* apClass, const uint64_t acFullNameHash) const;
std::map<uint64_t, RED4ext::CBaseFunction*> FindFunctions(const uint64_t acShortNameHash) const;
std::map<uint64_t, RED4ext::CBaseFunction*> FindFunctions(RED4ext::CClass* apClass, const uint64_t acShortNameHash, bool aIsMember) const;

sol::function MakeInvokableFunction(RED4ext::CBaseFunction* apFunc);
sol::function MakeInvokableOverload(std::map<uint64_t, RED4ext::CBaseFunction*> aOverloadedFuncs);

Expand Down
153 changes: 79 additions & 74 deletions src/scripting/FunctionOverride.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "FunctionOverride.h"
#include "Scripting.h"
#include <reverse/StrongReference.h>
#include <reverse/RTTIHelper.h>


static FunctionOverride* s_pOverride = nullptr;
Expand Down Expand Up @@ -399,93 +400,97 @@ void FunctionOverride::Override(const std::string& acTypeName, const std::string
// Get the real function
auto* pRealFunction = pClassType->GetFunction(RED4ext::FNV1a(acFullName.c_str()));

if (pRealFunction)
if (!pRealFunction)
{
std::unique_lock lock(m_lock);

CallChain* pEntry = nullptr;
auto itor = m_functions.find(pRealFunction);
pRealFunction = reinterpret_cast<RED4ext::CClassFunction*>(RTTIHelper::Get().FindFunction(pClassType, RED4ext::FNV1a(acFullName.c_str())));

// This function was never hooked
if (itor == std::end(m_functions))
if (!pRealFunction)
{
m_functions[pRealFunction] = {};
pEntry = &m_functions[pRealFunction];

/*
sub rsp, 56
mov rax, 0xDEADBEEFC0DEBAAD
mov qword ptr[rsp + 32], rax
mov rax, 0xDEADBEEFC0DEBAAD
call rax
add rsp, 56
ret
*/
uint8_t payload[] = {0x48, 0x83, 0xEC, 0x38, 0x48, 0xB8, 0xAD, 0xBA, 0xDE, 0xC0, 0xEF, 0xBE,
0xAD, 0xDE, 0x48, 0x89, 0x44, 0x24, 0x20, 0x48, 0xB8, 0xAD, 0xBA, 0xDE,
0xC0, 0xEF, 0xBE, 0xAD, 0xDE, 0xFF, 0xD0, 0x48, 0x83, 0xC4, 0x38, 0xC3};

auto funcAddr = reinterpret_cast<uintptr_t>(&FunctionOverride::HandleOverridenFunction);

std::memcpy(payload + 6, &pRealFunction, 8);
std::memcpy(payload + 21, &funcAddr, 8);

using TNativeScriptFunction = void (*)(RED4ext::IScriptable*, RED4ext::CStackFrame*, void*, int64_t);
auto* pExecutablePayload = static_cast<TNativeScriptFunction>(MakeExecutable(payload, std::size(payload)));

auto* const pFunc = RED4ext::CClassFunction::Create(pClassType, acFullName.c_str(), acShortName.c_str(),
pExecutablePayload);

pFunc->fullName = pRealFunction->fullName;
pFunc->shortName = pRealFunction->shortName;

pFunc->returnType = pRealFunction->returnType;
for (auto* p : pRealFunction->params)
{
pFunc->params.PushBack(p);
}

for (auto* p : pRealFunction->localVars)
{
pFunc->localVars.PushBack(p);
}

pFunc->unk20 = pRealFunction->unk20;
std::copy_n(pRealFunction->unk78, std::size(pRealFunction->unk78), pFunc->unk78);
pFunc->unk48 = pRealFunction->unk48;
pFunc->unkAC = pRealFunction->unkAC;
pFunc->flags = pRealFunction->flags;
pFunc->parent = pRealFunction->parent;
pFunc->flags.isNative = true;
spdlog::get("scripting")->error("Function {} in class {} does not exist", acFullName, acTypeName);
return;
}
}

pEntry->Trampoline = pFunc;
pEntry->pScripting = m_pScripting;
pEntry->CollectGarbage = aCollectGarbage;
std::unique_lock lock(m_lock);

// Swap the content of the real function with the one we just created
std::array<char, sizeof(RED4ext::CClassFunction)> tmpBuffer;
CallChain* pEntry = nullptr;
auto itor = m_functions.find(pRealFunction);

std::memcpy(&tmpBuffer, pRealFunction, sizeof(RED4ext::CClassFunction));
std::memcpy(pRealFunction, pFunc, sizeof(RED4ext::CClassFunction));
std::memcpy(pFunc, &tmpBuffer, sizeof(RED4ext::CClassFunction));
}
else
// This function was never hooked
if (itor == std::end(m_functions))
{
m_functions[pRealFunction] = {};
pEntry = &m_functions[pRealFunction];

/*
sub rsp, 56
mov rax, 0xDEADBEEFC0DEBAAD
mov qword ptr[rsp + 32], rax
mov rax, 0xDEADBEEFC0DEBAAD
call rax
add rsp, 56
ret
*/
uint8_t payload[] = {0x48, 0x83, 0xEC, 0x38, 0x48, 0xB8, 0xAD, 0xBA, 0xDE, 0xC0, 0xEF, 0xBE,
0xAD, 0xDE, 0x48, 0x89, 0x44, 0x24, 0x20, 0x48, 0xB8, 0xAD, 0xBA, 0xDE,
0xC0, 0xEF, 0xBE, 0xAD, 0xDE, 0xFF, 0xD0, 0x48, 0x83, 0xC4, 0x38, 0xC3};

auto funcAddr = reinterpret_cast<uintptr_t>(&FunctionOverride::HandleOverridenFunction);

std::memcpy(payload + 6, &pRealFunction, 8);
std::memcpy(payload + 21, &funcAddr, 8);

using TNativeScriptFunction = void (*)(RED4ext::IScriptable*, RED4ext::CStackFrame*, void*, int64_t);
auto* pExecutablePayload = static_cast<TNativeScriptFunction>(MakeExecutable(payload, std::size(payload)));

auto* const pFunc = RED4ext::CClassFunction::Create(pClassType, acFullName.c_str(), acShortName.c_str(),
pExecutablePayload);

pFunc->fullName = pRealFunction->fullName;
pFunc->shortName = pRealFunction->shortName;

pFunc->returnType = pRealFunction->returnType;
for (auto* p : pRealFunction->params)
{
pEntry = &itor.value();
pFunc->params.PushBack(p);
}

if (aFunction != sol::nil)
for (auto* p : pRealFunction->localVars)
{
auto pContext = TiltedPhoques::MakeUnique<Context>();
pContext->ScriptFunction = std::move(aFunction);
pContext->Environment = aEnvironment;
pContext->Forward = !aAbsolute;

pEntry->Calls.emplace_back(std::move(pContext));
pFunc->localVars.PushBack(p);
}

pFunc->unk20 = pRealFunction->unk20;
std::copy_n(pRealFunction->unk78, std::size(pRealFunction->unk78), pFunc->unk78);
pFunc->unk48 = pRealFunction->unk48;
pFunc->unkAC = pRealFunction->unkAC;
pFunc->flags = pRealFunction->flags;
pFunc->parent = pRealFunction->parent;
pFunc->flags.isNative = true;

pEntry->Trampoline = pFunc;
pEntry->pScripting = m_pScripting;
pEntry->CollectGarbage = aCollectGarbage;

// Swap the content of the real function with the one we just created
std::array<char, sizeof(RED4ext::CClassFunction)> tmpBuffer;

std::memcpy(&tmpBuffer, pRealFunction, sizeof(RED4ext::CClassFunction));
std::memcpy(pRealFunction, pFunc, sizeof(RED4ext::CClassFunction));
std::memcpy(pFunc, &tmpBuffer, sizeof(RED4ext::CClassFunction));
}
else
{
spdlog::get("scripting")->error("Function {} in class {} does not exist", acFullName, acTypeName);
pEntry = &itor.value();
}

if (aFunction != sol::nil)
{
auto pContext = TiltedPhoques::MakeUnique<Context>();
pContext->ScriptFunction = std::move(aFunction);
pContext->Environment = aEnvironment;
pContext->Forward = !aAbsolute;

pEntry->Calls.emplace_back(std::move(pContext));
}
}
42 changes: 8 additions & 34 deletions src/scripting/LuaVM_Hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,47 +28,21 @@ void LuaVM::HookLog(RED4ext::IScriptable*, RED4ext::CStackFrame* apStack, void*,

auto& console = CET::Get().GetOverlay().GetConsole();
if (console.GameLogEnabled())
spdlog::get("scripting")->info(text.c_str());
}

static const char* GetChannelStr(uint64_t hash)
{
switch (hash)
{
#define HASH_CASE(x) case RED4ext::FNV1a(x): return x
HASH_CASE("AI");
HASH_CASE("AICover");
HASH_CASE("ASSERT");
HASH_CASE("Damage");
HASH_CASE("DevelopmentManager");
HASH_CASE("Device");
HASH_CASE("Items");
HASH_CASE("ItemManager");
HASH_CASE("Puppet");
HASH_CASE("Scanner");
HASH_CASE("Stats");
HASH_CASE("StatPools");
HASH_CASE("Strike");
HASH_CASE("TargetManager");
HASH_CASE("Test");
HASH_CASE("UI");
HASH_CASE("Vehicles");
#undef HASH_CASE
}
return "";
spdlog::get("scripting")->info(ref.ref->c_str());
}

void LuaVM::HookLogChannel(RED4ext::IScriptable*, RED4ext::CStackFrame* apStack, void*, void*)
{
static RTTILocator s_stringLocator("String");
static RED4ext::CName s_debugChannel("DEBUG");

uint64_t channel_hash = 0;
RED4ext::CName channel;
apStack->unk30 = 0;
apStack->unk38 = 0;
uint8_t opcode = *(apStack->code++);
apStack->currentParam++;

RED4ext::OpcodeHandlers::Run(opcode, apStack->context, apStack, &channel_hash, nullptr);
RED4ext::OpcodeHandlers::Run(opcode, apStack->context, apStack, &channel, nullptr);

RED4ext::CString text{};
RED4ext::ScriptRef<RED4ext::CString> ref;
Expand All @@ -86,14 +60,14 @@ void LuaVM::HookLogChannel(RED4ext::IScriptable*, RED4ext::CStackFrame* apStack,
apStack->code++; // skip ParamEnd

auto& console = CET::Get().GetOverlay().GetConsole();
if (console.GameLogEnabled())
if (console.GameLogEnabled() || channel == s_debugChannel)
{
auto consoleLogger = spdlog::get("scripting");

std::string_view textSV = text.c_str();
std::string_view channelSV = GetChannelStr(channel_hash);
std::string_view textSV = ref.ref->c_str();
std::string_view channelSV = channel.ToString();
if (channelSV == "")
consoleLogger->info("[?{0:x}] {}", channel_hash, textSV);
consoleLogger->info("[?{0:x}] {}", channel.hash, textSV);
else
consoleLogger->info("[{}] {}", channelSV, textSV);
}
Expand Down
12 changes: 12 additions & 0 deletions src/scripting/Scripting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,18 @@ void Scripting::PostInitialize()

void Scripting::RegisterOverrides()
{
auto lua = m_lua.Lock();
auto& luaVm = lua.Get();

luaVm["RegisterGlobalInputListener"] = [](StrongReference& aSelf, sol::this_environment aThisEnv) {
sol::protected_function unregisterInputListener = aSelf.Index("UnregisterInputListener", aThisEnv);
sol::protected_function registerInputListener = aSelf.Index("RegisterInputListener", aThisEnv);

unregisterInputListener(aSelf, aSelf);
registerInputListener(aSelf, aSelf);
};

m_override.Override("PlayerPuppet", "EnableUIBlackboardListener", "EnableUIBlackboardListener", false, luaVm["RegisterGlobalInputListener"], sol::nil, false);
m_override.Override("PlayerPuppet", "OnDetach", "OnDetach", false, sol::nil, sol::nil, true);
m_override.Override("QuestTrackerGameController", "OnUninitialize", "OnUninitialize", false, sol::nil, sol::nil, true);
}
Expand Down

0 comments on commit 3d1c23d

Please sign in to comment.