Skip to content

Commit 1f2efec

Browse files
committed
fix: add more plugin guides
1 parent b9991e0 commit 1f2efec

File tree

2 files changed

+437
-5
lines changed

2 files changed

+437
-5
lines changed

content/6.plugins/3.polyhook/3.guide.md

Lines changed: 235 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,239 @@ description: A detailed guide on how to use the plugin effectively, ensuring you
44
icon: lucide:book-open-text
55
---
66

7+
## Hooking C/C++ Functions Dynamically in Any Language
8+
9+
It is a plugin that enables dynamic runtime hooking of C++ functions — including both **virtual function table (vtable)** hooks and **code detour** hooks. It’s based on the powerful [polyhook2](https://github.com/stevemk14ebr/PolyHook_2_0) backend and is designed to be easily integrated into your plugin or scripting environment.
10+
11+
This guide covers:
12+
13+
- Hooking detour (raw function address) functions
14+
- Hooking virtual functions (by index or by function pointer)
15+
- Registering pre- and post-callbacks
16+
- Inspecting and modifying function arguments and return values
17+
- Unhooking and managing callbacks
18+
19+
---
20+
21+
## Basic Concepts
22+
23+
### What is a Hook?
24+
25+
A **hook** is a method to intercept function calls. You can:
26+
27+
- Inspect/modify function arguments before the call (**pre**)
28+
- Observe/alter return value after the call (**post**)
29+
- Override or entirely skip the original function (**supercede**)
30+
31+
### Types of Hooks
32+
33+
- `HookDetour`: Hooks a standalone or static function.
34+
- `HookVirtual`: Hooks a class method via vtable index or function pointer.
35+
36+
---
37+
38+
## Data Types
39+
40+
Use `DataType` enum to describe argument and return types:
41+
42+
```
43+
enum class DataType : uint8_t {
44+
Void, Bool, Int8, UInt8, Int16, UInt16,
45+
Int32, UInt32, Int64, UInt64,
46+
Float, Double, Pointer, String
47+
};
48+
```
49+
50+
Use these consistently when describing function signatures to the hook APIs.
51+
52+
---
53+
54+
## Hooking Functions
55+
56+
### 1. Detour Hook
57+
58+
Use `HookDetour` to hook a global/static function:
59+
60+
```
61+
Callback* HookDetour(void* pFunc, DataType returnType, const plg::vector<DataType>& args, int varIndex);
62+
```
63+
64+
- `pFunc`: Pointer to the function to hook.
65+
- `returnType`: Return type using `DataType`.
66+
- `args`: List of argument types.
67+
- `varIndex`: Use `-1` for normal calls; set if variable argument.
68+
69+
**Example:**
70+
71+
```
72+
void* targetFunc = (void*) &DoSomething;
73+
plg::vector<DataType> args = { DataType::Int32, DataType::Pointer };
74+
Callback* cb = HookDetour(targetFunc, DataType::Void, args, -1);
75+
```
76+
77+
---
78+
79+
### 2. Virtual Hook (by index)
80+
81+
Hook a method from an object’s vtable:
82+
83+
```
84+
Callback* HookVirtual(void* pClass, int index, DataType returnType, const plg::vector<DataType>& args, int varIndex);
85+
```
86+
87+
**Example:**
88+
89+
```
90+
Callback* cb = HookVirtual(someObj, 3, DataType::Bool, { DataType::Pointer }, -1);
91+
```
92+
93+
You can also get the vtable index from a function pointer:
94+
95+
```
96+
int index = GetVTableIndex((void*) &MyClass::MyMethod);
97+
```
98+
799
::alert{type="warning" icon="lucide:triangle-alert"}
8-
The section is currently under development.
9-
::
100+
Getting the vtable index requires knowledge of the class layout and may not be portable across different compilers or platforms. Use with caution, works only if using C++ or C-like languages.
101+
::
102+
103+
---
104+
105+
### 3. Virtual Hook (by function pointer)
106+
107+
Instead of using vtable index:
108+
109+
```
110+
Callback* HookVirtualByFunc(void* pClass, void* pFunc, DataType returnType, const vector<DataType>& args, int varIndex);
111+
```
112+
113+
---
114+
115+
## Unhooking
116+
117+
- `UnhookDetour(void* pFunc)`
118+
- `UnhookVirtual(void* pClass, int index)`
119+
- `UnhookVirtualByFunc(void* pClass, void* pFunc)`
120+
- `UnhookAll()` – removes all hooks
121+
- `UnhookAllVirtual(void* pClass)` – removes all vtable hooks for a class
122+
123+
---
124+
125+
## Callback System
126+
127+
### 1. Register Callback
128+
129+
```
130+
bool AddCallback(Callback* cb, CallbackType type, CallbackHandler handler);
131+
```
132+
133+
- `type`: `CallbackType::Pre` or `CallbackType::Post`
134+
- `handler`: Function pointer
135+
136+
**Handler Signature:**
137+
138+
```
139+
ReturnAction myHandler(Callback* cb, const Parameters* params, int32_t count, const Return* ret, CallbackType type);
140+
```
141+
142+
Use this to inspect or modify arguments and returns.
143+
144+
### 2. ReturnAction
145+
146+
```
147+
enum class ReturnAction : int32_t {
148+
Ignored, // Don't interfere
149+
Handled, // Interfere but call real function
150+
Override, // Call real function but change return value
151+
Supercede // Skip real function entirely
152+
};
153+
```
154+
155+
---
156+
157+
## Access Arguments & Return
158+
159+
### Getting arguments:
160+
161+
```
162+
int val = GetArgumentInt32(params, 0);
163+
void* ptr = GetArgumentPointer(params, 1);
164+
```
165+
166+
### Setting arguments:
167+
168+
```
169+
SetArgumentInt32(params, 0, 42);
170+
SetArgumentPointer(params, 1, myPtr);
171+
```
172+
173+
### Getting return value:
174+
175+
```
176+
float retVal = GetReturnFloat(ret);
177+
```
178+
179+
### Overriding return:
180+
181+
```
182+
SetReturnFloat(ret, 1.0f);
183+
return ReturnAction::Supercede;
184+
```
185+
186+
---
187+
188+
## Full Example
189+
190+
Hook `int Add(int a, int b)` and modify result:
191+
192+
```
193+
ReturnAction preAdd(Callback* cb, const Parameters* params, int32_t count, const Return* ret, CallbackType type) {
194+
int32_t a = GetArgumentInt32(params, 0);
195+
int32_t b = GetArgumentInt32(params, 1);
196+
SetArgumentInt32(params, 0, a + 1);
197+
SetArgumentInt32(params, 1, b + 1);
198+
return ReturnAction::Handled;
199+
}
200+
201+
ReturnAction postAdd(Callback* cb, const Parameters* params, int32_t count, const Return* ret, CallbackType type) {
202+
int32_t result = GetReturnInt32(ret);
203+
SetReturnInt32(ret, result * 2);
204+
return ReturnAction::Override;
205+
}
206+
207+
void setup() {
208+
auto cb = HookDetour((void*)&Add, DataType::Int32, { DataType::Int32, DataType::Int32 }, -1);
209+
AddCallback(cb, CallbackType::Pre, preAdd);
210+
AddCallback(cb, CallbackType::Post, postAdd);
211+
}
212+
```
213+
214+
---
215+
216+
## Utility Functions
217+
218+
- `FindDetour`, `FindVirtual`, `FindVirtualByFunc`: Lookup hooks
219+
- `AreCallbacksRegistered`, `IsCallbackRegistered`: Introspection
220+
- `GetFunctionAddr`: Get function pointer (possibly detoured)
221+
- `GetOriginalAddr`: Get trampoline/original function
222+
223+
---
224+
225+
## Summary
226+
227+
:read-mode{title="Polyhook Header" to="https://github.com/untrustedmodders/plugify-source-2/blob/main/plugify/polyhook.hpp"}
228+
229+
| Action | Function |
230+
|---------------------|-------------------------------------------|
231+
| Hook Detour | `HookDetour` |
232+
| Hook Virtual (Index)| `HookVirtual` |
233+
| Hook Virtual (Func) | `HookVirtualByFunc` |
234+
| Add Callback | `AddCallback` |
235+
| Access Args | `GetArgumentX`, `SetArgumentX` |
236+
| Access Return | `GetReturnX`, `SetReturnX` |
237+
| Unhook | `UnhookDetour`, `UnhookVirtual`, etc. |
238+
| Get Addresses | `GetFunctionAddr`, `GetOriginalAddr` |
239+
240+
---
241+
242+
Use this guide as a reference when developing with your PolyHook-based plugin. Always validate pointer arguments and ensure type safety when casting arguments or return values.

0 commit comments

Comments
 (0)