Ray-Trace/vendor/dynlibutils/module_windows.cpp
2026-01-11 18:57:42 +04:00

196 lines
6.1 KiB
C++

// DynLibUtils
// Copyright (C) 2023 komashchenko (Phoenix)
// https://github.com/komashchenko/DynLibUtils
#include "module.h"
#include "memaddr.h"
#include <cstring>
#include <cmath>
#include <windows.h>
using namespace DynLibUtils;
CModule::~CModule()
{
if (m_pModuleHandle)
FreeLibrary(reinterpret_cast<HMODULE>(m_pModuleHandle));
}
static std::string GetModulePath(HMODULE hModule)
{
std::string modulePath(MAX_PATH, '\0');
while (true)
{
size_t len = GetModuleFileNameA(hModule, modulePath.data(), static_cast<DWORD>(modulePath.length()));
if (len == 0)
{
modulePath.clear();
break;
}
if (len < modulePath.length())
{
modulePath.resize(len);
break;
}
else
modulePath.resize(modulePath.length() * 2);
}
return modulePath;
}
//-----------------------------------------------------------------------------
// Purpose: Initializes the module from module name
// Input : svModuleName
// bExtension
// Output : bool
//-----------------------------------------------------------------------------
bool CModule::InitFromName(const std::string_view svModuleName, bool bExtension)
{
if (m_pModuleHandle)
return false;
if (svModuleName.empty())
return false;
std::string sModuleName(svModuleName);
if (!bExtension)
sModuleName.append(".dll");
HMODULE handle = GetModuleHandleA(sModuleName.c_str());
if (!handle)
return false;
std::string modulePath = ::GetModulePath(handle);
if(modulePath.empty())
return false;
if (!Init(modulePath))
return false;
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Initializes the module from module memory
// Input : pModuleMemory
// Output : bool
//-----------------------------------------------------------------------------
bool CModule::InitFromMemory(const CMemory pModuleMemory)
{
if (m_pModuleHandle)
return false;
if (!pModuleMemory)
return false;
MEMORY_BASIC_INFORMATION mbi;
if (!VirtualQuery(pModuleMemory, &mbi, sizeof(mbi)))
return false;
std::string modulePath = ::GetModulePath(reinterpret_cast<HMODULE>(mbi.AllocationBase));
if (modulePath.empty())
return false;
if (!Init(modulePath))
return false;
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Initializes a module descriptors
//-----------------------------------------------------------------------------
bool CModule::Init(const std::string_view svModelePath)
{
HMODULE handle = LoadLibraryExA(svModelePath.data(), nullptr, DONT_RESOLVE_DLL_REFERENCES);
if (!handle)
return false;
IMAGE_DOS_HEADER* pDOSHeader = reinterpret_cast<IMAGE_DOS_HEADER*>(handle);
IMAGE_NT_HEADERS64* pNTHeaders = reinterpret_cast<IMAGE_NT_HEADERS64*>(reinterpret_cast<uintptr_t>(handle) + pDOSHeader->e_lfanew);
const IMAGE_SECTION_HEADER* hSection = IMAGE_FIRST_SECTION(pNTHeaders); // Get first image section.
for (WORD i = 0; i < pNTHeaders->FileHeader.NumberOfSections; ++i) // Loop through the sections.
{
const IMAGE_SECTION_HEADER& hCurrentSection = hSection[i]; // Get current section.
m_vModuleSections.emplace_back(reinterpret_cast<const char*>(hCurrentSection.Name), static_cast<uintptr_t>(reinterpret_cast<uintptr_t>(handle) + hCurrentSection.VirtualAddress), hCurrentSection.SizeOfRawData); // Push back a struct with the section data.
}
m_pModuleHandle = handle;
m_sModulePath.assign(svModelePath);
m_ExecutableCode = GetSectionByName(".text");
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Gets an address of a virtual method table by rtti type descriptor name
// Input : svTableName
// bDecorated
// Output : CMemory
//-----------------------------------------------------------------------------
CMemory CModule::GetVirtualTableByName(const std::string_view svTableName, bool bDecorated) const
{
if(svTableName.empty())
return CMemory();
CModule::ModuleSections_t runTimeData = GetSectionByName(".data"), readOnlyData = GetSectionByName(".rdata");
if(!runTimeData.IsSectionValid() || !readOnlyData.IsSectionValid())
return CMemory();
std::string sDecoratedTableName(bDecorated ? svTableName : ".?AV" + std::string(svTableName) + "@@");
std::string sMask(sDecoratedTableName.length() + 1, 'x');
CMemory typeDescriptorName = FindPattern(sDecoratedTableName.data(), sMask, nullptr, &runTimeData);
if (!typeDescriptorName)
return CMemory();
CMemory rttiTypeDescriptor = typeDescriptorName.Offset(-0x10);
const uintptr_t rttiTDRva = rttiTypeDescriptor - GetModuleBase(); // The RTTI gets referenced by a 4-Byte RVA address. We need to scan for that address.
CMemory reference;
while ((reference = FindPattern(&rttiTDRva, "xxxx", reference, &readOnlyData))) // Get reference typeinfo in vtable
{
// Check if we got a RTTI Object Locator for this reference by checking if -0xC is 1, which is the 'signature' field which is always 1 on x64.
// Check that offset of this vtable is 0
if (reference.Offset(-0xC).GetValue<int32_t>() == 1 && reference.Offset(-0x8).GetValue<int32_t>() == 0)
{
CMemory referenceOffset = reference.Offset(-0xC);
CMemory rttiCompleteObjectLocator = FindPattern(&referenceOffset, "xxxxxxxx", nullptr, &readOnlyData);
if (rttiCompleteObjectLocator)
return rttiCompleteObjectLocator.Offset(0x8);
}
reference.OffsetSelf(0x4);
}
return CMemory();
}
//-----------------------------------------------------------------------------
// Purpose: Gets an address of a virtual method table by rtti type descriptor name
// Input : svFunctionName
// Output : CMemory
//-----------------------------------------------------------------------------
CMemory CModule::GetFunctionByName(const std::string_view svFunctionName) const noexcept
{
if(!m_pModuleHandle)
return CMemory();
if (svFunctionName.empty())
return CMemory();
return GetProcAddress(reinterpret_cast<HMODULE>(m_pModuleHandle), svFunctionName.data());
}
//-----------------------------------------------------------------------------
// Purpose: Returns the module base
//-----------------------------------------------------------------------------
CMemory CModule::GetModuleBase() const noexcept
{
return m_pModuleHandle;
}