Guest User

Untitled

a guest
Jul 19th, 2018
71
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 16.94 KB | None | 0 0
  1. // Possible defines:
  2. // CHDebug if defined, CHDebugLog is equivalent to CHLog; else, emits no code
  3. // CHUseSubstrate if defined, uses MSMessageHookEx to hook methods, otherwise uses internal hooking routines. Warning! super call closures are only available on ARM platforms for recent releases of MobileSubstrate
  4. // CHEnableProfiling if defined, enables calls to CHProfileScope()
  5. // CHAppName should be set to the name of the application (if not, defaults to "CaptainHook"); used for logging and profiling
  6.  
  7. #import <objc/runtime.h>
  8. #import <objc/message.h>
  9. #import <Foundation/NSObject.h>
  10.  
  11. #ifndef CHAppName
  12. #define CHAppName "CaptainHook"
  13. #endif
  14.  
  15. // Some Debugging/Logging Commands
  16.  
  17. #define CHStringify_(x) #x
  18. #define CHStringify(x) CHStringify_(x)
  19. #define CHConcat_(a, b) a ## b
  20. #define CHConcat(a, b) CHConcat_(a, b)
  21.  
  22. #define CHNothing() do { } while(0)
  23.  
  24. #define CHLocationInSource [NSString stringWithFormat:@CHStringify(__LINE__) " in %s", __FUNCTION__]
  25.  
  26. #define CHLog(args...) NSLog(@CHAppName ": %@", [NSString stringWithFormat:args])
  27. #define CHLogSource(args...) NSLog(@CHAppName " @ " CHStringify(__LINE__) " in %s: %@", __FUNCTION__, [NSString stringWithFormat:args])
  28.  
  29. #ifdef CHDebug
  30. #define CHDebugLog(args...) CHLog(args)
  31. #define CHDebugLogSource(args...) CHLogSource(args)
  32. #else
  33. #define CHDebugLog(args...) CHNothing()
  34. #define CHDebugLogSource(args...) CHNothing()
  35. #endif
  36.  
  37. // Constructor
  38. #define CHConstructor static __attribute__((constructor)) void CHConcat(CHConstructor, __LINE__)()
  39. #define CHInline inline __attribute__((always_inline))
  40.  
  41. // Retrieveing classes/testing against objects
  42.  
  43. #define CHDeclareClass(name) \
  44. @class name; \
  45. static id CHClass(name); \
  46. static id CHMetaClass(name); \
  47. static id CHSuperClass(name);
  48. #ifdef __cplusplus
  49. // C++ doesnt like to have multiple declarations of the same variable :(
  50. #define CHDeclareClass_(name) @class name;
  51. #else
  52. #define CHDeclareClass_(name) CHDeclareClass(name)
  53. #endif
  54. #define CHLoadLateClass(name) do { \
  55. CHClass(name) = objc_getClass(#name); \
  56. CHMetaClass(name) = object_getClass(CHClass(name)); \
  57. CHSuperClass(name) = class_getSuperclass(CHClass(name)); \
  58. } while(0)
  59. #define CHLoadClass(name) do { \
  60. CHClass(name) = [name class]; \
  61. CHMetaClass(name) = object_getClass(CHClass(name)); \
  62. CHSuperClass(name) = class_getSuperclass(CHClass(name)); \
  63. } while(0)
  64.  
  65. #define CHClass(name) name ## $
  66. #define CHMetaClass(name) name ## $m
  67. #define CHSuperClass(name) name ## $s
  68. #define CHAlloc(name) ((name *)[CHClass(name) alloc])
  69. #define CHSharedInstance(name) ((name *)[CHClass(name) sharedInstance])
  70. #define CHIsClass(obj, name) [obj isKindOfClass:CHClass(name)]
  71. #define CHRespondsTo(obj, sel) [obj respondsToSelector:@selector(sel)]
  72.  
  73. // To Load classes for hooking
  74.  
  75. #ifdef CHUseSubstrate
  76. #import <substrate.h>
  77. #define CHHookImpl(className, impName, classVar, sel) ({ \
  78. SEL selector = sel; \
  79. MSHookMessageEx(classVar, selector, (IMP)&$ ## className ## _ ## impName, (IMP *)&_ ## className ## _ ## impName); \
  80. if (!_ ## className ## _ ## impName) \
  81. class_addMethod(classVar, selector, (IMP)&$ ## className ## _ ## impName, "@@:"); \
  82. })
  83. #else
  84. #define CHHookImpl(className, impName, classVal, sel) ({ \
  85. Class classVar = classVal; \
  86. if (classVar) { \
  87. SEL selector = sel; \
  88. Method method = class_getInstanceMethod(classVar, selector); \
  89. if (method) { \
  90. _ ## className ## _ ## impName = &$$ ## className ## _ ## impName; \
  91. if (!class_addMethod(classVar, selector, (IMP)&$ ## className ## _ ## impName, method_getTypeEncoding(method))) { \
  92. _ ## className ## _ ## impName = (__typeof__(_ ## className ## _ ## impName))method_getImplementation(method); \
  93. method_setImplementation(method, (IMP)&$ ## className ## _ ## impName); \
  94. } \
  95. } else { \
  96. class_addMethod(classVar, selector, (IMP)&$ ## className ## _ ## impName, "@@:"); \
  97. } \
  98. } \
  99. })
  100. #endif
  101.  
  102. #define CHHook(class, imp) CHHookImpl(class, imp, CHClass(class), CHSelFromImpName(imp))
  103. #define CHHook0(class, name) CHHookImpl(class, name, CHClass(class), @selector(name))
  104. #define CHHook1(class, name1) CHHookImpl(class, name1 ## $, CHClass(class), @selector(name1:))
  105. #define CHHook2(class, name1, name2) CHHookImpl(class, name1 ## $ ## name2 ## $, CHClass(class), @selector(name1:name2:))
  106. #define CHHook3(class, name1, name2, name3) CHHookImpl(class, name1 ## $ ## name2 ## $ ## name3 ## $, CHClass(class), @selector(name1:name2:name3:))
  107. #define CHHook4(class, name1, name2, name3, name4) CHHookImpl(class, name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $, CHClass(class), @selector(name1:name2:name3:name4:))
  108. #define CHHook5(class, name1, name2, name3, name4, name5) CHHookImpl(class, name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $, CHClass(class), @selector(name1:name2:name3:name4:name5:))
  109.  
  110. #define CHClassHook(class, imp) CHHookImpl(class, imp, CHMetaClass(class), CHSelFromImpName(imp))
  111. #define CHClassHook0(class, name) CHHookImpl(class, name, CHMetaClass(class), @selector(name))
  112. #define CHClassHook1(class, name1) CHHookImpl(class, name1 ## $, CHMetaClass(class), @selector(name1:))
  113. #define CHClassHook2(class, name1, name2) CHHookImpl(class, name1 ## $ ## name2 ## $, CHMetaClass(class), @selector(name1:name2:))
  114. #define CHClassHook3(class, name1, name2, name3) CHHookImpl(class, name1 ## $ ## name2 ## $ ## name3 ## $, CHMetaClass(class), @selector(name1:name2:name3:))
  115. #define CHClassHook4(class, name1, name2, name3, name4) CHHookImpl(class, name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $, CHMetaClass(class), @selector(name1:name2:name3:name4:))
  116. #define CHClassHook5(class, name1, name2, name3, name4, name5) CHHookImpl(class, name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $, CHMetaClass(class), @selector(name1:name2:name3:name4:name5:))
  117.  
  118. // For Replacement Functions
  119. #ifdef CHUseSubstrate
  120. #define CHMethod_(type, class_type, class_name, name, supercall, args...) \
  121. CHDeclareClass_(class_name) \
  122. static type $ ## class_name ## _ ## name(class_type self, SEL _cmd, ##args)
  123. #else
  124. #define CHMethod_(type, class_type, class_name, name, supercall, args...) \
  125. CHDeclareClass_(class_name) \
  126. static type (*_ ## class_name ## _ ## name)(class_name *self, SEL _cmd, ##args); \
  127. static type $$ ## class_name ## _ ## name(class_name *self, SEL _cmd, ##args) { \
  128. typedef type (*supType)(id, SEL, ## args); \
  129. supType supFn = (supType)class_getMethodImplementation(CHSuperClass(class_name), _cmd); \
  130. return supFn supercall; \
  131. } \
  132. static type $ ## class_name ## _ ## name(class_type self, SEL _cmd, ##args)
  133. #endif
  134. #define CHMethod0(type, class_type, name) \
  135. CHMethod_(type, class_type *, class_type, name, (self, _cmd))
  136. #define CHMethod1(type, class_type, name1, type1, arg1) \
  137. CHMethod_(type, class_type *, class_type, name1 ## $, (self, _cmd, arg1), type1 arg1)
  138. #define CHMethod2(type, class_type, name1, type1, arg1, name2, type2, arg2) \
  139. CHMethod_(type, class_type *, class_type, name1 ## $ ## name2 ## $, (self, _cmd, arg1, arg2), type1 arg1, type2 arg2)
  140. #define CHMethod3(type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3) \
  141. CHMethod_(type, class_type *, class_type, name1 ## $ ## name2 ## $ ## name3 ## $, (self, _cmd, arg1, arg2, arg3), type1 arg1, type2 arg2, type3 arg3)
  142. #define CHMethod4(type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4) \
  143. CHMethod_(type, class_type *, class_type, name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $, (self, _cmd, arg1, arg2, arg3, arg4), type1 arg1, type2 arg2, type3 arg3, type4 arg4)
  144. #define CHMethod5(type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5) \
  145. CHMethod_(type, class_type *, class_type, name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## arg5 ## $, (self, _cmd, arg1, arg2, arg3, arg4, arg5), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5)
  146. #define CHClassMethod0(type, class_type, name) \
  147. CHMethod_(type, id, class_type, name, (self, _cmd))
  148. #define CHClassMethod1(type, class_type, name1, type1, arg1) \
  149. CHMethod_(type, id, class_type, name1 ## $, (self, _cmd, arg1), type1 arg1)
  150. #define CHClassMethod2(type, class_type, name1, type1, arg1, name2, type2, arg2) \
  151. CHMethod_(type, id, class_type, name1 ## $ ## name2 ## $, (self, _cmd, arg1, arg2), type1 arg1, type2 arg2)
  152. #define CHClassMethod3(type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3) \
  153. CHMethod_(type, id, class_type, name1 ## $ ## name2 ## $ ## name3 ## $, (self, _cmd, arg1, arg2, arg3), type1 arg1, type2 arg2, type3 arg3)
  154. #define CHClassMethod4(type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4) \
  155. CHMethod_(type, id, class_type, name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $, (self, _cmd, arg1, arg2, arg3, arg4), type1 arg1, type2 arg2, type3 arg3, type4 arg4)
  156. #define CHClassMethod5(type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5) \
  157. CHMethod_(type, id, class_type, name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## arg5 ## $, (self, _cmd, arg1, arg2, arg3, arg4, arg5), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5)
  158. #define CHSuper(class_type, _cmd, name, args...) \
  159. _ ## class_type ## _ ## name(self, _cmd, ##args)
  160. #define CHSuper0(class_type, name) \
  161. CHSuper(class_type, @selector(name), name)
  162. #define CHSuper1(class_type, name1, val1) \
  163. CHSuper(class_type, @selector(name1:), name1 ## $, val1)
  164. #define CHSuper2(class_type, name1, val1, name2, val2) \
  165. CHSuper(class_type, @selector(name1:name2:), name1 ## $ ## name2 ## $, val1, val2)
  166. #define CHSuper3(class_type, name1, val1, name2, val2, name3, val3) \
  167. CHSuper(class_type, @selector(name1:name2:name3:), name1 ## $ ## name2 ## $ ## name3 ## $, val1, val2, val3)
  168. #define CHSuper4(class_type, name1, val1, name2, val2, name3, val3, name4, val4) \
  169. CHSuper(class_type, @selector(name1:name2:name3:name4:), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $, val1, val2, val3, val4)
  170. #define CHSuper5(class_type, name1, val1, name2, val2, name3, val3, name4, val4, name5, val5) \
  171. CHSuper(class_type, @selector(name1:name2:name3:name4:name5:), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $, val1, val2, val3, val4, val5)
  172.  
  173. // Declarative-style
  174.  
  175. #define CHDeclareMethod_(type, class_type, class_name, name, supercall, sel, args...) \
  176. CHDeclareClass_(class_name) \
  177. static type (*_ ## class_name ## _ ## name)(class_name *self, SEL _cmd, ##args); \
  178. static type $$ ## class_name ## _ ## name(class_name *self, SEL _cmd, ##args); \
  179. static type $ ## class_name ## _ ## name(class_type self, SEL _cmd, ##args); \
  180. CHConstructor { \
  181. CHLoadLateClass(class_name); \
  182. CHHookImpl(class_name, name, CHClass(class_name), @selector(sel)); \
  183. } \
  184. CHMethod_(type, class_type, class_name, name, supercall, ##args)
  185. #define CHDeclareMethod0(type, class_type, name) \
  186. CHDeclareMethod_(type, class_type *, class_type, name, (self, _cmd), name)
  187. #define CHDeclareMethod1(type, class_type, name1, type1, arg1) \
  188. CHDeclareMethod_(type, class_type *, class_type, name1 ## $, (self, _cmd, arg1), name1:, type1 arg1)
  189. #define CHDeclareMethod2(type, class_type, name1, type1, arg1, name2, type2, arg2) \
  190. CHDeclareMethod_(type, class_type *, class_type, name1 ## $ ## name2 ## $, (self, _cmd, arg1, arg2), name1:name2:, type1 arg1, type2 arg2)
  191. #define CHDeclareMethod3(type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3) \
  192. CHDeclareMethod_(type, class_type *, class_type, name1 ## $ ## name2 ## $ ## name3 ## $, (self, _cmd, arg1, arg2, arg3), name1:name2:name3:, type1 arg1, type2 arg2, type3 arg3)
  193. #define CHDeclareMethod4(type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4) \
  194. CHDeclareMethod_(type, class_type *, class_type, name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $, (self, _cmd, arg1, arg2, arg3, arg4), name1:name2:name3:name4:, type1 arg1, type2 arg2, type3 arg3, type4 arg4)
  195. #define CHDeclareMethod5(type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5) \
  196. CHDeclareMethod_(type, class_type *, class_type, name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ name5 ## $, (self, _cmd, arg1, arg2, arg3, arg4, arg5), name1:name2:name3:name4:name5:, type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5)
  197.  
  198. #define CHDeclareClassMethod_(type, class_type, class_name, name, supercall, sel, args...) \
  199. CHDeclareClass_(class_name) \
  200. static type (*_ ## class_name ## _ ## name)(class_name *self, SEL _cmd, ##args); \
  201. static type $$ ## class_name ## _ ## name(class_name *self, SEL _cmd, ##args); \
  202. static type $ ## class_name ## _ ## name(class_type self, SEL _cmd, ##args); \
  203. CHConstructor { \
  204. CHLoadLateClass(class_name); \
  205. CHHookImpl(class_name, name, object_getClass(CHClass(class_name)), @selector(sel)); \
  206. } \
  207. CHMethod_(type, class_type, class_name, name, supercall, ##args)
  208. #define CHDeclareClassMethod0(type, class_type, name) \
  209. CHDeclareClassMethod_(type, id, class_type, name, (self, _cmd), name)
  210. #define CHDeclareClassMethod1(type, class_type, name1, type1, arg1) \
  211. CHDeclareClassMethod_(type, id, class_type, name1 ## $, (self, _cmd, arg1), name1:, type1 arg1)
  212. #define CHDeclareClassMethod2(type, class_type, name1, type1, arg1, name2, type2, arg2) \
  213. CHDeclareClassMethod_(type, id, class_type, name1 ## $ ## name2 ## $, (self, _cmd, arg1, arg2), name1:name2:, type1 arg1, type2 arg2)
  214. #define CHDeclareClassMethod3(type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3) \
  215. CHDeclareClassMethod_(type, id, class_type, name1 ## $ ## name2 ## $ ## name3 ## $, (self, _cmd, arg1, arg2, arg3), name1:name2:name3:, type1 arg1, type2 arg2, type3 arg3)
  216. #define CHDeclareClassMethod4(type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4) \
  217. CHDeclareClassMethod_(type, id, class_type, name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $, (self, _cmd, arg1, arg2, arg3, arg4), name1:name2:name3:name4:, type1 arg1, type2 arg2, type3 arg3, type4 arg4)
  218. #define CHDeclareClassMethod5(type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5) \
  219. CHDeclareClassMethod_(type, id, class_type, name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ name5 ## $, (self, _cmd, arg1, arg2, arg3, arg4, arg5), name1:name2:name3:name4:name5:, type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5)
  220. #define CHRegisterClass(name, superName) for (int _tmp = ({ CHClass(name) = objc_allocateClassPair(CHClass(superName), #name, 0); CHMetaClass(name) = object_getClass(CHClass(name)); CHSuperClass(name) = class_getSuperclass(CHClass(name)); 1; }); _tmp; _tmp = ({ objc_registerClassPair(CHClass(name)), 0; }))
  221.  
  222. // Add Ivar to a new class at runtime
  223. #define CHAddIvar(targetClass, name, type) \
  224. class_addIvar(targetClass, #name, sizeof(type), log2(sizeof(type)), @encode(type))
  225.  
  226. // Retrieve reference to an Ivar value (can read and assign)
  227. __attribute__((unused)) CHInline
  228. static void *CHIvar_(id object, const char *name)
  229. {
  230. Ivar ivar = class_getInstanceVariable(object_getClass(object), name);
  231. if (ivar)
  232. return (void *)&((char *)object)[ivar_getOffset(ivar)];
  233. return NULL;
  234. }
  235. #define CHIvar(object, name, type) \
  236. (*(type*)CHIvar_(object, #name))
  237. // Warning: Dereferences NULL if object is nil or name isn't found. To avoid this save &CHIvar(...) and test if != NULL
  238.  
  239. // Scope Autorelease
  240. __attribute__((unused)) CHInline
  241. static void CHScopeReleased(id sro)
  242. {
  243. [sro release];
  244. }
  245. #define CHScopeReleased \
  246. __attribute__((cleanup(CHScopeReleased)))
  247.  
  248. #ifdef __cplusplus
  249. extern "C" void *NSPushAutoreleasePool(NSUInteger capacity);
  250. extern "C" void NSPopAutoreleasePool(void *token);
  251. #else
  252. void *NSPushAutoreleasePool(NSUInteger capacity);
  253. void NSPopAutoreleasePool(void *token);
  254. #endif
  255. #define CHAutoreleasePoolForScope() \
  256. void *CHAutoreleasePoolForScope __attribute__((unused)) __attribute__((cleanup(NSPopAutoreleasePool))) = NSPushAutoreleasePool(0)
  257.  
  258. #define CHBuildAssert(condition) \
  259. ((void)sizeof(char[1 - 2*!!(condition)]))
  260.  
  261. // Profiling
  262.  
  263. #ifdef CHEnableProfiling
  264. #import <mach/mach_time.h>
  265. struct CHProfileData
  266. {
  267. NSString *message;
  268. uint64_t startTime;
  269. };
  270. __attribute__((unused)) CHInline
  271. static void CHInline CHProfileCalculateDurationAndLog(struct CHProfileData *profileData)
  272. {
  273. uint64_t duration = mach_absolute_time() - profileData->startTime;
  274. mach_timebase_info_data_t info;
  275. mach_timebase_info(&info);
  276. duration = (duration * info.numer) / info.denom;
  277. CHLog(@"Profile time: %lldns; %@", duration, profileData->message);
  278. }
  279. #define CHProfileScopeWithString(string) \
  280. struct CHProfileData _profileData __attribute__((cleanup(CHProfileCalculateDurationAndLog))) = ({ struct CHProfileData _tmp; _tmp.message = (string); _tmp.startTime = mach_absolute_time(); _tmp; })
  281. #else
  282. #define CHProfileScopeWithString(string) \
  283. CHNothing()
  284. #endif
  285. #define CHProfileScopeWithFormat(args...) \
  286. CHProfileScopeWithString(([NSString stringWithFormat:args]))
  287. #define CHProfileScope()
  288. CHProfileScopeWithFormat(@CHStringify(__LINE__) " in %s", __FUNCTION__)
Add Comment
Please, Sign In to add comment