1
0
Fork 0
x64dbg/src/dbg/dynamicptr.h

149 lines
3.7 KiB
C++

#pragma once
#include "memory.h"
template<typename T, bool ReadOnly = false, bool BreakOnFail = false>
class RemotePtr;
template<typename T, typename U>
RemotePtr<U> RemoteMemberPtr(duint Address, U T::*Member)
{
// Calculate the offset from the member to the class base
duint offset = ((char*) & ((T*)nullptr->*Member) - (char*)nullptr);
return RemotePtr<U>(Address + offset);
}
template<typename T, bool ReadOnly, bool BreakOnFail>
class RemotePtr
{
// Special template part of this class, everything here
// should not be touched
template<bool Condition, typename U>
using enableIf = typename std::enable_if<Condition, U>::type;
template<typename U>
using makePtrRemote = RemotePtr<U, ReadOnly, BreakOnFail>;
template<typename U>
struct isClass : std::integral_constant < bool, std::is_class<std::remove_pointer<U>>::value ||
std::is_class<std::remove_reference<U>>::value > {};
template<typename U>
struct isPtrClass : std::integral_constant < bool, !std::is_arithmetic<U>::value &&
isClass<U>::value > {};
public:
explicit RemotePtr(duint Address)
{
Init(Address);
}
explicit RemotePtr(PVOID Address)
{
Init((duint)Address);
}
~RemotePtr()
{
if(!ReadOnly && m_Modified)
Sync();
}
T get()
{
// Read the external program data; no user edits
Update();
return m_InternalData;
}
template<typename A, typename B, typename C = typename std::remove_pointer<A>::type>
enableIf<isPtrClass<A>::value, makePtrRemote<C>> next(A B::*Member)
{
// First the pointer is read
auto ptr = RemotePtr<PVOID, ReadOnly, BreakOnFail>(m_InternalAddr + memberOffset(Member));
// Now return the real data structure
return makePtrRemote<C>(ptr.get());
}
template<typename A, typename B>
enableIf<std::is_arithmetic<A>::value, makePtrRemote<A>> next(A B::*Member)
{
// Return direct value with adjusted offset
return makePtrRemote<A>(m_InternalAddr + memberOffset(Member));
}
template<typename A, typename B = T>
enableIf<isClass<T>::value, duint> memberOffset(A B::*Member)
{
return (char*) & ((typename std::remove_pointer<T>::type*)nullptr->*Member) - (char*)nullptr;
}
T* operator->()
{
// The user could modify our internal structure after
// return
m_Modified = true;
// Read the external program data; return a pointer
Update();
return &m_InternalData;
}
T operator=(const T & rhs)
{
// This operation is only allowed with ReadOnly==false
if(!ReadOnly)
{
// Otherwise sync it with the external program.
// The external program can be messing with data at the same time.
m_InternalData = rhs;
Sync();
// Re-read data and then send it to the user
return get();
}
if(BreakOnFail)
__debugbreak();
return rhs;
}
T operator()()
{
return get();
}
private:
inline void Update()
{
MemRead(m_InternalAddr, &m_InternalData, sizeof(T));
}
inline void Sync()
{
if(BreakOnFail)
{
if(ReadOnly)
__debugbreak();
if(!MemWrite(m_InternalAddr, &m_InternalData, sizeof(T)))
__debugbreak();
}
m_Modified = false;
}
inline void Init(duint Address)
{
m_Modified = false;
m_InternalAddr = Address;
memset(&m_InternalData, 0, sizeof(T));
}
bool m_Modified;
duint m_InternalAddr;
T m_InternalData;
};