├── .gitignore ├── .gitmodules ├── Compat.m ├── Core.m ├── Headers ├── HookKit.h └── HookKit │ ├── Compat.h │ ├── Core.h │ ├── Hook.h │ ├── Module+Internal.h │ └── Module.h ├── Hook.m ├── HookKit.tbd ├── LICENSE ├── Makefile ├── Module+Internal.m ├── Module.m ├── Modules ├── Dobby.bundle │ ├── HKDobby.h │ ├── HKDobby.m │ ├── Makefile │ ├── Module.m │ ├── Resources │ │ ├── Info.plist │ │ └── LICENSE │ ├── control │ └── vendor │ │ ├── HookKit.framework │ │ └── dobby │ │ ├── dobby.h │ │ └── libdobby.a ├── fishhook.bundle │ ├── HKFH.h │ ├── HKFH.m │ ├── Makefile │ ├── Module.m │ ├── Resources │ │ ├── Info.plist │ │ └── LICENSE │ ├── control │ └── vendor │ │ └── HookKit.framework ├── libellekit.bundle │ ├── HKElleKit.h │ ├── HKElleKit.m │ ├── Makefile │ ├── Module.m │ ├── Resources │ │ └── Info.plist │ ├── control │ └── vendor │ │ ├── HookKit.framework │ │ ├── lib_ellekit.tbd │ │ └── libhooker │ │ ├── libblackjack.h │ │ └── libhooker.h ├── libhooker.bundle │ ├── HKLH.h │ ├── HKLH.m │ ├── Makefile │ ├── Module.m │ ├── Resources │ │ └── Info.plist │ ├── control │ └── vendor │ │ ├── HookKit.framework │ │ └── libhooker │ │ ├── lib_blackjack.tbd │ │ ├── lib_libhooker.tbd │ │ ├── libblackjack.h │ │ └── libhooker.h ├── libsubstitute.bundle │ ├── HKSubstitute.h │ ├── HKSubstitute.m │ ├── Makefile │ ├── Module.m │ ├── Resources │ │ └── Info.plist │ ├── control │ └── vendor │ │ ├── HookKit.framework │ │ ├── _CydiaSubstrate.framework │ │ └── _CydiaSubstrate.tbd │ │ ├── substitute │ │ ├── lib_substitute.tbd │ │ └── substitute.h │ │ └── substrate │ │ └── substrate.h └── libsubstrate.bundle │ ├── HKSubstrate.h │ ├── HKSubstrate.m │ ├── Makefile │ ├── Module.m │ ├── Resources │ └── Info.plist │ ├── control │ └── vendor │ ├── HookKit.framework │ ├── _CydiaSubstrate.framework │ └── _CydiaSubstrate.tbd │ └── substrate │ └── substrate.h ├── README.md ├── Resources └── Info.plist ├── build.sh └── control /.gitignore: -------------------------------------------------------------------------------- 1 | .theos/ 2 | packages/ 3 | build/ 4 | .DS_Store 5 | .vscode/ 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Modules/fishhook.bundle/vendor/fishhook"] 2 | path = Modules/fishhook.bundle/vendor/fishhook 3 | url = https://github.com/facebook/fishhook.git 4 | [submodule "vendor/Modulous.framework"] 5 | path = vendor/Modulous.framework 6 | url = https://github.com/jjolano/Modulous.git 7 | [submodule "vendor/RootBridge.framework"] 8 | path = vendor/RootBridge.framework 9 | url = https://github.com/jjolano/RootBridge.git 10 | -------------------------------------------------------------------------------- /Compat.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import 5 | 6 | @implementation HKSubstitutor { 7 | NSMutableArray<__kindof HookKitHook *>* batchHooks; 8 | __kindof HookKitModule* module; 9 | } 10 | 11 | @synthesize types, batching; 12 | 13 | - (instancetype)init { 14 | if((self = [super init])) { 15 | batchHooks = [NSMutableArray new]; 16 | module = nil; 17 | types = 0; 18 | } 19 | 20 | return self; 21 | } 22 | 23 | - (void)initLibraries { 24 | HookKitCore* core = [HookKitCore sharedInstance]; 25 | module = [core defaultModule]; 26 | 27 | if(types != 0) { 28 | NSArray* typeinfo = [[self class] getSubstitutorTypeInfo:types]; 29 | 30 | if([typeinfo count]) { 31 | module = [core getModuleWithIdentifier:[typeinfo[0] objectForKey:@"id"]]; 32 | } 33 | } 34 | } 35 | 36 | + (hookkit_lib_t)getAvailableSubstitutorTypes { 37 | hookkit_lib_t types = 0; 38 | 39 | HookKitCore* core = [HookKitCore sharedInstance]; 40 | hookkit_lib_t type = 1; 41 | 42 | NSArray* module_infos = [core getModuleInfo]; 43 | 44 | for(__unused NSDictionary* module_info in module_infos) { 45 | types |= type; 46 | type = type * 2; 47 | } 48 | 49 | return types; 50 | } 51 | 52 | + (NSArray *)getSubstitutorTypeInfo:(hookkit_lib_t)types { 53 | NSMutableArray* result = [NSMutableArray new]; 54 | 55 | HookKitCore* core = [HookKitCore sharedInstance]; 56 | hookkit_lib_t type = 1; 57 | 58 | NSArray* module_infos = [core getModuleInfo]; 59 | 60 | for(NSDictionary* module_info in module_infos) { 61 | if((types & type) == type) { 62 | [result addObject:@{ 63 | @"id" : module_info[@"Identifier"], 64 | @"name" : module_info[@"Description"], 65 | @"type" : @(type) 66 | }]; 67 | } 68 | 69 | type = type * 2; 70 | } 71 | 72 | return [result copy]; 73 | } 74 | 75 | + (instancetype)substitutorWithTypes:(hookkit_lib_t)types { 76 | HKSubstitutor* substitutor = [self new]; 77 | [substitutor setTypes:types]; 78 | [substitutor initLibraries]; 79 | return substitutor; 80 | } 81 | 82 | + (instancetype)defaultSubstitutor { 83 | static HKSubstitutor* defaultSubstitutor = nil; 84 | static dispatch_once_t onceToken = 0; 85 | 86 | dispatch_once(&onceToken, ^{ 87 | defaultSubstitutor = [self new]; 88 | [defaultSubstitutor initLibraries]; 89 | }); 90 | 91 | return defaultSubstitutor; 92 | } 93 | 94 | - (hookkit_status_t)hookMessageInClass:(Class)objcClass withSelector:(SEL)selector withReplacement:(void *)replacement outOldPtr:(void **)old_ptr { 95 | HookKitClassHook* hook = [HookKitClassHook hook:objcClass selector:selector replacement:replacement orig:old_ptr]; 96 | 97 | if(batching) { 98 | [batchHooks addObject:hook]; 99 | return HK_OK; 100 | } 101 | 102 | return [module executeHook:hook] ? HK_OK : HK_ERR_NOT_SUPPORTED; 103 | } 104 | 105 | - (hookkit_status_t)hookFunction:(void *)function withReplacement:(void *)replacement outOldPtr:(void **)old_ptr { 106 | HookKitFunctionHook* hook = [HookKitFunctionHook hook:function replacement:replacement orig:old_ptr]; 107 | 108 | if(batching) { 109 | [batchHooks addObject:hook]; 110 | return HK_OK; 111 | } 112 | 113 | return [module executeHook:hook] ? HK_OK : HK_ERR_NOT_SUPPORTED; 114 | } 115 | 116 | - (hookkit_status_t)hookMemory:(void *)target withData:(const void *)data size:(size_t)size { 117 | HookKitMemoryHook* hook = [HookKitMemoryHook hook:target data:data size:size]; 118 | 119 | if(batching) { 120 | [batchHooks addObject:hook]; 121 | return HK_OK; 122 | } 123 | 124 | return [module executeHook:hook] ? HK_OK : HK_ERR_NOT_SUPPORTED; 125 | } 126 | 127 | - (HKImageRef)openImage:(NSString *)path { 128 | return (HKImageRef)[module openImageWithPath:path]; 129 | } 130 | 131 | - (void)closeImage:(HKImageRef)image { 132 | [module closeImage:(hookkit_image_t)image]; 133 | } 134 | 135 | - (hookkit_status_t)findSymbolsInImage:(HKImageRef)image symbolNames:(NSArray *)symbolNames outSymbols:(NSArray **)outSymbols { 136 | NSMutableArray* outSyms = [NSMutableArray new]; 137 | 138 | for(NSString* symbolName in symbolNames) { 139 | [outSyms addObject:[NSValue valueWithPointer:[self findSymbolInImage:image symbolName:symbolName]]]; 140 | } 141 | 142 | *outSymbols = [outSyms copy]; 143 | return HK_OK; 144 | } 145 | 146 | - (void *)findSymbolInImage:(HKImageRef)image symbolName:(NSString *)symbolName { 147 | return [module findSymbolName:symbolName inImage:(hookkit_image_t)image]; 148 | } 149 | 150 | - (hookkit_status_t)executeHooks { 151 | int result = [module executeHooks:batchHooks]; 152 | [batchHooks removeAllObjects]; 153 | 154 | return result ? HK_OK : HK_ERR; 155 | } 156 | 157 | - (int)getLibErrno:(hookkit_lib_t *)outType { 158 | return 0; 159 | } 160 | @end 161 | -------------------------------------------------------------------------------- /Core.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | 5 | @implementation HookKitCore { 6 | ModulousLoader* loader; 7 | NSMutableDictionary* registeredModules; 8 | } 9 | 10 | + (instancetype)sharedInstance { 11 | static HookKitCore* sharedInstance = nil; 12 | static dispatch_once_t onceToken = 0; 13 | 14 | dispatch_once(&onceToken, ^{ 15 | sharedInstance = [self new]; 16 | }); 17 | 18 | return sharedInstance; 19 | } 20 | 21 | - (__kindof HookKitModule *)defaultModule { 22 | static __kindof HookKitModule* defaultModule = nil; 23 | static dispatch_once_t onceToken = 0; 24 | 25 | dispatch_once(&onceToken, ^{ 26 | // load the highest priority module 27 | NSArray* modulous_infos = [[loader getModuleInfo] sortedArrayUsingComparator:^NSComparisonResult(NSDictionary* a, NSDictionary* b) { 28 | NSDictionary* info_a = [a objectForKey:@"ModuleInfo"]; 29 | NSDictionary* info_b = [b objectForKey:@"ModuleInfo"]; 30 | NSNumber* prio_a = [info_a objectForKey:@"Priority"]; 31 | NSNumber* prio_b = [info_b objectForKey:@"Priority"]; 32 | 33 | if(!prio_a) { 34 | prio_a = @(100); 35 | } 36 | 37 | if(!prio_b) { 38 | prio_b = @(100); 39 | } 40 | 41 | return [prio_a compare:prio_b]; 42 | }]; 43 | 44 | if(modulous_infos) { 45 | for(NSDictionary* modulous_info in modulous_infos) { 46 | NSString* modulous_identifier = [modulous_info objectForKey:@"CFBundleIdentifier"]; 47 | NSDictionary* info = [modulous_info objectForKey:@"ModuleInfo"]; 48 | 49 | if(info) { 50 | NSString* module_identifier = [info objectForKey:@"Identifier"]; 51 | 52 | [loader loadModulesWithIdentifiers:@[modulous_identifier]]; 53 | defaultModule = [self getModuleWithIdentifier:module_identifier]; 54 | } 55 | 56 | if(defaultModule) { 57 | break; 58 | } 59 | } 60 | } 61 | }); 62 | 63 | return defaultModule; 64 | } 65 | 66 | - (NSArray *)getModuleInfo { 67 | NSMutableArray* infos = [NSMutableArray new]; 68 | NSArray* modulous_infos = [loader getModuleInfo]; 69 | 70 | if(modulous_infos) { 71 | for(NSDictionary* modulous_info in modulous_infos) { 72 | NSDictionary* info = [modulous_info objectForKey:@"ModuleInfo"]; 73 | 74 | if(info) { 75 | [infos addObject:info]; 76 | } 77 | } 78 | } 79 | 80 | return [infos copy]; 81 | } 82 | 83 | - (NSDictionary *)getModuleInfoWithIdentifier:(NSString *)identifier { 84 | NSArray* modulous_infos = [loader getModuleInfo]; 85 | 86 | if(modulous_infos) { 87 | for(NSDictionary* modulous_info in modulous_infos) { 88 | NSDictionary* info = [modulous_info objectForKey:@"ModuleInfo"]; 89 | 90 | if(info && [[info objectForKey:@"Identifier"] isEqualToString:identifier]) { 91 | return info; 92 | } 93 | } 94 | } 95 | 96 | return nil; 97 | } 98 | 99 | - (__kindof HookKitModule *)getModuleWithIdentifier:(NSString *)identifier { 100 | __kindof HookKitModule* result = nil; 101 | 102 | @synchronized(registeredModules) { 103 | result = [registeredModules objectForKey:identifier]; 104 | } 105 | 106 | if(!result) { 107 | NSArray* modulous_infos = [loader getModuleInfo]; 108 | 109 | if(modulous_infos) { 110 | for(NSDictionary* modulous_info in modulous_infos) { 111 | NSString* modulous_identifier = [modulous_info objectForKey:@"CFBundleIdentifier"]; 112 | NSDictionary* info = [modulous_info objectForKey:@"ModuleInfo"]; 113 | 114 | if(info && [[info objectForKey:@"Identifier"] isEqualToString:identifier]) { 115 | // load module with modulous 116 | [loader loadModulesWithIdentifiers:@[modulous_identifier]]; 117 | } 118 | } 119 | } 120 | 121 | @synchronized(registeredModules) { 122 | result = [registeredModules objectForKey:identifier]; 123 | } 124 | } 125 | 126 | return result; 127 | } 128 | 129 | - (void)registerModule:(__kindof HookKitModule *)module withIdentifier:(NSString *)identifier { 130 | if(module && identifier) { 131 | @synchronized(registeredModules) { 132 | [registeredModules setObject:module forKey:identifier]; 133 | } 134 | } 135 | } 136 | 137 | - (instancetype)init { 138 | if((self = [super init])) { 139 | loader = [ModulousLoader loaderWithPath:[RootBridge getJBPath:@"/Library/Modulous/HookKit"]]; 140 | registeredModules = [NSMutableDictionary new]; 141 | } 142 | 143 | return self; 144 | } 145 | @end -------------------------------------------------------------------------------- /Headers/HookKit.h: -------------------------------------------------------------------------------- 1 | #ifndef hookkit_h 2 | #define hookkit_h 3 | 4 | #import 5 | #import 6 | #import 7 | #import 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /Headers/HookKit/Compat.h: -------------------------------------------------------------------------------- 1 | #ifndef hookkit_compat_h 2 | #define hookkit_compat_h 3 | 4 | #import 5 | 6 | typedef enum { 7 | HK_OK = 0, 8 | HK_ERR = (1 << 0), 9 | HK_ERR_NOT_SUPPORTED = (1 << 1) 10 | } hookkit_status_t; 11 | 12 | typedef enum { 13 | HK_LIB_NONE = 0 14 | } hookkit_lib_t; 15 | 16 | typedef const struct HKImage* HKImageRef; 17 | 18 | @interface HKSubstitutor : NSObject 19 | @property (assign, nonatomic) hookkit_lib_t types; 20 | @property (assign, nonatomic) BOOL batching; 21 | 22 | // Internally loads selected hooking libraries and resolves symbols. Use if setting the types property manually after instance creation. 23 | - (void)initLibraries; 24 | 25 | // Returns an integer representing available substitutor types on the system. Use getSubstitutorTypeInfo to receive an array for more details. 26 | + (hookkit_lib_t)getAvailableSubstitutorTypes; 27 | 28 | // Returns an array of dictionaries containing information on given substitutor types, as supported by the running version of HookKit. 29 | + (NSArray *)getSubstitutorTypeInfo:(hookkit_lib_t)types; 30 | 31 | // Creates an instance of HKSubstitutor with given substitutor types. 32 | + (instancetype)substitutorWithTypes:(hookkit_lib_t)types; 33 | 34 | // Creates an instance of HKSubstitutor using the currently loaded substitutor. 35 | + (instancetype)defaultSubstitutor; 36 | 37 | // Hook method for Objective-C runtime methods. Returns HK_OK if successful. 38 | - (hookkit_status_t)hookMessageInClass:(Class)objcClass withSelector:(SEL)selector withReplacement:(void *)replacement outOldPtr:(void **)old_ptr; 39 | 40 | // Hook method for C functions. Executes immediately if batching property is disabled. Returns HK_OK if successful. 41 | - (hookkit_status_t)hookFunction:(void *)function withReplacement:(void *)replacement outOldPtr:(void **)old_ptr; 42 | 43 | // Hook method for memory patching. Executes immediately if batching property is disabled. Returns HK_OK if successful. 44 | - (hookkit_status_t)hookMemory:(void *)target withData:(const void *)data size:(size_t)size; 45 | 46 | // Returns an opaque pointer to an image for use with findSymbol(s)InImage methods, or NULL if unsuccessful. 47 | - (HKImageRef)openImage:(NSString *)path; 48 | 49 | // Closes the image handle from openImage. 50 | - (void)closeImage:(HKImageRef)image; 51 | 52 | // Locates private symbols within a given image, and outputs results to outSymbols. image == NULL is supported if the hooking library implements MSFindSymbol. Returns HK_OK if successful. 53 | - (hookkit_status_t)findSymbolsInImage:(HKImageRef)image symbolNames:(NSArray *)symbolNames outSymbols:(NSArray **)outSymbols; 54 | 55 | // Just like findSymbolsInImage, but for one symbol. Returns the symbol address, or NULL if not found. 56 | - (void *)findSymbolInImage:(HKImageRef)image symbolName:(NSString *)symbolName; 57 | 58 | // If batching property is enabled, performs all hooks made with batching (if supported) prior to this method being called. Returns HK_OK if successful. 59 | - (hookkit_status_t)executeHooks; 60 | 61 | // Returns the error number returned by the last hook method call, if available. 62 | - (int)getLibErrno:(hookkit_lib_t *)outType; 63 | @end 64 | 65 | // C-style macros for convenience 66 | #ifndef HK_SUBSTITUTOR 67 | #define HK_SUBSTITUTOR [HKSubstitutor defaultSubstitutor] 68 | #endif 69 | 70 | #define HKEnableBatching() [HK_SUBSTITUTOR setBatching:YES] 71 | #define HKDisableBatching() [HK_SUBSTITUTOR setBatching:NO] 72 | #define HKExecuteBatch() [HK_SUBSTITUTOR executeHooks] 73 | 74 | #define HKHookFunction(_symbol, _replace, _result) [HK_SUBSTITUTOR hookFunction:_symbol withReplacement:_replace outOldPtr:_result] 75 | #define HKHookMemory(_target, _data, _size) [HK_SUBSTITUTOR hookMemory:_target withData:_data size:_size] 76 | #define HKHookMessage(_class, _sel, _imp, _result) [HK_SUBSTITUTOR hookMessageInClass:_class withSelector:_sel withReplacement:_imp outOldPtr:(void **)_result] 77 | 78 | #define HKOpenImage(_path) (void *)[HK_SUBSTITUTOR openImage:@(_path)] 79 | #define HKCloseImage(_image) [HK_SUBSTITUTOR closeImage:(HKImageRef)_image] 80 | #define HKFindSymbol(_image, _sym) [HK_SUBSTITUTOR findSymbolInImage:(HKImageRef)_image symbolName:@(_sym)] 81 | #endif 82 | -------------------------------------------------------------------------------- /Headers/HookKit/Core.h: -------------------------------------------------------------------------------- 1 | #ifndef hookkit_core_h 2 | #define hookkit_core_h 3 | 4 | #import 5 | #import 6 | 7 | @interface HookKitCore : NSObject 8 | + (instancetype)sharedInstance; 9 | - (__kindof HookKitModule *)defaultModule; 10 | 11 | - (NSArray *)getModuleInfo; 12 | - (NSDictionary *)getModuleInfoWithIdentifier:(NSString *)identifier; 13 | 14 | - (__kindof HookKitModule *)getModuleWithIdentifier:(NSString *)identifier; 15 | 16 | - (void)registerModule:(__kindof HookKitModule *)module withIdentifier:(NSString *)identifier; 17 | @end 18 | #endif 19 | -------------------------------------------------------------------------------- /Headers/HookKit/Hook.h: -------------------------------------------------------------------------------- 1 | #ifndef hookkit_hook_h 2 | #define hookkit_hook_h 3 | 4 | #import 5 | 6 | @interface HookKitHook : NSObject 7 | @end 8 | 9 | @interface HookKitClassHook : HookKitHook 10 | @property (assign, nonatomic) Class objcClass; 11 | @property (assign, nonatomic) SEL selector; 12 | @property (assign, nonatomic) void* replacement; 13 | @property (assign, nonatomic) void** orig; 14 | 15 | + (instancetype)hook:(Class)objcClass selector:(SEL)selector replacement:(void *)replacement orig:(void **)orig; 16 | @end 17 | 18 | @interface HookKitFunctionHook : HookKitHook 19 | @property (assign, nonatomic) void* function; 20 | @property (assign, nonatomic) void* replacement; 21 | @property (assign, nonatomic) void** orig; 22 | 23 | + (instancetype)hook:(void *)function replacement:(void *)replacement orig:(void **)orig; 24 | @end 25 | 26 | @interface HookKitMemoryHook : HookKitHook 27 | @property (assign, nonatomic) void* target; 28 | @property (assign, nonatomic) const void* data; 29 | @property (assign, nonatomic) size_t size; 30 | 31 | + (instancetype)hook:(void *)target data:(const void *)data size:(size_t)size; 32 | @end 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /Headers/HookKit/Module+Internal.h: -------------------------------------------------------------------------------- 1 | #ifndef hookkit_module_internal_h 2 | #define hookkit_module_internal_h 3 | 4 | #import 5 | #import 6 | #import 7 | 8 | @interface HookKitModule (Internal) 9 | - (BOOL)_hookClass:(Class)objcClass selector:(SEL)selector replacement:(void *)replacement orig:(void **)orig; 10 | - (BOOL)_hookFunction:(void *)function replacement:(void *)replacement orig:(void **)orig; 11 | - (int)_hookFunctions:(NSArray *)functions; 12 | - (BOOL)_hookRegion:(void *)target data:(const void *)data size:(size_t)size; 13 | - (int)_hookRegions:(NSArray *)regions; 14 | 15 | - (void *)_openImage:(const char *)path; 16 | - (void)_closeImage:(void *)image; 17 | 18 | - (void *)_findSymbol:(const char *)symbol image:(void *)image; 19 | @end 20 | #endif 21 | -------------------------------------------------------------------------------- /Headers/HookKit/Module.h: -------------------------------------------------------------------------------- 1 | #ifndef hookkit_module_h 2 | #define hookkit_module_h 3 | 4 | #import 5 | #import 6 | 7 | typedef const struct HKImage* hookkit_image_t; 8 | 9 | @interface HookKitModule : NSObject 10 | @property (assign, nonatomic) BOOL functionHookBatchingSupported; 11 | @property (assign, nonatomic) BOOL memoryHookBatchingSupported; 12 | @property (assign, nonatomic) BOOL nullImageSearchSupported; 13 | 14 | - (BOOL)executeHook:(__kindof HookKitHook *)hook; 15 | - (int)executeHooks:(NSArray<__kindof HookKitHook *> *)hooks; 16 | 17 | - (hookkit_image_t)openImageWithURL:(NSURL *)url; 18 | - (hookkit_image_t)openImageWithPath:(NSString *)path; 19 | - (void)closeImage:(hookkit_image_t)image; 20 | 21 | - (void *)findSymbolName:(NSString *)name; 22 | - (void *)findSymbolName:(NSString *)name inImage:(hookkit_image_t)image; 23 | @end 24 | #endif 25 | -------------------------------------------------------------------------------- /Hook.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @implementation HookKitHook 4 | @end 5 | 6 | @implementation HookKitClassHook 7 | @synthesize objcClass, selector, replacement, orig; 8 | 9 | + (instancetype)hook:(Class)objcClass selector:(SEL)selector replacement:(void *)replacement orig:(void **)orig { 10 | HookKitClassHook* hook = [HookKitClassHook new]; 11 | 12 | [hook setObjcClass:objcClass]; 13 | [hook setSelector:selector]; 14 | [hook setReplacement:replacement]; 15 | [hook setOrig:orig]; 16 | 17 | return hook; 18 | } 19 | @end 20 | 21 | @implementation HookKitFunctionHook 22 | @synthesize function, replacement, orig; 23 | 24 | + (instancetype)hook:(void *)function replacement:(void *)replacement orig:(void **)orig { 25 | HookKitFunctionHook* hook = [HookKitFunctionHook new]; 26 | 27 | [hook setFunction:function]; 28 | [hook setReplacement:replacement]; 29 | [hook setOrig:orig]; 30 | 31 | return hook; 32 | } 33 | @end 34 | 35 | @implementation HookKitMemoryHook 36 | @synthesize target, data, size; 37 | 38 | + (instancetype)hook:(void *)target data:(const void *)data size:(size_t)size { 39 | HookKitMemoryHook* hook = [HookKitMemoryHook new]; 40 | 41 | [hook setTarget:target]; 42 | [hook setData:data]; 43 | [hook setSize:size]; 44 | 45 | return hook; 46 | } 47 | @end 48 | -------------------------------------------------------------------------------- /HookKit.tbd: -------------------------------------------------------------------------------- 1 | --- 2 | archs: [ armv7, armv7s, arm64, arm64e ] 3 | platform: ios 4 | install-name: '@rpath/HookKit.framework/HookKit' 5 | current-version: 0 6 | compatibility-version: 0 7 | exports: 8 | - archs: [ armv7, armv7s, arm64, arm64e ] 9 | objc-classes: [ _HookKitCore, _HookKitModule, _HookKitHook, 10 | _HookKitFunctionHook, _HookKitMemoryHook, 11 | _HookKitClassHook, _HKSubstitutor ] 12 | ... 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2022, jjolano 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ARCHS ?= armv7 armv7s arm64 arm64e 2 | TARGET ?= iphone:clang:14.5:8.0 3 | 4 | include $(THEOS)/makefiles/common.mk 5 | 6 | FRAMEWORK_NAME = HookKit 7 | 8 | HookKit_FILES = Core.m Module.m Module+Internal.m Hook.m Compat.m 9 | HookKit_FRAMEWORKS = Foundation 10 | HookKit_EXTRA_FRAMEWORKS = Modulous RootBridge 11 | HookKit_INSTALL_PATH = /Library/Frameworks 12 | HookKit_CFLAGS = -fobjc-arc -IHeaders -Ivendor/Modulous.framework/Headers -Ivendor/RootBridge.framework/Headers 13 | HookKit_LDFLAGS = -Fvendor -install_name @rpath/HookKit.framework/HookKit 14 | HookKit_LDFLAGS += -rpath /Library/Frameworks -rpath /var/jb/Library/Frameworks -rpath /usr/lib -rpath /var/jb/usr/lib 15 | 16 | include $(THEOS_MAKE_PATH)/framework.mk 17 | -------------------------------------------------------------------------------- /Module+Internal.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @implementation HookKitModule (Internal) 5 | - (BOOL)_hookClass:(Class)objcClass selector:(SEL)selector replacement:(void *)replacement orig:(void **)orig { 6 | __kindof HookKitModule* module = [[HookKitCore sharedInstance] defaultModule]; 7 | 8 | if(module && module != self) { 9 | return [module _hookClass:objcClass selector:selector replacement:replacement orig:orig]; 10 | } 11 | 12 | return NO; 13 | } 14 | 15 | - (BOOL)_hookFunction:(void *)function replacement:(void *)replacement orig:(void **)orig { 16 | __kindof HookKitModule* module = [[HookKitCore sharedInstance] defaultModule]; 17 | 18 | if(module && module != self) { 19 | return [module _hookFunction:function replacement:replacement orig:orig]; 20 | } 21 | 22 | return NO; 23 | } 24 | 25 | - (int)_hookFunctions:(NSArray *)functions { 26 | __kindof HookKitModule* module = [[HookKitCore sharedInstance] defaultModule]; 27 | 28 | if(module && module != self) { 29 | return [module _hookFunctions:functions]; 30 | } 31 | 32 | return -1; 33 | } 34 | 35 | - (BOOL)_hookRegion:(void *)target data:(const void *)data size:(size_t)size { 36 | __kindof HookKitModule* module = [[HookKitCore sharedInstance] defaultModule]; 37 | 38 | if(module && module != self) { 39 | return [module _hookRegion:target data:data size:size]; 40 | } 41 | 42 | return NO; 43 | } 44 | 45 | - (int)_hookRegions:(NSArray *)regions { 46 | __kindof HookKitModule* module = [[HookKitCore sharedInstance] defaultModule]; 47 | 48 | if(module && module != self) { 49 | return [module _hookRegions:regions]; 50 | } 51 | 52 | return -1; 53 | } 54 | 55 | - (void *)_openImage:(const char *)path { 56 | __kindof HookKitModule* module = [[HookKitCore sharedInstance] defaultModule]; 57 | 58 | if(module && module != self) { 59 | return [module _openImage:path]; 60 | } 61 | 62 | return NULL; 63 | } 64 | 65 | - (void)_closeImage:(void *)image { 66 | __kindof HookKitModule* module = [[HookKitCore sharedInstance] defaultModule]; 67 | 68 | if(module && module != self) { 69 | return [module _closeImage:image]; 70 | } 71 | } 72 | 73 | - (void *)_findSymbol:(const char *)symbol image:(void *)image { 74 | __kindof HookKitModule* module = [[HookKitCore sharedInstance] defaultModule]; 75 | 76 | if(module && module != self) { 77 | return [module _findSymbol:symbol image:image]; 78 | } 79 | 80 | return NULL; 81 | } 82 | @end 83 | -------------------------------------------------------------------------------- /Module.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | 5 | #import 6 | 7 | @implementation HookKitModule 8 | @synthesize functionHookBatchingSupported, memoryHookBatchingSupported, nullImageSearchSupported; 9 | 10 | - (BOOL)executeHook:(__kindof HookKitHook *)hook { 11 | if([hook isKindOfClass:[HookKitClassHook class]]) { 12 | HookKitClassHook* classHook = hook; 13 | return [self _hookClass:[classHook objcClass] selector:[classHook selector] replacement:[classHook replacement] orig:[classHook orig]]; 14 | } 15 | 16 | if([hook isKindOfClass:[HookKitFunctionHook class]]) { 17 | HookKitFunctionHook* functionHook = hook; 18 | return [self _hookFunction:[functionHook function] replacement:[functionHook replacement] orig:[functionHook orig]]; 19 | } 20 | 21 | if([hook isKindOfClass:[HookKitMemoryHook class]]) { 22 | HookKitMemoryHook* memoryHook = hook; 23 | return [self _hookRegion:[memoryHook target] data:[memoryHook data] size:[memoryHook size]]; 24 | } 25 | 26 | return NO; 27 | } 28 | 29 | - (int)executeHooks:(NSArray<__kindof HookKitHook *> *)hooks { 30 | int total = [hooks count]; 31 | int result = 0; 32 | 33 | NSMutableArray* functionHooks = [self functionHookBatchingSupported] ? [NSMutableArray new] : nil; 34 | NSMutableArray* memoryHooks = [self memoryHookBatchingSupported] ? [NSMutableArray new] : nil; 35 | 36 | for(__kindof HookKitHook* hook in hooks) { 37 | if([hook isKindOfClass:[HookKitClassHook class]]) { 38 | if([self executeHook:hook]) { 39 | result += 1; 40 | } 41 | 42 | continue; 43 | } 44 | 45 | if([hook isKindOfClass:[HookKitFunctionHook class]]) { 46 | if(functionHooks) { 47 | [functionHooks addObject:hook]; 48 | } else { 49 | if([self executeHook:hook]) { 50 | result += 1; 51 | } 52 | } 53 | 54 | continue; 55 | } 56 | 57 | if([hook isKindOfClass:[HookKitMemoryHook class]]) { 58 | if(memoryHooks) { 59 | [memoryHooks addObject:hook]; 60 | } else { 61 | if([self executeHook:hook]) { 62 | result += 1; 63 | } 64 | } 65 | 66 | continue; 67 | } 68 | } 69 | 70 | if(functionHooks) { 71 | result += [self _hookFunctions:functionHooks]; 72 | } 73 | 74 | if(memoryHooks) { 75 | result += [self _hookRegions:memoryHooks]; 76 | } 77 | 78 | if(result < total) { 79 | NSLog(@"[HookKit] warning: successfully hooked less than expected (%d/%lu)", result, (unsigned long)total); 80 | } 81 | 82 | return result; 83 | } 84 | 85 | - (hookkit_image_t)openImageWithURL:(NSURL *)url { 86 | if(!url) { 87 | return NULL; 88 | } 89 | 90 | return (hookkit_image_t)[self _openImage:[[url path] fileSystemRepresentation]]; 91 | } 92 | 93 | - (hookkit_image_t)openImageWithPath:(NSString *)path { 94 | if(!path) { 95 | return NULL; 96 | } 97 | 98 | NSURL* file_url = [NSURL fileURLWithPath:path isDirectory:NO]; 99 | return [self openImageWithURL:file_url]; 100 | } 101 | 102 | - (void)closeImage:(hookkit_image_t)image { 103 | if(image) { 104 | [self _closeImage:(void *)image]; 105 | } 106 | } 107 | 108 | - (void *)findSymbolName:(NSString *)name { 109 | if(!name) { 110 | return NULL; 111 | } 112 | 113 | return [self findSymbolName:name inImage:NULL]; 114 | } 115 | 116 | - (void *)findSymbolName:(NSString *)name inImage:(hookkit_image_t)image { 117 | if(!name) { 118 | return NULL; 119 | } 120 | 121 | if([self nullImageSearchSupported] || image) { 122 | return [self _findSymbol:[name UTF8String] image:(void *)image]; 123 | } 124 | 125 | // iterate through all loaded dyld images and call findSymbol 126 | int count = _dyld_image_count(); 127 | 128 | for(int i = 0; i < count; i++) { 129 | const char* image_name = _dyld_get_image_name(i); 130 | 131 | if(image_name) { 132 | void* _image = [self _openImage:image_name]; 133 | void* symbol = [self _findSymbol:[name UTF8String] image:_image]; 134 | [self _closeImage:_image]; 135 | 136 | if(symbol) { 137 | NSLog(@"[HookKit] found symbol %@ in image %s", name, image_name); 138 | return symbol; 139 | } 140 | } 141 | } 142 | 143 | return NULL; 144 | } 145 | @end 146 | -------------------------------------------------------------------------------- /Modules/Dobby.bundle/HKDobby.h: -------------------------------------------------------------------------------- 1 | #ifndef hkdobby_h 2 | #define hkdobby_h 3 | 4 | #import 5 | 6 | @interface HKDobby : HookKitModule 7 | @end 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /Modules/Dobby.bundle/HKDobby.m: -------------------------------------------------------------------------------- 1 | #import "HKDobby.h" 2 | #import "vendor/dobby/dobby.h" 3 | 4 | #import 5 | #import 6 | 7 | @implementation HKDobby 8 | // - (BOOL)_hookClass:(Class)objcClass selector:(SEL)selector replacement:(void *)replacement orig:(void **)orig { 9 | // return NO; 10 | // } 11 | 12 | - (BOOL)_hookFunction:(void *)function replacement:(void *)replacement orig:(void **)orig { 13 | dobby_enable_near_branch_trampoline(); 14 | int result = DobbyHook(function, replacement, (dobby_dummy_func_t *)orig); 15 | dobby_disable_near_branch_trampoline(); 16 | 17 | return result == 0; 18 | } 19 | 20 | - (int)_hookFunctions:(NSArray *)functions { 21 | int result = 0; 22 | 23 | dobby_enable_near_branch_trampoline(); 24 | 25 | for(HookKitFunctionHook* function in functions) { 26 | if(DobbyHook([function function], [function replacement], (dobby_dummy_func_t *)[function orig]) == 0) { 27 | result += 1; 28 | } 29 | } 30 | 31 | dobby_disable_near_branch_trampoline(); 32 | return result; 33 | } 34 | 35 | - (BOOL)_hookRegion:(void *)target data:(const void *)data size:(size_t)size { 36 | return DobbyCodePatch(target, (uint8_t *)data, size) == 0; 37 | } 38 | 39 | - (int)_hookRegions:(NSArray *)regions { 40 | return -1; 41 | } 42 | 43 | - (void *)_openImage:(const char *)path { 44 | void* image = malloc(sizeof(const char *) * strlen(path)); 45 | 46 | if(image) { 47 | strcpy(image, path); 48 | return image; 49 | } 50 | 51 | return NULL; 52 | } 53 | 54 | - (void)_closeImage:(void *)image { 55 | if(image) { 56 | free(image); 57 | } 58 | } 59 | 60 | - (void *)_findSymbol:(const char *)symbol image:(void *)image { 61 | return DobbySymbolResolver(image, symbol); 62 | } 63 | @end 64 | -------------------------------------------------------------------------------- /Modules/Dobby.bundle/Makefile: -------------------------------------------------------------------------------- 1 | ARCHS ?= arm64 arm64e 2 | TARGET ?= iphone:clang:14.5:14.0 3 | 4 | include $(THEOS)/makefiles/common.mk 5 | 6 | BUNDLE_NAME = HookKitDobbyModule 7 | HookKitDobbyModule_BUNDLE_EXTENSION = bundle 8 | HookKitDobbyModule_FILES = Module.m HKDobby.m 9 | HookKitDobbyModule_LIBRARIES = dobby 10 | HookKitDobbyModule_EXTRA_FRAMEWORKS = HookKit 11 | HookKitDobbyModule_CFLAGS = -fobjc-arc -Ivendor/HookKit.framework/Headers 12 | HookKitDobbyModule_LDFLAGS = -rpath /Library/Frameworks -rpath /var/jb/Library/Frameworks -rpath /usr/lib -rpath /var/jb/usr/lib 13 | HookKitDobbyModule_LDFLAGS += -Fvendor -Lvendor/dobby 14 | HookKitDobbyModule_INSTALL_PATH = /Library/Modulous/HookKit 15 | 16 | include $(THEOS_MAKE_PATH)/bundle.mk 17 | -------------------------------------------------------------------------------- /Modules/Dobby.bundle/Module.m: -------------------------------------------------------------------------------- 1 | #import "HKDobby.h" 2 | #import 3 | 4 | __attribute__ ((constructor)) static void module_init(void) { 5 | HKDobby* module = [HKDobby new]; 6 | 7 | // technically it doesn't support batch hooking but we want to override the method since 8 | // we need to use dobby's trampoline functions before hooking 9 | [module setFunctionHookBatchingSupported:YES]; 10 | [module setNullImageSearchSupported:YES]; 11 | 12 | [[HookKitCore sharedInstance] registerModule:module withIdentifier:@"dobby"]; 13 | } 14 | -------------------------------------------------------------------------------- /Modules/Dobby.bundle/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleName 6 | HookKitDobbyModule 7 | CFBundleExecutable 8 | HookKitDobbyModule 9 | CFBundleIdentifier 10 | me.jjolano.hkmodule.dobby 11 | CFBundleDevelopmentRegion 12 | English 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | ModuleInfo 22 | 23 | Author 24 | jjolano 25 | Version 26 | 1.0 27 | Description 28 | Dobby 29 | Priority 30 | 5 31 | Identifier 32 | dobby 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Modules/Dobby.bundle/Resources/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /Modules/Dobby.bundle/control: -------------------------------------------------------------------------------- 1 | Package: me.jjolano.hkmodule.dobby 2 | Name: HookKit Module (Dobby) 3 | Pre-Depends: me.jjolano.fmwk.hookkit 4 | Depends: firmware (>= 14.0) 5 | Version: 1.0.7 6 | Architecture: iphoneos-arm 7 | Description: This module provides Dobby library support for HookKit Framework. 8 | Maintainer: jjolano 9 | Author: jjolano 10 | Section: HookKit (Modules) 11 | -------------------------------------------------------------------------------- /Modules/Dobby.bundle/vendor/HookKit.framework: -------------------------------------------------------------------------------- 1 | ../../../ -------------------------------------------------------------------------------- /Modules/Dobby.bundle/vendor/dobby/dobby.h: -------------------------------------------------------------------------------- 1 | #ifndef dobby_h 2 | #define dobby_h 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | #include 10 | 11 | typedef uintptr_t addr_t; 12 | typedef uint32_t addr32_t; 13 | typedef uint64_t addr64_t; 14 | 15 | typedef void *dobby_dummy_func_t; 16 | typedef void *asm_func_t; 17 | 18 | #if defined(__arm__) 19 | typedef struct { 20 | uint32_t dummy_0; 21 | uint32_t dummy_1; 22 | 23 | uint32_t dummy_2; 24 | uint32_t sp; 25 | 26 | union { 27 | uint32_t r[13]; 28 | struct { 29 | uint32_t r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12; 30 | } regs; 31 | } general; 32 | 33 | uint32_t lr; 34 | } DobbyRegisterContext; 35 | #elif defined(__arm64__) || defined(__aarch64__) 36 | #define ARM64_TMP_REG_NDX_0 17 37 | 38 | typedef union _FPReg { 39 | __int128_t q; 40 | struct { 41 | double d1; 42 | double d2; 43 | } d; 44 | struct { 45 | float f1; 46 | float f2; 47 | float f3; 48 | float f4; 49 | } f; 50 | } FPReg; 51 | 52 | // register context 53 | typedef struct { 54 | uint64_t dmmpy_0; // dummy placeholder 55 | uint64_t sp; 56 | 57 | uint64_t dmmpy_1; // dummy placeholder 58 | union { 59 | uint64_t x[29]; 60 | struct { 61 | uint64_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, 62 | x23, x24, x25, x26, x27, x28; 63 | } regs; 64 | } general; 65 | 66 | uint64_t fp; 67 | uint64_t lr; 68 | 69 | union { 70 | FPReg q[32]; 71 | struct { 72 | FPReg q0, q1, q2, q3, q4, q5, q6, q7; 73 | // [!!! READ ME !!!] 74 | // for Arm64, can't access q8 - q31, unless you enable full floating-point register pack 75 | FPReg q8, q9, q10, q11, q12, q13, q14, q15, q16, q17, q18, q19, q20, q21, q22, q23, q24, q25, q26, q27, q28, q29, 76 | q30, q31; 77 | } regs; 78 | } floating; 79 | } DobbyRegisterContext; 80 | #elif defined(_M_IX86) || defined(__i386__) 81 | typedef struct _RegisterContext { 82 | uint32_t dummy_0; 83 | uint32_t esp; 84 | 85 | uint32_t dummy_1; 86 | uint32_t flags; 87 | 88 | union { 89 | struct { 90 | uint32_t eax, ebx, ecx, edx, ebp, esp, edi, esi; 91 | } regs; 92 | } general; 93 | 94 | } DobbyRegisterContext; 95 | #elif defined(_M_X64) || defined(__x86_64__) 96 | typedef struct { 97 | uint64_t dummy_0; 98 | uint64_t rsp; 99 | 100 | union { 101 | struct { 102 | uint64_t rax, rbx, rcx, rdx, rbp, rsp, rdi, rsi, r8, r9, r10, r11, r12, r13, r14, r15; 103 | } regs; 104 | } general; 105 | 106 | uint64_t dummy_1; 107 | uint64_t flags; 108 | } DobbyRegisterContext; 109 | #endif 110 | 111 | #define install_hook_name(name, fn_ret_t, fn_args_t...) \ 112 | static fn_ret_t fake_##name(fn_args_t); \ 113 | static fn_ret_t (*orig_##name)(fn_args_t); \ 114 | /* __attribute__((constructor)) */ static void install_hook_##name(void *sym_addr) { \ 115 | DobbyHook(sym_addr, (dobby_dummy_func_t)fake_##name, (dobby_dummy_func_t *)&orig_##name); \ 116 | return; \ 117 | } \ 118 | fn_ret_t fake_##name(fn_args_t) 119 | 120 | // memory code patch 121 | int DobbyCodePatch(void *address, uint8_t *buffer, uint32_t buffer_size); 122 | 123 | // function inline hook 124 | int DobbyHook(void *address, dobby_dummy_func_t replace_func, dobby_dummy_func_t *origin_func); 125 | 126 | // dynamic binary instruction instrument 127 | // for Arm64, can't access q8 - q31, unless enable full floating-point register pack 128 | typedef void (*dobby_instrument_callback_t)(void *address, DobbyRegisterContext *ctx); 129 | int DobbyInstrument(void *address, dobby_instrument_callback_t pre_handler); 130 | 131 | // destroy and restore code patch 132 | int DobbyDestroy(void *address); 133 | 134 | const char *DobbyGetVersion(); 135 | 136 | // symbol resolver 137 | void *DobbySymbolResolver(const char *image_name, const char *symbol_name); 138 | 139 | // import table replace 140 | int DobbyImportTableReplace(char *image_name, char *symbol_name, dobby_dummy_func_t fake_func, 141 | dobby_dummy_func_t *orig_func); 142 | 143 | // for arm, Arm64, try use b xxx instead of ldr absolute indirect branch 144 | // for x86, x64, always use absolute indirect jump 145 | void dobby_enable_near_branch_trampoline(); 146 | void dobby_disable_near_branch_trampoline(); 147 | 148 | #ifdef __cplusplus 149 | } 150 | #endif 151 | 152 | #endif 153 | -------------------------------------------------------------------------------- /Modules/Dobby.bundle/vendor/dobby/libdobby.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjolano/HookKit/a40f5157394d7f099af1a01a01b5ddd95e6d2ba3/Modules/Dobby.bundle/vendor/dobby/libdobby.a -------------------------------------------------------------------------------- /Modules/fishhook.bundle/HKFH.h: -------------------------------------------------------------------------------- 1 | #ifndef hkfh_h 2 | #define hkfh_h 3 | 4 | #import 5 | 6 | @interface HKFH : HookKitModule 7 | @end 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /Modules/fishhook.bundle/HKFH.m: -------------------------------------------------------------------------------- 1 | #import "HKFH.h" 2 | #import "vendor/fishhook/fishhook.h" 3 | 4 | #import 5 | 6 | @implementation HKFH 7 | // - (BOOL)_hookClass:(Class)objcClass selector:(SEL)selector replacement:(void *)replacement orig:(void **)orig { 8 | // return NO; 9 | // } 10 | 11 | - (BOOL)_hookFunction:(void *)function replacement:(void *)replacement orig:(void **)orig { 12 | Dl_info info; 13 | if(dladdr(function, &info)) { 14 | return rebind_symbols((struct rebinding[1]){{info.dli_sname, replacement, orig}}, 1) == 0; 15 | } else { 16 | // private symbol? 17 | return [super _hookFunction:function replacement:replacement orig:orig]; 18 | } 19 | 20 | return NO; 21 | } 22 | 23 | - (int)_hookFunctions:(NSArray *)functions { 24 | NSMutableData* hooks = [NSMutableData new]; 25 | int priv_count = 0; 26 | 27 | for(HookKitFunctionHook* function in functions) { 28 | Dl_info info; 29 | if(dladdr([function function], &info)) { 30 | struct rebinding hook = { 31 | info.dli_sname, [function replacement], [function orig] 32 | }; 33 | 34 | [hooks appendBytes:&hook length:sizeof(struct rebinding)]; 35 | } else { 36 | // private symbol? 37 | if([super _hookFunction:[function function] replacement:[function replacement] orig:[function orig]]) { 38 | priv_count += 1; 39 | } 40 | } 41 | } 42 | 43 | rebind_symbols((struct rebinding *)[hooks mutableBytes], [functions count]); 44 | return [functions count] + priv_count; 45 | } 46 | 47 | // - (BOOL)_hookRegion:(void *)target data:(const void *)data size:(size_t)size { 48 | // return NO; 49 | // } 50 | 51 | // - (int)_hookRegions:(NSArray *)regions { 52 | // return -1; 53 | // } 54 | 55 | // - (void *)_openImage:(const char *)path { 56 | // return (void *)MSGetImageByName(path); 57 | // } 58 | 59 | // - (void)_closeImage:(void *)image { 60 | // MSCloseImage((MSImageRef)image); 61 | // } 62 | 63 | // - (void *)_findSymbol:(const char *)symbol image:(void *)image { 64 | // return MSFindSymbol((MSImageRef)image, symbol); 65 | // } 66 | @end 67 | -------------------------------------------------------------------------------- /Modules/fishhook.bundle/Makefile: -------------------------------------------------------------------------------- 1 | ARCHS ?= armv7 armv7s arm64 arm64e 2 | TARGET ?= iphone:clang:14.5:8.0 3 | 4 | include $(THEOS)/makefiles/common.mk 5 | 6 | BUNDLE_NAME = HookKitFishhookModule 7 | HookKitFishhookModule_BUNDLE_EXTENSION = bundle 8 | HookKitFishhookModule_FILES = Module.m HKFH.m vendor/fishhook/fishhook.c 9 | HookKitFishhookModule_EXTRA_FRAMEWORKS = HookKit 10 | HookKitFishhookModule_CFLAGS = -fobjc-arc -Ivendor/HookKit.framework/Headers 11 | HookKitFishhookModule_LDFLAGS = -rpath /Library/Frameworks -rpath /var/jb/Library/Frameworks -rpath /usr/lib -rpath /var/jb/usr/lib 12 | HookKitFishhookModule_LDFLAGS += -Fvendor 13 | HookKitFishhookModule_INSTALL_PATH = /Library/Modulous/HookKit 14 | 15 | include $(THEOS_MAKE_PATH)/bundle.mk 16 | -------------------------------------------------------------------------------- /Modules/fishhook.bundle/Module.m: -------------------------------------------------------------------------------- 1 | #import "HKFH.h" 2 | #import 3 | 4 | __attribute__ ((constructor)) static void module_init(void) { 5 | HKFH* module = [HKFH new]; 6 | [module setFunctionHookBatchingSupported:YES]; 7 | 8 | [[HookKitCore sharedInstance] registerModule:module withIdentifier:@"fishhook"]; 9 | } 10 | -------------------------------------------------------------------------------- /Modules/fishhook.bundle/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleName 6 | HookKitFishhookModule 7 | CFBundleExecutable 8 | HookKitFishhookModule 9 | CFBundleIdentifier 10 | me.jjolano.hkmodule.fishhook 11 | CFBundleDevelopmentRegion 12 | English 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | ModuleInfo 22 | 23 | Author 24 | jjolano 25 | Version 26 | 1.0 27 | Description 28 | fishhook 29 | Priority 30 | 4 31 | Identifier 32 | fishhook 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Modules/fishhook.bundle/Resources/LICENSE: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, Facebook, Inc. 2 | // All rights reserved. 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // * Redistributions of source code must retain the above copyright notice, 6 | // this list of conditions and the following disclaimer. 7 | // * Redistributions in binary form must reproduce the above copyright notice, 8 | // this list of conditions and the following disclaimer in the documentation 9 | // and/or other materials provided with the distribution. 10 | // * Neither the name Facebook nor the names of its contributors may be used to 11 | // endorse or promote products derived from this software without specific 12 | // prior written permission. 13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 17 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /Modules/fishhook.bundle/control: -------------------------------------------------------------------------------- 1 | Package: me.jjolano.hkmodule.fishhook 2 | Name: HookKit Module (fishhook) 3 | Pre-Depends: me.jjolano.fmwk.hookkit 4 | Version: 1.0.8 5 | Architecture: iphoneos-arm 6 | Description: This module provides fishhook library support for HookKit Framework. 7 | Maintainer: jjolano 8 | Author: jjolano 9 | Section: HookKit (Modules) 10 | -------------------------------------------------------------------------------- /Modules/fishhook.bundle/vendor/HookKit.framework: -------------------------------------------------------------------------------- 1 | ../../../ -------------------------------------------------------------------------------- /Modules/libellekit.bundle/HKElleKit.h: -------------------------------------------------------------------------------- 1 | #ifndef hkellekit_h 2 | #define hkellekit_h 3 | 4 | #import 5 | 6 | @interface HKElleKit : HookKitModule 7 | @end 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /Modules/libellekit.bundle/HKElleKit.m: -------------------------------------------------------------------------------- 1 | #import "HKElleKit.h" 2 | #import "vendor/libhooker/libhooker.h" 3 | #import "vendor/libhooker/libblackjack.h" 4 | 5 | @implementation HKElleKit 6 | - (BOOL)_hookClass:(Class)objcClass selector:(SEL)selector replacement:(void *)replacement orig:(void **)orig { 7 | return LBHookMessage(objcClass, selector, replacement, orig) == LIBHOOKER_OK; 8 | } 9 | 10 | - (BOOL)_hookFunction:(void *)function replacement:(void *)replacement orig:(void **)orig { 11 | struct LHFunctionHook hook = { 12 | function, replacement, (void *)orig, NULL 13 | }; 14 | 15 | return LHHookFunctions(&hook, 1) == 1; 16 | } 17 | 18 | - (int)_hookFunctions:(NSArray *)functions { 19 | NSMutableData* hooks = [NSMutableData new]; 20 | 21 | for(HookKitFunctionHook* function in functions) { 22 | struct LHFunctionHook hook = { 23 | [function function], [function replacement], [function orig], NULL 24 | }; 25 | 26 | [hooks appendBytes:&hook length:sizeof(struct LHFunctionHook)]; 27 | } 28 | 29 | int result = LHHookFunctions([hooks mutableBytes], [functions count]); 30 | 31 | if(result < [functions count]) { 32 | NSLog(@"[HKElleKit] warning: batch LHHookFunctions retval less than expected (%d/%lu)", result, [functions count]); 33 | } 34 | 35 | return result; 36 | } 37 | 38 | - (BOOL)_hookRegion:(void *)target data:(const void *)data size:(size_t)size { 39 | struct LHMemoryPatch hook = { 40 | target, data, size, 0 41 | }; 42 | 43 | return LHPatchMemory(&hook, 1) == 1; 44 | } 45 | 46 | - (int)_hookRegions:(NSArray *)regions { 47 | NSMutableData* hooks = [NSMutableData new]; 48 | 49 | for(HookKitMemoryHook* region in regions) { 50 | struct LHMemoryPatch hook = { 51 | [region target], [region data], [region size], 0 52 | }; 53 | 54 | [hooks appendBytes:&hook length:sizeof(struct LHMemoryPatch)]; 55 | } 56 | 57 | int result = LHPatchMemory([hooks mutableBytes], [regions count]); 58 | 59 | if(result < [regions count]) { 60 | NSLog(@"[HKElleKit] warning: batch LHPatchMemory retval less than expected (%d/%lu)", result, [regions count]); 61 | } 62 | 63 | return result; 64 | } 65 | 66 | - (void *)_openImage:(const char *)path { 67 | return (void *)LHOpenImage(path); 68 | } 69 | 70 | - (void)_closeImage:(void *)image { 71 | LHCloseImage((struct libhooker_image *)image); 72 | } 73 | 74 | - (void *)_findSymbol:(const char *)symbol image:(void *)image { 75 | void* result = NULL; 76 | 77 | if(LHFindSymbols((struct libhooker_image *)image, &symbol, &result, 1)) { 78 | return result; 79 | } 80 | 81 | return NULL; 82 | } 83 | @end 84 | -------------------------------------------------------------------------------- /Modules/libellekit.bundle/Makefile: -------------------------------------------------------------------------------- 1 | ARCHS ?= arm64 arm64e 2 | TARGET ?= iphone:clang:latest:14.0 3 | 4 | include $(THEOS)/makefiles/common.mk 5 | 6 | BUNDLE_NAME = HookKitElleKitModule 7 | HookKitElleKitModule_BUNDLE_EXTENSION = bundle 8 | HookKitElleKitModule_FILES = Module.m HKElleKit.m 9 | HookKitElleKitModule_LIBRARIES = _ellekit 10 | HookKitElleKitModule_EXTRA_FRAMEWORKS = HookKit 11 | HookKitElleKitModule_CFLAGS = -fobjc-arc -Ivendor/HookKit.framework/Headers 12 | HookKitElleKitModule_LDFLAGS = -rpath /Library/Frameworks -rpath /var/jb/Library/Frameworks -rpath /usr/lib -rpath /var/jb/usr/lib 13 | HookKitElleKitModule_LDFLAGS += -Fvendor -Lvendor 14 | HookKitElleKitModule_INSTALL_PATH = /Library/Modulous/HookKit 15 | 16 | include $(THEOS_MAKE_PATH)/bundle.mk 17 | -------------------------------------------------------------------------------- /Modules/libellekit.bundle/Module.m: -------------------------------------------------------------------------------- 1 | #import "HKElleKit.h" 2 | #import 3 | 4 | __attribute__ ((constructor)) static void module_init(void) { 5 | HKElleKit* module = [HKElleKit new]; 6 | [module setFunctionHookBatchingSupported:YES]; 7 | [module setMemoryHookBatchingSupported:YES]; 8 | 9 | [[HookKitCore sharedInstance] registerModule:module withIdentifier:@"ellekit"]; 10 | } 11 | -------------------------------------------------------------------------------- /Modules/libellekit.bundle/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleName 6 | HookKitElleKitModule 7 | CFBundleExecutable 8 | HookKitElleKitModule 9 | CFBundleIdentifier 10 | me.jjolano.hkmodule.ellekit 11 | CFBundleDevelopmentRegion 12 | English 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | ModuleInfo 22 | 23 | Author 24 | jjolano 25 | Version 26 | 1.0 27 | Description 28 | ElleKit 29 | Priority 30 | 1 31 | Identifier 32 | ellekit 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Modules/libellekit.bundle/control: -------------------------------------------------------------------------------- 1 | Package: me.jjolano.hkmodule.ellekit 2 | Name: HookKit Module (ElleKit) 3 | Pre-Depends: me.jjolano.fmwk.hookkit 4 | Depends: ellekit 5 | Provides: me.jjolano.hkmodule.substrate 6 | Version: 1.0.7 7 | Architecture: iphoneos-arm 8 | Description: This module provides the ElleKit API for HookKit Framework. 9 | Maintainer: jjolano 10 | Author: jjolano 11 | Section: HookKit (Modules) 12 | -------------------------------------------------------------------------------- /Modules/libellekit.bundle/vendor/HookKit.framework: -------------------------------------------------------------------------------- 1 | ../../../ -------------------------------------------------------------------------------- /Modules/libellekit.bundle/vendor/lib_ellekit.tbd: -------------------------------------------------------------------------------- 1 | --- 2 | archs: [ arm64, arm64e ] 3 | platform: ios 4 | install-name: '@rpath/libellekit.dylib' 5 | current-version: 0.0.0 6 | compatibility-version: 0.0.0 7 | exports: 8 | - archs: [ arm64, arm64e ] 9 | symbols: [ _LHStrError, _LHOpenImage, _LHCloseImage, _LHFindSymbols, 10 | _LHExecMemory, _LHPatchMemory, _LHHookFunctions, 11 | _LBHookMessage ] 12 | ... 13 | -------------------------------------------------------------------------------- /Modules/libellekit.bundle/vendor/libhooker/libblackjack.h: -------------------------------------------------------------------------------- 1 | // 2 | // libblackjack.h 3 | // libblackjack 4 | // 5 | // Created by CoolStar on 2/24/20. 6 | // Copyright © 2020 CoolStar. All rights reserved. 7 | // 8 | 9 | #include "libhooker.h" 10 | 11 | #ifndef libblackjack_h 12 | #define libblackjack_h 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | /*! 19 | * @function LBHookMessage 20 | * 21 | * @abstract 22 | * Hook an Objective-C method 23 | * 24 | * @discussion 25 | * Libraries often need to hook Objective-C methods. This provides an easy way to hook the method and call to the 26 | * original method. This also provides a guarantee that hooking a class that doesn't implement a method won't overwrite the method 27 | * in the super class. 28 | * 29 | * @param class 30 | * The Objective C class to hook 31 | * 32 | * @param selector 33 | * The Objective C selector to hook 34 | * 35 | * @param replacement 36 | * A pointer to the replacement implementation that gets called instead of the original function 37 | * 38 | * @param old_ptr 39 | * A pointer to the original implementation that can be called if needed 40 | * 41 | * @result 42 | * Returns any errors that may have taken place when hooking the method 43 | */ 44 | enum LIBHOOKER_ERR LBHookMessage(Class objcClass, SEL selector, void *replacement, void *old_ptr); 45 | 46 | #ifdef __cplusplus 47 | } 48 | #endif 49 | 50 | #endif /* libblackjack_h */ -------------------------------------------------------------------------------- /Modules/libellekit.bundle/vendor/libhooker/libhooker.h: -------------------------------------------------------------------------------- 1 | // 2 | // libhooker.h 3 | // libhooker 4 | // 5 | // Created by CoolStar on 8/17/19. 6 | // Copyright © 2019 CoolStar. All rights reserved. 7 | // 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #ifndef libhooker_h 14 | #define libhooker_h 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | /*! 21 | * @enum libhooker errors 22 | * 23 | * @abstract 24 | * Get a human readable string for debugging purposes. 25 | * 26 | * @discussion 27 | * Passing zero for the value is useful for when two threads need to reconcile 28 | * the completion of a particular event. Passing a value greater than zero is 29 | * useful for managing a finite pool of resources, where the pool size is equal 30 | * to the value. 31 | * 32 | * @constant LIBHOOKER_OK No errors took place 33 | * @constant LIBHOOKER_ERR_SELECTOR_NOT_FOUND An Objective-C selector was not found. (This error is from libblackjack) 34 | * @constant LIBHOOKER_ERR_SHORT_FUNC A function was too short to hook 35 | * @constant LIBHOOKER_ERR_BAD_INSN_AT_START A problematic instruction was found at the start. We can't preserve the original function due to this instruction getting clobbered. 36 | * @constant LIBHOOKER_ERR_VM An error took place while handling memory pages 37 | * @constant LIBHOOKER_ERR_NO_SYMBOL No symbol was specified for hooking 38 | */ 39 | enum LIBHOOKER_ERR { 40 | LIBHOOKER_OK = 0, 41 | LIBHOOKER_ERR_SELECTOR_NOT_FOUND = 1, 42 | LIBHOOKER_ERR_SHORT_FUNC = 2, 43 | LIBHOOKER_ERR_BAD_INSN_AT_START = 3, 44 | LIBHOOKER_ERR_VM = 4, 45 | LIBHOOKER_ERR_NO_SYMBOL = 5 46 | }; 47 | 48 | /*! 49 | * @function LHStrError 50 | * 51 | * @abstract 52 | * Get a human readable string for debugging purposes. 53 | * 54 | * @discussion 55 | * Passing zero for the value is useful for when two threads need to reconcile 56 | * the completion of a particular event. Passing a value greater than zero is 57 | * useful for managing a finite pool of resources, where the pool size is equal 58 | * to the value. 59 | * 60 | * @param err 61 | * The raw error value. 62 | * 63 | * @result 64 | * A human-readable error string, or "Unknown Error" on invalid error. 65 | */ 66 | const char *LHStrError(enum LIBHOOKER_ERR err); 67 | 68 | /*! 69 | * @function LHOpenImage 70 | * 71 | * @abstract 72 | * Open a dylib for use with LHFindSymbols 73 | * 74 | * @discussion 75 | * dyld handles do not provide enough information to grab symbols. Use this to have libhooker load the dylib. 76 | * 77 | * @param path 78 | * The path to the image on disk or in the shared cache. 79 | * 80 | * @result 81 | * A handle to the dylib that may then be used with LHFindSymbols to find symbols. 82 | */ 83 | struct libhooker_image *LHOpenImage(const char *path); 84 | 85 | /*! 86 | * @function LHCloseImage 87 | * 88 | * @abstract 89 | * Close and free a dylib handle opened with LHOpenImage 90 | * 91 | * @param libhookerImage 92 | * The libhooker handle to the image on disk or in the shared cache. 93 | */ 94 | void LHCloseImage(struct libhooker_image *libhookerImage); 95 | 96 | /*! 97 | * @function LHFindSymbols 98 | * 99 | * @abstract 100 | * Search for symbols within a dylib either on disk or in the dyld shared cache. 101 | * 102 | * @discussion 103 | * dyld often is not able to find symbols that are present but not marked as public and/or exported. 104 | * Also often the dyld shared cache has symbols replaced with `` when loaded into memory. 105 | * 106 | * @param libhookerImage 107 | * The libhooker handle to the image on disk or in the shared cache 108 | * 109 | * @param symbolNames 110 | * An array of the symbol names to search for 111 | * 112 | * @param searchSyms 113 | * An array that gets populated with the symbols found 114 | * 115 | * @param searchSymCount 116 | * The number of symbols to search for 117 | * 118 | * @result 119 | * Returns true if all symbols were found 120 | */ 121 | bool LHFindSymbols(struct libhooker_image *libhookerImage, 122 | const char **symbolNames, 123 | void **searchSyms, 124 | size_t searchSymCount); 125 | 126 | /*! 127 | * @function LHExecMemory 128 | * 129 | * @abstract 130 | * Creates an executable page from raw instruction data 131 | * 132 | * @discussion 133 | * Sometimes a library may generate or load new code, but may simply want an executable page with this new code. 134 | * 135 | * @param page 136 | * A pointer that gets written to with the address of code in the new memory page 137 | * 138 | * @param data 139 | * An array of ARM64 opcodes to write to this new memory page. 140 | * 141 | * @param size 142 | * The size of data 143 | * 144 | * @result 145 | * Returns true if the memory was created. Returns false otherwise. 146 | */ 147 | bool LHExecMemory(void **page, void *data, size_t size); 148 | 149 | /*! 150 | * @struct LHMemoryPatch 151 | * 152 | * @abstract 153 | * Describes a memory region to patch 154 | * 155 | * @field destination 156 | * A pointer to the memory location to patch 157 | * 158 | * @field data 159 | * A pointer to the data to write at the patch location 160 | * 161 | * @field size 162 | * The number of bytes to write at the patch location 163 | * 164 | * @field options 165 | * A pointer to an extended options struct. Currently unused. 166 | * 167 | */ 168 | struct LHMemoryPatch { 169 | void *destination; 170 | const void *data; 171 | size_t size; 172 | void *options; 173 | }; 174 | 175 | /*! 176 | * @function LHPatchMemory 177 | * 178 | * @abstract 179 | * Patch memory (that may often be read-only or read/execute-only) 180 | * 181 | * @discussion 182 | * Sometimes low level memory access is required to hook parts of applications. This function 183 | * provides an easy way for libraries to do so, with a relatively safe guarantee of preserving 184 | * memory permissions, and re-mapping the memory if required. 185 | * 186 | * @param patches 187 | * A pointer to the destination to write to 188 | * 189 | * @param count 190 | * The number of memory regions to patch 191 | * 192 | * @result 193 | * Returns the number of memory regions successfully patched. This should match count if all regions were succesfully patched. 194 | * 195 | * @result errno 196 | * Returns any errors that may have taken place while hooking the functions 197 | */ 198 | int LHPatchMemory(const struct LHMemoryPatch *patches, int count); 199 | 200 | enum LHOptions { 201 | LHOptionsNone = 0, 202 | LHOptionsSetJumpReg = 1 203 | }; 204 | 205 | struct LHFunctionHookOptions { 206 | enum LHOptions options; 207 | int jmp_reg; 208 | }; 209 | 210 | /*! 211 | * @struct LHFunctionhook 212 | * 213 | * @abstract 214 | * Describes a function hook 215 | * 216 | * @field function 217 | * A pointer to the function to hook 218 | * 219 | * @field replacement 220 | * A pointer to the replacement function that will get called in place 221 | * 222 | * @field oldptr 223 | * If not null, this pointer gets written to with the address of a trampoline that lets you call the original function 224 | * 225 | * @discussion 226 | * Setting oldptr to null will allow libhooker to hook smaller functions and will skip over several checks since it does not need to try preserving the original function 227 | * 228 | * @field options 229 | * An optional field that may be populated with a pointer to an LHFunctionHookOptions struct 230 | */ 231 | struct LHFunctionHook { 232 | void *function; 233 | void *replacement; 234 | void *oldptr; 235 | struct LHFunctionHookOptions *options; 236 | }; 237 | 238 | /*! 239 | * @function LHHookFunctions 240 | * 241 | * @abstract 242 | * Hook Functions in memory 243 | * 244 | * @discussion 245 | * Libraries often need to hook functions in memory. This provides an easy way to hook the function and get back 246 | * a pointer to the original function, should you need to call it. 247 | * 248 | * @param hooks 249 | * An array of LHFunctionHook describing each function to hook 250 | * 251 | * @param count 252 | * The number of functions to hook 253 | * 254 | * @result 255 | * Returns the number of functions successfully hooked. This should match count if all functions were succesfully hooked. 256 | * 257 | * @result errno 258 | * Returns any errors that may have taken place while hooking the functions 259 | */ 260 | int LHHookFunctions(const struct LHFunctionHook *hooks, int count); 261 | 262 | #ifdef __cplusplus 263 | } 264 | #endif 265 | 266 | #endif /* libhooker_h */ 267 | -------------------------------------------------------------------------------- /Modules/libhooker.bundle/HKLH.h: -------------------------------------------------------------------------------- 1 | #ifndef hklh_h 2 | #define hklh_h 3 | 4 | #import 5 | 6 | @interface HKLH : HookKitModule 7 | @end 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /Modules/libhooker.bundle/HKLH.m: -------------------------------------------------------------------------------- 1 | #import "HKLH.h" 2 | #import "vendor/libhooker/libhooker.h" 3 | #import "vendor/libhooker/libblackjack.h" 4 | 5 | @implementation HKLH 6 | - (BOOL)_hookClass:(Class)objcClass selector:(SEL)selector replacement:(void *)replacement orig:(void **)orig { 7 | return LBHookMessage(objcClass, selector, replacement, orig) == LIBHOOKER_OK; 8 | } 9 | 10 | - (BOOL)_hookFunction:(void *)function replacement:(void *)replacement orig:(void **)orig { 11 | struct LHFunctionHook hook = { 12 | function, replacement, (void *)orig, NULL 13 | }; 14 | 15 | return LHHookFunctions(&hook, 1) == 1; 16 | } 17 | 18 | - (int)_hookFunctions:(NSArray *)functions { 19 | NSMutableData* hooks = [NSMutableData new]; 20 | 21 | for(HookKitFunctionHook* function in functions) { 22 | struct LHFunctionHook hook = { 23 | [function function], [function replacement], [function orig], NULL 24 | }; 25 | 26 | [hooks appendBytes:&hook length:sizeof(struct LHFunctionHook)]; 27 | } 28 | 29 | int result = LHHookFunctions([hooks mutableBytes], [functions count]); 30 | 31 | if(result < [functions count]) { 32 | NSLog(@"[HKLH] warning: batch LHHookFunctions retval less than expected (%d/%lu)", result, [functions count]); 33 | } 34 | 35 | return result; 36 | } 37 | 38 | - (BOOL)_hookRegion:(void *)target data:(const void *)data size:(size_t)size { 39 | struct LHMemoryPatch hook = { 40 | target, data, size, 0 41 | }; 42 | 43 | return LHPatchMemory(&hook, 1) == 1; 44 | } 45 | 46 | - (int)_hookRegions:(NSArray *)regions { 47 | NSMutableData* hooks = [NSMutableData new]; 48 | 49 | for(HookKitMemoryHook* region in regions) { 50 | struct LHMemoryPatch hook = { 51 | [region target], [region data], [region size], 0 52 | }; 53 | 54 | [hooks appendBytes:&hook length:sizeof(struct LHMemoryPatch)]; 55 | } 56 | 57 | int result = LHPatchMemory([hooks mutableBytes], [regions count]); 58 | 59 | if(result < [regions count]) { 60 | NSLog(@"[HKLH] warning: batch LHPatchMemory retval less than expected (%d/%lu)", result, [regions count]); 61 | } 62 | 63 | return result; 64 | } 65 | 66 | - (void *)_openImage:(const char *)path { 67 | return (void *)LHOpenImage(path); 68 | } 69 | 70 | - (void)_closeImage:(void *)image { 71 | LHCloseImage((struct libhooker_image *)image); 72 | } 73 | 74 | - (void *)_findSymbol:(const char *)symbol image:(void *)image { 75 | void* result = NULL; 76 | 77 | if(LHFindSymbols((struct libhooker_image *)image, &symbol, &result, 1)) { 78 | return result; 79 | } 80 | 81 | return NULL; 82 | } 83 | @end 84 | -------------------------------------------------------------------------------- /Modules/libhooker.bundle/Makefile: -------------------------------------------------------------------------------- 1 | ARCHS ?= arm64 arm64e 2 | TARGET ?= iphone:clang:14.5:11.0 3 | 4 | include $(THEOS)/makefiles/common.mk 5 | 6 | BUNDLE_NAME = HookKitLHModule 7 | HookKitLHModule_BUNDLE_EXTENSION = bundle 8 | HookKitLHModule_FILES = Module.m HKLH.m 9 | HookKitLHModule_LIBRARIES = _libhooker _blackjack 10 | HookKitLHModule_EXTRA_FRAMEWORKS = HookKit 11 | HookKitLHModule_CFLAGS = -fobjc-arc -Ivendor/HookKit.framework/Headers 12 | HookKitLHModule_LDFLAGS = -rpath /Library/Frameworks -rpath /var/jb/Library/Frameworks -rpath /usr/lib -rpath /var/jb/usr/lib 13 | HookKitLHModule_LDFLAGS += -Fvendor -Lvendor/libhooker 14 | HookKitLHModule_INSTALL_PATH = /Library/Modulous/HookKit 15 | 16 | include $(THEOS_MAKE_PATH)/bundle.mk 17 | -------------------------------------------------------------------------------- /Modules/libhooker.bundle/Module.m: -------------------------------------------------------------------------------- 1 | #import "HKLH.h" 2 | #import 3 | 4 | __attribute__ ((constructor)) static void module_init(void) { 5 | HKLH* module = [HKLH new]; 6 | [module setFunctionHookBatchingSupported:YES]; 7 | [module setMemoryHookBatchingSupported:YES]; 8 | 9 | [[HookKitCore sharedInstance] registerModule:module withIdentifier:@"libhooker"]; 10 | } 11 | -------------------------------------------------------------------------------- /Modules/libhooker.bundle/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleName 6 | HookKitLHModule 7 | CFBundleExecutable 8 | HookKitLHModule 9 | CFBundleIdentifier 10 | me.jjolano.hkmodule.libhooker 11 | CFBundleDevelopmentRegion 12 | English 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | ModuleInfo 22 | 23 | Author 24 | jjolano 25 | Version 26 | 1.0 27 | Description 28 | libhooker 29 | Priority 30 | 1 31 | Identifier 32 | libhooker 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Modules/libhooker.bundle/control: -------------------------------------------------------------------------------- 1 | Package: me.jjolano.hkmodule.libhooker 2 | Name: HookKit Module (libhooker) 3 | Pre-Depends: me.jjolano.fmwk.hookkit 4 | Depends: org.coolstar.libhooker (>= 1.0.0) 5 | Provides: me.jjolano.hkmodule.substrate 6 | Version: 1.0.7 7 | Architecture: iphoneos-arm 8 | Description: This module provides the libhooker API for HookKit Framework. 9 | Maintainer: jjolano 10 | Author: jjolano 11 | Section: HookKit (Modules) 12 | -------------------------------------------------------------------------------- /Modules/libhooker.bundle/vendor/HookKit.framework: -------------------------------------------------------------------------------- 1 | ../../../ -------------------------------------------------------------------------------- /Modules/libhooker.bundle/vendor/libhooker/lib_blackjack.tbd: -------------------------------------------------------------------------------- 1 | --- 2 | archs: [ arm64, arm64e, arm64_32 ] 3 | platform: ios 4 | install-name: '@rpath/libblackjack.dylib' 5 | current-version: 0.0.0 6 | compatibility-version: 0.0.0 7 | exports: 8 | - archs: [ arm64, arm64e, arm64_32 ] 9 | symbols: [ _LBHookMessage ] 10 | ... 11 | -------------------------------------------------------------------------------- /Modules/libhooker.bundle/vendor/libhooker/lib_libhooker.tbd: -------------------------------------------------------------------------------- 1 | --- 2 | archs: [ arm64, arm64e, arm64_32 ] 3 | platform: ios 4 | install-name: '@rpath/libhooker.dylib' 5 | current-version: 0.0.0 6 | compatibility-version: 0.0.0 7 | exports: 8 | - archs: [ arm64, arm64e, arm64_32 ] 9 | symbols: [ _LHStrError, _LHOpenImage, _LHCloseImage, _LHFindSymbols, 10 | _LHExecMemory, _LHPatchMemory, _LHHookFunctions ] 11 | ... 12 | -------------------------------------------------------------------------------- /Modules/libhooker.bundle/vendor/libhooker/libblackjack.h: -------------------------------------------------------------------------------- 1 | // 2 | // libblackjack.h 3 | // libblackjack 4 | // 5 | // Created by CoolStar on 2/24/20. 6 | // Copyright © 2020 CoolStar. All rights reserved. 7 | // 8 | 9 | #include "libhooker.h" 10 | 11 | #ifndef libblackjack_h 12 | #define libblackjack_h 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | /*! 19 | * @function LBHookMessage 20 | * 21 | * @abstract 22 | * Hook an Objective-C method 23 | * 24 | * @discussion 25 | * Libraries often need to hook Objective-C methods. This provides an easy way to hook the method and call to the 26 | * original method. This also provides a guarantee that hooking a class that doesn't implement a method won't overwrite the method 27 | * in the super class. 28 | * 29 | * @param class 30 | * The Objective C class to hook 31 | * 32 | * @param selector 33 | * The Objective C selector to hook 34 | * 35 | * @param replacement 36 | * A pointer to the replacement implementation that gets called instead of the original function 37 | * 38 | * @param old_ptr 39 | * A pointer to the original implementation that can be called if needed 40 | * 41 | * @result 42 | * Returns any errors that may have taken place when hooking the method 43 | */ 44 | enum LIBHOOKER_ERR LBHookMessage(Class objcClass, SEL selector, void *replacement, void *old_ptr); 45 | 46 | #ifdef __cplusplus 47 | } 48 | #endif 49 | 50 | #endif /* libblackjack_h */ -------------------------------------------------------------------------------- /Modules/libhooker.bundle/vendor/libhooker/libhooker.h: -------------------------------------------------------------------------------- 1 | // 2 | // libhooker.h 3 | // libhooker 4 | // 5 | // Created by CoolStar on 8/17/19. 6 | // Copyright © 2019 CoolStar. All rights reserved. 7 | // 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #ifndef libhooker_h 14 | #define libhooker_h 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | /*! 21 | * @enum libhooker errors 22 | * 23 | * @abstract 24 | * Get a human readable string for debugging purposes. 25 | * 26 | * @discussion 27 | * Passing zero for the value is useful for when two threads need to reconcile 28 | * the completion of a particular event. Passing a value greater than zero is 29 | * useful for managing a finite pool of resources, where the pool size is equal 30 | * to the value. 31 | * 32 | * @constant LIBHOOKER_OK No errors took place 33 | * @constant LIBHOOKER_ERR_SELECTOR_NOT_FOUND An Objective-C selector was not found. (This error is from libblackjack) 34 | * @constant LIBHOOKER_ERR_SHORT_FUNC A function was too short to hook 35 | * @constant LIBHOOKER_ERR_BAD_INSN_AT_START A problematic instruction was found at the start. We can't preserve the original function due to this instruction getting clobbered. 36 | * @constant LIBHOOKER_ERR_VM An error took place while handling memory pages 37 | * @constant LIBHOOKER_ERR_NO_SYMBOL No symbol was specified for hooking 38 | */ 39 | enum LIBHOOKER_ERR { 40 | LIBHOOKER_OK = 0, 41 | LIBHOOKER_ERR_SELECTOR_NOT_FOUND = 1, 42 | LIBHOOKER_ERR_SHORT_FUNC = 2, 43 | LIBHOOKER_ERR_BAD_INSN_AT_START = 3, 44 | LIBHOOKER_ERR_VM = 4, 45 | LIBHOOKER_ERR_NO_SYMBOL = 5 46 | }; 47 | 48 | /*! 49 | * @function LHStrError 50 | * 51 | * @abstract 52 | * Get a human readable string for debugging purposes. 53 | * 54 | * @discussion 55 | * Passing zero for the value is useful for when two threads need to reconcile 56 | * the completion of a particular event. Passing a value greater than zero is 57 | * useful for managing a finite pool of resources, where the pool size is equal 58 | * to the value. 59 | * 60 | * @param err 61 | * The raw error value. 62 | * 63 | * @result 64 | * A human-readable error string, or "Unknown Error" on invalid error. 65 | */ 66 | const char *LHStrError(enum LIBHOOKER_ERR err); 67 | 68 | /*! 69 | * @function LHOpenImage 70 | * 71 | * @abstract 72 | * Open a dylib for use with LHFindSymbols 73 | * 74 | * @discussion 75 | * dyld handles do not provide enough information to grab symbols. Use this to have libhooker load the dylib. 76 | * 77 | * @param path 78 | * The path to the image on disk or in the shared cache. 79 | * 80 | * @result 81 | * A handle to the dylib that may then be used with LHFindSymbols to find symbols. 82 | */ 83 | struct libhooker_image *LHOpenImage(const char *path); 84 | 85 | /*! 86 | * @function LHCloseImage 87 | * 88 | * @abstract 89 | * Close and free a dylib handle opened with LHOpenImage 90 | * 91 | * @param libhookerImage 92 | * The libhooker handle to the image on disk or in the shared cache. 93 | */ 94 | void LHCloseImage(struct libhooker_image *libhookerImage); 95 | 96 | /*! 97 | * @function LHFindSymbols 98 | * 99 | * @abstract 100 | * Search for symbols within a dylib either on disk or in the dyld shared cache. 101 | * 102 | * @discussion 103 | * dyld often is not able to find symbols that are present but not marked as public and/or exported. 104 | * Also often the dyld shared cache has symbols replaced with `` when loaded into memory. 105 | * 106 | * @param libhookerImage 107 | * The libhooker handle to the image on disk or in the shared cache 108 | * 109 | * @param symbolNames 110 | * An array of the symbol names to search for 111 | * 112 | * @param searchSyms 113 | * An array that gets populated with the symbols found 114 | * 115 | * @param searchSymCount 116 | * The number of symbols to search for 117 | * 118 | * @result 119 | * Returns true if all symbols were found 120 | */ 121 | bool LHFindSymbols(struct libhooker_image *libhookerImage, 122 | const char **symbolNames, 123 | void **searchSyms, 124 | size_t searchSymCount); 125 | 126 | /*! 127 | * @function LHExecMemory 128 | * 129 | * @abstract 130 | * Creates an executable page from raw instruction data 131 | * 132 | * @discussion 133 | * Sometimes a library may generate or load new code, but may simply want an executable page with this new code. 134 | * 135 | * @param page 136 | * A pointer that gets written to with the address of code in the new memory page 137 | * 138 | * @param data 139 | * An array of ARM64 opcodes to write to this new memory page. 140 | * 141 | * @param size 142 | * The size of data 143 | * 144 | * @result 145 | * Returns true if the memory was created. Returns false otherwise. 146 | */ 147 | bool LHExecMemory(void **page, void *data, size_t size); 148 | 149 | /*! 150 | * @struct LHMemoryPatch 151 | * 152 | * @abstract 153 | * Describes a memory region to patch 154 | * 155 | * @field destination 156 | * A pointer to the memory location to patch 157 | * 158 | * @field data 159 | * A pointer to the data to write at the patch location 160 | * 161 | * @field size 162 | * The number of bytes to write at the patch location 163 | * 164 | * @field options 165 | * A pointer to an extended options struct. Currently unused. 166 | * 167 | */ 168 | struct LHMemoryPatch { 169 | void *destination; 170 | const void *data; 171 | size_t size; 172 | void *options; 173 | }; 174 | 175 | /*! 176 | * @function LHPatchMemory 177 | * 178 | * @abstract 179 | * Patch memory (that may often be read-only or read/execute-only) 180 | * 181 | * @discussion 182 | * Sometimes low level memory access is required to hook parts of applications. This function 183 | * provides an easy way for libraries to do so, with a relatively safe guarantee of preserving 184 | * memory permissions, and re-mapping the memory if required. 185 | * 186 | * @param patches 187 | * A pointer to the destination to write to 188 | * 189 | * @param count 190 | * The number of memory regions to patch 191 | * 192 | * @result 193 | * Returns the number of memory regions successfully patched. This should match count if all regions were succesfully patched. 194 | * 195 | * @result errno 196 | * Returns any errors that may have taken place while hooking the functions 197 | */ 198 | int LHPatchMemory(const struct LHMemoryPatch *patches, int count); 199 | 200 | enum LHOptions { 201 | LHOptionsNone = 0, 202 | LHOptionsSetJumpReg = 1 203 | }; 204 | 205 | struct LHFunctionHookOptions { 206 | enum LHOptions options; 207 | int jmp_reg; 208 | }; 209 | 210 | /*! 211 | * @struct LHFunctionhook 212 | * 213 | * @abstract 214 | * Describes a function hook 215 | * 216 | * @field function 217 | * A pointer to the function to hook 218 | * 219 | * @field replacement 220 | * A pointer to the replacement function that will get called in place 221 | * 222 | * @field oldptr 223 | * If not null, this pointer gets written to with the address of a trampoline that lets you call the original function 224 | * 225 | * @discussion 226 | * Setting oldptr to null will allow libhooker to hook smaller functions and will skip over several checks since it does not need to try preserving the original function 227 | * 228 | * @field options 229 | * An optional field that may be populated with a pointer to an LHFunctionHookOptions struct 230 | */ 231 | struct LHFunctionHook { 232 | void *function; 233 | void *replacement; 234 | void *oldptr; 235 | struct LHFunctionHookOptions *options; 236 | }; 237 | 238 | /*! 239 | * @function LHHookFunctions 240 | * 241 | * @abstract 242 | * Hook Functions in memory 243 | * 244 | * @discussion 245 | * Libraries often need to hook functions in memory. This provides an easy way to hook the function and get back 246 | * a pointer to the original function, should you need to call it. 247 | * 248 | * @param hooks 249 | * An array of LHFunctionHook describing each function to hook 250 | * 251 | * @param count 252 | * The number of functions to hook 253 | * 254 | * @result 255 | * Returns the number of functions successfully hooked. This should match count if all functions were succesfully hooked. 256 | * 257 | * @result errno 258 | * Returns any errors that may have taken place while hooking the functions 259 | */ 260 | int LHHookFunctions(const struct LHFunctionHook *hooks, int count); 261 | 262 | #ifdef __cplusplus 263 | } 264 | #endif 265 | 266 | #endif /* libhooker_h */ 267 | -------------------------------------------------------------------------------- /Modules/libsubstitute.bundle/HKSubstitute.h: -------------------------------------------------------------------------------- 1 | #ifndef hksubstitute_h 2 | #define hksubstitute_h 3 | 4 | #import 5 | 6 | @interface HKSubstitute : HookKitModule 7 | @end 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /Modules/libsubstitute.bundle/HKSubstitute.m: -------------------------------------------------------------------------------- 1 | #import "HKSubstitute.h" 2 | #import "vendor/substitute/substitute.h" 3 | #import "vendor/substrate/substrate.h" 4 | 5 | @implementation HKSubstitute 6 | - (BOOL)_hookClass:(Class)objcClass selector:(SEL)selector replacement:(void *)replacement orig:(void **)orig { 7 | return substitute_hook_objc_message(objcClass, selector, replacement, orig, NULL) == SUBSTITUTE_OK; 8 | } 9 | 10 | - (BOOL)_hookFunction:(void *)function replacement:(void *)replacement orig:(void **)orig { 11 | struct substitute_function_hook hook = { 12 | function, replacement, orig, 0 13 | }; 14 | 15 | return substitute_hook_functions(&hook, 1, NULL, SUBSTITUTE_NO_THREAD_SAFETY) == SUBSTITUTE_OK; 16 | } 17 | 18 | - (int)_hookFunctions:(NSArray *)functions { 19 | NSMutableData* hooks = [NSMutableData new]; 20 | 21 | for(HookKitFunctionHook* function in functions) { 22 | struct substitute_function_hook hook = { 23 | [function function], [function replacement], [function orig], 0 24 | }; 25 | 26 | [hooks appendBytes:&hook length:sizeof(struct substitute_function_hook)]; 27 | } 28 | 29 | int result = substitute_hook_functions([hooks bytes], [functions count], NULL, SUBSTITUTE_NO_THREAD_SAFETY); 30 | 31 | if(result != SUBSTITUTE_OK) { 32 | NSLog(@"[HKSubstitute] warning: batch substitute_hook_functions retval: %d", result); 33 | } 34 | 35 | return [functions count]; 36 | } 37 | 38 | - (BOOL)_hookRegion:(void *)target data:(const void *)data size:(size_t)size { 39 | MSHookMemory(target, data, size); 40 | return YES; 41 | } 42 | 43 | - (int)_hookRegions:(NSArray *)regions { 44 | return -1; 45 | } 46 | 47 | - (void *)_openImage:(const char *)path { 48 | return (void *)substitute_open_image(path); 49 | } 50 | 51 | - (void)_closeImage:(void *)image { 52 | substitute_close_image((struct substitute_image *)image); 53 | } 54 | 55 | - (void *)_findSymbol:(const char *)symbol image:(void *)image { 56 | void* addr = NULL; 57 | int result = substitute_find_private_syms((struct substitute_image *)image, &symbol, &addr, 1); 58 | 59 | if(result != SUBSTITUTE_OK) { 60 | NSLog(@"[HKSubstitute] warning: substitute_find_private_syms retval: %d", result); 61 | } 62 | 63 | return addr; 64 | } 65 | @end 66 | -------------------------------------------------------------------------------- /Modules/libsubstitute.bundle/Makefile: -------------------------------------------------------------------------------- 1 | ARCHS ?= arm64 arm64e 2 | TARGET ?= iphone:clang:14.5:8.0 3 | 4 | include $(THEOS)/makefiles/common.mk 5 | 6 | BUNDLE_NAME = HookKitSubstituteModule 7 | HookKitSubstituteModule_BUNDLE_EXTENSION = bundle 8 | HookKitSubstituteModule_FILES = Module.m HKSubstitute.m 9 | HookKitSubstituteModule_LIBRARIES = _substitute 10 | HookKitSubstituteModule_EXTRA_FRAMEWORKS = HookKit _CydiaSubstrate 11 | HookKitSubstituteModule_CFLAGS = -fobjc-arc -Ivendor/HookKit.framework/Headers 12 | HookKitSubstituteModule_LDFLAGS = -rpath /Library/Frameworks -rpath /var/jb/Library/Frameworks -rpath /usr/lib -rpath /var/jb/usr/lib 13 | HookKitSubstituteModule_LDFLAGS += -Fvendor -Lvendor/substitute 14 | HookKitSubstituteModule_INSTALL_PATH = /Library/Modulous/HookKit 15 | 16 | include $(THEOS_MAKE_PATH)/bundle.mk 17 | -------------------------------------------------------------------------------- /Modules/libsubstitute.bundle/Module.m: -------------------------------------------------------------------------------- 1 | #import "HKSubstitute.h" 2 | #import 3 | 4 | __attribute__ ((constructor)) static void module_init(void) { 5 | HKSubstitute* module = [HKSubstitute new]; 6 | [module setFunctionHookBatchingSupported:YES]; 7 | 8 | [[HookKitCore sharedInstance] registerModule:module withIdentifier:@"substitute"]; 9 | } 10 | -------------------------------------------------------------------------------- /Modules/libsubstitute.bundle/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleName 6 | HookKitSubstituteModule 7 | CFBundleExecutable 8 | HookKitSubstituteModule 9 | CFBundleIdentifier 10 | me.jjolano.hkmodule.substitute 11 | CFBundleDevelopmentRegion 12 | English 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | ModuleInfo 22 | 23 | Author 24 | jjolano 25 | Version 26 | 1.0 27 | Description 28 | Substitute 29 | Priority 30 | 2 31 | Identifier 32 | substitute 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Modules/libsubstitute.bundle/control: -------------------------------------------------------------------------------- 1 | Package: me.jjolano.hkmodule.substitute 2 | Name: HookKit Module (Substitute) 3 | Pre-Depends: me.jjolano.fmwk.hookkit 4 | Depends: com.ex.substitute | com.ex.libsubstitute | science.xnu.substitute, mobilesubstrate 5 | Provides: me.jjolano.hkmodule.substrate 6 | Version: 1.0.10 7 | Architecture: iphoneos-arm 8 | Description: This module provides the Substitute API for HookKit Framework. 9 | Maintainer: jjolano 10 | Author: jjolano 11 | Section: HookKit (Modules) 12 | -------------------------------------------------------------------------------- /Modules/libsubstitute.bundle/vendor/HookKit.framework: -------------------------------------------------------------------------------- 1 | ../../../ -------------------------------------------------------------------------------- /Modules/libsubstitute.bundle/vendor/_CydiaSubstrate.framework/_CydiaSubstrate.tbd: -------------------------------------------------------------------------------- 1 | --- 2 | archs: [ armv7, armv7s, arm64, arm64e, i386, x86_64 ] 3 | platform: iphoneos 4 | install-name: '@rpath/CydiaSubstrate.framework/CydiaSubstrate' 5 | current-version: 0.0.0 6 | compatibility-version: 0.0.0 7 | exports: 8 | - archs: [ armv7, armv7s, arm64, arm64e, i386, x86_64 ] 9 | symbols: [ _MSCloseImage, _MSDebug, _MSFindAddress, _MSFindSymbol, 10 | _MSGetImageByName, _MSHookClassPair, _MSHookFunction, 11 | _MSHookMemory, _MSHookMessageEx, _MSImageAddress, 12 | _MSMapImage ] 13 | ... 14 | -------------------------------------------------------------------------------- /Modules/libsubstitute.bundle/vendor/substitute/lib_substitute.tbd: -------------------------------------------------------------------------------- 1 | --- 2 | archs: [ arm64, arm64e ] 3 | platform: ios 4 | install-name: '@rpath/libsubstitute.dylib' 5 | current-version: 0.0.0 6 | compatibility-version: 0.0.0 7 | exports: 8 | - archs: [ arm64, arm64e ] 9 | symbols: [ SubFindSymbol, SubGetImageByName, SubHookFunction, 10 | SubHookMemory, SubHookMessageEx, 11 | _substitute_close_image, _substitute_dlopen_in_pid, 12 | _substitute_find_private_syms, 13 | _substitute_free_created_imp, 14 | _substitute_hook_functions, 15 | _substitute_hook_objc_message, 16 | _substitute_interpose_imports, 17 | _substitute_open_image, _substitute_strerror ] 18 | ... 19 | -------------------------------------------------------------------------------- /Modules/libsubstitute.bundle/vendor/substitute/substitute.h: -------------------------------------------------------------------------------- 1 | /* 2 | libsubstitute - https://github.com/comex/substitute 3 | This header file itself is in the public domain (or in any jusrisdiction 4 | where the former is ineffective, CC0 1.0). 5 | */ 6 | 7 | #pragma once 8 | 9 | #if __has_include("substitute-internal.h") 10 | #include "substitute-internal.h" 11 | #endif 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif 20 | 21 | /* Error codes */ 22 | enum { 23 | /* TODO add numbers */ 24 | SUBSTITUTE_OK = 0, 25 | 26 | /* substitute_hook_functions: can't patch a function because it's too short- 27 | * i.e. there's an unconditional return instruction inside the patch region 28 | * (and not at its end) */ 29 | SUBSTITUTE_ERR_FUNC_TOO_SHORT = 1, 30 | 31 | /* substitute_hook_functions: can't patch a function because one of the 32 | * instructions within the patch region is one of a few special problematic 33 | * cases - if you get this on real code, the library should probably be 34 | * updated to handle that case properly */ 35 | SUBSTITUTE_ERR_FUNC_BAD_INSN_AT_START = 2, 36 | 37 | /* substitute_hook_functions: can't patch a function because one of the 38 | * instructions within the patch region (other than the last instruction) 39 | * is a call - meaning that a return address within the region (i.e. about 40 | * to point to clobbered code) could be on some thread's stack, where we 41 | * can't easily find and patch it. This check is skipped if 42 | * SUBSTITUTE_NO_THREAD_SAFETY is set. */ 43 | SUBSTITUTE_ERR_FUNC_CALLS_AT_START = 3, 44 | 45 | /* substitute_hook_functions: can't patch a function because the (somewhat 46 | * cursory) jump analysis found a jump later in the function to within the 47 | * patch region at the beginning */ 48 | SUBSTITUTE_ERR_FUNC_JUMPS_TO_START = 4, 49 | 50 | /* out of memory */ 51 | SUBSTITUTE_ERR_OOM = 5, 52 | 53 | /* substitute_hook_functions: mmap, mprotect, vm_copy, or 54 | * vm_remap failure 55 | * substitute_hook_objc_message: vm_remap failure 56 | * Most likely to come up with substitute_hook_functions if the kernel is 57 | * preventing pages from being marked executable. */ 58 | SUBSTITUTE_ERR_VM = 6, 59 | 60 | /* substitute_hook_functions: not on the main thread, and you did not pass 61 | * SUBSTITUTE_NO_THREAD_SAFETY */ 62 | SUBSTITUTE_ERR_NOT_ON_MAIN_THREAD = 7, 63 | 64 | /* substitute_hook_functions: when trying to patch the PC of other threads 65 | * (in case they were inside the patched prolog when they were suspended), 66 | * found a PC that was in the patch region but seemingly not at an 67 | * instruction boundary 68 | * The hooks were otherwise completed, but the thread in question will 69 | * probably crash now that its code has changed under it. */ 70 | SUBSTITUTE_ERR_UNEXPECTED_PC_ON_OTHER_THREAD = 8, 71 | 72 | /* substitute_hook_functions: destination was out of range, and mmap 73 | * wouldn't give us a trampoline in range */ 74 | SUBSTITUTE_ERR_OUT_OF_RANGE = 9, 75 | 76 | /* substitute_interpose_imports: couldn't redo relocation for an import 77 | * because the type was unknown */ 78 | SUBSTITUTE_ERR_UNKNOWN_RELOCATION_TYPE = 10, 79 | 80 | /* substitute_hook_objc_message: no such selector existed in the class's 81 | * inheritance tree */ 82 | SUBSTITUTE_ERR_NO_SUCH_SELECTOR = 11, 83 | 84 | /* substitute_hook_functions: OS error suspending other threads */ 85 | SUBSTITUTE_ERR_ADJUSTING_THREADS = 12, 86 | 87 | _SUBSTITUTE_CURRENT_MAX_ERR_PLUS_ONE, 88 | }; 89 | 90 | /* Get a string representation for a SUBSTITUTE_* error code. */ 91 | const char *substitute_strerror(int err); 92 | 93 | struct substitute_function_hook { 94 | /* The function to hook. (On ARM, Thumb functions are indicated as usual 95 | * for function pointers.) */ 96 | void *function; 97 | /* The replacement function. */ 98 | void *replacement; 99 | /* Optional: out *pointer* to function pointer to call old implementation 100 | * (i.e. given 'void (*old_foo)(...);', pass &old_foo) */ 101 | void *old_ptr; 102 | /* Currently unused; pass 0. (Protip: When using C {} struct initializer 103 | * syntax, you can just omit this.) */ 104 | int options; 105 | }; 106 | 107 | /* substitute_hook_functions options */ 108 | enum { 109 | SUBSTITUTE_NO_THREAD_SAFETY = 1, 110 | }; 111 | 112 | /* Patch the machine code of the specified functions to redirect them to the 113 | * specified replacements. 114 | * 115 | * After hooking, you can use the function pointer written to 'old_ptr' to call 116 | * the original implementation. (It points to a trampoline that executes the 117 | * original first few instructions, which were written over in the real 118 | * function, then jumps there for the rest.) 119 | * 120 | * This function must be called from the main thread. In return, it attempts 121 | * to be atomic in the face of concurrent calls to the functions being hooked. 122 | * Since there is no way to do that directly, it resorts to pausing all other 123 | * threads while doing its job; and since there is no way to do *that* 124 | * atomically on currently supported platforms, it does so by pausing each 125 | * thread one at a time. If multiple threads each tried to pause each other 126 | * this way, the process would be deadlocked, so mutual exclusion must be 127 | * implicitly provided by running on the main thread. 128 | * 129 | * You can disable the main thread check and all synchronization by passing 130 | * SUBSTITUTE_NO_THREAD_SAFETY. 131 | * 132 | * Why not just use a mutex to prevent deadlock? That would work between 133 | * multiple calls into libsubstitute, but there may be other libraries that 134 | * want to do the same thing and would not know about our mutex. My hope is 135 | * that using the main thread is sufficiently natural that the author of any 136 | * other similar library which cares about atomicity, noticing the same 137 | * concern, would independently come up with the same restriction - at least, 138 | * if they do not find an easier method to avoid deadlocks. Note that all 139 | * existing hooking libraries I know of make no attempt to do any 140 | * synchronization at all; this is fine if hooking is only done during 141 | * initialization while the process is single threaded, but I want to properly 142 | * support dynamic injection. (Note - if there is such an easier method on OS 143 | * X that does not involve spawning a separate process, I'd be curious to hear 144 | * about it.) 145 | * 146 | * 147 | * @hooks see struct substitute_function_hook 148 | * @nhooks number of hooks 149 | * @recordp if non-NULL, on success receives a pointer that can be used to 150 | * cleanly undo the hooks; currently unimplemented, so pass NULL 151 | * @options options - see above 152 | * @return SUBSTITUTE_OK, or any of most of the SUBSTITUTE_ERR_* 153 | */ 154 | struct substitute_function_hook_record; 155 | int substitute_hook_functions(const struct substitute_function_hook *hooks, 156 | size_t nhooks, 157 | struct substitute_function_hook_record **recordp, 158 | int options); 159 | 160 | #if 1 /* declare dynamic linker-related stuff? */ 161 | 162 | #ifdef __APPLE__ 163 | #include 164 | #ifdef __LP64__ 165 | typedef struct nlist_64 substitute_sym; 166 | #else 167 | typedef struct nlist substitute_sym; 168 | #endif 169 | #else 170 | #error No definition for substitute_sym! 171 | #endif 172 | 173 | struct substitute_image { 174 | #ifdef __APPLE__ 175 | intptr_t slide; 176 | const void *image_header; 177 | #endif 178 | /* possibly private fields... */ 179 | }; 180 | 181 | /* Look up an image currently loaded into the process. 182 | * 183 | * @filename the executable/library path (c.f. dyld(3) on Darwin) 184 | * @return a handle, or NULL if the image wasn't found 185 | */ 186 | struct substitute_image *substitute_open_image(const char *filename); 187 | 188 | /* Release a handle opened with substitute_open_image. 189 | * 190 | * @handle a banana 191 | */ 192 | void substitute_close_image(struct substitute_image *handle); 193 | 194 | /* Look up private symbols in an image currently loaded into the process. 195 | * 196 | * @handle handle opened with substitute_open_image 197 | * @names an array of symbol names to search for 198 | * @syms an array of void *, one per name; on return, each entry will be 199 | * filled in with the corresponding symbol address, or NULL if the 200 | * symbol wasn't found 201 | * (on ARM, this will be | 1 for Thumb functions) 202 | * @nsyms number of names 203 | * 204 | * @return SUBSTITUTE_OK (maybe errors in the future) 205 | */ 206 | int substitute_find_private_syms(struct substitute_image *handle, 207 | const char **__restrict names, 208 | void **__restrict syms, 209 | size_t nsyms); 210 | 211 | /* Get a pointer corresponding to a loaded symbol table entry. 212 | * @handle handle containing the symbol 213 | * @sym symbol 214 | * @return the pointer - on ARM, this can be | 1 for Thumb, like everything 215 | * else 216 | */ 217 | void *substitute_sym_to_ptr(struct substitute_image *handle, substitute_sym *sym); 218 | 219 | struct substitute_import_hook { 220 | /* The symbol name - this is raw, so C++ symbols are mangled, and on OS X 221 | * most symbols have '_' prepended. */ 222 | const char *name; 223 | /* The new import address. */ 224 | void *replacement; 225 | /* Optional: out pointer to old value. if there are multiple imports for 226 | * the same symbol, only one address is returned (hopefully they are all 227 | * equal) */ 228 | void *old_ptr; 229 | /* Currently unused; pass 0. (Protip: When using C {} struct initializer 230 | * syntax, you can just omit this.) */ 231 | int options; 232 | }; 233 | 234 | /* Directly modify the GOT/PLT entries from a specified image corresponding to 235 | * specified symbols. 236 | * 237 | * This can be used to 'hook' functions or even exported variables. Compared 238 | * to substitute_hook_functions, it has the following advantages: 239 | * 240 | * - It does not require the ability to patch executable code; accordingly, it 241 | * can (from a technical rather than policy perspective) be used in sandboxed 242 | * environments like iOS or PaX MPROTECT. 243 | * - On platforms without RELRO or similar, it is thread safe, as the patches 244 | * are done using atomic instructions. 245 | * - It does not require architecture specific code. 246 | * - It can be used to modify a single library's view of the world without 247 | * affecting the rest of the program. 248 | * 249 | * ...and the following disadvantages: 250 | * 251 | * - It only works for exported functions, and even then will not catch calls 252 | * from a library to its own exported functions. 253 | * - At present, it *only* works for a single importing library at a time. 254 | * Although it is not difficult on most platforms to iterate loaded libraries 255 | * in order to hook all of them, substitute does not currently provide this 256 | * functionality, traversing all libraries' symbol tables may be slow, and in 257 | * any case there is the matter of new importers being loaded after the fact. 258 | * 259 | * @handle handle of the importing library 260 | * @hooks see struct substitute_import_hook 261 | * @nhooks number of hooks 262 | * @recordp if non-NULL, on success receives a pointer that can be used to 263 | * cleanly undo the hooks; currently unimplemented, so pass NULL 264 | * @options options - pass 0 265 | * @return SUBSTITUTE_OK 266 | * SUBSTITUTE_ERR_UNKNOWN_RELOCATION_TYPE 267 | * SUBSTITUTE_ERR_VM - in the future with RELRO on Linux 268 | */ 269 | struct substitute_import_hook_record; 270 | int substitute_interpose_imports(const struct substitute_image *handle, 271 | const struct substitute_import_hook *hooks, 272 | size_t nhooks, 273 | struct substitute_import_hook_record **recordp, 274 | int options); 275 | 276 | 277 | #endif /* 1 */ 278 | 279 | #if defined(__APPLE__) 280 | #include 281 | /* Hook a method implementation for a given Objective-C class. By itself, this 282 | * function is thread safe: it is simply a wrapper for the atomic Objective-C 283 | * runtime call class_replaceMethod, plus the superclass-call generation 284 | * functionality described below, and some code to ensure atomicity if the 285 | * method is called while the function is in progress. However, it will race 286 | * with code that modifies class methods without using atomic runtime calls, 287 | * such as Substrate. 288 | * 289 | * @klass the class 290 | * @selector the selector 291 | * @replacement the new implementation (other APIs would call this an 292 | * IMP, but that isn't in general the real type of the 293 | * implementation, so declared as a void * here) 294 | * @old_ptr optional - out pointer to the 'old implementation'. 295 | * If there is no old implementation, a custom IMP is 296 | * returned that delegates to the superclass. This IMP can 297 | * be freed if desired with substitute_free_created_imp. 298 | * @created_imp_ptr optional - out pointer to whether a fake superclass-call 299 | * IMP has been placed in 300 | * 301 | * @return SUBSTITUTE_OK 302 | * SUBSTITUTE_ERR_NO_SUCH_SELECTOR 303 | */ 304 | int substitute_hook_objc_message(Class klass, SEL selector, void *replacement, 305 | void *old_ptr, bool *created_imp_ptr); 306 | 307 | void substitute_free_created_imp(IMP imp); 308 | #endif 309 | 310 | #ifdef __cplusplus 311 | } /* extern */ 312 | #endif 313 | -------------------------------------------------------------------------------- /Modules/libsubstitute.bundle/vendor/substrate/substrate.h: -------------------------------------------------------------------------------- 1 | /* Cydia Substrate - Powerful Code Insertion Platform 2 | * Copyright (C) 2008-2019 Jay Freeman (saurik) 3 | */ 4 | 5 | /* 6 | * Redistribution and use in source and binary 7 | * forms, with or without modification, are permitted 8 | * provided that the following conditions are met: 9 | * 10 | * 1. Redistributions of source code must retain the 11 | * above copyright notice, this list of conditions 12 | * and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the 14 | * above copyright notice, this list of conditions 15 | * and the following disclaimer in the documentation 16 | * and/or other materials provided with the 17 | * distribution. 18 | * 3. The name of the author may not be used to endorse 19 | * or promote products derived from this software 20 | * without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' 23 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 24 | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 25 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE 27 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 28 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 29 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 32 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 33 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 34 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 35 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #ifndef SUBSTRATE_H_ 39 | #define SUBSTRATE_H_ 40 | 41 | #ifdef __APPLE__ 42 | #ifdef __cplusplus 43 | extern "C" { 44 | #endif 45 | #include 46 | #ifdef __cplusplus 47 | } 48 | #endif 49 | 50 | #include 51 | #include 52 | #endif 53 | 54 | #include 55 | #include 56 | 57 | #include 58 | 59 | #define _finline \ 60 | inline __attribute__((__always_inline__)) 61 | #define _disused \ 62 | __attribute__((__unused__)) 63 | 64 | #ifdef __cplusplus 65 | #define _default(value) = value 66 | #else 67 | #define _default(value) 68 | #endif 69 | 70 | #ifdef __cplusplus 71 | extern "C" { 72 | #endif 73 | 74 | typedef const struct MSImage *MSImageRef; 75 | 76 | #ifdef __APPLE__ 77 | #ifndef __LP64__ 78 | typedef struct mach_header MSImageHeader; 79 | #else 80 | typedef struct mach_header_64 MSImageHeader; 81 | #endif 82 | #else 83 | typedef void MSImageHeader; 84 | #endif 85 | 86 | MSImageRef MSMapImage(const char *file); 87 | const MSImageHeader *MSImageAddress(MSImageRef image); 88 | void MSCloseImage(MSImageRef); 89 | 90 | MSImageRef MSGetImageByName(const char *file); 91 | 92 | void *MSFindSymbol(MSImageRef image, const char *name); 93 | char *MSFindAddress(MSImageRef image, void **address); 94 | 95 | void MSHookFunction(void *symbol, void *replace, void **result); 96 | void MSHookMemory(void *target, const void *data, size_t size); 97 | 98 | #ifdef __APPLE__ 99 | #ifdef __arm__ 100 | __attribute__((__deprecated__)) 101 | IMP MSHookMessage(Class _class, SEL sel, IMP imp, const char *prefix _default(NULL)); 102 | #endif 103 | void MSHookMessageEx(Class _class, SEL sel, IMP imp, IMP *result); 104 | void MSHookClassPair(Class target, Class hook, Class old); 105 | #endif 106 | 107 | #ifdef __ANDROID__ 108 | #include 109 | void MSJavaHookClassLoad(JNIEnv *jni, const char *name, void (*callback)(JNIEnv *, jclass, void *), void *data _default(NULL)); 110 | void MSJavaHookMethod(JNIEnv *jni, jclass _class, jmethodID methodID, void *function, void **result); 111 | void MSJavaBlessClassLoader(JNIEnv *jni, jobject loader); 112 | 113 | typedef struct MSJavaObjectKey_ *MSJavaObjectKey; 114 | MSJavaObjectKey MSJavaCreateObjectKey(); 115 | void MSJavaReleaseObjectKey(MSJavaObjectKey key); 116 | void *MSJavaGetObjectKey(JNIEnv *jni, jobject object, MSJavaObjectKey key); 117 | void MSJavaSetObjectKey(JNIEnv *jni, jobject object, MSJavaObjectKey key, void *value, void (*clean)(void *, JNIEnv *, void *) _default(NULL), void *data _default(NULL)); 118 | #endif 119 | 120 | #ifdef __cplusplus 121 | } 122 | #endif 123 | 124 | #ifdef __APPLE__ 125 | 126 | #define MSHookInterface(target, hook, base) \ 127 | @class target; \ 128 | @interface $ ## hook : base { target *$self; } @end \ 129 | @implementation $ ## hook \ 130 | + (void) initialize {} \ 131 | @end \ 132 | @interface hook : $ ## hook @end \ 133 | @implementation hook (MS) + (void) load { \ 134 | MSHookClassPair(objc_getClass(#target), self, class_getSuperclass(self)); \ 135 | } @end 136 | 137 | #define MSSelf ((__typeof__($self)) self) 138 | 139 | #endif 140 | 141 | #ifdef __cplusplus 142 | 143 | #ifdef __APPLE__ 144 | 145 | namespace etl { 146 | 147 | template 148 | struct Case { 149 | static char value[Case_ + 1]; 150 | }; 151 | 152 | typedef Case Yes; 153 | typedef Case No; 154 | 155 | namespace be { 156 | template 157 | static Yes CheckClass_(void (Checked_::*)()); 158 | 159 | template 160 | static No CheckClass_(...); 161 | } 162 | 163 | template 164 | struct IsClass { 165 | void gcc32(); 166 | 167 | static const bool value = (sizeof(be::CheckClass_(0).value) == sizeof(Yes::value)); 168 | }; 169 | 170 | } 171 | 172 | #ifdef __arm__ 173 | template 174 | __attribute__((__deprecated__)) 175 | static inline Type_ *MSHookMessage(Class _class, SEL sel, Type_ *imp, const char *prefix = NULL) { 176 | return reinterpret_cast(MSHookMessage(_class, sel, reinterpret_cast(imp), prefix)); 177 | } 178 | #endif 179 | 180 | template 181 | static inline void MSHookMessage(Class _class, SEL sel, Type_ *imp, Type_ **result) { 182 | return MSHookMessageEx(_class, sel, reinterpret_cast(imp), reinterpret_cast(result)); 183 | } 184 | 185 | template 186 | static inline Type_ &MSHookIvar(id self, const char *name) { 187 | Ivar ivar(class_getInstanceVariable(object_getClass(self), name)); 188 | void *pointer(ivar == NULL ? NULL : reinterpret_cast( 189 | #if __has_feature(objc_arc) 190 | (__bridge void *) 191 | #endif 192 | self) + ivar_getOffset(ivar)); 193 | return *reinterpret_cast(pointer); 194 | } 195 | 196 | #define MSAddMessage0(_class, type, arg0) \ 197 | class_addMethod($ ## _class, @selector(arg0), (IMP) &$ ## _class ## $ ## arg0, type); 198 | #define MSAddMessage1(_class, type, arg0) \ 199 | class_addMethod($ ## _class, @selector(arg0:), (IMP) &$ ## _class ## $ ## arg0 ## $, type); 200 | #define MSAddMessage2(_class, type, arg0, arg1) \ 201 | class_addMethod($ ## _class, @selector(arg0:arg1:), (IMP) &$ ## _class ## $ ## arg0 ## $ ## arg1 ## $, type); 202 | #define MSAddMessage3(_class, type, arg0, arg1, arg2) \ 203 | class_addMethod($ ## _class, @selector(arg0:arg1:arg2:), (IMP) &$ ## _class ## $ ## arg0 ## $ ## arg1 ## $ ## arg2 ## $, type); 204 | #define MSAddMessage4(_class, type, arg0, arg1, arg2, arg3) \ 205 | class_addMethod($ ## _class, @selector(arg0:arg1:arg2:arg3:), (IMP) &$ ## _class ## $ ## arg0 ## $ ## arg1 ## $ ## arg2 ## $ ## arg3 ## $, type); 206 | #define MSAddMessage5(_class, type, arg0, arg1, arg2, arg3, arg4) \ 207 | class_addMethod($ ## _class, @selector(arg0:arg1:arg2:arg3:arg4:), (IMP) &$ ## _class ## $ ## arg0 ## $ ## arg1 ## $ ## arg2 ## $ ## arg3 ## $ ## arg4 ## $, type); 208 | #define MSAddMessage6(_class, type, arg0, arg1, arg2, arg3, arg4, arg5) \ 209 | class_addMethod($ ## _class, @selector(arg0:arg1:arg2:arg3:arg4:arg5:), (IMP) &$ ## _class ## $ ## arg0 ## $ ## arg1 ## $ ## arg2 ## $ ## arg3 ## $ ## arg4 ## $ ## arg5 ## $, type); 210 | #define MSAddMessage7(_class, type, arg0, arg1, arg2, arg3, arg4, arg5, arg6) \ 211 | class_addMethod($ ## _class, @selector(arg0:arg1:arg2:arg3:arg4:arg5:arg6:), (IMP) &$ ## _class ## $ ## arg0 ## $ ## arg1 ## $ ## arg2 ## $ ## arg3 ## $ ## arg4 ## $ ## arg5 ## $ $$ arg6 ## $, type); 212 | #define MSAddMessage8(_class, type, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \ 213 | class_addMethod($ ## _class, @selector(arg0:arg1:arg2:arg3:arg4:arg5:arg6:arg7:), (IMP) &$ ## _class ## $ ## arg0 ## $ ## arg1 ## $ ## arg2 ## $ ## arg3 ## $ ## arg4 ## $ ## arg5 ## $ $$ arg6 ## $ ## arg7 ## $, type); 214 | 215 | #define MSHookMessage0(_class, arg0) \ 216 | MSHookMessage($ ## _class, @selector(arg0), MSHake(_class ## $ ## arg0)) 217 | #define MSHookMessage1(_class, arg0) \ 218 | MSHookMessage($ ## _class, @selector(arg0:), MSHake(_class ## $ ## arg0 ## $)) 219 | #define MSHookMessage2(_class, arg0, arg1) \ 220 | MSHookMessage($ ## _class, @selector(arg0:arg1:), MSHake(_class ## $ ## arg0 ## $ ## arg1 ## $)) 221 | #define MSHookMessage3(_class, arg0, arg1, arg2) \ 222 | MSHookMessage($ ## _class, @selector(arg0:arg1:arg2:), MSHake(_class ## $ ## arg0 ## $ ## arg1 ## $ ## arg2 ## $)) 223 | #define MSHookMessage4(_class, arg0, arg1, arg2, arg3) \ 224 | MSHookMessage($ ## _class, @selector(arg0:arg1:arg2:arg3:), MSHake(_class ## $ ## arg0 ## $ ## arg1 ## $ ## arg2 ## $ ## arg3 ## $)) 225 | #define MSHookMessage5(_class, arg0, arg1, arg2, arg3, arg4) \ 226 | MSHookMessage($ ## _class, @selector(arg0:arg1:arg2:arg3:arg4:), MSHake(_class ## $ ## arg0 ## $ ## arg1 ## $ ## arg2 ## $ ## arg3 ## $ ## arg4 ## $)) 227 | #define MSHookMessage6(_class, arg0, arg1, arg2, arg3, arg4, arg5) \ 228 | MSHookMessage($ ## _class, @selector(arg0:arg1:arg2:arg3:arg4:arg5:), MSHake(_class ## $ ## arg0 ## $ ## arg1 ## $ ## arg2 ## $ ## arg3 ## $ ## arg4 ## $ ## arg5 ## $)) 229 | #define MSHookMessage7(_class, arg0, arg1, arg2, arg3, arg4, arg5, arg6) \ 230 | MSHookMessage($ ## _class, @selector(arg0:arg1:arg2:arg3:arg4:arg5:arg6:), MSHake(_class ## $ ## arg0 ## $ ## arg1 ## $ ## arg2 ## $ ## arg3 ## $ ## arg4 ## $ ## arg5 ## $ ## arg6 ## $)) 231 | #define MSHookMessage8(_class, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \ 232 | MSHookMessage($ ## _class, @selector(arg0:arg1:arg2:arg3:arg4:arg5:arg6:arg7:), MSHake(_class ## $ ## arg0 ## $ ## arg1 ## $ ## arg2 ## $ ## arg3 ## $ ## arg4 ## $ ## arg5 ## $ ## arg6 ## $ ## arg7 ## $)) 233 | 234 | #define MSRegister_(name, dollar, colon) \ 235 | namespace { static class C_$ ## name ## $ ## dollar { public: _finline C_$ ## name ## $ ##dollar() { \ 236 | MSHookMessage($ ## name, @selector(colon), MSHake(name ## $ ## dollar)); \ 237 | } } V_$ ## name ## $ ## dollar; } \ 238 | 239 | #define MSIgnore_(name, dollar, colon) 240 | 241 | #ifdef __arm64__ 242 | #define MS_objc_msgSendSuper_stret objc_msgSendSuper 243 | #else 244 | #define MS_objc_msgSendSuper_stret objc_msgSendSuper_stret 245 | #endif 246 | 247 | #define MSMessage_(extra, type, _class, name, dollar, colon, call, args...) \ 248 | static type _$ ## name ## $ ## dollar(Class _cls, type (*_old)(_class, SEL, ## args, ...), type (*_spr)(struct objc_super *, SEL, ## args, ...), _class self, SEL _cmd, ## args); \ 249 | MSHook(type, name ## $ ## dollar, _class self, SEL _cmd, ## args) { \ 250 | Class const _cls($ ## name); \ 251 | type (* const _old)(_class, SEL, ## args, ...) = reinterpret_cast(_ ## name ## $ ## dollar); \ 252 | typedef type (*msgSendSuper_t)(struct objc_super *, SEL, ## args, ...); \ 253 | msgSendSuper_t const _spr(::etl::IsClass::value ? reinterpret_cast(&MS_objc_msgSendSuper_stret) : reinterpret_cast(&objc_msgSendSuper)); \ 254 | return _$ ## name ## $ ## dollar call; \ 255 | } \ 256 | extra(name, dollar, colon) \ 257 | static _finline type _$ ## name ## $ ## dollar(Class _cls, type (*_old)(_class, SEL, ## args, ...), type (*_spr)(struct objc_super *, SEL, ## args, ...), _class self, SEL _cmd, ## args) 258 | 259 | /* for((x=1;x!=7;++x)){ echo -n "#define MSMessage${x}_(extra, type, _class, name";for((y=0;y!=x;++y));do echo -n ", sel$y";done;for((y=0;y!=x;++y));do echo -n ", type$y, arg$y";done;echo ") \\";echo -n " MSMessage_(extra, type, _class, name,";for((y=0;y!=x;++y));do if [[ $y -ne 0 ]];then echo -n " ##";fi;echo -n " sel$y ## $";done;echo -n ", ";for((y=0;y!=x;++y));do echo -n "sel$y:";done;echo -n ", (_cls, _old, _spr, self, _cmd";for((y=0;y!=x;++y));do echo -n ", arg$y";done;echo -n ")";for((y=0;y!=x;++y));do echo -n ", type$y arg$y";done;echo ")";} */ 260 | 261 | #define MSMessage0_(extra, type, _class, name, sel0) \ 262 | MSMessage_(extra, type, _class, name, sel0, sel0, (_cls, _old, _spr, self, _cmd)) 263 | #define MSMessage1_(extra, type, _class, name, sel0, type0, arg0) \ 264 | MSMessage_(extra, type, _class, name, sel0 ## $, sel0:, (_cls, _old, _spr, self, _cmd, arg0), type0 arg0) 265 | #define MSMessage2_(extra, type, _class, name, sel0, sel1, type0, arg0, type1, arg1) \ 266 | MSMessage_(extra, type, _class, name, sel0 ## $ ## sel1 ## $, sel0:sel1:, (_cls, _old, _spr, self, _cmd, arg0, arg1), type0 arg0, type1 arg1) 267 | #define MSMessage3_(extra, type, _class, name, sel0, sel1, sel2, type0, arg0, type1, arg1, type2, arg2) \ 268 | MSMessage_(extra, type, _class, name, sel0 ## $ ## sel1 ## $ ## sel2 ## $, sel0:sel1:sel2:, (_cls, _old, _spr, self, _cmd, arg0, arg1, arg2), type0 arg0, type1 arg1, type2 arg2) 269 | #define MSMessage4_(extra, type, _class, name, sel0, sel1, sel2, sel3, type0, arg0, type1, arg1, type2, arg2, type3, arg3) \ 270 | MSMessage_(extra, type, _class, name, sel0 ## $ ## sel1 ## $ ## sel2 ## $ ## sel3 ## $, sel0:sel1:sel2:sel3:, (_cls, _old, _spr, self, _cmd, arg0, arg1, arg2, arg3), type0 arg0, type1 arg1, type2 arg2, type3 arg3) 271 | #define MSMessage5_(extra, type, _class, name, sel0, sel1, sel2, sel3, sel4, type0, arg0, type1, arg1, type2, arg2, type3, arg3, type4, arg4) \ 272 | MSMessage_(extra, type, _class, name, sel0 ## $ ## sel1 ## $ ## sel2 ## $ ## sel3 ## $ ## sel4 ## $, sel0:sel1:sel2:sel3:sel4:, (_cls, _old, _spr, self, _cmd, arg0, arg1, arg2, arg3, arg4), type0 arg0, type1 arg1, type2 arg2, type3 arg3, type4 arg4) 273 | #define MSMessage6_(extra, type, _class, name, sel0, sel1, sel2, sel3, sel4, sel5, type0, arg0, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5) \ 274 | MSMessage_(extra, type, _class, name, sel0 ## $ ## sel1 ## $ ## sel2 ## $ ## sel3 ## $ ## sel4 ## $ ## sel5 ## $, sel0:sel1:sel2:sel3:sel4:sel5:, (_cls, _old, _spr, self, _cmd, arg0, arg1, arg2, arg3, arg4, arg5), type0 arg0, type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) 275 | #define MSMessage7_(extra, type, _class, name, sel0, sel1, sel2, sel3, sel4, sel5, sel6, type0, arg0, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6) \ 276 | MSMessage_(extra, type, _class, name, sel0 ## $ ## sel1 ## $ ## sel2 ## $ ## sel3 ## $ ## sel4 ## $ ## sel5 ## $ ## sel6 ## $, sel0:sel1:sel2:sel3:sel4:sel5:sel6:, (_cls, _old, _spr, self, _cmd, arg0, arg1, arg2, arg3, arg4, arg5, arg6), type0 arg0, type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6) 277 | #define MSMessage8_(extra, type, _class, name, sel0, sel1, sel2, sel3, sel4, sel5, sel6, sel7, type0, arg0, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7) \ 278 | MSMessage_(extra, type, _class, name, sel0 ## $ ## sel1 ## $ ## sel2 ## $ ## sel3 ## $ ## sel4 ## $ ## sel5 ## $ ## sel6 ## $ ## sel7 ## $, sel0:sel1:sel2:sel3:sel4:sel5:sel6:sel7:, (_cls, _old, _spr, self, _cmd, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7), type0 arg0, type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6, type7 arg7) 279 | 280 | #define MSInstanceMessage0(type, _class, args...) MSMessage0_(MSIgnore_, type, _class *, _class, ## args) 281 | #define MSInstanceMessage1(type, _class, args...) MSMessage1_(MSIgnore_, type, _class *, _class, ## args) 282 | #define MSInstanceMessage2(type, _class, args...) MSMessage2_(MSIgnore_, type, _class *, _class, ## args) 283 | #define MSInstanceMessage3(type, _class, args...) MSMessage3_(MSIgnore_, type, _class *, _class, ## args) 284 | #define MSInstanceMessage4(type, _class, args...) MSMessage4_(MSIgnore_, type, _class *, _class, ## args) 285 | #define MSInstanceMessage5(type, _class, args...) MSMessage5_(MSIgnore_, type, _class *, _class, ## args) 286 | #define MSInstanceMessage6(type, _class, args...) MSMessage6_(MSIgnore_, type, _class *, _class, ## args) 287 | #define MSInstanceMessage7(type, _class, args...) MSMessage7_(MSIgnore_, type, _class *, _class, ## args) 288 | #define MSInstanceMessage8(type, _class, args...) MSMessage8_(MSIgnore_, type, _class *, _class, ## args) 289 | 290 | #define MSClassMessage0(type, _class, args...) MSMessage0_(MSIgnore_, type, Class, $ ## _class, ## args) 291 | #define MSClassMessage1(type, _class, args...) MSMessage1_(MSIgnore_, type, Class, $ ## _class, ## args) 292 | #define MSClassMessage2(type, _class, args...) MSMessage2_(MSIgnore_, type, Class, $ ## _class, ## args) 293 | #define MSClassMessage3(type, _class, args...) MSMessage3_(MSIgnore_, type, Class, $ ## _class, ## args) 294 | #define MSClassMessage4(type, _class, args...) MSMessage4_(MSIgnore_, type, Class, $ ## _class, ## args) 295 | #define MSClassMessage5(type, _class, args...) MSMessage5_(MSIgnore_, type, Class, $ ## _class, ## args) 296 | #define MSClassMessage6(type, _class, args...) MSMessage6_(MSIgnore_, type, Class, $ ## _class, ## args) 297 | #define MSClassMessage7(type, _class, args...) MSMessage7_(MSIgnore_, type, Class, $ ## _class, ## args) 298 | #define MSClassMessage8(type, _class, args...) MSMessage8_(MSIgnore_, type, Class, $ ## _class, ## args) 299 | 300 | #define MSInstanceMessageHook0(type, _class, args...) MSMessage0_(MSRegister_, type, _class *, _class, ## args) 301 | #define MSInstanceMessageHook1(type, _class, args...) MSMessage1_(MSRegister_, type, _class *, _class, ## args) 302 | #define MSInstanceMessageHook2(type, _class, args...) MSMessage2_(MSRegister_, type, _class *, _class, ## args) 303 | #define MSInstanceMessageHook3(type, _class, args...) MSMessage3_(MSRegister_, type, _class *, _class, ## args) 304 | #define MSInstanceMessageHook4(type, _class, args...) MSMessage4_(MSRegister_, type, _class *, _class, ## args) 305 | #define MSInstanceMessageHook5(type, _class, args...) MSMessage5_(MSRegister_, type, _class *, _class, ## args) 306 | #define MSInstanceMessageHook6(type, _class, args...) MSMessage6_(MSRegister_, type, _class *, _class, ## args) 307 | #define MSInstanceMessageHook7(type, _class, args...) MSMessage7_(MSRegister_, type, _class *, _class, ## args) 308 | #define MSInstanceMessageHook8(type, _class, args...) MSMessage8_(MSRegister_, type, _class *, _class, ## args) 309 | 310 | #define MSClassMessageHook0(type, _class, args...) MSMessage0_(MSRegister_, type, Class, $ ## _class, ## args) 311 | #define MSClassMessageHook1(type, _class, args...) MSMessage1_(MSRegister_, type, Class, $ ## _class, ## args) 312 | #define MSClassMessageHook2(type, _class, args...) MSMessage2_(MSRegister_, type, Class, $ ## _class, ## args) 313 | #define MSClassMessageHook3(type, _class, args...) MSMessage3_(MSRegister_, type, Class, $ ## _class, ## args) 314 | #define MSClassMessageHook4(type, _class, args...) MSMessage4_(MSRegister_, type, Class, $ ## _class, ## args) 315 | #define MSClassMessageHook5(type, _class, args...) MSMessage5_(MSRegister_, type, Class, $ ## _class, ## args) 316 | #define MSClassMessageHook6(type, _class, args...) MSMessage6_(MSRegister_, type, Class, $ ## _class, ## args) 317 | #define MSClassMessageHook7(type, _class, args...) MSMessage7_(MSRegister_, type, Class, $ ## _class, ## args) 318 | #define MSClassMessageHook8(type, _class, args...) MSMessage8_(MSRegister_, type, Class, $ ## _class, ## args) 319 | 320 | #define MSOldCall(args...) \ 321 | _old(self, _cmd, ## args) 322 | #define MSSuperCall(args...) \ 323 | _spr((struct objc_super[1]) {{self, class_getSuperclass(_cls)}}, _cmd, ## args) 324 | 325 | #define MSIvarHook(type, name) \ 326 | type &name(MSHookIvar(self, #name)) 327 | 328 | #define MSClassHook(name) \ 329 | @class name; \ 330 | static Class $ ## name = objc_getClass(#name); 331 | #define MSMetaClassHook(name) \ 332 | @class name; \ 333 | static Class $$ ## name = object_getClass($ ## name); 334 | 335 | #endif/*__APPLE__*/ 336 | 337 | template 338 | static inline void MSHookFunction(Type_ *symbol, Type_ *replace, Type_ **result) { 339 | return MSHookFunction( 340 | reinterpret_cast(symbol), 341 | reinterpret_cast(replace), 342 | reinterpret_cast(result) 343 | ); 344 | } 345 | 346 | template 347 | static inline void MSHookFunction(Type_ *symbol, Type_ *replace) { 348 | return MSHookFunction(symbol, replace, reinterpret_cast(NULL)); 349 | } 350 | 351 | template 352 | static inline void MSHookSymbol(Type_ *&value, const char *name, MSImageRef image = NULL) { 353 | value = reinterpret_cast(MSFindSymbol(image, name)); 354 | } 355 | 356 | template 357 | static inline void MSHookFunction(const char *name, Type_ *replace, Type_ **result = NULL) { 358 | Type_ *symbol; 359 | MSHookSymbol(symbol, name); 360 | return MSHookFunction(symbol, replace, result); 361 | } 362 | 363 | template 364 | static inline void MSHookFunction(MSImageRef image, const char *name, Type_ *replace, Type_ **result = NULL) { 365 | Type_ *symbol; 366 | MSHookSymbol(symbol, name, image); 367 | return MSHookFunction(symbol, replace, result); 368 | } 369 | 370 | template 371 | static inline void MSHookMemory(Type_ *target, const void *data, size_t size) { 372 | return MSHookMemory(reinterpret_cast(target), data, size); 373 | } 374 | 375 | #endif 376 | 377 | // g++ versions before 4.7 define __cplusplus to 1 378 | // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=1773 379 | #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) 380 | 381 | #ifdef __ANDROID__ 382 | 383 | template 384 | static inline void MSJavaHookMethod(JNIEnv *jni, jclass _class, jmethodID method, Type_ (*replace)(JNIEnv *, Kind_, Args_...), Type_ (**result)(JNIEnv *, Kind_, ...)) { 385 | return MSJavaHookMethod( 386 | jni, _class, method, 387 | reinterpret_cast(replace), 388 | reinterpret_cast(result) 389 | ); 390 | } 391 | 392 | #endif 393 | 394 | #endif 395 | 396 | #ifdef __ANDROID__ 397 | 398 | #ifdef __cplusplus 399 | 400 | static inline void MSAndroidGetPackage(JNIEnv *jni, jobject global, const char *name, jobject &local, jobject &loader) { 401 | jclass Context(jni->FindClass("android/content/Context")); 402 | jmethodID Context$createPackageContext(jni->GetMethodID(Context, "createPackageContext", "(Ljava/lang/String;I)Landroid/content/Context;")); 403 | jmethodID Context$getClassLoader(jni->GetMethodID(Context, "getClassLoader", "()Ljava/lang/ClassLoader;")); 404 | 405 | jstring string(jni->NewStringUTF(name)); 406 | local = jni->CallObjectMethod(global, Context$createPackageContext, string, 3); 407 | loader = jni->CallObjectMethod(local, Context$getClassLoader); 408 | } 409 | 410 | static inline jclass MSJavaFindClass(JNIEnv *jni, jobject loader, const char *name) { 411 | jclass Class(jni->FindClass("java/lang/Class")); 412 | jmethodID Class$forName(jni->GetStaticMethodID(Class, "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;")); 413 | 414 | jstring string(jni->NewStringUTF(name)); 415 | jobject _class(jni->CallStaticObjectMethod(Class, Class$forName, string, JNI_TRUE, loader)); 416 | 417 | if (jni->ExceptionCheck()) { 418 | jni->ExceptionClear(); 419 | return NULL; 420 | } 421 | 422 | return reinterpret_cast(_class); 423 | } 424 | 425 | _disused static void MSJavaCleanWeak(void *data, JNIEnv *jni, void *value) { 426 | jni->DeleteWeakGlobalRef(reinterpret_cast(value)); 427 | } 428 | 429 | #endif 430 | 431 | #endif 432 | 433 | #define MSHook(type, name, args...) \ 434 | _disused static type (*_ ## name)(args); \ 435 | static type $ ## name(args) 436 | 437 | #define MSJavaHook(type, name, arg0, args...) \ 438 | _disused static type (*_ ## name)(JNIEnv *jni, arg0, ...); \ 439 | static type $ ## name(JNIEnv *jni, arg0, ## args) 440 | 441 | #ifdef __cplusplus 442 | #define MSHake(name) \ 443 | &$ ## name, &_ ## name 444 | #else 445 | #define MSHake(name) \ 446 | &$ ## name, (void **) &_ ## name 447 | #endif 448 | 449 | #define SubstrateConcat_(lhs, rhs) \ 450 | lhs ## rhs 451 | #define SubstrateConcat(lhs, rhs) \ 452 | SubstrateConcat_(lhs, rhs) 453 | 454 | #define SubstrateStringize(value) \ 455 | #value 456 | 457 | #ifdef __APPLE__ 458 | #define SubstrateSection \ 459 | __attribute__((__section__("__TEXT, __substrate"))) 460 | #else 461 | #define SubstrateSection \ 462 | __attribute__((__section__(".substrate"))) 463 | #endif 464 | 465 | #ifdef __APPLE__ 466 | #define MSFilterCFBundleID "Filter:CFBundleID" 467 | #define MSFilterObjC_Class "Filter:ObjC.Class" 468 | #endif 469 | 470 | #ifdef __ANDROID__ 471 | #define MSFilterLibrary "Filter:Library" 472 | #endif 473 | 474 | #define MSFilterCFVersion "Filter:CFVersion" 475 | #define MSFilterExecutable "Filter:Executable" 476 | 477 | #define MSConfig(name, value) \ 478 | extern const char SubstrateConcat(_substrate_, __LINE__)[] SubstrateSection; \ 479 | const char SubstrateConcat(_substrate_, __LINE__)[] SubstrateSection = name "=" value; 480 | 481 | #define MSConfigValue(name, value) \ 482 | char SubstrateConcat(_substrate_MSConfigValue_Invalid_, __LINE__)[((double)value, 0)]; \ 483 | const char SubstrateConcat(_substrate_, __LINE__)[] SubstrateSection = name "=" SubstrateStringize(value); 484 | 485 | #define MSConfigRange(name, lo, hi) \ 486 | char SubstrateConcat(_substrate_MSConfigRange_Invalid_, __LINE__)[(double)lo <= (double)hi ? 0 : -1]; \ 487 | MSConfig(name, SubstrateStringize(lo) "," SubstrateStringize(hi)) 488 | 489 | #ifdef __cplusplus 490 | #define MSInitialize \ 491 | static void SubstrateConcat(_MSInitialize, __LINE__)(void); \ 492 | namespace { static class SubstrateConcat($MSInitialize, __LINE__) { public: _finline SubstrateConcat($MSInitialize, __LINE__)() { \ 493 | SubstrateConcat(_MSInitialize, __LINE__)(); \ 494 | } } SubstrateConcat($MSInitialize, __LINE__); } \ 495 | static void SubstrateConcat(_MSInitialize, __LINE__)() 496 | #else 497 | #define MSInitialize \ 498 | __attribute__((__constructor__)) static void SubstrateConcat(_MSInitialize, __LINE__)(void) 499 | #endif 500 | 501 | #define Foundation_f "/System/Library/Frameworks/Foundation.framework/Foundation" 502 | #define UIKit_f "/System/Library/Frameworks/UIKit.framework/UIKit" 503 | #define JavaScriptCore_f "/System/Library/PrivateFrameworks/JavaScriptCore.framework/JavaScriptCore" 504 | #define IOKit_f "/System/Library/Frameworks/IOKit.framework/IOKit" 505 | 506 | #endif//SUBSTRATE_H_ 507 | -------------------------------------------------------------------------------- /Modules/libsubstrate.bundle/HKSubstrate.h: -------------------------------------------------------------------------------- 1 | #ifndef hksubstrate_h 2 | #define hksubstrate_h 3 | 4 | #import 5 | 6 | @interface HKSubstrate : HookKitModule 7 | @end 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /Modules/libsubstrate.bundle/HKSubstrate.m: -------------------------------------------------------------------------------- 1 | #import "HKSubstrate.h" 2 | #import "vendor/substrate/substrate.h" 3 | 4 | @implementation HKSubstrate 5 | - (BOOL)_hookClass:(Class)objcClass selector:(SEL)selector replacement:(void *)replacement orig:(void **)orig { 6 | MSHookMessageEx(objcClass, selector, (IMP)replacement, (IMP *)orig); 7 | return YES; 8 | } 9 | 10 | - (BOOL)_hookFunction:(void *)function replacement:(void *)replacement orig:(void **)orig { 11 | MSHookFunction(function, replacement, orig); 12 | return YES; 13 | } 14 | 15 | - (int)_hookFunctions:(NSArray *)functions { 16 | return -1; 17 | } 18 | 19 | - (BOOL)_hookRegion:(void *)target data:(const void *)data size:(size_t)size { 20 | MSHookMemory(target, data, size); 21 | return YES; 22 | } 23 | 24 | - (int)_hookRegions:(NSArray *)regions { 25 | return -1; 26 | } 27 | 28 | - (void *)_openImage:(const char *)path { 29 | return (void *)MSGetImageByName(path); 30 | } 31 | 32 | - (void)_closeImage:(void *)image { 33 | // for some reason this symbol doesn't actually exist 34 | // MSCloseImage((MSImageRef)image); 35 | } 36 | 37 | - (void *)_findSymbol:(const char *)symbol image:(void *)image { 38 | return MSFindSymbol((MSImageRef)image, symbol); 39 | } 40 | @end 41 | -------------------------------------------------------------------------------- /Modules/libsubstrate.bundle/Makefile: -------------------------------------------------------------------------------- 1 | ARCHS ?= armv7 armv7s arm64 arm64e 2 | TARGET ?= iphone:clang:14.5:8.0 3 | 4 | include $(THEOS)/makefiles/common.mk 5 | 6 | BUNDLE_NAME = HookKitSubstrateModule 7 | HookKitSubstrateModule_BUNDLE_EXTENSION = bundle 8 | HookKitSubstrateModule_FILES = Module.m HKSubstrate.m 9 | HookKitSubstrateModule_EXTRA_FRAMEWORKS = HookKit _CydiaSubstrate 10 | HookKitSubstrateModule_CFLAGS = -fobjc-arc -Ivendor/HookKit.framework/Headers 11 | HookKitSubstrateModule_LDFLAGS = -rpath /Library/Frameworks -rpath /var/jb/Library/Frameworks -rpath /usr/lib -rpath /var/jb/usr/lib 12 | HookKitSubstrateModule_LDFLAGS += -Fvendor 13 | HookKitSubstrateModule_INSTALL_PATH = /Library/Modulous/HookKit 14 | 15 | include $(THEOS_MAKE_PATH)/bundle.mk 16 | -------------------------------------------------------------------------------- /Modules/libsubstrate.bundle/Module.m: -------------------------------------------------------------------------------- 1 | #import "HKSubstrate.h" 2 | #import 3 | 4 | __attribute__ ((constructor)) static void module_init(void) { 5 | HKSubstrate* module = [HKSubstrate new]; 6 | [module setNullImageSearchSupported:YES]; 7 | 8 | [[HookKitCore sharedInstance] registerModule:module withIdentifier:@"substrate"]; 9 | } 10 | -------------------------------------------------------------------------------- /Modules/libsubstrate.bundle/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleName 6 | HookKitSubstrateModule 7 | CFBundleExecutable 8 | HookKitSubstrateModule 9 | CFBundleIdentifier 10 | me.jjolano.hkmodule.substrate 11 | CFBundleDevelopmentRegion 12 | English 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | ModuleInfo 22 | 23 | Author 24 | jjolano 25 | Version 26 | 1.0 27 | Description 28 | Cydia Substrate 29 | Priority 30 | 3 31 | Identifier 32 | substrate 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Modules/libsubstrate.bundle/control: -------------------------------------------------------------------------------- 1 | Package: me.jjolano.hkmodule.substrate 2 | Name: HookKit Module (Cydia Substrate) 3 | Pre-Depends: me.jjolano.fmwk.hookkit 4 | Depends: mobilesubstrate 5 | Version: 1.0.8 6 | Architecture: iphoneos-arm 7 | Description: This module provides the Cydia Substrate API for HookKit Framework. 8 | Maintainer: jjolano 9 | Author: jjolano 10 | Section: HookKit (Modules) 11 | -------------------------------------------------------------------------------- /Modules/libsubstrate.bundle/vendor/HookKit.framework: -------------------------------------------------------------------------------- 1 | ../../../ -------------------------------------------------------------------------------- /Modules/libsubstrate.bundle/vendor/_CydiaSubstrate.framework/_CydiaSubstrate.tbd: -------------------------------------------------------------------------------- 1 | --- 2 | archs: [ armv7, armv7s, arm64, arm64e, i386, x86_64 ] 3 | platform: iphoneos 4 | install-name: '@rpath/CydiaSubstrate.framework/CydiaSubstrate' 5 | current-version: 0.0.0 6 | compatibility-version: 0.0.0 7 | exports: 8 | - archs: [ armv7, armv7s, arm64, arm64e, i386, x86_64 ] 9 | symbols: [ _MSCloseImage, _MSDebug, _MSFindAddress, _MSFindSymbol, 10 | _MSGetImageByName, _MSHookClassPair, _MSHookFunction, 11 | _MSHookMemory, _MSHookMessageEx, _MSImageAddress, 12 | _MSMapImage ] 13 | ... 14 | -------------------------------------------------------------------------------- /Modules/libsubstrate.bundle/vendor/substrate/substrate.h: -------------------------------------------------------------------------------- 1 | /* Cydia Substrate - Powerful Code Insertion Platform 2 | * Copyright (C) 2008-2019 Jay Freeman (saurik) 3 | */ 4 | 5 | /* 6 | * Redistribution and use in source and binary 7 | * forms, with or without modification, are permitted 8 | * provided that the following conditions are met: 9 | * 10 | * 1. Redistributions of source code must retain the 11 | * above copyright notice, this list of conditions 12 | * and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the 14 | * above copyright notice, this list of conditions 15 | * and the following disclaimer in the documentation 16 | * and/or other materials provided with the 17 | * distribution. 18 | * 3. The name of the author may not be used to endorse 19 | * or promote products derived from this software 20 | * without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' 23 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 24 | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 25 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE 27 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 28 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 29 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 32 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 33 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 34 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 35 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #ifndef SUBSTRATE_H_ 39 | #define SUBSTRATE_H_ 40 | 41 | #ifdef __APPLE__ 42 | #ifdef __cplusplus 43 | extern "C" { 44 | #endif 45 | #include 46 | #ifdef __cplusplus 47 | } 48 | #endif 49 | 50 | #include 51 | #include 52 | #endif 53 | 54 | #include 55 | #include 56 | 57 | #include 58 | 59 | #define _finline \ 60 | inline __attribute__((__always_inline__)) 61 | #define _disused \ 62 | __attribute__((__unused__)) 63 | 64 | #ifdef __cplusplus 65 | #define _default(value) = value 66 | #else 67 | #define _default(value) 68 | #endif 69 | 70 | #ifdef __cplusplus 71 | extern "C" { 72 | #endif 73 | 74 | typedef const struct MSImage *MSImageRef; 75 | 76 | #ifdef __APPLE__ 77 | #ifndef __LP64__ 78 | typedef struct mach_header MSImageHeader; 79 | #else 80 | typedef struct mach_header_64 MSImageHeader; 81 | #endif 82 | #else 83 | typedef void MSImageHeader; 84 | #endif 85 | 86 | MSImageRef MSMapImage(const char *file); 87 | const MSImageHeader *MSImageAddress(MSImageRef image); 88 | void MSCloseImage(MSImageRef); 89 | 90 | MSImageRef MSGetImageByName(const char *file); 91 | 92 | void *MSFindSymbol(MSImageRef image, const char *name); 93 | char *MSFindAddress(MSImageRef image, void **address); 94 | 95 | void MSHookFunction(void *symbol, void *replace, void **result); 96 | void MSHookMemory(void *target, const void *data, size_t size); 97 | 98 | #ifdef __APPLE__ 99 | #ifdef __arm__ 100 | __attribute__((__deprecated__)) 101 | IMP MSHookMessage(Class _class, SEL sel, IMP imp, const char *prefix _default(NULL)); 102 | #endif 103 | void MSHookMessageEx(Class _class, SEL sel, IMP imp, IMP *result); 104 | void MSHookClassPair(Class target, Class hook, Class old); 105 | #endif 106 | 107 | #ifdef __ANDROID__ 108 | #include 109 | void MSJavaHookClassLoad(JNIEnv *jni, const char *name, void (*callback)(JNIEnv *, jclass, void *), void *data _default(NULL)); 110 | void MSJavaHookMethod(JNIEnv *jni, jclass _class, jmethodID methodID, void *function, void **result); 111 | void MSJavaBlessClassLoader(JNIEnv *jni, jobject loader); 112 | 113 | typedef struct MSJavaObjectKey_ *MSJavaObjectKey; 114 | MSJavaObjectKey MSJavaCreateObjectKey(); 115 | void MSJavaReleaseObjectKey(MSJavaObjectKey key); 116 | void *MSJavaGetObjectKey(JNIEnv *jni, jobject object, MSJavaObjectKey key); 117 | void MSJavaSetObjectKey(JNIEnv *jni, jobject object, MSJavaObjectKey key, void *value, void (*clean)(void *, JNIEnv *, void *) _default(NULL), void *data _default(NULL)); 118 | #endif 119 | 120 | #ifdef __cplusplus 121 | } 122 | #endif 123 | 124 | #ifdef __APPLE__ 125 | 126 | #define MSHookInterface(target, hook, base) \ 127 | @class target; \ 128 | @interface $ ## hook : base { target *$self; } @end \ 129 | @implementation $ ## hook \ 130 | + (void) initialize {} \ 131 | @end \ 132 | @interface hook : $ ## hook @end \ 133 | @implementation hook (MS) + (void) load { \ 134 | MSHookClassPair(objc_getClass(#target), self, class_getSuperclass(self)); \ 135 | } @end 136 | 137 | #define MSSelf ((__typeof__($self)) self) 138 | 139 | #endif 140 | 141 | #ifdef __cplusplus 142 | 143 | #ifdef __APPLE__ 144 | 145 | namespace etl { 146 | 147 | template 148 | struct Case { 149 | static char value[Case_ + 1]; 150 | }; 151 | 152 | typedef Case Yes; 153 | typedef Case No; 154 | 155 | namespace be { 156 | template 157 | static Yes CheckClass_(void (Checked_::*)()); 158 | 159 | template 160 | static No CheckClass_(...); 161 | } 162 | 163 | template 164 | struct IsClass { 165 | void gcc32(); 166 | 167 | static const bool value = (sizeof(be::CheckClass_(0).value) == sizeof(Yes::value)); 168 | }; 169 | 170 | } 171 | 172 | #ifdef __arm__ 173 | template 174 | __attribute__((__deprecated__)) 175 | static inline Type_ *MSHookMessage(Class _class, SEL sel, Type_ *imp, const char *prefix = NULL) { 176 | return reinterpret_cast(MSHookMessage(_class, sel, reinterpret_cast(imp), prefix)); 177 | } 178 | #endif 179 | 180 | template 181 | static inline void MSHookMessage(Class _class, SEL sel, Type_ *imp, Type_ **result) { 182 | return MSHookMessageEx(_class, sel, reinterpret_cast(imp), reinterpret_cast(result)); 183 | } 184 | 185 | template 186 | static inline Type_ &MSHookIvar(id self, const char *name) { 187 | Ivar ivar(class_getInstanceVariable(object_getClass(self), name)); 188 | void *pointer(ivar == NULL ? NULL : reinterpret_cast( 189 | #if __has_feature(objc_arc) 190 | (__bridge void *) 191 | #endif 192 | self) + ivar_getOffset(ivar)); 193 | return *reinterpret_cast(pointer); 194 | } 195 | 196 | #define MSAddMessage0(_class, type, arg0) \ 197 | class_addMethod($ ## _class, @selector(arg0), (IMP) &$ ## _class ## $ ## arg0, type); 198 | #define MSAddMessage1(_class, type, arg0) \ 199 | class_addMethod($ ## _class, @selector(arg0:), (IMP) &$ ## _class ## $ ## arg0 ## $, type); 200 | #define MSAddMessage2(_class, type, arg0, arg1) \ 201 | class_addMethod($ ## _class, @selector(arg0:arg1:), (IMP) &$ ## _class ## $ ## arg0 ## $ ## arg1 ## $, type); 202 | #define MSAddMessage3(_class, type, arg0, arg1, arg2) \ 203 | class_addMethod($ ## _class, @selector(arg0:arg1:arg2:), (IMP) &$ ## _class ## $ ## arg0 ## $ ## arg1 ## $ ## arg2 ## $, type); 204 | #define MSAddMessage4(_class, type, arg0, arg1, arg2, arg3) \ 205 | class_addMethod($ ## _class, @selector(arg0:arg1:arg2:arg3:), (IMP) &$ ## _class ## $ ## arg0 ## $ ## arg1 ## $ ## arg2 ## $ ## arg3 ## $, type); 206 | #define MSAddMessage5(_class, type, arg0, arg1, arg2, arg3, arg4) \ 207 | class_addMethod($ ## _class, @selector(arg0:arg1:arg2:arg3:arg4:), (IMP) &$ ## _class ## $ ## arg0 ## $ ## arg1 ## $ ## arg2 ## $ ## arg3 ## $ ## arg4 ## $, type); 208 | #define MSAddMessage6(_class, type, arg0, arg1, arg2, arg3, arg4, arg5) \ 209 | class_addMethod($ ## _class, @selector(arg0:arg1:arg2:arg3:arg4:arg5:), (IMP) &$ ## _class ## $ ## arg0 ## $ ## arg1 ## $ ## arg2 ## $ ## arg3 ## $ ## arg4 ## $ ## arg5 ## $, type); 210 | #define MSAddMessage7(_class, type, arg0, arg1, arg2, arg3, arg4, arg5, arg6) \ 211 | class_addMethod($ ## _class, @selector(arg0:arg1:arg2:arg3:arg4:arg5:arg6:), (IMP) &$ ## _class ## $ ## arg0 ## $ ## arg1 ## $ ## arg2 ## $ ## arg3 ## $ ## arg4 ## $ ## arg5 ## $ $$ arg6 ## $, type); 212 | #define MSAddMessage8(_class, type, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \ 213 | class_addMethod($ ## _class, @selector(arg0:arg1:arg2:arg3:arg4:arg5:arg6:arg7:), (IMP) &$ ## _class ## $ ## arg0 ## $ ## arg1 ## $ ## arg2 ## $ ## arg3 ## $ ## arg4 ## $ ## arg5 ## $ $$ arg6 ## $ ## arg7 ## $, type); 214 | 215 | #define MSHookMessage0(_class, arg0) \ 216 | MSHookMessage($ ## _class, @selector(arg0), MSHake(_class ## $ ## arg0)) 217 | #define MSHookMessage1(_class, arg0) \ 218 | MSHookMessage($ ## _class, @selector(arg0:), MSHake(_class ## $ ## arg0 ## $)) 219 | #define MSHookMessage2(_class, arg0, arg1) \ 220 | MSHookMessage($ ## _class, @selector(arg0:arg1:), MSHake(_class ## $ ## arg0 ## $ ## arg1 ## $)) 221 | #define MSHookMessage3(_class, arg0, arg1, arg2) \ 222 | MSHookMessage($ ## _class, @selector(arg0:arg1:arg2:), MSHake(_class ## $ ## arg0 ## $ ## arg1 ## $ ## arg2 ## $)) 223 | #define MSHookMessage4(_class, arg0, arg1, arg2, arg3) \ 224 | MSHookMessage($ ## _class, @selector(arg0:arg1:arg2:arg3:), MSHake(_class ## $ ## arg0 ## $ ## arg1 ## $ ## arg2 ## $ ## arg3 ## $)) 225 | #define MSHookMessage5(_class, arg0, arg1, arg2, arg3, arg4) \ 226 | MSHookMessage($ ## _class, @selector(arg0:arg1:arg2:arg3:arg4:), MSHake(_class ## $ ## arg0 ## $ ## arg1 ## $ ## arg2 ## $ ## arg3 ## $ ## arg4 ## $)) 227 | #define MSHookMessage6(_class, arg0, arg1, arg2, arg3, arg4, arg5) \ 228 | MSHookMessage($ ## _class, @selector(arg0:arg1:arg2:arg3:arg4:arg5:), MSHake(_class ## $ ## arg0 ## $ ## arg1 ## $ ## arg2 ## $ ## arg3 ## $ ## arg4 ## $ ## arg5 ## $)) 229 | #define MSHookMessage7(_class, arg0, arg1, arg2, arg3, arg4, arg5, arg6) \ 230 | MSHookMessage($ ## _class, @selector(arg0:arg1:arg2:arg3:arg4:arg5:arg6:), MSHake(_class ## $ ## arg0 ## $ ## arg1 ## $ ## arg2 ## $ ## arg3 ## $ ## arg4 ## $ ## arg5 ## $ ## arg6 ## $)) 231 | #define MSHookMessage8(_class, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \ 232 | MSHookMessage($ ## _class, @selector(arg0:arg1:arg2:arg3:arg4:arg5:arg6:arg7:), MSHake(_class ## $ ## arg0 ## $ ## arg1 ## $ ## arg2 ## $ ## arg3 ## $ ## arg4 ## $ ## arg5 ## $ ## arg6 ## $ ## arg7 ## $)) 233 | 234 | #define MSRegister_(name, dollar, colon) \ 235 | namespace { static class C_$ ## name ## $ ## dollar { public: _finline C_$ ## name ## $ ##dollar() { \ 236 | MSHookMessage($ ## name, @selector(colon), MSHake(name ## $ ## dollar)); \ 237 | } } V_$ ## name ## $ ## dollar; } \ 238 | 239 | #define MSIgnore_(name, dollar, colon) 240 | 241 | #ifdef __arm64__ 242 | #define MS_objc_msgSendSuper_stret objc_msgSendSuper 243 | #else 244 | #define MS_objc_msgSendSuper_stret objc_msgSendSuper_stret 245 | #endif 246 | 247 | #define MSMessage_(extra, type, _class, name, dollar, colon, call, args...) \ 248 | static type _$ ## name ## $ ## dollar(Class _cls, type (*_old)(_class, SEL, ## args, ...), type (*_spr)(struct objc_super *, SEL, ## args, ...), _class self, SEL _cmd, ## args); \ 249 | MSHook(type, name ## $ ## dollar, _class self, SEL _cmd, ## args) { \ 250 | Class const _cls($ ## name); \ 251 | type (* const _old)(_class, SEL, ## args, ...) = reinterpret_cast(_ ## name ## $ ## dollar); \ 252 | typedef type (*msgSendSuper_t)(struct objc_super *, SEL, ## args, ...); \ 253 | msgSendSuper_t const _spr(::etl::IsClass::value ? reinterpret_cast(&MS_objc_msgSendSuper_stret) : reinterpret_cast(&objc_msgSendSuper)); \ 254 | return _$ ## name ## $ ## dollar call; \ 255 | } \ 256 | extra(name, dollar, colon) \ 257 | static _finline type _$ ## name ## $ ## dollar(Class _cls, type (*_old)(_class, SEL, ## args, ...), type (*_spr)(struct objc_super *, SEL, ## args, ...), _class self, SEL _cmd, ## args) 258 | 259 | /* for((x=1;x!=7;++x)){ echo -n "#define MSMessage${x}_(extra, type, _class, name";for((y=0;y!=x;++y));do echo -n ", sel$y";done;for((y=0;y!=x;++y));do echo -n ", type$y, arg$y";done;echo ") \\";echo -n " MSMessage_(extra, type, _class, name,";for((y=0;y!=x;++y));do if [[ $y -ne 0 ]];then echo -n " ##";fi;echo -n " sel$y ## $";done;echo -n ", ";for((y=0;y!=x;++y));do echo -n "sel$y:";done;echo -n ", (_cls, _old, _spr, self, _cmd";for((y=0;y!=x;++y));do echo -n ", arg$y";done;echo -n ")";for((y=0;y!=x;++y));do echo -n ", type$y arg$y";done;echo ")";} */ 260 | 261 | #define MSMessage0_(extra, type, _class, name, sel0) \ 262 | MSMessage_(extra, type, _class, name, sel0, sel0, (_cls, _old, _spr, self, _cmd)) 263 | #define MSMessage1_(extra, type, _class, name, sel0, type0, arg0) \ 264 | MSMessage_(extra, type, _class, name, sel0 ## $, sel0:, (_cls, _old, _spr, self, _cmd, arg0), type0 arg0) 265 | #define MSMessage2_(extra, type, _class, name, sel0, sel1, type0, arg0, type1, arg1) \ 266 | MSMessage_(extra, type, _class, name, sel0 ## $ ## sel1 ## $, sel0:sel1:, (_cls, _old, _spr, self, _cmd, arg0, arg1), type0 arg0, type1 arg1) 267 | #define MSMessage3_(extra, type, _class, name, sel0, sel1, sel2, type0, arg0, type1, arg1, type2, arg2) \ 268 | MSMessage_(extra, type, _class, name, sel0 ## $ ## sel1 ## $ ## sel2 ## $, sel0:sel1:sel2:, (_cls, _old, _spr, self, _cmd, arg0, arg1, arg2), type0 arg0, type1 arg1, type2 arg2) 269 | #define MSMessage4_(extra, type, _class, name, sel0, sel1, sel2, sel3, type0, arg0, type1, arg1, type2, arg2, type3, arg3) \ 270 | MSMessage_(extra, type, _class, name, sel0 ## $ ## sel1 ## $ ## sel2 ## $ ## sel3 ## $, sel0:sel1:sel2:sel3:, (_cls, _old, _spr, self, _cmd, arg0, arg1, arg2, arg3), type0 arg0, type1 arg1, type2 arg2, type3 arg3) 271 | #define MSMessage5_(extra, type, _class, name, sel0, sel1, sel2, sel3, sel4, type0, arg0, type1, arg1, type2, arg2, type3, arg3, type4, arg4) \ 272 | MSMessage_(extra, type, _class, name, sel0 ## $ ## sel1 ## $ ## sel2 ## $ ## sel3 ## $ ## sel4 ## $, sel0:sel1:sel2:sel3:sel4:, (_cls, _old, _spr, self, _cmd, arg0, arg1, arg2, arg3, arg4), type0 arg0, type1 arg1, type2 arg2, type3 arg3, type4 arg4) 273 | #define MSMessage6_(extra, type, _class, name, sel0, sel1, sel2, sel3, sel4, sel5, type0, arg0, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5) \ 274 | MSMessage_(extra, type, _class, name, sel0 ## $ ## sel1 ## $ ## sel2 ## $ ## sel3 ## $ ## sel4 ## $ ## sel5 ## $, sel0:sel1:sel2:sel3:sel4:sel5:, (_cls, _old, _spr, self, _cmd, arg0, arg1, arg2, arg3, arg4, arg5), type0 arg0, type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) 275 | #define MSMessage7_(extra, type, _class, name, sel0, sel1, sel2, sel3, sel4, sel5, sel6, type0, arg0, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6) \ 276 | MSMessage_(extra, type, _class, name, sel0 ## $ ## sel1 ## $ ## sel2 ## $ ## sel3 ## $ ## sel4 ## $ ## sel5 ## $ ## sel6 ## $, sel0:sel1:sel2:sel3:sel4:sel5:sel6:, (_cls, _old, _spr, self, _cmd, arg0, arg1, arg2, arg3, arg4, arg5, arg6), type0 arg0, type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6) 277 | #define MSMessage8_(extra, type, _class, name, sel0, sel1, sel2, sel3, sel4, sel5, sel6, sel7, type0, arg0, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7) \ 278 | MSMessage_(extra, type, _class, name, sel0 ## $ ## sel1 ## $ ## sel2 ## $ ## sel3 ## $ ## sel4 ## $ ## sel5 ## $ ## sel6 ## $ ## sel7 ## $, sel0:sel1:sel2:sel3:sel4:sel5:sel6:sel7:, (_cls, _old, _spr, self, _cmd, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7), type0 arg0, type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6, type7 arg7) 279 | 280 | #define MSInstanceMessage0(type, _class, args...) MSMessage0_(MSIgnore_, type, _class *, _class, ## args) 281 | #define MSInstanceMessage1(type, _class, args...) MSMessage1_(MSIgnore_, type, _class *, _class, ## args) 282 | #define MSInstanceMessage2(type, _class, args...) MSMessage2_(MSIgnore_, type, _class *, _class, ## args) 283 | #define MSInstanceMessage3(type, _class, args...) MSMessage3_(MSIgnore_, type, _class *, _class, ## args) 284 | #define MSInstanceMessage4(type, _class, args...) MSMessage4_(MSIgnore_, type, _class *, _class, ## args) 285 | #define MSInstanceMessage5(type, _class, args...) MSMessage5_(MSIgnore_, type, _class *, _class, ## args) 286 | #define MSInstanceMessage6(type, _class, args...) MSMessage6_(MSIgnore_, type, _class *, _class, ## args) 287 | #define MSInstanceMessage7(type, _class, args...) MSMessage7_(MSIgnore_, type, _class *, _class, ## args) 288 | #define MSInstanceMessage8(type, _class, args...) MSMessage8_(MSIgnore_, type, _class *, _class, ## args) 289 | 290 | #define MSClassMessage0(type, _class, args...) MSMessage0_(MSIgnore_, type, Class, $ ## _class, ## args) 291 | #define MSClassMessage1(type, _class, args...) MSMessage1_(MSIgnore_, type, Class, $ ## _class, ## args) 292 | #define MSClassMessage2(type, _class, args...) MSMessage2_(MSIgnore_, type, Class, $ ## _class, ## args) 293 | #define MSClassMessage3(type, _class, args...) MSMessage3_(MSIgnore_, type, Class, $ ## _class, ## args) 294 | #define MSClassMessage4(type, _class, args...) MSMessage4_(MSIgnore_, type, Class, $ ## _class, ## args) 295 | #define MSClassMessage5(type, _class, args...) MSMessage5_(MSIgnore_, type, Class, $ ## _class, ## args) 296 | #define MSClassMessage6(type, _class, args...) MSMessage6_(MSIgnore_, type, Class, $ ## _class, ## args) 297 | #define MSClassMessage7(type, _class, args...) MSMessage7_(MSIgnore_, type, Class, $ ## _class, ## args) 298 | #define MSClassMessage8(type, _class, args...) MSMessage8_(MSIgnore_, type, Class, $ ## _class, ## args) 299 | 300 | #define MSInstanceMessageHook0(type, _class, args...) MSMessage0_(MSRegister_, type, _class *, _class, ## args) 301 | #define MSInstanceMessageHook1(type, _class, args...) MSMessage1_(MSRegister_, type, _class *, _class, ## args) 302 | #define MSInstanceMessageHook2(type, _class, args...) MSMessage2_(MSRegister_, type, _class *, _class, ## args) 303 | #define MSInstanceMessageHook3(type, _class, args...) MSMessage3_(MSRegister_, type, _class *, _class, ## args) 304 | #define MSInstanceMessageHook4(type, _class, args...) MSMessage4_(MSRegister_, type, _class *, _class, ## args) 305 | #define MSInstanceMessageHook5(type, _class, args...) MSMessage5_(MSRegister_, type, _class *, _class, ## args) 306 | #define MSInstanceMessageHook6(type, _class, args...) MSMessage6_(MSRegister_, type, _class *, _class, ## args) 307 | #define MSInstanceMessageHook7(type, _class, args...) MSMessage7_(MSRegister_, type, _class *, _class, ## args) 308 | #define MSInstanceMessageHook8(type, _class, args...) MSMessage8_(MSRegister_, type, _class *, _class, ## args) 309 | 310 | #define MSClassMessageHook0(type, _class, args...) MSMessage0_(MSRegister_, type, Class, $ ## _class, ## args) 311 | #define MSClassMessageHook1(type, _class, args...) MSMessage1_(MSRegister_, type, Class, $ ## _class, ## args) 312 | #define MSClassMessageHook2(type, _class, args...) MSMessage2_(MSRegister_, type, Class, $ ## _class, ## args) 313 | #define MSClassMessageHook3(type, _class, args...) MSMessage3_(MSRegister_, type, Class, $ ## _class, ## args) 314 | #define MSClassMessageHook4(type, _class, args...) MSMessage4_(MSRegister_, type, Class, $ ## _class, ## args) 315 | #define MSClassMessageHook5(type, _class, args...) MSMessage5_(MSRegister_, type, Class, $ ## _class, ## args) 316 | #define MSClassMessageHook6(type, _class, args...) MSMessage6_(MSRegister_, type, Class, $ ## _class, ## args) 317 | #define MSClassMessageHook7(type, _class, args...) MSMessage7_(MSRegister_, type, Class, $ ## _class, ## args) 318 | #define MSClassMessageHook8(type, _class, args...) MSMessage8_(MSRegister_, type, Class, $ ## _class, ## args) 319 | 320 | #define MSOldCall(args...) \ 321 | _old(self, _cmd, ## args) 322 | #define MSSuperCall(args...) \ 323 | _spr((struct objc_super[1]) {{self, class_getSuperclass(_cls)}}, _cmd, ## args) 324 | 325 | #define MSIvarHook(type, name) \ 326 | type &name(MSHookIvar(self, #name)) 327 | 328 | #define MSClassHook(name) \ 329 | @class name; \ 330 | static Class $ ## name = objc_getClass(#name); 331 | #define MSMetaClassHook(name) \ 332 | @class name; \ 333 | static Class $$ ## name = object_getClass($ ## name); 334 | 335 | #endif/*__APPLE__*/ 336 | 337 | template 338 | static inline void MSHookFunction(Type_ *symbol, Type_ *replace, Type_ **result) { 339 | return MSHookFunction( 340 | reinterpret_cast(symbol), 341 | reinterpret_cast(replace), 342 | reinterpret_cast(result) 343 | ); 344 | } 345 | 346 | template 347 | static inline void MSHookFunction(Type_ *symbol, Type_ *replace) { 348 | return MSHookFunction(symbol, replace, reinterpret_cast(NULL)); 349 | } 350 | 351 | template 352 | static inline void MSHookSymbol(Type_ *&value, const char *name, MSImageRef image = NULL) { 353 | value = reinterpret_cast(MSFindSymbol(image, name)); 354 | } 355 | 356 | template 357 | static inline void MSHookFunction(const char *name, Type_ *replace, Type_ **result = NULL) { 358 | Type_ *symbol; 359 | MSHookSymbol(symbol, name); 360 | return MSHookFunction(symbol, replace, result); 361 | } 362 | 363 | template 364 | static inline void MSHookFunction(MSImageRef image, const char *name, Type_ *replace, Type_ **result = NULL) { 365 | Type_ *symbol; 366 | MSHookSymbol(symbol, name, image); 367 | return MSHookFunction(symbol, replace, result); 368 | } 369 | 370 | template 371 | static inline void MSHookMemory(Type_ *target, const void *data, size_t size) { 372 | return MSHookMemory(reinterpret_cast(target), data, size); 373 | } 374 | 375 | #endif 376 | 377 | // g++ versions before 4.7 define __cplusplus to 1 378 | // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=1773 379 | #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) 380 | 381 | #ifdef __ANDROID__ 382 | 383 | template 384 | static inline void MSJavaHookMethod(JNIEnv *jni, jclass _class, jmethodID method, Type_ (*replace)(JNIEnv *, Kind_, Args_...), Type_ (**result)(JNIEnv *, Kind_, ...)) { 385 | return MSJavaHookMethod( 386 | jni, _class, method, 387 | reinterpret_cast(replace), 388 | reinterpret_cast(result) 389 | ); 390 | } 391 | 392 | #endif 393 | 394 | #endif 395 | 396 | #ifdef __ANDROID__ 397 | 398 | #ifdef __cplusplus 399 | 400 | static inline void MSAndroidGetPackage(JNIEnv *jni, jobject global, const char *name, jobject &local, jobject &loader) { 401 | jclass Context(jni->FindClass("android/content/Context")); 402 | jmethodID Context$createPackageContext(jni->GetMethodID(Context, "createPackageContext", "(Ljava/lang/String;I)Landroid/content/Context;")); 403 | jmethodID Context$getClassLoader(jni->GetMethodID(Context, "getClassLoader", "()Ljava/lang/ClassLoader;")); 404 | 405 | jstring string(jni->NewStringUTF(name)); 406 | local = jni->CallObjectMethod(global, Context$createPackageContext, string, 3); 407 | loader = jni->CallObjectMethod(local, Context$getClassLoader); 408 | } 409 | 410 | static inline jclass MSJavaFindClass(JNIEnv *jni, jobject loader, const char *name) { 411 | jclass Class(jni->FindClass("java/lang/Class")); 412 | jmethodID Class$forName(jni->GetStaticMethodID(Class, "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;")); 413 | 414 | jstring string(jni->NewStringUTF(name)); 415 | jobject _class(jni->CallStaticObjectMethod(Class, Class$forName, string, JNI_TRUE, loader)); 416 | 417 | if (jni->ExceptionCheck()) { 418 | jni->ExceptionClear(); 419 | return NULL; 420 | } 421 | 422 | return reinterpret_cast(_class); 423 | } 424 | 425 | _disused static void MSJavaCleanWeak(void *data, JNIEnv *jni, void *value) { 426 | jni->DeleteWeakGlobalRef(reinterpret_cast(value)); 427 | } 428 | 429 | #endif 430 | 431 | #endif 432 | 433 | #define MSHook(type, name, args...) \ 434 | _disused static type (*_ ## name)(args); \ 435 | static type $ ## name(args) 436 | 437 | #define MSJavaHook(type, name, arg0, args...) \ 438 | _disused static type (*_ ## name)(JNIEnv *jni, arg0, ...); \ 439 | static type $ ## name(JNIEnv *jni, arg0, ## args) 440 | 441 | #ifdef __cplusplus 442 | #define MSHake(name) \ 443 | &$ ## name, &_ ## name 444 | #else 445 | #define MSHake(name) \ 446 | &$ ## name, (void **) &_ ## name 447 | #endif 448 | 449 | #define SubstrateConcat_(lhs, rhs) \ 450 | lhs ## rhs 451 | #define SubstrateConcat(lhs, rhs) \ 452 | SubstrateConcat_(lhs, rhs) 453 | 454 | #define SubstrateStringize(value) \ 455 | #value 456 | 457 | #ifdef __APPLE__ 458 | #define SubstrateSection \ 459 | __attribute__((__section__("__TEXT, __substrate"))) 460 | #else 461 | #define SubstrateSection \ 462 | __attribute__((__section__(".substrate"))) 463 | #endif 464 | 465 | #ifdef __APPLE__ 466 | #define MSFilterCFBundleID "Filter:CFBundleID" 467 | #define MSFilterObjC_Class "Filter:ObjC.Class" 468 | #endif 469 | 470 | #ifdef __ANDROID__ 471 | #define MSFilterLibrary "Filter:Library" 472 | #endif 473 | 474 | #define MSFilterCFVersion "Filter:CFVersion" 475 | #define MSFilterExecutable "Filter:Executable" 476 | 477 | #define MSConfig(name, value) \ 478 | extern const char SubstrateConcat(_substrate_, __LINE__)[] SubstrateSection; \ 479 | const char SubstrateConcat(_substrate_, __LINE__)[] SubstrateSection = name "=" value; 480 | 481 | #define MSConfigValue(name, value) \ 482 | char SubstrateConcat(_substrate_MSConfigValue_Invalid_, __LINE__)[((double)value, 0)]; \ 483 | const char SubstrateConcat(_substrate_, __LINE__)[] SubstrateSection = name "=" SubstrateStringize(value); 484 | 485 | #define MSConfigRange(name, lo, hi) \ 486 | char SubstrateConcat(_substrate_MSConfigRange_Invalid_, __LINE__)[(double)lo <= (double)hi ? 0 : -1]; \ 487 | MSConfig(name, SubstrateStringize(lo) "," SubstrateStringize(hi)) 488 | 489 | #ifdef __cplusplus 490 | #define MSInitialize \ 491 | static void SubstrateConcat(_MSInitialize, __LINE__)(void); \ 492 | namespace { static class SubstrateConcat($MSInitialize, __LINE__) { public: _finline SubstrateConcat($MSInitialize, __LINE__)() { \ 493 | SubstrateConcat(_MSInitialize, __LINE__)(); \ 494 | } } SubstrateConcat($MSInitialize, __LINE__); } \ 495 | static void SubstrateConcat(_MSInitialize, __LINE__)() 496 | #else 497 | #define MSInitialize \ 498 | __attribute__((__constructor__)) static void SubstrateConcat(_MSInitialize, __LINE__)(void) 499 | #endif 500 | 501 | #define Foundation_f "/System/Library/Frameworks/Foundation.framework/Foundation" 502 | #define UIKit_f "/System/Library/Frameworks/UIKit.framework/UIKit" 503 | #define JavaScriptCore_f "/System/Library/PrivateFrameworks/JavaScriptCore.framework/JavaScriptCore" 504 | #define IOKit_f "/System/Library/Frameworks/IOKit.framework/IOKit" 505 | 506 | #endif//SUBSTRATE_H_ 507 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HookKit 2 | 3 | An iOS developer framework for unified hooking methods. 4 | 5 | ## Advantages and Disadvantages 6 | 7 | Advantages: 8 | 9 | * Improved performance through use of batch hooking (if available). 10 | * Ability to utilize different hooking libraries from your tweak. [Shadow](https://github.com/jjolano/shadow) provides this functionality. 11 | 12 | Disadvantages: 13 | 14 | * Some library-specific functionality is not implemented (yet) 15 | * Existing tweaks will need to be rewritten/recompiled to use HookKit 16 | 17 | ## Credits 18 | 19 | ### fishhook 20 | 21 | 22 | 23 | ### Dobby 24 | 25 | 26 | 27 | ### libhooker 28 | 29 | 30 | 31 | ### Substitute 32 | 33 | 34 | 35 | ### ElleKit 36 | 37 | 38 | -------------------------------------------------------------------------------- /Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | HookKit 9 | CFBundleIdentifier 10 | me.jjolano.fmwk.hookkit 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | FMWK 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | PWD=$(dirname -- "$0") 5 | cd $PWD 6 | 7 | # create fresh build directory 8 | rm -rf $PWD/build 9 | mkdir -p $PWD/build 10 | 11 | # build main project (rootless ver.) 12 | make clean && 13 | THEOS_PACKAGE_SCHEME=rootless ARCHS="arm64 arm64e" TARGET=iphone:clang:latest:14.0 make package FINALPACKAGE=1 && 14 | cp -p "`ls -dtr1 packages/* | tail -1`" $PWD/build/ 15 | 16 | rm -rf $THEOS/lib/HookKit.framework 17 | 18 | # build main project (rooted ver.) 19 | make clean && 20 | make package FINALPACKAGE=1 && 21 | cp -p "`ls -dtr1 packages/* | tail -1`" $PWD/build/ 22 | 23 | rm -rf $THEOS/lib/HookKit.framework 24 | 25 | # build modules 26 | for d in Modules/*.bundle ; do 27 | (cd $d && make clean && make package FINALPACKAGE=1 && cp -p "`ls -dtr1 packages/* | tail -1`" ../../build/) || true 28 | (cd $d && make clean && THEOS_PACKAGE_SCHEME=rootless ARCHS="arm64 arm64e" TARGET=iphone:clang:latest:14.0 make package FINALPACKAGE=1 && cp -p "`ls -dtr1 packages/* | tail -1`" ../../build/) || true 29 | done 30 | -------------------------------------------------------------------------------- /control: -------------------------------------------------------------------------------- 1 | Package: me.jjolano.fmwk.hookkit 2 | Name: HookKit Framework 3 | Depends: firmware (>= 8.0), me.jjolano.fmwk.modulous, me.jjolano.fmwk.rootbridge 4 | Version: 1.0.15 5 | Architecture: iphoneos-arm 6 | Description: An iOS developer framework for unified hooking methods. 7 | Maintainer: jjolano 8 | Author: jjolano 9 | Section: Development 10 | Tag: role::developer 11 | --------------------------------------------------------------------------------