├── .gitignore ├── FishhookDemo.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── FishhookDemo ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── FishhookVC.h ├── FishhookVC.m ├── Info.plist ├── RuntimeVC.h ├── RuntimeVC.m ├── ViewController.h ├── ViewController.m ├── fishhook.c ├── fishhook.h └── main.m ├── FishhookDemoTests ├── FishhookDemoTests.m └── Info.plist ├── FishhookDemoUITests ├── FishhookDemoUITests.m └── Info.plist └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | # CocoaPods 32 | # 33 | # We recommend against adding the Pods directory to your .gitignore. However 34 | # you should judge for yourself, the pros and cons are mentioned at: 35 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 36 | # 37 | # Pods/ 38 | 39 | # Carthage 40 | # 41 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 42 | # Carthage/Checkouts 43 | 44 | Carthage/Build 45 | 46 | # fastlane 47 | # 48 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 49 | # screenshots whenever they are needed. 50 | # For more information about the recommended setup visit: 51 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 52 | 53 | fastlane/report.xml 54 | fastlane/Preview.html 55 | fastlane/screenshots/**/*.png 56 | fastlane/test_output 57 | 58 | # Code Injection 59 | # 60 | # After new code Injection tools there's a generated folder /iOSInjectionProject 61 | # https://github.com/johnno1962/injectionforxcode 62 | 63 | iOSInjectionProject/ 64 | -------------------------------------------------------------------------------- /FishhookDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | F709E3332244F2AB00DE296C /* fishhook.c in Sources */ = {isa = PBXBuildFile; fileRef = F709E3312244F2AB00DE296C /* fishhook.c */; }; 11 | F788FBCC2243A19200F5F2AA /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = F788FBCB2243A19200F5F2AA /* AppDelegate.m */; }; 12 | F788FBCF2243A19200F5F2AA /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F788FBCE2243A19200F5F2AA /* ViewController.m */; }; 13 | F788FBD22243A19200F5F2AA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F788FBD02243A19200F5F2AA /* Main.storyboard */; }; 14 | F788FBD42243A19300F5F2AA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F788FBD32243A19300F5F2AA /* Assets.xcassets */; }; 15 | F788FBD72243A19300F5F2AA /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F788FBD52243A19300F5F2AA /* LaunchScreen.storyboard */; }; 16 | F788FBDA2243A19300F5F2AA /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = F788FBD92243A19300F5F2AA /* main.m */; }; 17 | F788FBE42243A19300F5F2AA /* FishhookDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F788FBE32243A19300F5F2AA /* FishhookDemoTests.m */; }; 18 | F788FBEF2243A19300F5F2AA /* FishhookDemoUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = F788FBEE2243A19300F5F2AA /* FishhookDemoUITests.m */; }; 19 | F788FBFE2243A4B300F5F2AA /* RuntimeVC.m in Sources */ = {isa = PBXBuildFile; fileRef = F788FBFD2243A4B300F5F2AA /* RuntimeVC.m */; }; 20 | F788FC012243A4C200F5F2AA /* FishhookVC.m in Sources */ = {isa = PBXBuildFile; fileRef = F788FC002243A4C200F5F2AA /* FishhookVC.m */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXContainerItemProxy section */ 24 | F788FBE02243A19300F5F2AA /* PBXContainerItemProxy */ = { 25 | isa = PBXContainerItemProxy; 26 | containerPortal = F788FBBF2243A19100F5F2AA /* Project object */; 27 | proxyType = 1; 28 | remoteGlobalIDString = F788FBC62243A19200F5F2AA; 29 | remoteInfo = FishhookDemo; 30 | }; 31 | F788FBEB2243A19300F5F2AA /* PBXContainerItemProxy */ = { 32 | isa = PBXContainerItemProxy; 33 | containerPortal = F788FBBF2243A19100F5F2AA /* Project object */; 34 | proxyType = 1; 35 | remoteGlobalIDString = F788FBC62243A19200F5F2AA; 36 | remoteInfo = FishhookDemo; 37 | }; 38 | /* End PBXContainerItemProxy section */ 39 | 40 | /* Begin PBXFileReference section */ 41 | F709E3312244F2AB00DE296C /* fishhook.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fishhook.c; sourceTree = ""; }; 42 | F709E3322244F2AB00DE296C /* fishhook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fishhook.h; sourceTree = ""; }; 43 | F788FBC72243A19200F5F2AA /* FishhookDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FishhookDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 44 | F788FBCA2243A19200F5F2AA /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 45 | F788FBCB2243A19200F5F2AA /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 46 | F788FBCD2243A19200F5F2AA /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 47 | F788FBCE2243A19200F5F2AA /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 48 | F788FBD12243A19200F5F2AA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 49 | F788FBD32243A19300F5F2AA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 50 | F788FBD62243A19300F5F2AA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 51 | F788FBD82243A19300F5F2AA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 52 | F788FBD92243A19300F5F2AA /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 53 | F788FBDF2243A19300F5F2AA /* FishhookDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FishhookDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 54 | F788FBE32243A19300F5F2AA /* FishhookDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FishhookDemoTests.m; sourceTree = ""; }; 55 | F788FBE52243A19300F5F2AA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 56 | F788FBEA2243A19300F5F2AA /* FishhookDemoUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FishhookDemoUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 57 | F788FBEE2243A19300F5F2AA /* FishhookDemoUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FishhookDemoUITests.m; sourceTree = ""; }; 58 | F788FBF02243A19300F5F2AA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 59 | F788FBFC2243A4B300F5F2AA /* RuntimeVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RuntimeVC.h; sourceTree = ""; }; 60 | F788FBFD2243A4B300F5F2AA /* RuntimeVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RuntimeVC.m; sourceTree = ""; }; 61 | F788FBFF2243A4C200F5F2AA /* FishhookVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FishhookVC.h; sourceTree = ""; }; 62 | F788FC002243A4C200F5F2AA /* FishhookVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FishhookVC.m; sourceTree = ""; }; 63 | /* End PBXFileReference section */ 64 | 65 | /* Begin PBXFrameworksBuildPhase section */ 66 | F788FBC42243A19200F5F2AA /* Frameworks */ = { 67 | isa = PBXFrameworksBuildPhase; 68 | buildActionMask = 2147483647; 69 | files = ( 70 | ); 71 | runOnlyForDeploymentPostprocessing = 0; 72 | }; 73 | F788FBDC2243A19300F5F2AA /* Frameworks */ = { 74 | isa = PBXFrameworksBuildPhase; 75 | buildActionMask = 2147483647; 76 | files = ( 77 | ); 78 | runOnlyForDeploymentPostprocessing = 0; 79 | }; 80 | F788FBE72243A19300F5F2AA /* Frameworks */ = { 81 | isa = PBXFrameworksBuildPhase; 82 | buildActionMask = 2147483647; 83 | files = ( 84 | ); 85 | runOnlyForDeploymentPostprocessing = 0; 86 | }; 87 | /* End PBXFrameworksBuildPhase section */ 88 | 89 | /* Begin PBXGroup section */ 90 | F788FBBE2243A19100F5F2AA = { 91 | isa = PBXGroup; 92 | children = ( 93 | F788FBC92243A19200F5F2AA /* FishhookDemo */, 94 | F788FBE22243A19300F5F2AA /* FishhookDemoTests */, 95 | F788FBED2243A19300F5F2AA /* FishhookDemoUITests */, 96 | F788FBC82243A19200F5F2AA /* Products */, 97 | ); 98 | sourceTree = ""; 99 | }; 100 | F788FBC82243A19200F5F2AA /* Products */ = { 101 | isa = PBXGroup; 102 | children = ( 103 | F788FBC72243A19200F5F2AA /* FishhookDemo.app */, 104 | F788FBDF2243A19300F5F2AA /* FishhookDemoTests.xctest */, 105 | F788FBEA2243A19300F5F2AA /* FishhookDemoUITests.xctest */, 106 | ); 107 | name = Products; 108 | sourceTree = ""; 109 | }; 110 | F788FBC92243A19200F5F2AA /* FishhookDemo */ = { 111 | isa = PBXGroup; 112 | children = ( 113 | F709E3322244F2AB00DE296C /* fishhook.h */, 114 | F709E3312244F2AB00DE296C /* fishhook.c */, 115 | F788FBCA2243A19200F5F2AA /* AppDelegate.h */, 116 | F788FBCB2243A19200F5F2AA /* AppDelegate.m */, 117 | F788FBCD2243A19200F5F2AA /* ViewController.h */, 118 | F788FBCE2243A19200F5F2AA /* ViewController.m */, 119 | F788FBFC2243A4B300F5F2AA /* RuntimeVC.h */, 120 | F788FBFD2243A4B300F5F2AA /* RuntimeVC.m */, 121 | F788FBFF2243A4C200F5F2AA /* FishhookVC.h */, 122 | F788FC002243A4C200F5F2AA /* FishhookVC.m */, 123 | F788FBD02243A19200F5F2AA /* Main.storyboard */, 124 | F788FBD32243A19300F5F2AA /* Assets.xcassets */, 125 | F788FBD52243A19300F5F2AA /* LaunchScreen.storyboard */, 126 | F788FBD82243A19300F5F2AA /* Info.plist */, 127 | F788FBD92243A19300F5F2AA /* main.m */, 128 | ); 129 | path = FishhookDemo; 130 | sourceTree = ""; 131 | }; 132 | F788FBE22243A19300F5F2AA /* FishhookDemoTests */ = { 133 | isa = PBXGroup; 134 | children = ( 135 | F788FBE32243A19300F5F2AA /* FishhookDemoTests.m */, 136 | F788FBE52243A19300F5F2AA /* Info.plist */, 137 | ); 138 | path = FishhookDemoTests; 139 | sourceTree = ""; 140 | }; 141 | F788FBED2243A19300F5F2AA /* FishhookDemoUITests */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | F788FBEE2243A19300F5F2AA /* FishhookDemoUITests.m */, 145 | F788FBF02243A19300F5F2AA /* Info.plist */, 146 | ); 147 | path = FishhookDemoUITests; 148 | sourceTree = ""; 149 | }; 150 | /* End PBXGroup section */ 151 | 152 | /* Begin PBXNativeTarget section */ 153 | F788FBC62243A19200F5F2AA /* FishhookDemo */ = { 154 | isa = PBXNativeTarget; 155 | buildConfigurationList = F788FBF32243A19300F5F2AA /* Build configuration list for PBXNativeTarget "FishhookDemo" */; 156 | buildPhases = ( 157 | F788FBC32243A19200F5F2AA /* Sources */, 158 | F788FBC42243A19200F5F2AA /* Frameworks */, 159 | F788FBC52243A19200F5F2AA /* Resources */, 160 | ); 161 | buildRules = ( 162 | ); 163 | dependencies = ( 164 | ); 165 | name = FishhookDemo; 166 | productName = FishhookDemo; 167 | productReference = F788FBC72243A19200F5F2AA /* FishhookDemo.app */; 168 | productType = "com.apple.product-type.application"; 169 | }; 170 | F788FBDE2243A19300F5F2AA /* FishhookDemoTests */ = { 171 | isa = PBXNativeTarget; 172 | buildConfigurationList = F788FBF62243A19300F5F2AA /* Build configuration list for PBXNativeTarget "FishhookDemoTests" */; 173 | buildPhases = ( 174 | F788FBDB2243A19300F5F2AA /* Sources */, 175 | F788FBDC2243A19300F5F2AA /* Frameworks */, 176 | F788FBDD2243A19300F5F2AA /* Resources */, 177 | ); 178 | buildRules = ( 179 | ); 180 | dependencies = ( 181 | F788FBE12243A19300F5F2AA /* PBXTargetDependency */, 182 | ); 183 | name = FishhookDemoTests; 184 | productName = FishhookDemoTests; 185 | productReference = F788FBDF2243A19300F5F2AA /* FishhookDemoTests.xctest */; 186 | productType = "com.apple.product-type.bundle.unit-test"; 187 | }; 188 | F788FBE92243A19300F5F2AA /* FishhookDemoUITests */ = { 189 | isa = PBXNativeTarget; 190 | buildConfigurationList = F788FBF92243A19300F5F2AA /* Build configuration list for PBXNativeTarget "FishhookDemoUITests" */; 191 | buildPhases = ( 192 | F788FBE62243A19300F5F2AA /* Sources */, 193 | F788FBE72243A19300F5F2AA /* Frameworks */, 194 | F788FBE82243A19300F5F2AA /* Resources */, 195 | ); 196 | buildRules = ( 197 | ); 198 | dependencies = ( 199 | F788FBEC2243A19300F5F2AA /* PBXTargetDependency */, 200 | ); 201 | name = FishhookDemoUITests; 202 | productName = FishhookDemoUITests; 203 | productReference = F788FBEA2243A19300F5F2AA /* FishhookDemoUITests.xctest */; 204 | productType = "com.apple.product-type.bundle.ui-testing"; 205 | }; 206 | /* End PBXNativeTarget section */ 207 | 208 | /* Begin PBXProject section */ 209 | F788FBBF2243A19100F5F2AA /* Project object */ = { 210 | isa = PBXProject; 211 | attributes = { 212 | LastUpgradeCheck = 1010; 213 | ORGANIZATIONNAME = DengBin; 214 | TargetAttributes = { 215 | F788FBC62243A19200F5F2AA = { 216 | CreatedOnToolsVersion = 10.1; 217 | }; 218 | F788FBDE2243A19300F5F2AA = { 219 | CreatedOnToolsVersion = 10.1; 220 | TestTargetID = F788FBC62243A19200F5F2AA; 221 | }; 222 | F788FBE92243A19300F5F2AA = { 223 | CreatedOnToolsVersion = 10.1; 224 | TestTargetID = F788FBC62243A19200F5F2AA; 225 | }; 226 | }; 227 | }; 228 | buildConfigurationList = F788FBC22243A19100F5F2AA /* Build configuration list for PBXProject "FishhookDemo" */; 229 | compatibilityVersion = "Xcode 9.3"; 230 | developmentRegion = en; 231 | hasScannedForEncodings = 0; 232 | knownRegions = ( 233 | en, 234 | Base, 235 | ); 236 | mainGroup = F788FBBE2243A19100F5F2AA; 237 | productRefGroup = F788FBC82243A19200F5F2AA /* Products */; 238 | projectDirPath = ""; 239 | projectRoot = ""; 240 | targets = ( 241 | F788FBC62243A19200F5F2AA /* FishhookDemo */, 242 | F788FBDE2243A19300F5F2AA /* FishhookDemoTests */, 243 | F788FBE92243A19300F5F2AA /* FishhookDemoUITests */, 244 | ); 245 | }; 246 | /* End PBXProject section */ 247 | 248 | /* Begin PBXResourcesBuildPhase section */ 249 | F788FBC52243A19200F5F2AA /* Resources */ = { 250 | isa = PBXResourcesBuildPhase; 251 | buildActionMask = 2147483647; 252 | files = ( 253 | F788FBD72243A19300F5F2AA /* LaunchScreen.storyboard in Resources */, 254 | F788FBD42243A19300F5F2AA /* Assets.xcassets in Resources */, 255 | F788FBD22243A19200F5F2AA /* Main.storyboard in Resources */, 256 | ); 257 | runOnlyForDeploymentPostprocessing = 0; 258 | }; 259 | F788FBDD2243A19300F5F2AA /* Resources */ = { 260 | isa = PBXResourcesBuildPhase; 261 | buildActionMask = 2147483647; 262 | files = ( 263 | ); 264 | runOnlyForDeploymentPostprocessing = 0; 265 | }; 266 | F788FBE82243A19300F5F2AA /* Resources */ = { 267 | isa = PBXResourcesBuildPhase; 268 | buildActionMask = 2147483647; 269 | files = ( 270 | ); 271 | runOnlyForDeploymentPostprocessing = 0; 272 | }; 273 | /* End PBXResourcesBuildPhase section */ 274 | 275 | /* Begin PBXSourcesBuildPhase section */ 276 | F788FBC32243A19200F5F2AA /* Sources */ = { 277 | isa = PBXSourcesBuildPhase; 278 | buildActionMask = 2147483647; 279 | files = ( 280 | F788FBCF2243A19200F5F2AA /* ViewController.m in Sources */, 281 | F788FBDA2243A19300F5F2AA /* main.m in Sources */, 282 | F788FC012243A4C200F5F2AA /* FishhookVC.m in Sources */, 283 | F788FBCC2243A19200F5F2AA /* AppDelegate.m in Sources */, 284 | F709E3332244F2AB00DE296C /* fishhook.c in Sources */, 285 | F788FBFE2243A4B300F5F2AA /* RuntimeVC.m in Sources */, 286 | ); 287 | runOnlyForDeploymentPostprocessing = 0; 288 | }; 289 | F788FBDB2243A19300F5F2AA /* Sources */ = { 290 | isa = PBXSourcesBuildPhase; 291 | buildActionMask = 2147483647; 292 | files = ( 293 | F788FBE42243A19300F5F2AA /* FishhookDemoTests.m in Sources */, 294 | ); 295 | runOnlyForDeploymentPostprocessing = 0; 296 | }; 297 | F788FBE62243A19300F5F2AA /* Sources */ = { 298 | isa = PBXSourcesBuildPhase; 299 | buildActionMask = 2147483647; 300 | files = ( 301 | F788FBEF2243A19300F5F2AA /* FishhookDemoUITests.m in Sources */, 302 | ); 303 | runOnlyForDeploymentPostprocessing = 0; 304 | }; 305 | /* End PBXSourcesBuildPhase section */ 306 | 307 | /* Begin PBXTargetDependency section */ 308 | F788FBE12243A19300F5F2AA /* PBXTargetDependency */ = { 309 | isa = PBXTargetDependency; 310 | target = F788FBC62243A19200F5F2AA /* FishhookDemo */; 311 | targetProxy = F788FBE02243A19300F5F2AA /* PBXContainerItemProxy */; 312 | }; 313 | F788FBEC2243A19300F5F2AA /* PBXTargetDependency */ = { 314 | isa = PBXTargetDependency; 315 | target = F788FBC62243A19200F5F2AA /* FishhookDemo */; 316 | targetProxy = F788FBEB2243A19300F5F2AA /* PBXContainerItemProxy */; 317 | }; 318 | /* End PBXTargetDependency section */ 319 | 320 | /* Begin PBXVariantGroup section */ 321 | F788FBD02243A19200F5F2AA /* Main.storyboard */ = { 322 | isa = PBXVariantGroup; 323 | children = ( 324 | F788FBD12243A19200F5F2AA /* Base */, 325 | ); 326 | name = Main.storyboard; 327 | sourceTree = ""; 328 | }; 329 | F788FBD52243A19300F5F2AA /* LaunchScreen.storyboard */ = { 330 | isa = PBXVariantGroup; 331 | children = ( 332 | F788FBD62243A19300F5F2AA /* Base */, 333 | ); 334 | name = LaunchScreen.storyboard; 335 | sourceTree = ""; 336 | }; 337 | /* End PBXVariantGroup section */ 338 | 339 | /* Begin XCBuildConfiguration section */ 340 | F788FBF12243A19300F5F2AA /* Debug */ = { 341 | isa = XCBuildConfiguration; 342 | buildSettings = { 343 | ALWAYS_SEARCH_USER_PATHS = NO; 344 | CLANG_ANALYZER_NONNULL = YES; 345 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 346 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 347 | CLANG_CXX_LIBRARY = "libc++"; 348 | CLANG_ENABLE_MODULES = YES; 349 | CLANG_ENABLE_OBJC_ARC = YES; 350 | CLANG_ENABLE_OBJC_WEAK = YES; 351 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 352 | CLANG_WARN_BOOL_CONVERSION = YES; 353 | CLANG_WARN_COMMA = YES; 354 | CLANG_WARN_CONSTANT_CONVERSION = YES; 355 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 356 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 357 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 358 | CLANG_WARN_EMPTY_BODY = YES; 359 | CLANG_WARN_ENUM_CONVERSION = YES; 360 | CLANG_WARN_INFINITE_RECURSION = YES; 361 | CLANG_WARN_INT_CONVERSION = YES; 362 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 363 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 364 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 365 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 366 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 367 | CLANG_WARN_STRICT_PROTOTYPES = YES; 368 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 369 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 370 | CLANG_WARN_UNREACHABLE_CODE = YES; 371 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 372 | CODE_SIGN_IDENTITY = "iPhone Developer"; 373 | COPY_PHASE_STRIP = NO; 374 | DEBUG_INFORMATION_FORMAT = dwarf; 375 | ENABLE_STRICT_OBJC_MSGSEND = YES; 376 | ENABLE_TESTABILITY = YES; 377 | GCC_C_LANGUAGE_STANDARD = gnu11; 378 | GCC_DYNAMIC_NO_PIC = NO; 379 | GCC_NO_COMMON_BLOCKS = YES; 380 | GCC_OPTIMIZATION_LEVEL = 0; 381 | GCC_PREPROCESSOR_DEFINITIONS = ( 382 | "DEBUG=1", 383 | "$(inherited)", 384 | ); 385 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 386 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 387 | GCC_WARN_UNDECLARED_SELECTOR = YES; 388 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 389 | GCC_WARN_UNUSED_FUNCTION = YES; 390 | GCC_WARN_UNUSED_VARIABLE = YES; 391 | IPHONEOS_DEPLOYMENT_TARGET = 12.1; 392 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 393 | MTL_FAST_MATH = YES; 394 | ONLY_ACTIVE_ARCH = YES; 395 | SDKROOT = iphoneos; 396 | }; 397 | name = Debug; 398 | }; 399 | F788FBF22243A19300F5F2AA /* Release */ = { 400 | isa = XCBuildConfiguration; 401 | buildSettings = { 402 | ALWAYS_SEARCH_USER_PATHS = NO; 403 | CLANG_ANALYZER_NONNULL = YES; 404 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 405 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 406 | CLANG_CXX_LIBRARY = "libc++"; 407 | CLANG_ENABLE_MODULES = YES; 408 | CLANG_ENABLE_OBJC_ARC = YES; 409 | CLANG_ENABLE_OBJC_WEAK = YES; 410 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 411 | CLANG_WARN_BOOL_CONVERSION = YES; 412 | CLANG_WARN_COMMA = YES; 413 | CLANG_WARN_CONSTANT_CONVERSION = YES; 414 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 415 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 416 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 417 | CLANG_WARN_EMPTY_BODY = YES; 418 | CLANG_WARN_ENUM_CONVERSION = YES; 419 | CLANG_WARN_INFINITE_RECURSION = YES; 420 | CLANG_WARN_INT_CONVERSION = YES; 421 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 422 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 423 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 424 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 425 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 426 | CLANG_WARN_STRICT_PROTOTYPES = YES; 427 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 428 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 429 | CLANG_WARN_UNREACHABLE_CODE = YES; 430 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 431 | CODE_SIGN_IDENTITY = "iPhone Developer"; 432 | COPY_PHASE_STRIP = NO; 433 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 434 | ENABLE_NS_ASSERTIONS = NO; 435 | ENABLE_STRICT_OBJC_MSGSEND = YES; 436 | GCC_C_LANGUAGE_STANDARD = gnu11; 437 | GCC_NO_COMMON_BLOCKS = YES; 438 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 439 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 440 | GCC_WARN_UNDECLARED_SELECTOR = YES; 441 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 442 | GCC_WARN_UNUSED_FUNCTION = YES; 443 | GCC_WARN_UNUSED_VARIABLE = YES; 444 | IPHONEOS_DEPLOYMENT_TARGET = 12.1; 445 | MTL_ENABLE_DEBUG_INFO = NO; 446 | MTL_FAST_MATH = YES; 447 | SDKROOT = iphoneos; 448 | VALIDATE_PRODUCT = YES; 449 | }; 450 | name = Release; 451 | }; 452 | F788FBF42243A19300F5F2AA /* Debug */ = { 453 | isa = XCBuildConfiguration; 454 | buildSettings = { 455 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 456 | CODE_SIGN_STYLE = Automatic; 457 | DEVELOPMENT_TEAM = FG83S5U636; 458 | INFOPLIST_FILE = FishhookDemo/Info.plist; 459 | LD_RUNPATH_SEARCH_PATHS = ( 460 | "$(inherited)", 461 | "@executable_path/Frameworks", 462 | ); 463 | PRODUCT_BUNDLE_IDENTIFIER = com.dengbin.FishhookDemo; 464 | PRODUCT_NAME = "$(TARGET_NAME)"; 465 | TARGETED_DEVICE_FAMILY = "1,2"; 466 | }; 467 | name = Debug; 468 | }; 469 | F788FBF52243A19300F5F2AA /* Release */ = { 470 | isa = XCBuildConfiguration; 471 | buildSettings = { 472 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 473 | CODE_SIGN_STYLE = Automatic; 474 | DEVELOPMENT_TEAM = FG83S5U636; 475 | INFOPLIST_FILE = FishhookDemo/Info.plist; 476 | LD_RUNPATH_SEARCH_PATHS = ( 477 | "$(inherited)", 478 | "@executable_path/Frameworks", 479 | ); 480 | PRODUCT_BUNDLE_IDENTIFIER = com.dengbin.FishhookDemo; 481 | PRODUCT_NAME = "$(TARGET_NAME)"; 482 | TARGETED_DEVICE_FAMILY = "1,2"; 483 | }; 484 | name = Release; 485 | }; 486 | F788FBF72243A19300F5F2AA /* Debug */ = { 487 | isa = XCBuildConfiguration; 488 | buildSettings = { 489 | BUNDLE_LOADER = "$(TEST_HOST)"; 490 | CODE_SIGN_STYLE = Automatic; 491 | DEVELOPMENT_TEAM = FG83S5U636; 492 | INFOPLIST_FILE = FishhookDemoTests/Info.plist; 493 | LD_RUNPATH_SEARCH_PATHS = ( 494 | "$(inherited)", 495 | "@executable_path/Frameworks", 496 | "@loader_path/Frameworks", 497 | ); 498 | PRODUCT_BUNDLE_IDENTIFIER = com.dengbin.FishhookDemoTests; 499 | PRODUCT_NAME = "$(TARGET_NAME)"; 500 | TARGETED_DEVICE_FAMILY = "1,2"; 501 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FishhookDemo.app/FishhookDemo"; 502 | }; 503 | name = Debug; 504 | }; 505 | F788FBF82243A19300F5F2AA /* Release */ = { 506 | isa = XCBuildConfiguration; 507 | buildSettings = { 508 | BUNDLE_LOADER = "$(TEST_HOST)"; 509 | CODE_SIGN_STYLE = Automatic; 510 | DEVELOPMENT_TEAM = FG83S5U636; 511 | INFOPLIST_FILE = FishhookDemoTests/Info.plist; 512 | LD_RUNPATH_SEARCH_PATHS = ( 513 | "$(inherited)", 514 | "@executable_path/Frameworks", 515 | "@loader_path/Frameworks", 516 | ); 517 | PRODUCT_BUNDLE_IDENTIFIER = com.dengbin.FishhookDemoTests; 518 | PRODUCT_NAME = "$(TARGET_NAME)"; 519 | TARGETED_DEVICE_FAMILY = "1,2"; 520 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FishhookDemo.app/FishhookDemo"; 521 | }; 522 | name = Release; 523 | }; 524 | F788FBFA2243A19300F5F2AA /* Debug */ = { 525 | isa = XCBuildConfiguration; 526 | buildSettings = { 527 | CODE_SIGN_STYLE = Automatic; 528 | DEVELOPMENT_TEAM = FG83S5U636; 529 | INFOPLIST_FILE = FishhookDemoUITests/Info.plist; 530 | LD_RUNPATH_SEARCH_PATHS = ( 531 | "$(inherited)", 532 | "@executable_path/Frameworks", 533 | "@loader_path/Frameworks", 534 | ); 535 | PRODUCT_BUNDLE_IDENTIFIER = com.dengbin.FishhookDemoUITests; 536 | PRODUCT_NAME = "$(TARGET_NAME)"; 537 | TARGETED_DEVICE_FAMILY = "1,2"; 538 | TEST_TARGET_NAME = FishhookDemo; 539 | }; 540 | name = Debug; 541 | }; 542 | F788FBFB2243A19300F5F2AA /* Release */ = { 543 | isa = XCBuildConfiguration; 544 | buildSettings = { 545 | CODE_SIGN_STYLE = Automatic; 546 | DEVELOPMENT_TEAM = FG83S5U636; 547 | INFOPLIST_FILE = FishhookDemoUITests/Info.plist; 548 | LD_RUNPATH_SEARCH_PATHS = ( 549 | "$(inherited)", 550 | "@executable_path/Frameworks", 551 | "@loader_path/Frameworks", 552 | ); 553 | PRODUCT_BUNDLE_IDENTIFIER = com.dengbin.FishhookDemoUITests; 554 | PRODUCT_NAME = "$(TARGET_NAME)"; 555 | TARGETED_DEVICE_FAMILY = "1,2"; 556 | TEST_TARGET_NAME = FishhookDemo; 557 | }; 558 | name = Release; 559 | }; 560 | /* End XCBuildConfiguration section */ 561 | 562 | /* Begin XCConfigurationList section */ 563 | F788FBC22243A19100F5F2AA /* Build configuration list for PBXProject "FishhookDemo" */ = { 564 | isa = XCConfigurationList; 565 | buildConfigurations = ( 566 | F788FBF12243A19300F5F2AA /* Debug */, 567 | F788FBF22243A19300F5F2AA /* Release */, 568 | ); 569 | defaultConfigurationIsVisible = 0; 570 | defaultConfigurationName = Release; 571 | }; 572 | F788FBF32243A19300F5F2AA /* Build configuration list for PBXNativeTarget "FishhookDemo" */ = { 573 | isa = XCConfigurationList; 574 | buildConfigurations = ( 575 | F788FBF42243A19300F5F2AA /* Debug */, 576 | F788FBF52243A19300F5F2AA /* Release */, 577 | ); 578 | defaultConfigurationIsVisible = 0; 579 | defaultConfigurationName = Release; 580 | }; 581 | F788FBF62243A19300F5F2AA /* Build configuration list for PBXNativeTarget "FishhookDemoTests" */ = { 582 | isa = XCConfigurationList; 583 | buildConfigurations = ( 584 | F788FBF72243A19300F5F2AA /* Debug */, 585 | F788FBF82243A19300F5F2AA /* Release */, 586 | ); 587 | defaultConfigurationIsVisible = 0; 588 | defaultConfigurationName = Release; 589 | }; 590 | F788FBF92243A19300F5F2AA /* Build configuration list for PBXNativeTarget "FishhookDemoUITests" */ = { 591 | isa = XCConfigurationList; 592 | buildConfigurations = ( 593 | F788FBFA2243A19300F5F2AA /* Debug */, 594 | F788FBFB2243A19300F5F2AA /* Release */, 595 | ); 596 | defaultConfigurationIsVisible = 0; 597 | defaultConfigurationName = Release; 598 | }; 599 | /* End XCConfigurationList section */ 600 | }; 601 | rootObject = F788FBBF2243A19100F5F2AA /* Project object */; 602 | } 603 | -------------------------------------------------------------------------------- /FishhookDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /FishhookDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // FishhookDemo 4 | // 5 | // Created by DengBin on 2019/3/21. 6 | // Copyright © 2019 DengBin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /FishhookDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // FishhookDemo 4 | // 5 | // Created by DengBin on 2019/3/21. 6 | // Copyright © 2019 DengBin. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 18 | NSLog(@"application"); 19 | NSLog(@"application2"); 20 | printf("application3"); 21 | printf("application4"); 22 | [self mylog]; 23 | [self mylog2]; 24 | return YES; 25 | } 26 | 27 | - (void)mylog{ 28 | NSLog(@"mylog"); 29 | } 30 | 31 | - (void)mylog2{ 32 | NSLog(@"mylog"); 33 | } 34 | 35 | 36 | 37 | - (void)applicationWillResignActive:(UIApplication *)application { 38 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 39 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 40 | } 41 | 42 | 43 | - (void)applicationDidEnterBackground:(UIApplication *)application { 44 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 45 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 46 | } 47 | 48 | 49 | - (void)applicationWillEnterForeground:(UIApplication *)application { 50 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 51 | } 52 | 53 | 54 | - (void)applicationDidBecomeActive:(UIApplication *)application { 55 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 56 | } 57 | 58 | 59 | - (void)applicationWillTerminate:(UIApplication *)application { 60 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 61 | } 62 | 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /FishhookDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /FishhookDemo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /FishhookDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /FishhookDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 73 | 81 | 89 | 97 | 105 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /FishhookDemo/FishhookVC.h: -------------------------------------------------------------------------------- 1 | // 2 | // FishhookVC.h 3 | // FishhookDemo 4 | // 5 | // Created by DengBin on 2019/3/21. 6 | // Copyright © 2019 DengBin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface FishhookVC : UIViewController 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /FishhookDemo/FishhookVC.m: -------------------------------------------------------------------------------- 1 | // 2 | // FishhookVC.m 3 | // FishhookDemo 4 | // 5 | // Created by DengBin on 2019/3/21. 6 | // Copyright © 2019 DengBin. All rights reserved. 7 | // 8 | 9 | #import "FishhookVC.h" 10 | #import "fishhook.h" 11 | 12 | @interface FishhookVC () 13 | 14 | @end 15 | 16 | @implementation FishhookVC 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | NSLog(@"log来了,老弟"); 21 | 22 | struct rebinding nslog; 23 | nslog.name = "NSLog"; 24 | nslog.replacement = my_nslog; 25 | nslog.replaced = (void *)&sys_nslog; 26 | struct rebinding rebs[1] = {nslog}; 27 | rebind_symbols(rebs, 1); 28 | 29 | } 30 | //---------------------------------更改NSLog----------- 31 | //函数指针 32 | static void(*sys_nslog)(NSString * format,...); 33 | 34 | //定义一个新的函数 35 | void my_nslog(NSString * format,...){ 36 | format = [format stringByAppendingString:@"你咋又来了 \n"]; 37 | //调用原始的 38 | sys_nslog(format); 39 | } 40 | 41 | 42 | 43 | -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 44 | { 45 | NSLog(@"log又来了,老弟!!"); 46 | add(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,14,15,16,17,18,19,20,21,22,23,2425,26,27,28,29,30,31,32,33); 47 | // add3(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,14,15,16,17,18,19,20,21); 48 | } 49 | 50 | int add(int a,int b,int c,int d,int e,int f,int g,int h,int i,int j,int k,int l,int m,int m1,int m2,int m3,int m4,int m5,int m6,int m7,int m8,int n1,int n2,int n3,int n4,int n5,int n6,int n7,int n8,int n9,int n10,int n11) { 51 | int xx = a+b+c+d+e+f+g+h+i+j+k+l+m+m1+m2+m3+m4+m5+m6+m7+m8; 52 | return xx; 53 | } 54 | 55 | int add2(int a,int b,int c,int d,int e) { 56 | int xx = a+b+c+d+e; 57 | return xx; 58 | } 59 | 60 | int add3(int a,int b,int c,int d,int e,int f,int g,int h,int i,int j,int k,int l,int m,int m1,int m2,int m3,int m4,int m5,int m6,int m7,int m8) { 61 | int xx = a+b+c+d+e+f+g+h+i+j+k+l+m+m1+m2+m3+m4+m5+m6+m7+m8; 62 | return xx; 63 | } 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /FishhookDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /FishhookDemo/RuntimeVC.h: -------------------------------------------------------------------------------- 1 | // 2 | // RuntimeVC.h 3 | // FishhookDemo 4 | // 5 | // Created by DengBin on 2019/3/21. 6 | // Copyright © 2019 DengBin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface RuntimeVC : UIViewController 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /FishhookDemo/RuntimeVC.m: -------------------------------------------------------------------------------- 1 | // 2 | // RuntimeVC.m 3 | // FishhookDemo 4 | // 5 | // Created by DengBin on 2019/3/21. 6 | // Copyright © 2019 DengBin. All rights reserved. 7 | // 8 | 9 | #import "RuntimeVC.h" 10 | #import 11 | 12 | @interface RuntimeVC () 13 | 14 | 15 | - (IBAction)log1Action:(id)sender; 16 | 17 | - (IBAction)log1ActionHook:(id)sender; 18 | 19 | - (IBAction)log2Action:(id)sender; 20 | 21 | - (IBAction)log2ActionHook:(id)sender; 22 | 23 | - (IBAction)log3Action:(id)sender; 24 | 25 | - (IBAction)log3ActionHook:(id)sender; 26 | @end 27 | 28 | @implementation RuntimeVC 29 | 30 | - (void)viewDidLoad { 31 | [super viewDidLoad]; 32 | // Do any additional setup after loading the view. 33 | } 34 | 35 | - (IBAction)log1Action:(id)sender { 36 | NSLog(@"->1<-"); 37 | } 38 | 39 | - (IBAction)log2Action:(id)sender { 40 | NSLog(@"->2<-"); 41 | } 42 | 43 | - (IBAction)log3Action:(id)sender { 44 | NSLog(@"->3<-"); 45 | } 46 | 47 | 48 | - (IBAction)log1ActionHook:(id)sender { 49 | [self exchangeInstanceMethod:[self class] method1Sel:@selector(log1Action:) method2Sel:@selector(new_log1Action:)]; 50 | } 51 | 52 | - (IBAction)log2ActionHook:(id)sender { 53 | 54 | Method new_method = class_getInstanceMethod([self class], @selector(new_log2Action:)); 55 | IMP new_methodIMP = method_getImplementation(new_method); 56 | const char *typeEncoding = method_getTypeEncoding(new_method); 57 | class_replaceMethod([self class], @selector(log2Action:), new_methodIMP, typeEncoding); 58 | } 59 | 60 | IMP (*old_onMethod)(id self,SEL _cmd); 61 | - (IBAction)log3ActionHook:(id)sender { 62 | //GET & SET 63 | Method onLog3Action = class_getInstanceMethod([self class], sel_registerName("log3Action:")); 64 | //1.保存原始的IMP 65 | old_onMethod = method_getImplementation(onLog3Action); 66 | //2.SET 67 | method_setImplementation(onLog3Action, (IMP)new_log3Action); 68 | } 69 | 70 | 71 | - (void)new_log1Action:(id)sender { 72 | NSLog(@"->1<-来不了了"); 73 | } 74 | 75 | - (void)new_log2Action:(id)sender { 76 | NSLog(@"->2<-来不了了"); 77 | } 78 | 79 | void new_log3Action(id self,SEL _cmd,id sender){ 80 | NSLog(@"->3<-来不了了"); 81 | } 82 | 83 | 84 | - (void)exchangeInstanceMethod:(Class)anClass method1Sel:(SEL)method1Sel method2Sel:(SEL)method2Sel { 85 | Method originalMethod = class_getInstanceMethod(anClass, method1Sel); 86 | Method swizzledMethod = class_getInstanceMethod(anClass, method2Sel); 87 | 88 | BOOL didAddMethod = 89 | class_addMethod(anClass, 90 | method1Sel, 91 | method_getImplementation(swizzledMethod), 92 | method_getTypeEncoding(swizzledMethod)); 93 | 94 | if (didAddMethod) { 95 | class_replaceMethod(anClass, 96 | method2Sel, 97 | method_getImplementation(originalMethod), 98 | method_getTypeEncoding(originalMethod)); 99 | } 100 | 101 | else { 102 | method_exchangeImplementations(originalMethod, swizzledMethod); 103 | } 104 | } 105 | 106 | 107 | @end 108 | -------------------------------------------------------------------------------- /FishhookDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // FishhookDemo 4 | // 5 | // Created by DengBin on 2019/3/21. 6 | // Copyright © 2019 DengBin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /FishhookDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // FishhookDemo 4 | // 5 | // Created by DengBin on 2019/3/21. 6 | // Copyright © 2019 DengBin. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | @interface ViewController () 12 | 13 | @property (weak, nonatomic) IBOutlet UITableView *tableView; 14 | 15 | /* titles */ 16 | @property (nonatomic,strong) NSArray *titles; 17 | @end 18 | 19 | @implementation ViewController 20 | 21 | - (void)viewDidLoad { 22 | [super viewDidLoad]; 23 | self.titles = @[@"runtime",@"fishhook"]; 24 | // Do any additional setup after loading the view, typically from a nib. 25 | } 26 | 27 | #pragma mark - UITableViewDataSource && UITableViewDelegate 28 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ 29 | return 1; 30 | } 31 | 32 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ 33 | return self.titles.count; 34 | } 35 | 36 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ 37 | return 44; 38 | } 39 | 40 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ 41 | static NSString *cellIdentifier = @"cellIdentifier"; 42 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; 43 | if ( !cell ) { 44 | cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier]; 45 | cell.accessoryType = UITableViewCellAccessoryNone; 46 | cell.selectionStyle = UITableViewCellSelectionStyleNone; 47 | cell.backgroundColor = [UIColor whiteColor]; 48 | cell.contentView.backgroundColor = [UIColor whiteColor]; 49 | } 50 | cell.textLabel.text = self.titles[indexPath.row]; 51 | return cell; 52 | } 53 | 54 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ 55 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 56 | NSString *segueIdentifier = @""; 57 | if (indexPath.row == 0) { 58 | segueIdentifier = @"goToRuntimeVC"; 59 | } 60 | else { 61 | segueIdentifier = @"goToFishhookVC"; 62 | } 63 | [self performSegueWithIdentifier:segueIdentifier sender:nil]; 64 | } 65 | @end 66 | -------------------------------------------------------------------------------- /FishhookDemo/fishhook.c: -------------------------------------------------------------------------------- 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. 23 | 24 | #include "fishhook.h" 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #ifdef __LP64__ 35 | typedef struct mach_header_64 mach_header_t; 36 | typedef struct segment_command_64 segment_command_t; 37 | typedef struct section_64 section_t; 38 | typedef struct nlist_64 nlist_t; 39 | #define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT_64 40 | #else 41 | typedef struct mach_header mach_header_t; 42 | typedef struct segment_command segment_command_t; 43 | typedef struct section section_t; 44 | typedef struct nlist nlist_t; 45 | #define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT 46 | #endif 47 | 48 | #ifndef SEG_DATA_CONST 49 | #define SEG_DATA_CONST "__DATA_CONST" 50 | #endif 51 | 52 | struct rebindings_entry { 53 | struct rebinding *rebindings; 54 | size_t rebindings_nel; 55 | struct rebindings_entry *next; 56 | }; 57 | 58 | static struct rebindings_entry *_rebindings_head; 59 | 60 | // 给需要rebinding的方法结构体开辟出对应的空间 61 | // 生成对应的链表结构(rebindings_entry) 62 | static int prepend_rebindings(struct rebindings_entry **rebindings_head, 63 | struct rebinding rebindings[], 64 | size_t nel) { 65 | // 开辟一个rebindings_entry大小的空间 66 | struct rebindings_entry *new_entry = (struct rebindings_entry *) malloc(sizeof(struct rebindings_entry)); 67 | if (!new_entry) { 68 | return -1; 69 | } 70 | // 一共有nel个rebinding 71 | new_entry->rebindings = (struct rebinding *) malloc(sizeof(struct rebinding) * nel); 72 | if (!new_entry->rebindings) { 73 | free(new_entry); 74 | return -1; 75 | } 76 | // 将rebinding赋值给new_entry->rebindings 77 | memcpy(new_entry->rebindings, rebindings, sizeof(struct rebinding) * nel); 78 | // 继续赋值nel 79 | new_entry->rebindings_nel = nel; 80 | // 每次都将new_entry插入头部 81 | new_entry->next = *rebindings_head; 82 | // rebindings_head重新指向头部 83 | *rebindings_head = new_entry; 84 | return 0; 85 | } 86 | 87 | static void perform_rebinding_with_section(struct rebindings_entry *rebindings, 88 | section_t *section, 89 | intptr_t slide, 90 | nlist_t *symtab, 91 | char *strtab, 92 | uint32_t *indirect_symtab) { 93 | // reserved1对应的的是indirect_symbol中的offset,也就是indirect_symbol的真实地址 94 | // indirect_symtab+offset就是indirect_symbol_indices(indirect_symbol的数组) 95 | uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1; 96 | // 函数地址,addr就是section的偏移地址 97 | void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr); 98 | // 遍历section中的每个符号 99 | for (uint i = 0; i < section->size / sizeof(void *); i++) { 100 | // 访问indirect_symbol,symtab_index就是indirect_symbol中data的值 101 | uint32_t symtab_index = indirect_symbol_indices[i]; 102 | if (symtab_index == INDIRECT_SYMBOL_ABS || symtab_index == INDIRECT_SYMBOL_LOCAL || 103 | symtab_index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS)) { 104 | continue; 105 | } 106 | // 访问symbol_table,根据symtab_index获取到symbol_table中的偏移offset 107 | uint32_t strtab_offset = symtab[symtab_index].n_un.n_strx; 108 | // 访问string_table,根据strtab_offset获取symbol_name 109 | char *symbol_name = strtab + strtab_offset; 110 | // string_table中的所有函数名都是以"."开始的,所以一个函数一定有两个字符 111 | bool symbol_name_longer_than_1 = symbol_name[0] && symbol_name[1]; 112 | struct rebindings_entry *cur = rebindings; 113 | // 已经存入的rebindings_entry 114 | while (cur) { 115 | // 循环每个entry中需要重绑定的函数 116 | for (uint j = 0; j < cur->rebindings_nel; j++) { 117 | // 判断symbol_name是否是一个正确的函数名 118 | // 需要被重绑定的函数名是否与当前symbol_name相等 119 | if (symbol_name_longer_than_1 && 120 | strcmp(&symbol_name[1], cur->rebindings[j].name) == 0) { 121 | // 判断replaced是否存在 122 | // 判断replaced和老的函数是否是一样的 123 | if (cur->rebindings[j].replaced != NULL && 124 | indirect_symbol_bindings[i] != cur->rebindings[j].replacement) { 125 | // 将原函数的地址给新函数replaced 126 | *(cur->rebindings[j].replaced) = indirect_symbol_bindings[i]; 127 | } 128 | // 将replacement赋值给刚刚找到的 129 | indirect_symbol_bindings[i] = cur->rebindings[j].replacement; 130 | goto symbol_loop; 131 | } 132 | } 133 | // 继续下一个需要绑定的函数 134 | cur = cur->next; 135 | } 136 | symbol_loop:; 137 | } 138 | } 139 | 140 | static void rebind_symbols_for_image(struct rebindings_entry *rebindings, 141 | const struct mach_header *header, 142 | intptr_t slide) { 143 | Dl_info info; 144 | // 判断当前macho是否在进程里,如果不在则直接返回 145 | if (dladdr(header, &info) == 0) { 146 | return; 147 | } 148 | 149 | // 定义好几个变量,后面去遍历查找 150 | segment_command_t *cur_seg_cmd; 151 | // MachO中Load Commons中的linkedit 152 | segment_command_t *linkedit_segment = NULL; 153 | // MachO中LC_SYMTAB 154 | struct symtab_command* symtab_cmd = NULL; 155 | // MachO中LC_DYSYMTAB 156 | struct dysymtab_command* dysymtab_cmd = NULL; 157 | 158 | // header的首地址+mach_header的内存大小 159 | // 得到跳过mach_header的地址,也就是直接到Load Commons的地址 160 | uintptr_t cur = (uintptr_t)header + sizeof(mach_header_t); 161 | // 遍历Load Commons 找到上面三个遍历 162 | for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { 163 | cur_seg_cmd = (segment_command_t *)cur; 164 | // 如果是LC_SEGMENT_64 165 | if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { 166 | // 找到linkedit 167 | if (strcmp(cur_seg_cmd->segname, SEG_LINKEDIT) == 0) { 168 | linkedit_segment = cur_seg_cmd; 169 | } 170 | } 171 | // 如果是LC_SYMTAB,就找到了symtab_cmd 172 | else if (cur_seg_cmd->cmd == LC_SYMTAB) { 173 | symtab_cmd = (struct symtab_command*)cur_seg_cmd; 174 | } 175 | // 如果是LC_DYSYMTAB,就找到了dysymtab_cmd 176 | else if (cur_seg_cmd->cmd == LC_DYSYMTAB) { 177 | dysymtab_cmd = (struct dysymtab_command*)cur_seg_cmd; 178 | } 179 | } 180 | // 下面其中任何一个值没有都直接return 181 | // 因为image不是需要找的image 182 | if (!symtab_cmd || !dysymtab_cmd || !linkedit_segment || 183 | !dysymtab_cmd->nindirectsyms) { 184 | return; 185 | } 186 | 187 | // Find base symbol/string table addresses 188 | // 找到linkedit的头地址 189 | // linkedit_base其实就是MachO的头地址!!!可以通过查看linkedit_base值和image list命令查看验证!!! 190 | /********************************************************** 191 | Linkedit虚拟地址 = PAGEZERO(64位下1G) + FileOffset 192 | MachO地址 = PAGEZERO + ASLR 193 | 上面两个公式是已知的 得到下面这个公式 194 | MachO文件地址 = Linkedit虚拟地址 - FileOffset + ASLR(slide) 195 | **********************************************************/ 196 | uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff; 197 | // 获取symbol_table的真实地址 198 | nlist_t *symtab = (nlist_t *)(linkedit_base + symtab_cmd->symoff); 199 | // 获取string_table的真实地址 200 | char *strtab = (char *)(linkedit_base + symtab_cmd->stroff); 201 | 202 | // Get indirect symbol table (array of uint32_t indices into symbol table) 203 | // 获取indirect_symtab的真实地址 204 | uint32_t *indirect_symtab = (uint32_t *)(linkedit_base + dysymtab_cmd->indirectsymoff); 205 | // 同样的,得到跳过mach_header的地址,得到Load Commons的地址 206 | cur = (uintptr_t)header + sizeof(mach_header_t); 207 | // 遍历Load Commons,找到对应符号进行重新绑定 208 | for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { 209 | cur_seg_cmd = (segment_command_t *)cur; 210 | if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { 211 | // 如果不是__DATA段,也不是__DATA_CONST段,直接跳过 212 | if (strcmp(cur_seg_cmd->segname, SEG_DATA) != 0 && 213 | strcmp(cur_seg_cmd->segname, SEG_DATA_CONST) != 0) { 214 | continue; 215 | } 216 | // 遍历所有的segment 217 | for (uint j = 0; j < cur_seg_cmd->nsects; j++) { 218 | section_t *sect = 219 | (section_t *)(cur + sizeof(segment_command_t)) + j; 220 | // 找懒加载表S_LAZY_SYMBOL_POINTERS 221 | if ((sect->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS) { 222 | // 重绑定的真正函数 223 | perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab); 224 | } 225 | // 找非懒加载表S_NON_LAZY_SYMBOL_POINTERS 226 | if ((sect->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS) { 227 | // 重绑定的真正函数 228 | perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab); 229 | } 230 | } 231 | } 232 | } 233 | } 234 | 235 | static void _rebind_symbols_for_image(const struct mach_header *header, 236 | intptr_t slide) { 237 | // 找到对应的符号,进行重绑定 238 | rebind_symbols_for_image(_rebindings_head, header, slide); 239 | } 240 | 241 | // 在知道确定的MachO,可以使用该方法 242 | int rebind_symbols_image(void *header, 243 | intptr_t slide, 244 | struct rebinding rebindings[], 245 | size_t rebindings_nel) { 246 | struct rebindings_entry *rebindings_head = NULL; 247 | int retval = prepend_rebindings(&rebindings_head, rebindings, rebindings_nel); 248 | rebind_symbols_for_image(rebindings_head, (const struct mach_header *) header, slide); 249 | if (rebindings_head) { 250 | free(rebindings_head->rebindings); 251 | } 252 | free(rebindings_head); 253 | return retval; 254 | } 255 | 256 | int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel) { 257 | int retval = prepend_rebindings(&_rebindings_head, rebindings, rebindings_nel); 258 | if (retval < 0) { 259 | return retval; 260 | } 261 | // If this was the first call, register callback for image additions (which is also invoked for 262 | // existing images, otherwise, just run on existing images 263 | if (!_rebindings_head->next) { 264 | // 向每个image注册_rebind_symbols_for_image函数,并且立即触发一次 265 | _dyld_register_func_for_add_image(_rebind_symbols_for_image); 266 | } else { 267 | // _dyld_image_count() 获取image数量 268 | uint32_t c = _dyld_image_count(); 269 | for (uint32_t i = 0; i < c; i++) { 270 | // _dyld_get_image_header(i) 获取第i个image的header指针 271 | // _dyld_get_image_vmaddr_slide(i) 获取第i个image的基址 272 | _rebind_symbols_for_image(_dyld_get_image_header(i), _dyld_get_image_vmaddr_slide(i)); 273 | } 274 | } 275 | return retval; 276 | } 277 | 278 | -------------------------------------------------------------------------------- /FishhookDemo/fishhook.h: -------------------------------------------------------------------------------- 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. 23 | 24 | #ifndef fishhook_h 25 | #define fishhook_h 26 | 27 | #include 28 | #include 29 | 30 | #if !defined(FISHHOOK_EXPORT) 31 | #define FISHHOOK_VISIBILITY __attribute__((visibility("hidden"))) 32 | #else 33 | #define FISHHOOK_VISIBILITY __attribute__((visibility("default"))) 34 | #endif 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif //__cplusplus 39 | 40 | /* 41 | * A structure representing a particular intended rebinding from a symbol 42 | * name to its replacement 43 | */ 44 | struct rebinding { 45 | const char *name; // 需要替换的函数名 46 | void *replacement; // 新函数的指针 47 | void **replaced; // 老函数的新指针 48 | }; 49 | 50 | /* 51 | * For each rebinding in rebindings, rebinds references to external, indirect 52 | * symbols with the specified name to instead point at replacement for each 53 | * image in the calling process as well as for all future images that are loaded 54 | * by the process. If rebind_functions is called more than once, the symbols to 55 | * rebind are added to the existing list of rebindings, and if a given symbol 56 | * is rebound more than once, the later rebinding will take precedence. 57 | */ 58 | FISHHOOK_VISIBILITY 59 | int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel); 60 | 61 | /* 62 | * Rebinds as above, but only in the specified image. The header should point 63 | * to the mach-o header, the slide should be the slide offset. Others as above. 64 | */ 65 | FISHHOOK_VISIBILITY 66 | int rebind_symbols_image(void *header, 67 | intptr_t slide, 68 | struct rebinding rebindings[], 69 | size_t rebindings_nel); 70 | 71 | #ifdef __cplusplus 72 | } 73 | #endif //__cplusplus 74 | 75 | #endif //fishhook_h 76 | 77 | -------------------------------------------------------------------------------- /FishhookDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // FishhookDemo 4 | // 5 | // Created by DengBin on 2019/3/21. 6 | // Copyright © 2019 DengBin. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /FishhookDemoTests/FishhookDemoTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // FishhookDemoTests.m 3 | // FishhookDemoTests 4 | // 5 | // Created by DengBin on 2019/3/21. 6 | // Copyright © 2019 DengBin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface FishhookDemoTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation FishhookDemoTests 16 | 17 | - (void)setUp { 18 | // Put setup code here. This method is called before the invocation of each test method in the class. 19 | } 20 | 21 | - (void)tearDown { 22 | // Put teardown code here. This method is called after the invocation of each test method in the class. 23 | } 24 | 25 | - (void)testExample { 26 | // This is an example of a functional test case. 27 | // Use XCTAssert and related functions to verify your tests produce the correct results. 28 | } 29 | 30 | - (void)testPerformanceExample { 31 | // This is an example of a performance test case. 32 | [self measureBlock:^{ 33 | // Put the code you want to measure the time of here. 34 | }]; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /FishhookDemoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /FishhookDemoUITests/FishhookDemoUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // FishhookDemoUITests.m 3 | // FishhookDemoUITests 4 | // 5 | // Created by DengBin on 2019/3/21. 6 | // Copyright © 2019 DengBin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface FishhookDemoUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation FishhookDemoUITests 16 | 17 | - (void)setUp { 18 | // Put setup code here. This method is called before the invocation of each test method in the class. 19 | 20 | // In UI tests it is usually best to stop immediately when a failure occurs. 21 | self.continueAfterFailure = NO; 22 | 23 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 24 | [[[XCUIApplication alloc] init] launch]; 25 | 26 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 27 | } 28 | 29 | - (void)tearDown { 30 | // Put teardown code here. This method is called after the invocation of each test method in the class. 31 | } 32 | 33 | - (void)testExample { 34 | // Use recording to get started writing UI tests. 35 | // Use XCTAssert and related functions to verify your tests produce the correct results. 36 | } 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /FishhookDemoUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FishhookDemo 2 | 3 | ## 本仓库包含 4 | * 利用runtime来hook的OC方法的三种方式 5 | * fishhook的demo 6 | * fishhook源码的超详细注释 7 | 8 | 仓库对应博文:[iOS逆向(6)-从fishhook看runtime,hook系统C函数](https://www.jianshu.com/p/b6a72aa6c146) 9 | --------------------------------------------------------------------------------