Skip to content

Commit 73ab6cd

Browse files
Wend4rkomashchenko
andcommitted
Add VTHook header
Co-authored-by: komashchenko <komashchenko@users.noreply.github.com>
1 parent 80c310b commit 73ab6cd

1 file changed

Lines changed: 105 additions & 0 deletions

File tree

include/dynlibutils/vthook.hpp

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
//
2+
// DynLibUtils
3+
// Copyright (C) 2023-2025 Vladimir Ezhikov (Wend4r) & komashchenko (Phoenix)
4+
// Licensed under the MIT license. See LICENSE file in the project root for details.
5+
//
6+
7+
#ifndef DYNLIBUTILS_VTHOOK_HPP
8+
#define DYNLIBUTILS_VTHOOK_HPP
9+
#pragma once
10+
11+
#include "memaddr.hpp"
12+
13+
#if __unix__
14+
# include <sys/mman.h>
15+
# include <unistd.h>
16+
#endif
17+
18+
#include <cassert>
19+
20+
namespace DynLibUtils {
21+
22+
class MemUnprotector
23+
{
24+
public:
25+
MemUnprotector(CMemory pAddress, size_t nLength = sizeof(void*))
26+
{
27+
#if _WIN32
28+
VirtualProtect(pAddress, nLength, PAGE_EXECUTE_READWRITE, &m_nOldProtection);
29+
30+
m_pAddress = pAddress;
31+
m_nLength = nLength;
32+
#else
33+
long nPageSize = sysconf(_SC_PAGESIZE);
34+
CMemory pPageStart = pAddress & ~(nPageSize - 1l);
35+
CMemory pPageEnd = (pAddress + nLength + nPageSize - 1l) & ~(nPageSize - 1l);
36+
size_t nAligned = pPageEnd - pPageStart;
37+
38+
mprotect(pPageStart, nAligned, PROT_READ | PROT_WRITE | PROT_EXEC);
39+
40+
m_pAddress = pPageStart;
41+
m_nLength = nAligned;
42+
m_nOldProtection = PROT_READ | PROT_WRITE; //TODO: Need to parse /proc/self/maps
43+
#endif
44+
}
45+
46+
~MemUnprotector()
47+
{
48+
#if _WIN32
49+
DWORD origProtect;
50+
VirtualProtect(m_pAddress, m_nLength, m_nOldProtection, &origProtect);
51+
#else
52+
mprotect(m_pAddress, m_nLength, m_nOldProtection);
53+
#endif
54+
}
55+
56+
private:
57+
size_t m_nLength;
58+
unsigned long m_nOldProtection;
59+
60+
CMemory m_pAddress;
61+
}; // class MemUnprotector
62+
63+
template <typename T, typename C, typename ...Args>
64+
class VTHook
65+
{
66+
public:
67+
VTHook() = default;
68+
~VTHook() { Unhook(); }
69+
70+
bool IsHooked() const { return m_pOriginalFn.IsValid(); }
71+
72+
void Hook(CMemory pVTable, int index, T(*pFn)(C*, Args...))
73+
{
74+
assert(!IsHooked());
75+
76+
m_vmpFn = pVTable.Offset(index * sizeof(void*));
77+
m_pOriginalFn = m_vmpFn.Deref();
78+
79+
MemUnprotector unprotector(m_vmpFn);
80+
81+
*m_vmpFn.RCast<T(**)(C*, Args...)>() = pFn;
82+
}
83+
84+
void Unhook()
85+
{
86+
assert(IsHooked());
87+
88+
MemUnprotector unprotector(m_vmpFn);
89+
90+
*m_vmpFn.RCast<void**>() = m_pOriginalFn;
91+
92+
m_vmpFn = nullptr;
93+
m_pOriginalFn = nullptr;
94+
}
95+
96+
T Call(C* pThis, Args... args) { return m_pOriginalFn.RCast<T(*)(C*, Args...)>()(pThis, args...); }
97+
98+
private:
99+
CMemory m_vmpFn;
100+
CMemory m_pOriginalFn;
101+
}; // class VTHook
102+
103+
} // namespace DynLibUtils
104+
105+
#endif // DYNLIBUTILS_VTHOOK_HPP

0 commit comments

Comments
 (0)