├── README.md ├── XcodePatch.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcuserdata │ └── cyandev.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── XcodePatch ├── XCPConsoleIMEFreezingPatch.m ├── hook_utils.c └── hook_utils.h └── screenshot.png /README.md: -------------------------------------------------------------------------------- 1 | # Xcode Patch 2 | 3 | > [Xcode is worst IDE I have ever used](https://www.reddit.com/r/iOSProgramming/comments/fmys59/xcode_is_worst_ide_i_have_ever_used/) 4 | 5 | Xcode 13.3 introduced a very annoying bug. When you type anything with Chinese IME in the LLDB console, the whole app freezes! I did some investigation and fixed this issue before Apple publishes the next release. 6 | 7 | ![Screenshot](./screenshot.png) 8 | 9 | If you can't stand this issue either, this patch is gonna help you. **But I highly recommend you to wait for the next release, because this approach will require you to re-sign your Xcode!** 10 | 11 | ## Instructions 12 | 13 | ### 1. Re-sign Xcode 14 | There are many ways to re-sign Xcode. For example, I'm using a little [Python script](https://github.com/slegetank/ResignXcode) and it works pretty well. You can simply pick a method that you have been validated. 15 | 16 | ### 2. Validate Re-sign 17 | Launch Xcode and try attaching it via LLDB. If it succeeded, everything is ok and keep going. Otherwise, you are not lucky today. 18 | 19 | ### 3. Compile the Patch 20 | Open `XcodePatch.xcodeproj` and click the build button. Grab the produced `libXcodePatch.dylib` file and copy it to `/usr/local/lib`. 21 | 22 | ### 4. Inject the Patch 23 | 24 | > Before modifying the executable file, consider backing it up first in case there are something unexpected happened and broke the executable. (Backing up only the main executable file is enough) 25 | 26 | Now you need to make Xcode load the patch library. Here I will use Python with [LIEF](https://lief-project.github.io/) library. 27 | 28 | If you haven't installed LIEF: 29 | 30 | ```bash 31 | pip3 install lief 32 | ``` 33 | 34 | then execute the following script: 35 | 36 | ```python 37 | import lief 38 | import shutil 39 | 40 | xcode_path = "/path/to/Xcode.app/Contents/MacOS/Xcode" 41 | 42 | # backup the executable file 43 | shutil.copyfile(xcode_path, f"{xcode_path}.bak") 44 | 45 | xcode_fat = lief.MachO.parse(xcode_path) 46 | xcode = xcode_fat.take(lief.MachO.CPU_TYPES.ARM64) # or `x86_64` for Intel-based Mac 47 | 48 | patch_lib = lief.MachO.DylibCommand.weak_lib('/usr/local/lib/libXcodePatch.dylib') 49 | xcode.add(patch_lib) 50 | 51 | xcode.write(xcode_path) 52 | ``` 53 | 54 | ### 5. Re-sign Xcode Again 55 | Since you just modified the executable file of Xcode, you need to re-sign the bundle again. Don't worry, you had validated the possibility of self-signing Xcode earlier, just repeat the first step. 56 | 57 | ## Future Directions 58 | 59 | * Make this repository a universal patch collection for Xcode. 60 | * A easy-to-use re-signing tool. 61 | 62 | ## Known Issues 63 | 64 | * Re-signing Xcode will make Apple Developer accounts integration unable to work (as well as "Automatically manage signing"). 65 | 66 | ## Disclaimer 67 | 68 | During your operations, Xcode can be broken and cannot be opened anymore. This is irrelevant to this repository. Please don't install this patch when you are urgent about doing your serious work or something. 69 | 70 | This patch contains nothing malicious, read the code if you still have concern. -------------------------------------------------------------------------------- /XcodePatch.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 55; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | FA0FA64E27F310A500F984D8 /* hook_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = FA0FA64B27F310A500F984D8 /* hook_utils.c */; }; 11 | FA0FA64F27F310A500F984D8 /* hook_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0FA64C27F310A500F984D8 /* hook_utils.h */; }; 12 | FA0FA65027F310A500F984D8 /* XCPConsoleIMEFreezingPatch.m in Sources */ = {isa = PBXBuildFile; fileRef = FA0FA64D27F310A500F984D8 /* XCPConsoleIMEFreezingPatch.m */; }; 13 | /* End PBXBuildFile section */ 14 | 15 | /* Begin PBXFileReference section */ 16 | FA0FA63F27F3107E00F984D8 /* libXcodePatch.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libXcodePatch.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; 17 | FA0FA64B27F310A500F984D8 /* hook_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hook_utils.c; sourceTree = ""; }; 18 | FA0FA64C27F310A500F984D8 /* hook_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hook_utils.h; sourceTree = ""; }; 19 | FA0FA64D27F310A500F984D8 /* XCPConsoleIMEFreezingPatch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XCPConsoleIMEFreezingPatch.m; sourceTree = ""; }; 20 | FA0FA65127F310CF00F984D8 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 21 | /* End PBXFileReference section */ 22 | 23 | /* Begin PBXFrameworksBuildPhase section */ 24 | FA0FA63D27F3107E00F984D8 /* Frameworks */ = { 25 | isa = PBXFrameworksBuildPhase; 26 | buildActionMask = 2147483647; 27 | files = ( 28 | ); 29 | runOnlyForDeploymentPostprocessing = 0; 30 | }; 31 | /* End PBXFrameworksBuildPhase section */ 32 | 33 | /* Begin PBXGroup section */ 34 | FA0FA63627F3107E00F984D8 = { 35 | isa = PBXGroup; 36 | children = ( 37 | FA0FA65127F310CF00F984D8 /* README.md */, 38 | FA0FA64127F3107E00F984D8 /* XcodePatch */, 39 | FA0FA64027F3107E00F984D8 /* Products */, 40 | ); 41 | sourceTree = ""; 42 | }; 43 | FA0FA64027F3107E00F984D8 /* Products */ = { 44 | isa = PBXGroup; 45 | children = ( 46 | FA0FA63F27F3107E00F984D8 /* libXcodePatch.dylib */, 47 | ); 48 | name = Products; 49 | sourceTree = ""; 50 | }; 51 | FA0FA64127F3107E00F984D8 /* XcodePatch */ = { 52 | isa = PBXGroup; 53 | children = ( 54 | FA0FA64B27F310A500F984D8 /* hook_utils.c */, 55 | FA0FA64C27F310A500F984D8 /* hook_utils.h */, 56 | FA0FA64D27F310A500F984D8 /* XCPConsoleIMEFreezingPatch.m */, 57 | ); 58 | path = XcodePatch; 59 | sourceTree = ""; 60 | }; 61 | /* End PBXGroup section */ 62 | 63 | /* Begin PBXHeadersBuildPhase section */ 64 | FA0FA63B27F3107E00F984D8 /* Headers */ = { 65 | isa = PBXHeadersBuildPhase; 66 | buildActionMask = 2147483647; 67 | files = ( 68 | FA0FA64F27F310A500F984D8 /* hook_utils.h in Headers */, 69 | ); 70 | runOnlyForDeploymentPostprocessing = 0; 71 | }; 72 | /* End PBXHeadersBuildPhase section */ 73 | 74 | /* Begin PBXNativeTarget section */ 75 | FA0FA63E27F3107E00F984D8 /* XcodePatch */ = { 76 | isa = PBXNativeTarget; 77 | buildConfigurationList = FA0FA64827F3107E00F984D8 /* Build configuration list for PBXNativeTarget "XcodePatch" */; 78 | buildPhases = ( 79 | FA0FA63B27F3107E00F984D8 /* Headers */, 80 | FA0FA63C27F3107E00F984D8 /* Sources */, 81 | FA0FA63D27F3107E00F984D8 /* Frameworks */, 82 | ); 83 | buildRules = ( 84 | ); 85 | dependencies = ( 86 | ); 87 | name = XcodePatch; 88 | productName = XcodePatch; 89 | productReference = FA0FA63F27F3107E00F984D8 /* libXcodePatch.dylib */; 90 | productType = "com.apple.product-type.library.dynamic"; 91 | }; 92 | /* End PBXNativeTarget section */ 93 | 94 | /* Begin PBXProject section */ 95 | FA0FA63727F3107E00F984D8 /* Project object */ = { 96 | isa = PBXProject; 97 | attributes = { 98 | BuildIndependentTargetsInParallel = 1; 99 | LastUpgradeCheck = 1330; 100 | TargetAttributes = { 101 | FA0FA63E27F3107E00F984D8 = { 102 | CreatedOnToolsVersion = 13.3; 103 | }; 104 | }; 105 | }; 106 | buildConfigurationList = FA0FA63A27F3107E00F984D8 /* Build configuration list for PBXProject "XcodePatch" */; 107 | compatibilityVersion = "Xcode 13.0"; 108 | developmentRegion = en; 109 | hasScannedForEncodings = 0; 110 | knownRegions = ( 111 | en, 112 | Base, 113 | ); 114 | mainGroup = FA0FA63627F3107E00F984D8; 115 | productRefGroup = FA0FA64027F3107E00F984D8 /* Products */; 116 | projectDirPath = ""; 117 | projectRoot = ""; 118 | targets = ( 119 | FA0FA63E27F3107E00F984D8 /* XcodePatch */, 120 | ); 121 | }; 122 | /* End PBXProject section */ 123 | 124 | /* Begin PBXSourcesBuildPhase section */ 125 | FA0FA63C27F3107E00F984D8 /* Sources */ = { 126 | isa = PBXSourcesBuildPhase; 127 | buildActionMask = 2147483647; 128 | files = ( 129 | FA0FA65027F310A500F984D8 /* XCPConsoleIMEFreezingPatch.m in Sources */, 130 | FA0FA64E27F310A500F984D8 /* hook_utils.c in Sources */, 131 | ); 132 | runOnlyForDeploymentPostprocessing = 0; 133 | }; 134 | /* End PBXSourcesBuildPhase section */ 135 | 136 | /* Begin XCBuildConfiguration section */ 137 | FA0FA64627F3107E00F984D8 /* Debug */ = { 138 | isa = XCBuildConfiguration; 139 | buildSettings = { 140 | ALWAYS_SEARCH_USER_PATHS = NO; 141 | CLANG_ANALYZER_NONNULL = YES; 142 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 143 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; 144 | CLANG_ENABLE_MODULES = YES; 145 | CLANG_ENABLE_OBJC_ARC = YES; 146 | CLANG_ENABLE_OBJC_WEAK = YES; 147 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 148 | CLANG_WARN_BOOL_CONVERSION = YES; 149 | CLANG_WARN_COMMA = YES; 150 | CLANG_WARN_CONSTANT_CONVERSION = YES; 151 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 152 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 153 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 154 | CLANG_WARN_EMPTY_BODY = YES; 155 | CLANG_WARN_ENUM_CONVERSION = YES; 156 | CLANG_WARN_INFINITE_RECURSION = YES; 157 | CLANG_WARN_INT_CONVERSION = YES; 158 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 159 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 160 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 161 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 162 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 163 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 164 | CLANG_WARN_STRICT_PROTOTYPES = YES; 165 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 166 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 167 | CLANG_WARN_UNREACHABLE_CODE = YES; 168 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 169 | COPY_PHASE_STRIP = NO; 170 | DEBUG_INFORMATION_FORMAT = dwarf; 171 | ENABLE_STRICT_OBJC_MSGSEND = YES; 172 | ENABLE_TESTABILITY = YES; 173 | GCC_C_LANGUAGE_STANDARD = gnu11; 174 | GCC_DYNAMIC_NO_PIC = NO; 175 | GCC_NO_COMMON_BLOCKS = YES; 176 | GCC_OPTIMIZATION_LEVEL = 0; 177 | GCC_PREPROCESSOR_DEFINITIONS = ( 178 | "DEBUG=1", 179 | "$(inherited)", 180 | ); 181 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 182 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 183 | GCC_WARN_UNDECLARED_SELECTOR = YES; 184 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 185 | GCC_WARN_UNUSED_FUNCTION = YES; 186 | GCC_WARN_UNUSED_VARIABLE = YES; 187 | MACOSX_DEPLOYMENT_TARGET = 12.0; 188 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 189 | MTL_FAST_MATH = YES; 190 | ONLY_ACTIVE_ARCH = YES; 191 | SDKROOT = macosx; 192 | }; 193 | name = Debug; 194 | }; 195 | FA0FA64727F3107E00F984D8 /* Release */ = { 196 | isa = XCBuildConfiguration; 197 | buildSettings = { 198 | ALWAYS_SEARCH_USER_PATHS = NO; 199 | CLANG_ANALYZER_NONNULL = YES; 200 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 201 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; 202 | CLANG_ENABLE_MODULES = YES; 203 | CLANG_ENABLE_OBJC_ARC = YES; 204 | CLANG_ENABLE_OBJC_WEAK = YES; 205 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 206 | CLANG_WARN_BOOL_CONVERSION = YES; 207 | CLANG_WARN_COMMA = YES; 208 | CLANG_WARN_CONSTANT_CONVERSION = YES; 209 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 210 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 211 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 212 | CLANG_WARN_EMPTY_BODY = YES; 213 | CLANG_WARN_ENUM_CONVERSION = YES; 214 | CLANG_WARN_INFINITE_RECURSION = YES; 215 | CLANG_WARN_INT_CONVERSION = YES; 216 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 217 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 218 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 219 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 220 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 221 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 222 | CLANG_WARN_STRICT_PROTOTYPES = YES; 223 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 224 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 225 | CLANG_WARN_UNREACHABLE_CODE = YES; 226 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 227 | COPY_PHASE_STRIP = NO; 228 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 229 | ENABLE_NS_ASSERTIONS = NO; 230 | ENABLE_STRICT_OBJC_MSGSEND = YES; 231 | GCC_C_LANGUAGE_STANDARD = gnu11; 232 | GCC_NO_COMMON_BLOCKS = YES; 233 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 234 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 235 | GCC_WARN_UNDECLARED_SELECTOR = YES; 236 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 237 | GCC_WARN_UNUSED_FUNCTION = YES; 238 | GCC_WARN_UNUSED_VARIABLE = YES; 239 | MACOSX_DEPLOYMENT_TARGET = 12.0; 240 | MTL_ENABLE_DEBUG_INFO = NO; 241 | MTL_FAST_MATH = YES; 242 | SDKROOT = macosx; 243 | }; 244 | name = Release; 245 | }; 246 | FA0FA64927F3107E00F984D8 /* Debug */ = { 247 | isa = XCBuildConfiguration; 248 | buildSettings = { 249 | CODE_SIGN_STYLE = Automatic; 250 | DYLIB_COMPATIBILITY_VERSION = 1; 251 | DYLIB_CURRENT_VERSION = 1; 252 | EXECUTABLE_PREFIX = lib; 253 | PRODUCT_NAME = "$(TARGET_NAME)"; 254 | SKIP_INSTALL = YES; 255 | }; 256 | name = Debug; 257 | }; 258 | FA0FA64A27F3107E00F984D8 /* Release */ = { 259 | isa = XCBuildConfiguration; 260 | buildSettings = { 261 | CODE_SIGN_STYLE = Automatic; 262 | DYLIB_COMPATIBILITY_VERSION = 1; 263 | DYLIB_CURRENT_VERSION = 1; 264 | EXECUTABLE_PREFIX = lib; 265 | PRODUCT_NAME = "$(TARGET_NAME)"; 266 | SKIP_INSTALL = YES; 267 | }; 268 | name = Release; 269 | }; 270 | /* End XCBuildConfiguration section */ 271 | 272 | /* Begin XCConfigurationList section */ 273 | FA0FA63A27F3107E00F984D8 /* Build configuration list for PBXProject "XcodePatch" */ = { 274 | isa = XCConfigurationList; 275 | buildConfigurations = ( 276 | FA0FA64627F3107E00F984D8 /* Debug */, 277 | FA0FA64727F3107E00F984D8 /* Release */, 278 | ); 279 | defaultConfigurationIsVisible = 0; 280 | defaultConfigurationName = Release; 281 | }; 282 | FA0FA64827F3107E00F984D8 /* Build configuration list for PBXNativeTarget "XcodePatch" */ = { 283 | isa = XCConfigurationList; 284 | buildConfigurations = ( 285 | FA0FA64927F3107E00F984D8 /* Debug */, 286 | FA0FA64A27F3107E00F984D8 /* Release */, 287 | ); 288 | defaultConfigurationIsVisible = 0; 289 | defaultConfigurationName = Release; 290 | }; 291 | /* End XCConfigurationList section */ 292 | }; 293 | rootObject = FA0FA63727F3107E00F984D8 /* Project object */; 294 | } 295 | -------------------------------------------------------------------------------- /XcodePatch.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /XcodePatch.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /XcodePatch.xcodeproj/xcuserdata/cyandev.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | XcodePatch.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /XcodePatch/XCPConsoleIMEFreezingPatch.m: -------------------------------------------------------------------------------- 1 | // 2 | // XCPConsoleIMEFreezingPatch.m 3 | // XcodePatch 4 | // 5 | // Created by Cyandev on 2022/3/29. 6 | // 7 | 8 | #import 9 | 10 | #import "hook_utils.h" 11 | 12 | @interface XCPConsoleIMEFreezingPatch : NSObject 13 | @end 14 | 15 | @implementation XCPConsoleIMEFreezingPatch 16 | 17 | + (Class)buggyViewClass __attribute__((objc_direct)) { 18 | static Class cls = nil; 19 | if (!cls) { 20 | cls = objc_getClass("SourceEditor.SourceEditorContentView"); 21 | } 22 | return cls; 23 | } 24 | 25 | + (void)load { 26 | NSLog(@"** XCPConsoleIMEFreezingPatch loaded! **"); 27 | 28 | Class targetCls = objc_getClass("_NSViewBackingLayer"); 29 | SEL targetSEL = sel_registerName("layoutSublayers"); 30 | xcp_hook_method(targetCls, targetSEL, ^id(IMP origIMP) { 31 | return ^(id _self) { 32 | static void *kResetTimerKey = &kResetTimerKey; 33 | static void *kLayoutCyclesKey = &kLayoutCyclesKey; 34 | 35 | id view = [_self delegate]; 36 | if ([view class] == [self buggyViewClass]) { 37 | NSTimer *timer = objc_getAssociatedObject(view, kResetTimerKey); 38 | if (!timer) { 39 | // Create a timer to reset the counter of the receiver view. 40 | __weak id weakView = view; 41 | timer = [NSTimer scheduledTimerWithTimeInterval:0.1 repeats:YES block:^(NSTimer * _Nonnull timer) { 42 | __strong id strongView = weakView; 43 | if (!strongView) { 44 | [timer invalidate]; 45 | return; 46 | } 47 | objc_setAssociatedObject(strongView, kLayoutCyclesKey, @(0), OBJC_ASSOCIATION_COPY_NONATOMIC); 48 | }]; 49 | objc_setAssociatedObject(view, kResetTimerKey, timer, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 50 | } 51 | 52 | NSInteger layoutCycles = ((NSNumber *) objc_getAssociatedObject(view, kLayoutCyclesKey)).integerValue; 53 | if (layoutCycles > 100) { 54 | // Unreasonable layout cycles in one frame, ignore further invocation until 55 | // the frame is finished. 56 | return; 57 | } 58 | objc_setAssociatedObject(view, kLayoutCyclesKey, @(layoutCycles + 1), OBJC_ASSOCIATION_COPY_NONATOMIC); 59 | } 60 | 61 | ((void (*)(id, SEL)) origIMP)(_self, nil); 62 | }; 63 | }); 64 | } 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /XcodePatch/hook_utils.c: -------------------------------------------------------------------------------- 1 | // 2 | // hook_utils.c 3 | // XcodePatch 4 | // 5 | // Created by Cyandev on 2022/3/29. 6 | // 7 | 8 | #include "hook_utils.h" 9 | 10 | void xcp_hook_method(Class cls, SEL sel, id (^interceptorBuilder)(IMP origIMP)) { 11 | Method meth = class_getInstanceMethod(cls, sel); 12 | IMP origIMP = method_getImplementation(meth); 13 | id interceptor = interceptorBuilder(origIMP); 14 | method_setImplementation(meth, imp_implementationWithBlock(interceptor)); 15 | } 16 | -------------------------------------------------------------------------------- /XcodePatch/hook_utils.h: -------------------------------------------------------------------------------- 1 | // 2 | // hook_utils.h 3 | // XcodePatch 4 | // 5 | // Created by Cyandev on 2022/3/29. 6 | // 7 | 8 | #ifndef hook_utils_h 9 | #define hook_utils_h 10 | 11 | #import 12 | 13 | extern void xcp_hook_method(Class cls, SEL sel, id (^interceptorBuilder)(IMP origIMP)); 14 | 15 | #endif /* hook_utils_h */ 16 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixzii/XcodePatch/93f35e21d7d366965f3fe300f427f190c5063b84/screenshot.png --------------------------------------------------------------------------------