-
Notifications
You must be signed in to change notification settings - Fork 6
/
DHHookCommon.h
141 lines (128 loc) · 4.78 KB
/
DHHookCommon.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#import <DHCommon.h>
#import <substrate.h>
#import <objc/runtime.h>
#import <string.h>
/*
* Many thanks to ashikase+saurik for the original HOOK/CALL_ORIG macros.
*/
/*
* All hook names are created/specified with $ in place of : for selector names.
* init::: -> init$$$
* destroyChildren:withMethod: -> destroyChildren$withMethod$
* init -> init
*/
/*
* HOOK(class, name, type, args...)
*
* Example:
* HOOK(Class, init, id) {
* ...
* }
*
* HOOK(Class, initWithFrame$andOtherThing$, id, CGRect frame, id otherThing) {
* ...
* }
*
* Creates a static variable (in the form of _class$name) to store the original message address, and a function to replace it,
* in the form of $class$name.
* type is the return type, and args are all the message arguments, in order; args is optional.
*/
#define HOOK(class, name, type, args...) \
static type (*_ ## class ## $ ## name)(class *self, SEL sel, ## args); \
static type $ ## class ## $ ## name(class *self, SEL sel, ## args)
#define IMPLEMENTATION(class, name, type, args...) \
static type $ ## class ## $ ## name(class *self, SEL sel, ## args)
/*
* CALL_ORIG(class, name, args...)
*
* Example:
* CALL_ORIG(Class, init);
* CALL_ORIG(Class, initWithFrame$andOtherThing$, frame, otherThing);
*
* Calls an original implementation (_class$name).
*/
#define CALL_ORIG(class, name, args...) \
_ ## class ## $ ## name(self, sel, ## args)
/*
* GET_CLASS(class)
*
* Example:
* GET_CLASS(UIToolbarButton);
*
* Simply creates a variable (named $class) to store a class for the HOOK_MESSAGE_* macros.
* To avoid having to call objc_getClass over and over, and to provide a uniform naming scheme.
*/
#define GET_CLASS(class) \
Class $ ## class = objc_getClass(#class)
/*
* HOOK_MESSAGE(class, sel)
*
* Example:
* HOOK_MESSAGE(Class, init);
*
* Saves the original implementation of sel to a static variable named after _class$sel (created with HOOK), after
* replacing it with $class$sel (created with HOOK).
*
* This exists because sometimes you just want to hook a message with no args, without having to specify a replacement
* or call __getsel
*/
#define HOOK_MESSAGE(class, sel) \
_ ## class ## $ ## sel = MSHookMessage(DHClass(class), @selector(sel), &$ ## class ## $ ## sel)
#define ADD_MESSAGE(class, sel) \
MSHookMessage(DHClass(class), @selector(sel), &$ ## class ## $ ## sel)
/*
* HOOK_MESSAGE_WITH_SINGLE_ARG(class, sel)
*
* Example:
* HOOK_MESSAGE_WITH_SINGLE_ARG(Class, initWithFrame);
*
* Shorthand for HOOK_MESSAGE_REPLACEMENT(Class, sel:, sel$)
*/
#define HOOK_MESSAGE_WITH_SINGLE_ARG(class, sel) \
_ ## class ## $ ## sel ## $ = MSHookMessage(DHClass(class), @selector(sel:), &$ ## class ## $ ## sel ## $)
static inline SEL __getsel(const char *in) __attribute__((always_inline));
static inline SEL __getsel(const char *in) {
int len = strlen(in) + 1;
char selector[len];
for(int i = 0; i < len; i++)
selector[i] = (in[i] == '$' ? ':' : in[i]);
return sel_getUid(selector);
}
/*
* HOOK_MESSAGE_AUTO(class, replace)
*
* Example:
* HOOK_MESSAGE_AUTO(Class, initWithFrame$andOtherThing$andAnotherThing$);
*
* Beware, __getsel (string copy/transform) is called every time this macro is used.
* Automatically turns a replacement selector in the $ format into a SEL, as a shorter form of HOOK_MESSAGE_REPLACEMENT.
*
* Saves the original implementation to a static variable named after _class$replace (created with HOOK), after
* replacing it with $class$replace (created with HOOK).
*/
#define HOOK_MESSAGE_AUTO(class, replace) \
_ ## class ## $ ## replace = MSHookMessage(DHClass(class), __getsel(#replace), &$ ## class ## $ ## replace)
#define ADD_MESSAGE_AUTO(class, replace) \
MSHookMessage(DHClass(class), __getsel(#replace), &$ ## class ## $ ## replace)
/*
* HOOK_MESSAGE_REPLACEMENT(class, sel, replace)
*
* Example:
* HOOK_MESSAGE_REPLACEMENT(Class, initWithFrame:andOtherThing:andAnotherThing:, initWithFrame$andOtherThing$andAnotherThing$);
*
* Saves the original implementation to a static variable named after _class$replace (created with HOOK), after
* replacing it with $class$replace (created with HOOK).
*/
#define HOOK_MESSAGE_REPLACEMENT(class, sel, replace) \
_ ## class ## $ ## replace = MSHookMessage(DHClass(class), @selector(sel), &$ ## class ## $ ## replace)
#define ADD_MESSAGE_REPLACEMENT(class, sel, replace) \
MSHookMessage(DHClass(class), @selector(sel), &$ ## class ## $ ## replace)
#define HOOK_MESSAGE_ARGS HOOK_MESSAGE_WITH_SINGLE_ARG
#define HOOK_MESSAGE_EX HOOK_MESSAGE_AUTO
#define HOOK_MESSAGE_F HOOK_MESSAGE_REPLACEMENT
#define ADD_MESSAGE_F ADD_MESSAGE_REPLACEMENT
#define DHGetClass GET_CLASS
#define DHHookMessageWithReplacement HOOK_MESSAGE_REPLACEMENT
#define DHHookMessageWithAutoRename HOOK_MESSAGE_AUTO
#define DHHookMessage HOOK_MESSAGE_AUTO
#define DHAddMessage ADD_MESSAGE_AUTO