Initial commit
This commit is contained in:
commit
3dd53cf457
105 changed files with 35670 additions and 0 deletions
21
vendor/dynlibutils/LICENSE
vendored
Normal file
21
vendor/dynlibutils/LICENSE
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2023 komashchenko (Phoenix)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
9
vendor/dynlibutils/README.md
vendored
Normal file
9
vendor/dynlibutils/README.md
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
DynLibUtils is a library for interacting with dynamically loaded libraries (DLL, SO).
|
||||
Allows to get library sections, find pattern in memory and VirtualTable address by name.
|
||||
|
||||
This library is designed to simplify development for CS2 server, supports Windows/Linux x86_64.
|
||||
|
||||
Usage
|
||||
------------
|
||||
|
||||
Copy the source and header files to your project and add [`module.cpp`](module.cpp) in your build.
|
||||
152
vendor/dynlibutils/memaddr.h
vendored
Normal file
152
vendor/dynlibutils/memaddr.h
vendored
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
// DynLibUtils
|
||||
// Copyright (C) 2023 komashchenko (Phoenix)
|
||||
// https://github.com/komashchenko/DynLibUtils
|
||||
|
||||
#ifndef DYNLIBUTILS_MEMADDR_H
|
||||
#define DYNLIBUTILS_MEMADDR_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
namespace DynLibUtils {
|
||||
|
||||
class CMemory
|
||||
{
|
||||
public:
|
||||
CMemory() : m_ptr(0) {}
|
||||
CMemory(const CMemory&) noexcept = default;
|
||||
CMemory& operator= (const CMemory&) noexcept = default;
|
||||
CMemory(CMemory&& other) noexcept : m_ptr(std::exchange(other.m_ptr, 0)) {}
|
||||
CMemory(const uintptr_t ptr) : m_ptr(ptr) {}
|
||||
CMemory(const void* ptr) : m_ptr(reinterpret_cast<uintptr_t>(ptr)) {}
|
||||
|
||||
inline operator uintptr_t() const noexcept
|
||||
{
|
||||
return m_ptr;
|
||||
}
|
||||
|
||||
inline operator void*() const noexcept
|
||||
{
|
||||
return reinterpret_cast<void*>(m_ptr);
|
||||
}
|
||||
|
||||
explicit inline operator bool() const noexcept
|
||||
{
|
||||
return m_ptr != 0;
|
||||
}
|
||||
|
||||
inline bool operator!= (const CMemory& addr) const noexcept
|
||||
{
|
||||
return m_ptr != addr.m_ptr;
|
||||
}
|
||||
|
||||
inline bool operator== (const CMemory& addr) const noexcept
|
||||
{
|
||||
return m_ptr == addr.m_ptr;
|
||||
}
|
||||
|
||||
inline bool operator== (const uintptr_t& addr) const noexcept
|
||||
{
|
||||
return m_ptr == addr;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline uintptr_t GetPtr() const noexcept
|
||||
{
|
||||
return m_ptr;
|
||||
}
|
||||
|
||||
template<class T> [[nodiscard]] inline T GetValue() const noexcept
|
||||
{
|
||||
return *reinterpret_cast<T*>(m_ptr);
|
||||
}
|
||||
|
||||
template<typename T> [[nodiscard]] inline T CCast() const noexcept
|
||||
{
|
||||
return (T)m_ptr;
|
||||
}
|
||||
|
||||
template<typename T> [[nodiscard]] inline T RCast() const noexcept
|
||||
{
|
||||
return reinterpret_cast<T>(m_ptr);
|
||||
}
|
||||
|
||||
template<typename T> [[nodiscard]] inline T UCast() const noexcept
|
||||
{
|
||||
union { uintptr_t m_ptr; T cptr; } cast;
|
||||
return cast.m_ptr = m_ptr, cast.cptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline CMemory Offset(ptrdiff_t offset) const noexcept
|
||||
{
|
||||
return m_ptr + offset;
|
||||
}
|
||||
|
||||
inline CMemory& OffsetSelf(ptrdiff_t offset) noexcept
|
||||
{
|
||||
m_ptr += offset;
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline CMemory Deref(int deref = 1) const
|
||||
{
|
||||
uintptr_t reference = m_ptr;
|
||||
|
||||
while (deref--)
|
||||
{
|
||||
if (reference)
|
||||
reference = *reinterpret_cast<uintptr_t*>(reference);
|
||||
}
|
||||
|
||||
return reference;
|
||||
}
|
||||
|
||||
inline CMemory& DerefSelf(int deref = 1)
|
||||
{
|
||||
while (deref--)
|
||||
{
|
||||
if (m_ptr)
|
||||
m_ptr = *reinterpret_cast<uintptr_t*>(m_ptr);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline CMemory FollowNearCall(const ptrdiff_t opcodeOffset = 0x1, const ptrdiff_t nextInstructionOffset = 0x5) const
|
||||
{
|
||||
return ResolveRelativeAddress(opcodeOffset, nextInstructionOffset);
|
||||
}
|
||||
|
||||
inline CMemory& FollowNearCallSelf(const ptrdiff_t opcodeOffset = 0x1, const ptrdiff_t nextInstructionOffset = 0x5)
|
||||
{
|
||||
return ResolveRelativeAddressSelf(opcodeOffset, nextInstructionOffset);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline CMemory ResolveRelativeAddress(const ptrdiff_t registerOffset = 0x0, const ptrdiff_t nextInstructionOffset = 0x4) const
|
||||
{
|
||||
const uintptr_t skipRegister = m_ptr + registerOffset;
|
||||
const int32_t relativeAddress = *reinterpret_cast<int32_t*>(skipRegister);
|
||||
const uintptr_t nextInstruction = m_ptr + nextInstructionOffset;
|
||||
return nextInstruction + relativeAddress;
|
||||
}
|
||||
|
||||
inline CMemory& ResolveRelativeAddressSelf(const ptrdiff_t registerOffset = 0x0, const ptrdiff_t nextInstructionOffset = 0x4)
|
||||
{
|
||||
const uintptr_t skipRegister = m_ptr + registerOffset;
|
||||
const int32_t relativeAddress = *reinterpret_cast<int32_t*>(skipRegister);
|
||||
const uintptr_t nextInstruction = m_ptr + nextInstructionOffset;
|
||||
m_ptr = nextInstruction + relativeAddress;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
uintptr_t m_ptr;
|
||||
};
|
||||
|
||||
} // namespace DynLibUtils
|
||||
|
||||
#endif // DYNLIBUTILS_MEMADDR_H
|
||||
203
vendor/dynlibutils/module.cpp
vendored
Normal file
203
vendor/dynlibutils/module.cpp
vendored
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
// DynLibUtils
|
||||
// Copyright (C) 2023 komashchenko (Phoenix)
|
||||
// https://github.com/komashchenko/DynLibUtils
|
||||
|
||||
#include "module.h"
|
||||
#include "memaddr.h"
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
#include <emmintrin.h>
|
||||
|
||||
using namespace DynLibUtils;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: constructor
|
||||
// Input : szModuleName (without extension .dll/.so)
|
||||
//-----------------------------------------------------------------------------
|
||||
CModule::CModule(const std::string_view szModuleName) : m_pModuleHandle(nullptr)
|
||||
{
|
||||
InitFromName(szModuleName);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: constructor
|
||||
// Input : pModuleMemory
|
||||
//-----------------------------------------------------------------------------
|
||||
CModule::CModule(const CMemory pModuleMemory) : m_pModuleHandle(nullptr)
|
||||
{
|
||||
InitFromMemory(pModuleMemory);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Converts a string pattern with wildcards to an array of bytes and mask
|
||||
// Input : svInput
|
||||
// Output : std::pair<std::vector<uint8_t>, std::string>
|
||||
//-----------------------------------------------------------------------------
|
||||
std::pair<std::vector<uint8_t>, std::string> CModule::PatternToMaskedBytes(const std::string_view svInput)
|
||||
{
|
||||
char* pszPatternStart = const_cast<char*>(svInput.data());
|
||||
char* pszPatternEnd = pszPatternStart + svInput.size();
|
||||
std::vector<uint8_t> vBytes;
|
||||
std::string svMask;
|
||||
|
||||
for (char* pszCurrentByte = pszPatternStart; pszCurrentByte < pszPatternEnd; ++pszCurrentByte)
|
||||
{
|
||||
if (*pszCurrentByte == '?')
|
||||
{
|
||||
++pszCurrentByte;
|
||||
if (*pszCurrentByte == '?')
|
||||
{
|
||||
++pszCurrentByte; // Skip double wildcard.
|
||||
}
|
||||
|
||||
vBytes.push_back(0); // Push the byte back as invalid.
|
||||
svMask += '?';
|
||||
}
|
||||
else
|
||||
{
|
||||
vBytes.push_back(static_cast<uint8_t>(strtoul(pszCurrentByte, &pszCurrentByte, 16)));
|
||||
svMask += 'x';
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair(std::move(vBytes), std::move(svMask));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Finds an array of bytes in process memory using SIMD instructions
|
||||
// Input : *pPattern
|
||||
// szMask
|
||||
// pStartAddress
|
||||
// *pModuleSection
|
||||
// Output : CMemory
|
||||
//-----------------------------------------------------------------------------
|
||||
CMemory CModule::FindPattern(const CMemory pPattern, const std::string_view szMask, const CMemory pStartAddress, const ModuleSections_t* pModuleSection) const
|
||||
{
|
||||
const uint8_t* pattern = pPattern.RCast<const uint8_t*>();
|
||||
const ModuleSections_t* section = pModuleSection ? pModuleSection : &m_ExecutableCode;
|
||||
if (!section->IsSectionValid())
|
||||
return CMemory();
|
||||
|
||||
const uintptr_t nBase = section->m_pSectionBase;
|
||||
const size_t nSize = section->m_nSectionSize;
|
||||
|
||||
const size_t nMaskLen = szMask.length();
|
||||
const uint8_t* pData = reinterpret_cast<uint8_t*>(nBase);
|
||||
const uint8_t* pEnd = pData + nSize - nMaskLen;
|
||||
|
||||
if(pStartAddress)
|
||||
{
|
||||
const uint8_t* startAddress = pStartAddress.RCast<uint8_t*>();
|
||||
if(pData > startAddress || startAddress > pEnd)
|
||||
return CMemory();
|
||||
|
||||
pData = startAddress;
|
||||
}
|
||||
|
||||
int nMasks[64]; // 64*16 = enough masks for 1024 bytes.
|
||||
const uint8_t iNumMasks = static_cast<uint8_t>(std::ceil(static_cast<float>(nMaskLen) / 16.f));
|
||||
|
||||
memset(nMasks, 0, iNumMasks * sizeof(int));
|
||||
for (uint8_t i = 0; i < iNumMasks; ++i)
|
||||
{
|
||||
for (int8_t j = static_cast<int8_t>(std::min<size_t>(nMaskLen - i * 16, 16)) - 1; j >= 0; --j)
|
||||
{
|
||||
if (szMask[i * 16 + j] == 'x')
|
||||
{
|
||||
nMasks[i] |= 1 << j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const __m128i xmm1 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(pattern));
|
||||
__m128i xmm2, xmm3, msks;
|
||||
for (; pData != pEnd; _mm_prefetch(reinterpret_cast<const char*>(++pData + 64), _MM_HINT_NTA))
|
||||
{
|
||||
xmm2 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(pData));
|
||||
msks = _mm_cmpeq_epi8(xmm1, xmm2);
|
||||
if ((_mm_movemask_epi8(msks) & nMasks[0]) == nMasks[0])
|
||||
{
|
||||
bool bFound = true;
|
||||
for (uint8_t i = 1; i < iNumMasks; ++i)
|
||||
{
|
||||
xmm2 = _mm_loadu_si128(reinterpret_cast<const __m128i*>((pData + i * 16)));
|
||||
xmm3 = _mm_loadu_si128(reinterpret_cast<const __m128i*>((pattern + i * 16)));
|
||||
msks = _mm_cmpeq_epi8(xmm2, xmm3);
|
||||
if ((_mm_movemask_epi8(msks) & nMasks[i]) != nMasks[i])
|
||||
{
|
||||
bFound = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bFound)
|
||||
return pData;
|
||||
}
|
||||
}
|
||||
|
||||
return CMemory();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Finds a string pattern in process memory using SIMD instructions
|
||||
// Input : svPattern
|
||||
// pStartAddress
|
||||
// *pModuleSection
|
||||
// Output : CMemory
|
||||
//-----------------------------------------------------------------------------
|
||||
CMemory CModule::FindPattern(const std::string_view svPattern, const CMemory pStartAddress, const ModuleSections_t* pModuleSection) const
|
||||
{
|
||||
const std::pair patternInfo = PatternToMaskedBytes(svPattern);
|
||||
return FindPattern(patternInfo.first.data(), patternInfo.second, pStartAddress, pModuleSection);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Gets a module section by name (example: '.rdata', '.text')
|
||||
// Input : svModuleName
|
||||
// Output : ModuleSections_t
|
||||
//-----------------------------------------------------------------------------
|
||||
CModule::ModuleSections_t CModule::GetSectionByName(const std::string_view svSectionName) const
|
||||
{
|
||||
for (const ModuleSections_t& section : m_vModuleSections)
|
||||
{
|
||||
if (section.m_svSectionName == svSectionName)
|
||||
return section;
|
||||
}
|
||||
|
||||
return ModuleSections_t();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the module handle
|
||||
//-----------------------------------------------------------------------------
|
||||
void* CModule::GetModuleHandle() const noexcept
|
||||
{
|
||||
return m_pModuleHandle;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the module path
|
||||
//-----------------------------------------------------------------------------
|
||||
std::string_view CModule::GetModulePath() const
|
||||
{
|
||||
return m_sModulePath;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the module name
|
||||
//-----------------------------------------------------------------------------
|
||||
std::string_view CModule::GetModuleName() const
|
||||
{
|
||||
std::string_view svModulePath(m_sModulePath);
|
||||
return svModulePath.substr(svModulePath.find_last_of("/\\") + 1);
|
||||
}
|
||||
|
||||
#ifndef DYNLIBUTILS_SEPARATE_SOURCE_FILES
|
||||
#if defined _WIN32 && _M_X64
|
||||
#include "module_windows.cpp"
|
||||
#elif defined __linux__ && __x86_64__
|
||||
#include "module_linux.cpp"
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
#endif
|
||||
#endif
|
||||
77
vendor/dynlibutils/module.h
vendored
Normal file
77
vendor/dynlibutils/module.h
vendored
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
// DynLibUtils
|
||||
// Copyright (C) 2023 komashchenko (Phoenix)
|
||||
// https://github.com/komashchenko/DynLibUtils
|
||||
|
||||
#ifndef DYNLIBUTILS_MODULE_H
|
||||
#define DYNLIBUTILS_MODULE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "memaddr.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
namespace DynLibUtils {
|
||||
|
||||
class CModule
|
||||
{
|
||||
public:
|
||||
struct ModuleSections_t
|
||||
{
|
||||
ModuleSections_t() : m_nSectionSize(0) {}
|
||||
ModuleSections_t(const ModuleSections_t&) = default;
|
||||
ModuleSections_t& operator= (const ModuleSections_t&) = default;
|
||||
ModuleSections_t(ModuleSections_t&& other) noexcept : m_svSectionName(std::move(other.m_svSectionName)), m_pSectionBase(std::move(other.m_pSectionBase)), m_nSectionSize(std::exchange(other.m_nSectionSize, 0)) {}
|
||||
ModuleSections_t(const std::string_view svSectionName, uintptr_t pSectionBase, size_t nSectionSize) : m_svSectionName(svSectionName), m_pSectionBase(pSectionBase), m_nSectionSize(nSectionSize) {}
|
||||
|
||||
[[nodiscard]] inline bool IsSectionValid() const noexcept
|
||||
{
|
||||
return m_pSectionBase;
|
||||
}
|
||||
|
||||
std::string m_svSectionName; // Name of section.
|
||||
CMemory m_pSectionBase; // Start address of section.
|
||||
size_t m_nSectionSize; // Size of section.
|
||||
};
|
||||
|
||||
CModule() : m_pModuleHandle(nullptr) {}
|
||||
~CModule();
|
||||
CModule (const CModule&) = delete;
|
||||
CModule& operator= (const CModule&) = delete;
|
||||
CModule(CModule&& other) noexcept : m_ExecutableCode(std::move(other.m_ExecutableCode)), m_sModulePath(std::move(other.m_sModulePath)), m_pModuleHandle(std::exchange(other.m_pModuleHandle, nullptr)), m_vModuleSections(std::move(other.m_vModuleSections)) {}
|
||||
explicit CModule(const std::string_view svModuleName);
|
||||
explicit CModule(const char* pszModuleName) : CModule(std::string_view(pszModuleName)) {}
|
||||
explicit CModule(const std::string& sModuleName) : CModule(std::string_view(sModuleName)) {}
|
||||
CModule(const CMemory pModuleMemory);
|
||||
|
||||
bool InitFromName(const std::string_view svModuleName, bool bExtension = false);
|
||||
bool InitFromMemory(const CMemory pModuleMemory);
|
||||
|
||||
[[nodiscard]] static std::pair<std::vector<uint8_t>, std::string> PatternToMaskedBytes(const std::string_view svInput);
|
||||
[[nodiscard]] CMemory FindPattern(const CMemory pPattern, const std::string_view szMask, const CMemory pStartAddress = nullptr, const ModuleSections_t* pModuleSection = nullptr) const;
|
||||
[[nodiscard]] CMemory FindPattern(const std::string_view svPattern, const CMemory pStartAddress = nullptr, const ModuleSections_t* pModuleSection = nullptr) const;
|
||||
|
||||
[[nodiscard]] CMemory GetVirtualTableByName(const std::string_view svTableName, bool bDecorated = false) const;
|
||||
[[nodiscard]] CMemory GetFunctionByName(const std::string_view svFunctionName) const noexcept;
|
||||
|
||||
[[nodiscard]] ModuleSections_t GetSectionByName(const std::string_view svSectionName) const;
|
||||
[[nodiscard]] void* GetModuleHandle() const noexcept;
|
||||
[[nodiscard]] CMemory GetModuleBase() const noexcept;
|
||||
[[nodiscard]] std::string_view GetModulePath() const;
|
||||
[[nodiscard]] std::string_view GetModuleName() const;
|
||||
|
||||
private:
|
||||
bool Init(const std::string_view svModelePath);
|
||||
|
||||
ModuleSections_t m_ExecutableCode;
|
||||
std::string m_sModulePath;
|
||||
void* m_pModuleHandle;
|
||||
std::vector<ModuleSections_t> m_vModuleSections;
|
||||
};
|
||||
|
||||
} // namespace DynLibUtils
|
||||
|
||||
#endif // DYNLIBUTILS_MODULE_H
|
||||
219
vendor/dynlibutils/module_linux.cpp
vendored
Normal file
219
vendor/dynlibutils/module_linux.cpp
vendored
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
// DynLibUtils
|
||||
// Copyright (C) 2023 komashchenko (Phoenix)
|
||||
// https://github.com/komashchenko/DynLibUtils
|
||||
|
||||
#include "module.h"
|
||||
#include "memaddr.h"
|
||||
#include <cstring>
|
||||
#include <link.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
using namespace DynLibUtils;
|
||||
|
||||
CModule::~CModule()
|
||||
{
|
||||
if (m_pModuleHandle)
|
||||
dlclose(m_pModuleHandle);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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(".so");
|
||||
|
||||
struct dl_data
|
||||
{
|
||||
ElfW(Addr) addr;
|
||||
const char* moduleName;
|
||||
const char* modulePath;
|
||||
} dldata{ 0, sModuleName.c_str(), {} };
|
||||
|
||||
dl_iterate_phdr([](dl_phdr_info* info, size_t /* size */, void* data)
|
||||
{
|
||||
dl_data* dldata = reinterpret_cast<dl_data*>(data);
|
||||
|
||||
if (std::strstr(info->dlpi_name, dldata->moduleName) != nullptr)
|
||||
{
|
||||
dldata->addr = info->dlpi_addr;
|
||||
dldata->modulePath = info->dlpi_name;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}, &dldata);
|
||||
|
||||
if (!dldata.addr)
|
||||
return false;
|
||||
|
||||
if (!Init(dldata.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;
|
||||
|
||||
Dl_info info;
|
||||
if (!dladdr(pModuleMemory, &info) || !info.dli_fbase || !info.dli_fname)
|
||||
return false;
|
||||
|
||||
if (!Init(info.dli_fname))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Initializes a module descriptors
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CModule::Init(const std::string_view svModelePath)
|
||||
{
|
||||
void* handle = dlopen(svModelePath.data(), RTLD_LAZY | RTLD_NOLOAD);
|
||||
if (!handle)
|
||||
return false;
|
||||
|
||||
link_map* lmap;
|
||||
if (dlinfo(handle, RTLD_DI_LINKMAP, &lmap) != 0)
|
||||
{
|
||||
dlclose(handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
int fd = open(lmap->l_name, O_RDONLY);
|
||||
if (fd == -1)
|
||||
{
|
||||
dlclose(handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
struct stat st;
|
||||
if (fstat(fd, &st) == 0)
|
||||
{
|
||||
void* map = mmap(nullptr, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if (map != MAP_FAILED)
|
||||
{
|
||||
ElfW(Ehdr)* ehdr = static_cast<ElfW(Ehdr)*>(map);
|
||||
ElfW(Shdr)* shdrs = reinterpret_cast<ElfW(Shdr)*>(reinterpret_cast<uintptr_t>(ehdr) + ehdr->e_shoff);
|
||||
const char* strTab = reinterpret_cast<const char*>(reinterpret_cast<uintptr_t>(ehdr) + shdrs[ehdr->e_shstrndx].sh_offset);
|
||||
|
||||
for (auto i = 0; i < ehdr->e_shnum; ++i) // Loop through the sections.
|
||||
{
|
||||
ElfW(Shdr)* shdr = reinterpret_cast<ElfW(Shdr)*>(reinterpret_cast<uintptr_t>(shdrs) + i * ehdr->e_shentsize);
|
||||
if (*(strTab + shdr->sh_name) == '\0')
|
||||
continue;
|
||||
|
||||
m_vModuleSections.emplace_back(strTab + shdr->sh_name, static_cast<uintptr_t>(lmap->l_addr + shdr->sh_addr), shdr->sh_size);
|
||||
}
|
||||
|
||||
munmap(map, st.st_size);
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
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 readOnlyData = GetSectionByName(".rodata"), readOnlyRelocations = GetSectionByName(".data.rel.ro");
|
||||
if (!readOnlyData.IsSectionValid() || !readOnlyRelocations.IsSectionValid())
|
||||
return CMemory();
|
||||
|
||||
std::string sDecoratedTableName(bDecorated ? svTableName : std::to_string(svTableName.length()) + std::string(svTableName));
|
||||
std::string sMask(sDecoratedTableName.length() + 1, 'x');
|
||||
|
||||
CMemory typeInfoName = FindPattern(sDecoratedTableName.data(), sMask, nullptr, &readOnlyData);
|
||||
if (!typeInfoName)
|
||||
return CMemory();
|
||||
|
||||
CMemory referenceTypeName = FindPattern(&typeInfoName, "xxxxxxxx", nullptr, &readOnlyRelocations); // Get reference to type name.
|
||||
if (!referenceTypeName)
|
||||
return CMemory();
|
||||
|
||||
CMemory typeInfo = referenceTypeName.Offset(-0x8); // Offset -0x8 to typeinfo.
|
||||
|
||||
for (const auto& sectionName : { std::string_view(".data.rel.ro"), std::string_view(".data.rel.ro.local") })
|
||||
{
|
||||
CModule::ModuleSections_t section = GetSectionByName(sectionName);
|
||||
if (!section.IsSectionValid())
|
||||
continue;
|
||||
|
||||
CMemory reference;
|
||||
while ((reference = FindPattern(&typeInfo, "xxxxxxxx", reference, §ion))) // Get reference typeinfo in vtable
|
||||
{
|
||||
if (reference.Offset(-0x8).GetValue<int64_t>() == 0) // Offset to this.
|
||||
{
|
||||
return reference.Offset(0x8);
|
||||
}
|
||||
|
||||
reference.OffsetSelf(0x8);
|
||||
}
|
||||
}
|
||||
|
||||
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 dlsym(m_pModuleHandle, svFunctionName.data());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the module base
|
||||
//-----------------------------------------------------------------------------
|
||||
CMemory CModule::GetModuleBase() const noexcept
|
||||
{
|
||||
return static_cast<link_map*>(m_pModuleHandle)->l_addr;
|
||||
}
|
||||
196
vendor/dynlibutils/module_windows.cpp
vendored
Normal file
196
vendor/dynlibutils/module_windows.cpp
vendored
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
// 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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue