DHHookCommon.h 4.8 KB

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