调用 PluginBase / Call
Call / CallDyn / Method / VMT 选型与基址
shared/PluginBase.h · 命名空间 plugin
优先顺序:已有 C++ 封装 → Command → Call → 最后才 patch。
| 场景 | 选用 |
|---|---|
| 编译期已知地址、cdecl | Call / CallAndReturn |
| thiscall | CallMethod / CallMethodAndReturn |
| 运行时才有地址(Pattern / 重定位) | CallDyn* |
| 地址已是绝对、不要再加基址 | *DynGlobal |
| 虚表槽 | CallVirtualMethod* |
编译期地址 → Call*
运行时地址 → CallDyn*(多数配合 GetGlobalAddress / Pattern)
*DynGlobal 不做重定位
不要在这些时机 Call 游戏逻辑
静态构造 / DllMain / 对象池尚未建立 / 设备 Lost 之后继续画或调渲染相关逻辑。
无返回 cdecl
Call
编译期地址 · cdecl
无返回的 cdecl 调用。address 按 void(__cdecl*)(Args...) 解释。调用约定错误会破坏栈。固定 RVA 换游戏版本通常要更新,或改用 Pattern + CallDyn。
template <uintptr_t address, typename... Args>
void Call(Args... args);有返回 cdecl
CallAndReturn
编译期地址 · cdecl
Ret 写在模板参数最前。
template <typename Ret, uintptr_t address, typename... Args>
Ret CallAndReturn(Args... args);stdcall
CallStd / CallStdAndReturn
编译期地址 · stdcall
游戏内多数并不是 stdcall,确认约定后再用。
template <uintptr_t address, typename... Args>
void CallStd(Args... args);
template <typename Ret, uintptr_t address, typename... Args>
Ret CallStdAndReturn(Args... args);thiscall 方法
CallMethod / CallMethodAndReturn
编译期地址 · thiscall
第一个参数是 this,必须有效。
template <uintptr_t address, typename C, typename... Args>
void CallMethod(C _this, Args... args);
template <typename Ret, uintptr_t address, typename C, typename... Args>
Ret CallMethodAndReturn(C _this, Args... args);虚表方法
CallVirtualMethod / CallVirtualMethodAndReturn
虚表下标
模板参数是虚表 下标,不是函数地址。下标错误几乎必崩。
template <uintptr_t tableIndex, typename C, typename... Args>
void CallVirtualMethod(C _this, Args... args);
template <typename Ret, uintptr_t tableIndex, typename C, typename... Args>
Ret CallVirtualMethodAndReturn(C _this, Args... args);运行时地址 cdecl
CallDyn / CallAndReturnDyn
运行时 · cdecl · 重定位
内部会做重定位。地址为 0 时不要调用。
template <typename... Args>
void CallDyn(uintptr_t address, Args... args);
template <typename Ret, typename... Args>
Ret CallAndReturnDyn(uintptr_t address, Args... args);运行时地址 stdcall
CallStdDyn / CallStdAndReturnDyn
template <typename... Args>
void CallStdDyn(uintptr_t address, Args... args);
template <typename Ret, typename... Args>
Ret CallStdAndReturnDyn(uintptr_t address, Args... args);运行时地址 thiscall
CallMethodDyn / CallMethodAndReturnDyn
template <typename C, typename... Args>
void CallMethodDyn(uintptr_t address, C _this, Args... args);
template <typename Ret, typename C, typename... Args>
Ret CallMethodAndReturnDyn(uintptr_t address, C _this, Args... args);绝对地址 cdecl
CallDynGlobal / CallAndReturnDynGlobal
绝对地址 · 不重定位
template <typename... Args>
void CallDynGlobal(uintptr_t address, Args... args);
template <typename Ret, typename... Args>
Ret CallAndReturnDynGlobal(uintptr_t address, Args... args);绝对地址 thiscall
CallMethodDynGlobal / CallMethodAndReturnDynGlobal
template <typename C, typename... Args>
void CallMethodDynGlobal(uintptr_t address, C _this, Args... args);
template <typename Ret, typename C, typename... Args>
Ret CallMethodAndReturnDynGlobal(uintptr_t address, C _this, Args... args);取虚表
GetVMT
取虚表指针,或某一槽位。
inline void** GetVMT(const void* self);
inline void* GetVMT(const void* self, size_t index);基址与绝对地址
GetBaseAddress / GetGlobalAddress
DynAddress.h
模块基址;RVA → 绝对地址。
uintptr_t GetBaseAddress();
uintptr_t GetGlobalAddress(uintptr_t address);分配与释放
operator_new / operator_delete 族
等价于 new / delete,必须成对使用。
template <typename ClassType, typename... ArgTypes>
ClassType* operator_new(ArgTypes... args);
template <typename ClassType>
ClassType* operator_new_array(size_t size);
template <typename ClassType>
void operator_delete(ClassType* data);
template <typename ClassType>
void operator_delete_array(ClassType* data);栈上临时对象
stack_object
template <typename T>
struct stack_object {
template <typename... ArgTypes>
stack_object(ArgTypes... args);
T* operator->();
T& get_object();
};SDK 版本
Core::GetVersion
namespace Core {
PLUGIN_API unsigned int GetVersion();
}跨游戏取值
BY_GAME
宏
按当前工程宏取三端之一。
BY_GAME(iii_val, vc_val, sa_val)