├── .gitignore ├── LICENSE ├── README.md └── SwiftDemo ├── SwiftDemo.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ └── SwiftDemo.xcscheme ├── SwiftDemo ├── AppDelegate.swift ├── Assets.xcassets │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── SceneDelegate.swift ├── SwiftDefines.h ├── SwiftDemo-Bridging-Header.h ├── SwiftMethodTableModel.h ├── SwiftMethodTableModel.m ├── ViewController.swift ├── WBOCTest.h └── WBOCTest.m ├── SwiftDemoTests ├── Info.plist └── SwiftDemoTests.swift └── SwiftDemoUITests ├── Info.plist └── SwiftDemoUITests.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## User settings 6 | xcuserdata/ 7 | 8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 9 | *.xcscmblueprint 10 | *.xccheckout 11 | 12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 13 | build/ 14 | DerivedData/ 15 | *.moved-aside 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | 28 | ## App packaging 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | # CocoaPods 34 | # 35 | # We recommend against adding the Pods directory to your .gitignore. However 36 | # you should judge for yourself, the pros and cons are mentioned at: 37 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 38 | # 39 | # Pods/ 40 | # 41 | # Add this line if you want to avoid checking in source code from the Xcode workspace 42 | # *.xcworkspace 43 | 44 | # Carthage 45 | # 46 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 47 | # Carthage/Checkouts 48 | 49 | Carthage/Build/ 50 | 51 | # fastlane 52 | # 53 | # It is recommended to not store the screenshots in the git repo. 54 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 55 | # For more information about the recommended setup visit: 56 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 57 | 58 | fastlane/report.xml 59 | fastlane/Preview.html 60 | fastlane/screenshots/**/*.png 61 | fastlane/test_output 62 | 63 | # Code Injection 64 | # 65 | # After new code Injection tools there's a generated folder /iOSInjectionProject 66 | # https://github.com/johnno1962/injectionforxcode 67 | 68 | iOSInjectionProject/ 69 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2005-present, dengzhuli. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above 9 | copyright notice, this list of conditions and the following 10 | disclaimer in the documentation and/or other materials provided 11 | with the distribution. 12 | * Neither the name of dengzhuli nor the names of its 13 | contributors may be used to endorse or promote products derived 14 | from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 23 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SwiftVTHook(beta) 2 | 3 | ## 介绍 4 | SwiftVTHook 是一种基于Swift的虚函数表的函数hook 方案,目前已经形成demo。不包括Swift msg_send以及静态地址直接调用的方式进行函数调用。 5 | 6 | ## 进展 7 | 目前SwiftVTHook处于理论实验阶段,编译器对Swift的优化影响、泛型、Type结构等还需要进一步完善。 8 | 9 | ## demo 10 | demo 只支持真机arm64架构。建议release模式下进行编译运行。由于相对对OC比较熟悉,因此核心代码采用OC编写。 11 | 12 | ## 风险 13 | 在修改编译选项时,代码可能存在优化,跳表方式的函数调用转为静态地址调用,因此可能失效。 14 | 另外, 15 | demo中可能存在的问题通过 #warning 的方式做了介绍 16 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 37419AA125E8CB9F007A613C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37419AA025E8CB9F007A613C /* AppDelegate.swift */; }; 11 | 37419AA325E8CB9F007A613C /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37419AA225E8CB9F007A613C /* SceneDelegate.swift */; }; 12 | 37419AA525E8CB9F007A613C /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37419AA425E8CB9F007A613C /* ViewController.swift */; }; 13 | 37419AA825E8CB9F007A613C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 37419AA625E8CB9F007A613C /* Main.storyboard */; }; 14 | 37419AAA25E8CBA0007A613C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 37419AA925E8CBA0007A613C /* Assets.xcassets */; }; 15 | 37419AAD25E8CBA0007A613C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 37419AAB25E8CBA0007A613C /* LaunchScreen.storyboard */; }; 16 | 37419AB825E8CBA0007A613C /* SwiftDemoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37419AB725E8CBA0007A613C /* SwiftDemoTests.swift */; }; 17 | 37419AC325E8CBA0007A613C /* SwiftDemoUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37419AC225E8CBA0007A613C /* SwiftDemoUITests.swift */; }; 18 | 37419AD625E8CBBF007A613C /* WBOCTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 37419AD525E8CBBF007A613C /* WBOCTest.m */; }; 19 | 37BE2D1625ED035B00B68782 /* SwiftMethodTableModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 37BE2D1525ED035B00B68782 /* SwiftMethodTableModel.m */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXContainerItemProxy section */ 23 | 37419AB425E8CBA0007A613C /* PBXContainerItemProxy */ = { 24 | isa = PBXContainerItemProxy; 25 | containerPortal = 37419A9525E8CB9F007A613C /* Project object */; 26 | proxyType = 1; 27 | remoteGlobalIDString = 37419A9C25E8CB9F007A613C; 28 | remoteInfo = SwiftDemo; 29 | }; 30 | 37419ABF25E8CBA0007A613C /* PBXContainerItemProxy */ = { 31 | isa = PBXContainerItemProxy; 32 | containerPortal = 37419A9525E8CB9F007A613C /* Project object */; 33 | proxyType = 1; 34 | remoteGlobalIDString = 37419A9C25E8CB9F007A613C; 35 | remoteInfo = SwiftDemo; 36 | }; 37 | /* End PBXContainerItemProxy section */ 38 | 39 | /* Begin PBXFileReference section */ 40 | 37419A9D25E8CB9F007A613C /* SwiftDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 37419AA025E8CB9F007A613C /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 42 | 37419AA225E8CB9F007A613C /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 43 | 37419AA425E8CB9F007A613C /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 44 | 37419AA725E8CB9F007A613C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 45 | 37419AA925E8CBA0007A613C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 46 | 37419AAC25E8CBA0007A613C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 47 | 37419AAE25E8CBA0007A613C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 48 | 37419AB325E8CBA0007A613C /* SwiftDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | 37419AB725E8CBA0007A613C /* SwiftDemoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftDemoTests.swift; sourceTree = ""; }; 50 | 37419AB925E8CBA0007A613C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 51 | 37419ABE25E8CBA0007A613C /* SwiftDemoUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftDemoUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 52 | 37419AC225E8CBA0007A613C /* SwiftDemoUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftDemoUITests.swift; sourceTree = ""; }; 53 | 37419AC425E8CBA0007A613C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 54 | 37419AD325E8CBBE007A613C /* SwiftDemo-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SwiftDemo-Bridging-Header.h"; sourceTree = ""; }; 55 | 37419AD425E8CBBF007A613C /* WBOCTest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WBOCTest.h; sourceTree = ""; }; 56 | 37419AD525E8CBBF007A613C /* WBOCTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WBOCTest.m; sourceTree = ""; }; 57 | 37419AF525E8F69F007A613C /* SwiftDefines.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwiftDefines.h; sourceTree = ""; }; 58 | 37BE2D1425ED035B00B68782 /* SwiftMethodTableModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwiftMethodTableModel.h; sourceTree = ""; }; 59 | 37BE2D1525ED035B00B68782 /* SwiftMethodTableModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SwiftMethodTableModel.m; sourceTree = ""; }; 60 | /* End PBXFileReference section */ 61 | 62 | /* Begin PBXFrameworksBuildPhase section */ 63 | 37419A9A25E8CB9F007A613C /* Frameworks */ = { 64 | isa = PBXFrameworksBuildPhase; 65 | buildActionMask = 2147483647; 66 | files = ( 67 | ); 68 | runOnlyForDeploymentPostprocessing = 0; 69 | }; 70 | 37419AB025E8CBA0007A613C /* Frameworks */ = { 71 | isa = PBXFrameworksBuildPhase; 72 | buildActionMask = 2147483647; 73 | files = ( 74 | ); 75 | runOnlyForDeploymentPostprocessing = 0; 76 | }; 77 | 37419ABB25E8CBA0007A613C /* Frameworks */ = { 78 | isa = PBXFrameworksBuildPhase; 79 | buildActionMask = 2147483647; 80 | files = ( 81 | ); 82 | runOnlyForDeploymentPostprocessing = 0; 83 | }; 84 | /* End PBXFrameworksBuildPhase section */ 85 | 86 | /* Begin PBXGroup section */ 87 | 37419A9425E8CB9F007A613C = { 88 | isa = PBXGroup; 89 | children = ( 90 | 37419A9F25E8CB9F007A613C /* SwiftDemo */, 91 | 37419AB625E8CBA0007A613C /* SwiftDemoTests */, 92 | 37419AC125E8CBA0007A613C /* SwiftDemoUITests */, 93 | 37419A9E25E8CB9F007A613C /* Products */, 94 | ); 95 | sourceTree = ""; 96 | }; 97 | 37419A9E25E8CB9F007A613C /* Products */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | 37419A9D25E8CB9F007A613C /* SwiftDemo.app */, 101 | 37419AB325E8CBA0007A613C /* SwiftDemoTests.xctest */, 102 | 37419ABE25E8CBA0007A613C /* SwiftDemoUITests.xctest */, 103 | ); 104 | name = Products; 105 | sourceTree = ""; 106 | }; 107 | 37419A9F25E8CB9F007A613C /* SwiftDemo */ = { 108 | isa = PBXGroup; 109 | children = ( 110 | 37419AA025E8CB9F007A613C /* AppDelegate.swift */, 111 | 37419AA225E8CB9F007A613C /* SceneDelegate.swift */, 112 | 37419AA425E8CB9F007A613C /* ViewController.swift */, 113 | 37419AD425E8CBBF007A613C /* WBOCTest.h */, 114 | 37419AD525E8CBBF007A613C /* WBOCTest.m */, 115 | 37BE2D1425ED035B00B68782 /* SwiftMethodTableModel.h */, 116 | 37BE2D1525ED035B00B68782 /* SwiftMethodTableModel.m */, 117 | 37419AF525E8F69F007A613C /* SwiftDefines.h */, 118 | 37419AA625E8CB9F007A613C /* Main.storyboard */, 119 | 37419AA925E8CBA0007A613C /* Assets.xcassets */, 120 | 37419AAB25E8CBA0007A613C /* LaunchScreen.storyboard */, 121 | 37419AAE25E8CBA0007A613C /* Info.plist */, 122 | 37419AD325E8CBBE007A613C /* SwiftDemo-Bridging-Header.h */, 123 | ); 124 | path = SwiftDemo; 125 | sourceTree = ""; 126 | }; 127 | 37419AB625E8CBA0007A613C /* SwiftDemoTests */ = { 128 | isa = PBXGroup; 129 | children = ( 130 | 37419AB725E8CBA0007A613C /* SwiftDemoTests.swift */, 131 | 37419AB925E8CBA0007A613C /* Info.plist */, 132 | ); 133 | path = SwiftDemoTests; 134 | sourceTree = ""; 135 | }; 136 | 37419AC125E8CBA0007A613C /* SwiftDemoUITests */ = { 137 | isa = PBXGroup; 138 | children = ( 139 | 37419AC225E8CBA0007A613C /* SwiftDemoUITests.swift */, 140 | 37419AC425E8CBA0007A613C /* Info.plist */, 141 | ); 142 | path = SwiftDemoUITests; 143 | sourceTree = ""; 144 | }; 145 | /* End PBXGroup section */ 146 | 147 | /* Begin PBXNativeTarget section */ 148 | 37419A9C25E8CB9F007A613C /* SwiftDemo */ = { 149 | isa = PBXNativeTarget; 150 | buildConfigurationList = 37419AC725E8CBA0007A613C /* Build configuration list for PBXNativeTarget "SwiftDemo" */; 151 | buildPhases = ( 152 | 37419A9925E8CB9F007A613C /* Sources */, 153 | 37419A9A25E8CB9F007A613C /* Frameworks */, 154 | 37419A9B25E8CB9F007A613C /* Resources */, 155 | ); 156 | buildRules = ( 157 | ); 158 | dependencies = ( 159 | ); 160 | name = SwiftDemo; 161 | productName = SwiftDemo; 162 | productReference = 37419A9D25E8CB9F007A613C /* SwiftDemo.app */; 163 | productType = "com.apple.product-type.application"; 164 | }; 165 | 37419AB225E8CBA0007A613C /* SwiftDemoTests */ = { 166 | isa = PBXNativeTarget; 167 | buildConfigurationList = 37419ACA25E8CBA0007A613C /* Build configuration list for PBXNativeTarget "SwiftDemoTests" */; 168 | buildPhases = ( 169 | 37419AAF25E8CBA0007A613C /* Sources */, 170 | 37419AB025E8CBA0007A613C /* Frameworks */, 171 | 37419AB125E8CBA0007A613C /* Resources */, 172 | ); 173 | buildRules = ( 174 | ); 175 | dependencies = ( 176 | 37419AB525E8CBA0007A613C /* PBXTargetDependency */, 177 | ); 178 | name = SwiftDemoTests; 179 | productName = SwiftDemoTests; 180 | productReference = 37419AB325E8CBA0007A613C /* SwiftDemoTests.xctest */; 181 | productType = "com.apple.product-type.bundle.unit-test"; 182 | }; 183 | 37419ABD25E8CBA0007A613C /* SwiftDemoUITests */ = { 184 | isa = PBXNativeTarget; 185 | buildConfigurationList = 37419ACD25E8CBA0007A613C /* Build configuration list for PBXNativeTarget "SwiftDemoUITests" */; 186 | buildPhases = ( 187 | 37419ABA25E8CBA0007A613C /* Sources */, 188 | 37419ABB25E8CBA0007A613C /* Frameworks */, 189 | 37419ABC25E8CBA0007A613C /* Resources */, 190 | ); 191 | buildRules = ( 192 | ); 193 | dependencies = ( 194 | 37419AC025E8CBA0007A613C /* PBXTargetDependency */, 195 | ); 196 | name = SwiftDemoUITests; 197 | productName = SwiftDemoUITests; 198 | productReference = 37419ABE25E8CBA0007A613C /* SwiftDemoUITests.xctest */; 199 | productType = "com.apple.product-type.bundle.ui-testing"; 200 | }; 201 | /* End PBXNativeTarget section */ 202 | 203 | /* Begin PBXProject section */ 204 | 37419A9525E8CB9F007A613C /* Project object */ = { 205 | isa = PBXProject; 206 | attributes = { 207 | LastSwiftUpdateCheck = 1220; 208 | LastUpgradeCheck = 1220; 209 | TargetAttributes = { 210 | 37419A9C25E8CB9F007A613C = { 211 | CreatedOnToolsVersion = 12.2; 212 | LastSwiftMigration = 1220; 213 | }; 214 | 37419AB225E8CBA0007A613C = { 215 | CreatedOnToolsVersion = 12.2; 216 | TestTargetID = 37419A9C25E8CB9F007A613C; 217 | }; 218 | 37419ABD25E8CBA0007A613C = { 219 | CreatedOnToolsVersion = 12.2; 220 | TestTargetID = 37419A9C25E8CB9F007A613C; 221 | }; 222 | }; 223 | }; 224 | buildConfigurationList = 37419A9825E8CB9F007A613C /* Build configuration list for PBXProject "SwiftDemo" */; 225 | compatibilityVersion = "Xcode 9.3"; 226 | developmentRegion = en; 227 | hasScannedForEncodings = 0; 228 | knownRegions = ( 229 | en, 230 | Base, 231 | ); 232 | mainGroup = 37419A9425E8CB9F007A613C; 233 | productRefGroup = 37419A9E25E8CB9F007A613C /* Products */; 234 | projectDirPath = ""; 235 | projectRoot = ""; 236 | targets = ( 237 | 37419A9C25E8CB9F007A613C /* SwiftDemo */, 238 | 37419AB225E8CBA0007A613C /* SwiftDemoTests */, 239 | 37419ABD25E8CBA0007A613C /* SwiftDemoUITests */, 240 | ); 241 | }; 242 | /* End PBXProject section */ 243 | 244 | /* Begin PBXResourcesBuildPhase section */ 245 | 37419A9B25E8CB9F007A613C /* Resources */ = { 246 | isa = PBXResourcesBuildPhase; 247 | buildActionMask = 2147483647; 248 | files = ( 249 | 37419AAD25E8CBA0007A613C /* LaunchScreen.storyboard in Resources */, 250 | 37419AAA25E8CBA0007A613C /* Assets.xcassets in Resources */, 251 | 37419AA825E8CB9F007A613C /* Main.storyboard in Resources */, 252 | ); 253 | runOnlyForDeploymentPostprocessing = 0; 254 | }; 255 | 37419AB125E8CBA0007A613C /* Resources */ = { 256 | isa = PBXResourcesBuildPhase; 257 | buildActionMask = 2147483647; 258 | files = ( 259 | ); 260 | runOnlyForDeploymentPostprocessing = 0; 261 | }; 262 | 37419ABC25E8CBA0007A613C /* Resources */ = { 263 | isa = PBXResourcesBuildPhase; 264 | buildActionMask = 2147483647; 265 | files = ( 266 | ); 267 | runOnlyForDeploymentPostprocessing = 0; 268 | }; 269 | /* End PBXResourcesBuildPhase section */ 270 | 271 | /* Begin PBXSourcesBuildPhase section */ 272 | 37419A9925E8CB9F007A613C /* Sources */ = { 273 | isa = PBXSourcesBuildPhase; 274 | buildActionMask = 2147483647; 275 | files = ( 276 | 37419AD625E8CBBF007A613C /* WBOCTest.m in Sources */, 277 | 37419AA525E8CB9F007A613C /* ViewController.swift in Sources */, 278 | 37BE2D1625ED035B00B68782 /* SwiftMethodTableModel.m in Sources */, 279 | 37419AA125E8CB9F007A613C /* AppDelegate.swift in Sources */, 280 | 37419AA325E8CB9F007A613C /* SceneDelegate.swift in Sources */, 281 | ); 282 | runOnlyForDeploymentPostprocessing = 0; 283 | }; 284 | 37419AAF25E8CBA0007A613C /* Sources */ = { 285 | isa = PBXSourcesBuildPhase; 286 | buildActionMask = 2147483647; 287 | files = ( 288 | 37419AB825E8CBA0007A613C /* SwiftDemoTests.swift in Sources */, 289 | ); 290 | runOnlyForDeploymentPostprocessing = 0; 291 | }; 292 | 37419ABA25E8CBA0007A613C /* Sources */ = { 293 | isa = PBXSourcesBuildPhase; 294 | buildActionMask = 2147483647; 295 | files = ( 296 | 37419AC325E8CBA0007A613C /* SwiftDemoUITests.swift in Sources */, 297 | ); 298 | runOnlyForDeploymentPostprocessing = 0; 299 | }; 300 | /* End PBXSourcesBuildPhase section */ 301 | 302 | /* Begin PBXTargetDependency section */ 303 | 37419AB525E8CBA0007A613C /* PBXTargetDependency */ = { 304 | isa = PBXTargetDependency; 305 | target = 37419A9C25E8CB9F007A613C /* SwiftDemo */; 306 | targetProxy = 37419AB425E8CBA0007A613C /* PBXContainerItemProxy */; 307 | }; 308 | 37419AC025E8CBA0007A613C /* PBXTargetDependency */ = { 309 | isa = PBXTargetDependency; 310 | target = 37419A9C25E8CB9F007A613C /* SwiftDemo */; 311 | targetProxy = 37419ABF25E8CBA0007A613C /* PBXContainerItemProxy */; 312 | }; 313 | /* End PBXTargetDependency section */ 314 | 315 | /* Begin PBXVariantGroup section */ 316 | 37419AA625E8CB9F007A613C /* Main.storyboard */ = { 317 | isa = PBXVariantGroup; 318 | children = ( 319 | 37419AA725E8CB9F007A613C /* Base */, 320 | ); 321 | name = Main.storyboard; 322 | sourceTree = ""; 323 | }; 324 | 37419AAB25E8CBA0007A613C /* LaunchScreen.storyboard */ = { 325 | isa = PBXVariantGroup; 326 | children = ( 327 | 37419AAC25E8CBA0007A613C /* Base */, 328 | ); 329 | name = LaunchScreen.storyboard; 330 | sourceTree = ""; 331 | }; 332 | /* End PBXVariantGroup section */ 333 | 334 | /* Begin XCBuildConfiguration section */ 335 | 37419AC525E8CBA0007A613C /* Debug */ = { 336 | isa = XCBuildConfiguration; 337 | buildSettings = { 338 | ALWAYS_SEARCH_USER_PATHS = NO; 339 | CLANG_ANALYZER_NONNULL = YES; 340 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 341 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 342 | CLANG_CXX_LIBRARY = "libc++"; 343 | CLANG_ENABLE_MODULES = YES; 344 | CLANG_ENABLE_OBJC_ARC = YES; 345 | CLANG_ENABLE_OBJC_WEAK = YES; 346 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 347 | CLANG_WARN_BOOL_CONVERSION = YES; 348 | CLANG_WARN_COMMA = YES; 349 | CLANG_WARN_CONSTANT_CONVERSION = YES; 350 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 351 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 352 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 353 | CLANG_WARN_EMPTY_BODY = YES; 354 | CLANG_WARN_ENUM_CONVERSION = YES; 355 | CLANG_WARN_INFINITE_RECURSION = YES; 356 | CLANG_WARN_INT_CONVERSION = YES; 357 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 358 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 359 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 360 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 361 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 362 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 363 | CLANG_WARN_STRICT_PROTOTYPES = YES; 364 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 365 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 366 | CLANG_WARN_UNREACHABLE_CODE = YES; 367 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 368 | COPY_PHASE_STRIP = NO; 369 | DEBUG_INFORMATION_FORMAT = dwarf; 370 | ENABLE_STRICT_OBJC_MSGSEND = YES; 371 | ENABLE_TESTABILITY = YES; 372 | GCC_C_LANGUAGE_STANDARD = gnu11; 373 | GCC_DYNAMIC_NO_PIC = NO; 374 | GCC_NO_COMMON_BLOCKS = YES; 375 | GCC_OPTIMIZATION_LEVEL = s; 376 | GCC_PREPROCESSOR_DEFINITIONS = ( 377 | "DEBUG=1", 378 | "$(inherited)", 379 | ); 380 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 381 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 382 | GCC_WARN_UNDECLARED_SELECTOR = YES; 383 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 384 | GCC_WARN_UNUSED_FUNCTION = YES; 385 | GCC_WARN_UNUSED_VARIABLE = YES; 386 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 387 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 388 | MTL_FAST_MATH = YES; 389 | ONLY_ACTIVE_ARCH = YES; 390 | SDKROOT = iphoneos; 391 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 392 | SWIFT_COMPILATION_MODE = wholemodule; 393 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 394 | }; 395 | name = Debug; 396 | }; 397 | 37419AC625E8CBA0007A613C /* Release */ = { 398 | isa = XCBuildConfiguration; 399 | buildSettings = { 400 | ALWAYS_SEARCH_USER_PATHS = NO; 401 | CLANG_ANALYZER_NONNULL = YES; 402 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 403 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 404 | CLANG_CXX_LIBRARY = "libc++"; 405 | CLANG_ENABLE_MODULES = YES; 406 | CLANG_ENABLE_OBJC_ARC = YES; 407 | CLANG_ENABLE_OBJC_WEAK = YES; 408 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 409 | CLANG_WARN_BOOL_CONVERSION = YES; 410 | CLANG_WARN_COMMA = YES; 411 | CLANG_WARN_CONSTANT_CONVERSION = YES; 412 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 413 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 414 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 415 | CLANG_WARN_EMPTY_BODY = YES; 416 | CLANG_WARN_ENUM_CONVERSION = YES; 417 | CLANG_WARN_INFINITE_RECURSION = YES; 418 | CLANG_WARN_INT_CONVERSION = YES; 419 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 420 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 421 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 422 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 423 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 424 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 425 | CLANG_WARN_STRICT_PROTOTYPES = YES; 426 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 427 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 428 | CLANG_WARN_UNREACHABLE_CODE = YES; 429 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 430 | COPY_PHASE_STRIP = NO; 431 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 432 | ENABLE_NS_ASSERTIONS = NO; 433 | ENABLE_STRICT_OBJC_MSGSEND = YES; 434 | GCC_C_LANGUAGE_STANDARD = gnu11; 435 | GCC_NO_COMMON_BLOCKS = YES; 436 | GCC_OPTIMIZATION_LEVEL = s; 437 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 438 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 439 | GCC_WARN_UNDECLARED_SELECTOR = YES; 440 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 441 | GCC_WARN_UNUSED_FUNCTION = YES; 442 | GCC_WARN_UNUSED_VARIABLE = YES; 443 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 444 | MTL_ENABLE_DEBUG_INFO = NO; 445 | MTL_FAST_MATH = YES; 446 | SDKROOT = iphoneos; 447 | SWIFT_COMPILATION_MODE = wholemodule; 448 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 449 | VALIDATE_PRODUCT = YES; 450 | }; 451 | name = Release; 452 | }; 453 | 37419AC825E8CBA0007A613C /* Debug */ = { 454 | isa = XCBuildConfiguration; 455 | buildSettings = { 456 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 457 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 458 | CLANG_ENABLE_MODULES = YES; 459 | CODE_SIGN_STYLE = Automatic; 460 | DEVELOPMENT_TEAM = EJA352Y795; 461 | GCC_OPTIMIZATION_LEVEL = 0; 462 | INFOPLIST_FILE = SwiftDemo/Info.plist; 463 | LD_RUNPATH_SEARCH_PATHS = ( 464 | "$(inherited)", 465 | "@executable_path/Frameworks", 466 | ); 467 | LLVM_LTO = YES; 468 | PRODUCT_BUNDLE_IDENTIFIER = "-8.SwiftDemo"; 469 | PRODUCT_NAME = "$(TARGET_NAME)"; 470 | SWIFT_COMPILATION_MODE = wholemodule; 471 | SWIFT_OBJC_BRIDGING_HEADER = "SwiftDemo/SwiftDemo-Bridging-Header.h"; 472 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 473 | SWIFT_VERSION = 5.0; 474 | TARGETED_DEVICE_FAMILY = "1,2"; 475 | }; 476 | name = Debug; 477 | }; 478 | 37419AC925E8CBA0007A613C /* Release */ = { 479 | isa = XCBuildConfiguration; 480 | buildSettings = { 481 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 482 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 483 | CLANG_ENABLE_MODULES = YES; 484 | CODE_SIGN_STYLE = Automatic; 485 | DEVELOPMENT_TEAM = EJA352Y795; 486 | GCC_OPTIMIZATION_LEVEL = 0; 487 | INFOPLIST_FILE = SwiftDemo/Info.plist; 488 | LD_RUNPATH_SEARCH_PATHS = ( 489 | "$(inherited)", 490 | "@executable_path/Frameworks", 491 | ); 492 | LLVM_LTO = YES; 493 | PRODUCT_BUNDLE_IDENTIFIER = "-8.SwiftDemo"; 494 | PRODUCT_NAME = "$(TARGET_NAME)"; 495 | SWIFT_OBJC_BRIDGING_HEADER = "SwiftDemo/SwiftDemo-Bridging-Header.h"; 496 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 497 | SWIFT_VERSION = 5.0; 498 | TARGETED_DEVICE_FAMILY = "1,2"; 499 | }; 500 | name = Release; 501 | }; 502 | 37419ACB25E8CBA0007A613C /* Debug */ = { 503 | isa = XCBuildConfiguration; 504 | buildSettings = { 505 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 506 | BUNDLE_LOADER = "$(TEST_HOST)"; 507 | CODE_SIGN_STYLE = Automatic; 508 | DEVELOPMENT_TEAM = EJA352Y795; 509 | INFOPLIST_FILE = SwiftDemoTests/Info.plist; 510 | IPHONEOS_DEPLOYMENT_TARGET = 14.2; 511 | LD_RUNPATH_SEARCH_PATHS = ( 512 | "$(inherited)", 513 | "@executable_path/Frameworks", 514 | "@loader_path/Frameworks", 515 | ); 516 | PRODUCT_BUNDLE_IDENTIFIER = "-8.SwiftDemoTests"; 517 | PRODUCT_NAME = "$(TARGET_NAME)"; 518 | SWIFT_VERSION = 5.0; 519 | TARGETED_DEVICE_FAMILY = "1,2"; 520 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftDemo.app/SwiftDemo"; 521 | }; 522 | name = Debug; 523 | }; 524 | 37419ACC25E8CBA0007A613C /* Release */ = { 525 | isa = XCBuildConfiguration; 526 | buildSettings = { 527 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 528 | BUNDLE_LOADER = "$(TEST_HOST)"; 529 | CODE_SIGN_STYLE = Automatic; 530 | DEVELOPMENT_TEAM = EJA352Y795; 531 | INFOPLIST_FILE = SwiftDemoTests/Info.plist; 532 | IPHONEOS_DEPLOYMENT_TARGET = 14.2; 533 | LD_RUNPATH_SEARCH_PATHS = ( 534 | "$(inherited)", 535 | "@executable_path/Frameworks", 536 | "@loader_path/Frameworks", 537 | ); 538 | PRODUCT_BUNDLE_IDENTIFIER = "-8.SwiftDemoTests"; 539 | PRODUCT_NAME = "$(TARGET_NAME)"; 540 | SWIFT_VERSION = 5.0; 541 | TARGETED_DEVICE_FAMILY = "1,2"; 542 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftDemo.app/SwiftDemo"; 543 | }; 544 | name = Release; 545 | }; 546 | 37419ACE25E8CBA0007A613C /* Debug */ = { 547 | isa = XCBuildConfiguration; 548 | buildSettings = { 549 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 550 | CODE_SIGN_STYLE = Automatic; 551 | DEVELOPMENT_TEAM = EJA352Y795; 552 | INFOPLIST_FILE = SwiftDemoUITests/Info.plist; 553 | LD_RUNPATH_SEARCH_PATHS = ( 554 | "$(inherited)", 555 | "@executable_path/Frameworks", 556 | "@loader_path/Frameworks", 557 | ); 558 | PRODUCT_BUNDLE_IDENTIFIER = "-8.SwiftDemoUITests"; 559 | PRODUCT_NAME = "$(TARGET_NAME)"; 560 | SWIFT_VERSION = 5.0; 561 | TARGETED_DEVICE_FAMILY = "1,2"; 562 | TEST_TARGET_NAME = SwiftDemo; 563 | }; 564 | name = Debug; 565 | }; 566 | 37419ACF25E8CBA0007A613C /* Release */ = { 567 | isa = XCBuildConfiguration; 568 | buildSettings = { 569 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 570 | CODE_SIGN_STYLE = Automatic; 571 | DEVELOPMENT_TEAM = EJA352Y795; 572 | INFOPLIST_FILE = SwiftDemoUITests/Info.plist; 573 | LD_RUNPATH_SEARCH_PATHS = ( 574 | "$(inherited)", 575 | "@executable_path/Frameworks", 576 | "@loader_path/Frameworks", 577 | ); 578 | PRODUCT_BUNDLE_IDENTIFIER = "-8.SwiftDemoUITests"; 579 | PRODUCT_NAME = "$(TARGET_NAME)"; 580 | SWIFT_VERSION = 5.0; 581 | TARGETED_DEVICE_FAMILY = "1,2"; 582 | TEST_TARGET_NAME = SwiftDemo; 583 | }; 584 | name = Release; 585 | }; 586 | /* End XCBuildConfiguration section */ 587 | 588 | /* Begin XCConfigurationList section */ 589 | 37419A9825E8CB9F007A613C /* Build configuration list for PBXProject "SwiftDemo" */ = { 590 | isa = XCConfigurationList; 591 | buildConfigurations = ( 592 | 37419AC525E8CBA0007A613C /* Debug */, 593 | 37419AC625E8CBA0007A613C /* Release */, 594 | ); 595 | defaultConfigurationIsVisible = 0; 596 | defaultConfigurationName = Release; 597 | }; 598 | 37419AC725E8CBA0007A613C /* Build configuration list for PBXNativeTarget "SwiftDemo" */ = { 599 | isa = XCConfigurationList; 600 | buildConfigurations = ( 601 | 37419AC825E8CBA0007A613C /* Debug */, 602 | 37419AC925E8CBA0007A613C /* Release */, 603 | ); 604 | defaultConfigurationIsVisible = 0; 605 | defaultConfigurationName = Release; 606 | }; 607 | 37419ACA25E8CBA0007A613C /* Build configuration list for PBXNativeTarget "SwiftDemoTests" */ = { 608 | isa = XCConfigurationList; 609 | buildConfigurations = ( 610 | 37419ACB25E8CBA0007A613C /* Debug */, 611 | 37419ACC25E8CBA0007A613C /* Release */, 612 | ); 613 | defaultConfigurationIsVisible = 0; 614 | defaultConfigurationName = Release; 615 | }; 616 | 37419ACD25E8CBA0007A613C /* Build configuration list for PBXNativeTarget "SwiftDemoUITests" */ = { 617 | isa = XCConfigurationList; 618 | buildConfigurations = ( 619 | 37419ACE25E8CBA0007A613C /* Debug */, 620 | 37419ACF25E8CBA0007A613C /* Release */, 621 | ); 622 | defaultConfigurationIsVisible = 0; 623 | defaultConfigurationName = Release; 624 | }; 625 | /* End XCConfigurationList section */ 626 | }; 627 | rootObject = 37419A9525E8CB9F007A613C /* Project object */; 628 | } 629 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo.xcodeproj/xcshareddata/xcschemes/SwiftDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 63 | 65 | 71 | 72 | 73 | 74 | 80 | 82 | 88 | 89 | 90 | 91 | 93 | 94 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // SwiftDemo 4 | // 5 | // Created by 邓竹立 on 2021/2/26. 6 | // 7 | 8 | import UIKit 9 | 10 | @main 11 | class AppDelegate: UIResponder, UIApplicationDelegate { 12 | 13 | 14 | 15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 16 | // Override point for customization after application launch. 17 | return true 18 | } 19 | 20 | // MARK: UISceneSession Lifecycle 21 | 22 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 23 | // Called when a new scene session is being created. 24 | // Use this method to select a configuration to create the new scene with. 25 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 26 | } 27 | 28 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 29 | // Called when the user discards a scene session. 30 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 31 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 32 | } 33 | 34 | 35 | } 36 | 37 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/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 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/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 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIApplicationSceneManifest 24 | 25 | UIApplicationSupportsMultipleScenes 26 | 27 | UISceneConfigurations 28 | 29 | UIWindowSceneSessionRoleApplication 30 | 31 | 32 | UISceneConfigurationName 33 | Default Configuration 34 | UISceneDelegateClassName 35 | $(PRODUCT_MODULE_NAME).SceneDelegate 36 | UISceneStoryboardFile 37 | Main 38 | 39 | 40 | 41 | 42 | UIApplicationSupportsIndirectInputEvents 43 | 44 | UILaunchStoryboardName 45 | LaunchScreen 46 | UIMainStoryboardFile 47 | Main 48 | UIRequiredDeviceCapabilities 49 | 50 | armv7 51 | 52 | UISupportedInterfaceOrientations 53 | 54 | UIInterfaceOrientationPortrait 55 | UIInterfaceOrientationLandscapeLeft 56 | UIInterfaceOrientationLandscapeRight 57 | 58 | UISupportedInterfaceOrientations~ipad 59 | 60 | UIInterfaceOrientationPortrait 61 | UIInterfaceOrientationPortraitUpsideDown 62 | UIInterfaceOrientationLandscapeLeft 63 | UIInterfaceOrientationLandscapeRight 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // SwiftDemo 4 | // 5 | // Created by 邓竹立 on 2021/2/26. 6 | // 7 | 8 | import UIKit 9 | 10 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 11 | 12 | var window: UIWindow? 13 | 14 | 15 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 16 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 17 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 18 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 19 | guard let _ = (scene as? UIWindowScene) else { return } 20 | } 21 | 22 | func sceneDidDisconnect(_ scene: UIScene) { 23 | // Called as the scene is being released by the system. 24 | // This occurs shortly after the scene enters the background, or when its session is discarded. 25 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 26 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). 27 | } 28 | 29 | func sceneDidBecomeActive(_ scene: UIScene) { 30 | // Called when the scene has moved from an inactive state to an active state. 31 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 32 | } 33 | 34 | func sceneWillResignActive(_ scene: UIScene) { 35 | // Called when the scene will move from an active state to an inactive state. 36 | // This may occur due to temporary interruptions (ex. an incoming phone call). 37 | } 38 | 39 | func sceneWillEnterForeground(_ scene: UIScene) { 40 | // Called as the scene transitions from the background to the foreground. 41 | // Use this method to undo the changes made on entering the background. 42 | } 43 | 44 | func sceneDidEnterBackground(_ scene: UIScene) { 45 | // Called as the scene transitions from the foreground to the background. 46 | // Use this method to save data, release shared resources, and store enough scene-specific state information 47 | // to restore the scene back to its current state. 48 | } 49 | 50 | 51 | } 52 | 53 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/SwiftDefines.h: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftDefines.h 3 | // SwiftDemo 4 | // 5 | // Created by 邓竹立 on 2021/2/26. 6 | // 7 | 8 | #ifndef SwiftDefines_h 9 | #define SwiftDefines_h 10 | 11 | // https://github.com/apple/swift/blob/e6af50198d49b006bf07c8c014242df7e29d39c9/include/swift/ABI/MetadataValues.h 12 | typedef NS_ENUM(NSInteger, SwiftKind) { 13 | SwiftKindUnknown = -1, // UnKnown 14 | SwiftKindModule = 0, // Module 15 | SwiftKindProtocol = 3, // Protocol 16 | SwiftKindClass = 16, // Class 17 | SwiftKindStruct = 17, // Struct 18 | SwiftKindEnum = 18 // Enum 19 | }; 20 | 21 | struct SwiftType { 22 | uint32_t Flag; 23 | uint32_t Parent; 24 | }; 25 | 26 | struct SwiftMethod { 27 | uint32_t Flag; 28 | uint32_t Offset; 29 | }; 30 | 31 | struct SwiftOverrideMethod { 32 | uint32_t OverrideClass; 33 | uint32_t OverrideMethod; 34 | uint32_t Method; 35 | }; 36 | 37 | struct SwiftBaseType { 38 | uint32_t Flag; 39 | uint32_t Parent; 40 | int32_t Name; 41 | int32_t AccessFunction; 42 | int32_t FieldDescriptor; 43 | }; 44 | 45 | struct SwiftClassTypeNoMethods { 46 | uint32_t Flag; 47 | uint32_t Parent; 48 | int32_t Name; 49 | int32_t AccessFunction; 50 | int32_t FieldDescriptor; 51 | int32_t SuperclassType; 52 | uint32_t MetadataNegativeSizeInWords; 53 | uint32_t MetadataPositiveSizeInWords; 54 | uint32_t NumImmediateMembers; 55 | uint32_t NumFields; 56 | uint32_t FieldOffsetVectorOffset; 57 | }; 58 | 59 | struct SwiftClass { 60 | NSInteger kind; 61 | id superclass; 62 | NSInteger reserveword1; 63 | NSInteger reserveword2; 64 | NSUInteger rodataPointer; 65 | UInt32 classFlags; 66 | UInt32 instanceAddressPoint; 67 | UInt32 instanceSize; 68 | UInt16 instanceAlignmentMask; 69 | UInt16 runtimeReservedField; 70 | UInt32 classObjectSize; 71 | UInt32 classObjectAddressPoint; 72 | NSInteger nominalTypeDescriptor; 73 | NSInteger ivarDestroyer; 74 | //---------------------------------- 75 | //witnessTable[0]A 76 | //witnessTable[1]B 77 | //witnessTable[2]C 78 | //witnessTable[3]D 79 | //witnessTable[4]E 80 | //witnessTable[5]F 81 | //witnessTable[6]G 82 | }; 83 | 84 | typedef NS_ENUM(NSInteger, SwiftMethodKind) { 85 | SwiftMethodKindMethod = 0, // method 86 | SwiftMethodKindInit = 1, //init 87 | SwiftMethodKindGetter = 2, // get 88 | SwiftMethodKindSetter = 3, // set 89 | SwiftMethodKindModify = 4, // modify 90 | SwiftMethodKindRead = 5, // read 91 | }; 92 | 93 | typedef NS_ENUM(NSInteger, SwiftMethodType) { 94 | SwiftMethodTypeKind = 0x0F, 95 | SwiftMethodTypeInstance = 0x10, 96 | SwiftMethodTypeDynamic = 0x20, 97 | SwiftMethodTypeExtraDiscriminatorShift = 16, 98 | SwiftMethodTypeExtraDiscriminator = 0xFFFF0000, 99 | }; 100 | 101 | 102 | #endif /* SwiftDefines_h */ 103 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/SwiftDemo-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | #import "WBOCTest.h" 5 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/SwiftMethodTableModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftMethodTableModel.h 3 | // SwiftDemo 4 | // 5 | // Created by 邓竹立 on 2021/3/1. 6 | // 7 | 8 | #import 9 | #import "SwiftDefines.h" 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | 13 | @interface SwiftOverrideMethodModel : NSObject 14 | 15 | @property (copy,atomic) NSString *overrideClassName; 16 | 17 | @property (assign,atomic) uintptr_t overrideClass; 18 | 19 | @property (assign,atomic) uintptr_t overrideMethod; 20 | 21 | @property (assign,atomic) uintptr_t method; 22 | 23 | @end 24 | 25 | 26 | @interface SwiftMethodTableModel : NSObject 27 | 28 | @property (strong,atomic)NSArray *vTable; 29 | 30 | @property (strong,atomic)NSArray *overrideTable; 31 | 32 | @end 33 | 34 | NS_ASSUME_NONNULL_END 35 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/SwiftMethodTableModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftMethodTableModel.m 3 | // SwiftDemo 4 | // 5 | // Created by 邓竹立 on 2021/3/1. 6 | // 7 | 8 | #import "SwiftMethodTableModel.h" 9 | 10 | @implementation SwiftOverrideMethodModel 11 | 12 | @end 13 | 14 | @implementation SwiftMethodTableModel 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // SwiftDemo 4 | // 5 | // Created by 邓竹立 on 2021/2/26. 6 | // 7 | import UIKit 8 | class ViewController: UIViewController { 9 | 10 | override func viewDidLoad() { 11 | super.viewDidLoad() 12 | let myTest = MyTestClass.init() 13 | myTest.helloWorld() 14 | //hook 15 | print("\n------ replace MyTestClass.helloWorld() with HookTestClass.helloWorld() -------\n") 16 | WBOCTest.replace(HookTestClass.self); 17 | //hook 生效 18 | myTest.helloWorld() 19 | } 20 | } 21 | 22 | class MyTestClass { 23 | func helloWorld() { 24 | print("call helloWorld() in MyTestClass") 25 | } 26 | } 27 | 28 | class SubTestClass: MyTestClass { 29 | override func helloWorld() { 30 | print("call helloWorld() in SubTestClass") 31 | } 32 | } 33 | class HookTestClass: MyTestClass { 34 | override func helloWorld() { 35 | print("\n********** call helloWorld() in HookTestClass **********") 36 | super.helloWorld() 37 | print("********** call helloWorld() in HookTestClass end **********\n") 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/WBOCTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // WBOCTest.h 3 | // SwiftDemo 4 | // 5 | // Created by 邓竹立 on 2021/2/26. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface WBOCTest : NSObject 13 | 14 | + (void)replace:(id)obj0 methodIndex0:(int)mInx0 withClass:(id)obj1 methodIndex1:(int)mInx1; 15 | 16 | + (void)replace:(id)class; 17 | 18 | @end 19 | 20 | NS_ASSUME_NONNULL_END 21 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/WBOCTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // WBOCTest.m 3 | // SwiftDemo 4 | // 5 | // Created by 邓竹立 on 2021/2/26. 6 | // 7 | 8 | #import "WBOCTest.h" 9 | #import 10 | #import 11 | #import "SwiftDefines.h" 12 | #import "SwiftMethodTableModel.h" 13 | 14 | @implementation WBOCTest 15 | 16 | + (void)load{ 17 | NSLog(@"_mh_execute_header = %lu",((uintptr_t)&_mh_execute_header)); 18 | } 19 | 20 | + (void)replace:(id)obj0 methodIndex0:(int)mInx0 withClass:(id)obj1 methodIndex1:(int)mInx1{ 21 | 22 | NSString *className0 = NSStringFromClass([obj0 class]); 23 | NSString *className1 = NSStringFromClass([obj1 class]); 24 | 25 | NSArray *methods0 = [self findMethodTable:className0].vTable; 26 | NSArray *methods1 = [self findMethodTable:className1].vTable; 27 | 28 | if (methods0.count >= mInx0 && 29 | methods1.count >= mInx1) { 30 | 31 | uintptr_t imp0 = [methods0[mInx0] unsignedIntegerValue]; 32 | uintptr_t imp1 = [methods1[mInx1] unsignedIntegerValue]; 33 | 34 | struct SwiftClass* swiftClass = (__bridge struct SwiftClass * )obj0; 35 | 36 | UInt32 classObjectSize = swiftClass->classObjectSize; 37 | UInt32 classObjectAddressPoint = swiftClass->classObjectAddressPoint; 38 | 39 | int sizeOfVTable = (classObjectSize - classObjectAddressPoint) - 10 * sizeof(NSInteger); 40 | int totalVTableSize = sizeOfVTable / sizeof(NSInteger); 41 | 42 | for (int i = 0 ; i < totalVTableSize; i++) { 43 | uintptr_t tmp = (uintptr_t)swiftClass + (10 + i) * sizeof(NSInteger); 44 | uintptr_t funcAddress = (uintptr_t)*(void **)tmp; 45 | if (funcAddress == imp0) { 46 | memset((void*)tmp, 0, sizeof(NSInteger)); 47 | memcpy((void*)tmp, &imp1, sizeof(NSInteger)); 48 | break; 49 | } 50 | } 51 | return; 52 | } 53 | } 54 | 55 | + (void)doReplace:(struct SwiftClass*)swiftClass oriIMP:(uintptr_t)oriIMP replace:(uintptr_t)replaceIMP{ 56 | UInt32 classObjectSize = swiftClass->classObjectSize; 57 | UInt32 classObjectAddressPoint = swiftClass->classObjectAddressPoint; 58 | 59 | int sizeOfVTable = (classObjectSize - classObjectAddressPoint) - 10 * sizeof(NSInteger); 60 | int totalVTableSize = sizeOfVTable / sizeof(NSInteger); 61 | for (int i = 0 ; i < totalVTableSize; i++) { 62 | uintptr_t tmp = (uintptr_t)swiftClass + (10 + i) * sizeof(NSInteger); 63 | uintptr_t funcAddress = (uintptr_t)*(void **)tmp; 64 | if (funcAddress == oriIMP) { 65 | memset((void*)tmp, 0, sizeof(NSInteger)); 66 | memcpy((void*)tmp, &replaceIMP, sizeof(NSInteger)); 67 | break; 68 | } 69 | } 70 | } 71 | 72 | #warning 编译器能做哪些优化?优化对VTable是否有影响? 73 | #warning 隐约记得在调研Mach-O时,有的相对地址计算完后很小,不能-linkbase,这里没有做容错,可能会有安全隐患 74 | #warning 不同版本的Xcode 编译及不同的版本适配,是否会有问题?另外,能否适配__RODATA也没做验证 75 | + (void)replace:(id)class{ 76 | const struct segment_command_64 *linkedit = getsegbyname("__LINKEDIT"); 77 | uintptr_t linkBase = linkedit->vmaddr-linkedit->fileoff; 78 | 79 | NSString *className = NSStringFromClass([class class]); 80 | NSArray *overrideTable = [self findMethodTable:className].overrideTable; 81 | struct SwiftClass* swiftClass = (__bridge struct SwiftClass * )class; 82 | for (SwiftOverrideMethodModel *overrideMethodModel in overrideTable) { 83 | id superclass = swiftClass->superclass; 84 | if (!superclass) {continue;} 85 | 86 | uintptr_t replaceIMP = overrideMethodModel.method; 87 | struct SwiftMethod *method = (struct SwiftMethod*)(overrideMethodModel.overrideMethod); 88 | uintptr_t oriIMP = (uintptr_t)method + sizeof(UInt32) + method->Offset - linkBase; 89 | //目前仅限实例方法生效 90 | #warning 编译器会自动生成一些函数,比如我继承了一个类,重写了2个函数,但是重写表中有3个函数,显然有一个不是我们需要的,能否精确识别出来这个函数?目前是通过函数的示例方法来限定的 91 | if (([self getSwiftMethodKind:method] == SwiftMethodKindMethod || 92 | [self getSwiftMethodKind:method] == SwiftMethodKindModify)&& 93 | [self getSwiftMethodType:method] == SwiftMethodTypeInstance) { 94 | struct SwiftClass* targetClass = (__bridge struct SwiftClass*)superclass; 95 | [self doReplace:targetClass oriIMP:oriIMP replace:replaceIMP]; 96 | } 97 | } 98 | } 99 | 100 | + (SwiftMethodTableModel *)findMethodTable:(NSString *)class{ 101 | 102 | SwiftMethodTableModel *methodTableModel = [SwiftMethodTableModel new]; 103 | //获取__swift5_types 数据 104 | NSUInteger textTypesSize = 0; 105 | char *types = getsectdata("__TEXT", "__swift5_types", &textTypesSize); 106 | uintptr_t exeHeader = (uintptr_t)(&_mh_execute_header); 107 | const struct segment_command_64 *linkedit = getsegbyname("__LINKEDIT"); 108 | 109 | //计算linkBase 110 | uintptr_t linkBase = linkedit->vmaddr-linkedit->fileoff; 111 | 112 | NSUInteger location = 0; 113 | for (int i = 0; i < textTypesSize / sizeof(UInt32); i++) { 114 | 115 | uintptr_t offset = (uintptr_t)types + location - linkBase; 116 | location += sizeof(uint32_t); 117 | uintptr_t address = exeHeader + offset; 118 | UInt32 content = (UInt32)*(UInt32*)address; 119 | uintptr_t typeOffset = content + offset - linkBase; 120 | uintptr_t typeAddress = exeHeader + typeOffset; 121 | 122 | //不是类,则不处理 123 | struct SwiftType *type = (struct SwiftType *)typeAddress; 124 | if ((type->Flag & 0x1f) != SwiftKindClass ){ 125 | continue; 126 | } 127 | 128 | NSMutableArray *vTable = @[].mutableCopy; 129 | NSMutableArray *ovTable = @[].mutableCopy; 130 | 131 | struct SwiftBaseType *baseType = (struct SwiftBaseType *)typeAddress; 132 | NSString *name = [self getTypeName:typeOffset]; 133 | if (![class isEqualToString:name]) { 134 | continue; 135 | } 136 | //遍历Vtable和overrideTable 137 | BOOL hasVtable = [self hasVTable:baseType]; 138 | BOOL hasOverrideTable = [self hasOverrideTable:baseType]; 139 | BOOL hasSingletonMetadataInitialization = [self hasSingletonMetadataInitialization:baseType]; 140 | BOOL hasResilientSuperclass = [self hasResilientSuperclass:baseType]; 141 | short genericSize = [self addPlaceholderWithGeneric:typeOffset]; 142 | if (!hasVtable && !hasOverrideTable ) {continue;} 143 | 144 | #warning typeLocation的计算在hasSingletonMetadataInitialization 和 有泛型的情况下可能会存在问题,因为我修改了SwiftClassTypeNoMethods 结构体,但是后面计算没有做适配修改(先跑通流程再处理) 145 | uintptr_t typeLocation = typeOffset + sizeof(struct SwiftClassTypeNoMethods) + genericSize + (hasResilientSuperclass?4:0)+ (hasSingletonMetadataInitialization?12:0) + (hasVtable?4:0) + exeHeader; 146 | 147 | if ([self hasVTable:baseType]) { 148 | UInt32* methodNum = (UInt32*)typeLocation; 149 | uintptr_t methodLocation = sizeof(UInt32); 150 | for (int j = 0; j < *methodNum; j ++) { 151 | uintptr_t methodAddress = typeLocation + methodLocation; 152 | struct SwiftMethod *methodType = (struct SwiftMethod *)methodAddress; 153 | if (methodType->Flag == 0x10) { 154 | uintptr_t imp = ((long)methodType + sizeof(UInt32) + methodType->Offset - linkBase); 155 | [vTable addObject:@(imp)]; 156 | } 157 | methodLocation += sizeof(struct SwiftMethod); 158 | } 159 | } 160 | if ([self hasOverrideTable:baseType]) { 161 | UInt32* methodNum = (UInt32*)typeLocation; 162 | uintptr_t methodLocation = sizeof(UInt32); 163 | for (int j = 0; j < *methodNum; j ++) { 164 | uintptr_t methodAddress = typeLocation + methodLocation; 165 | struct SwiftOverrideMethod *methodType = (struct SwiftOverrideMethod *)methodAddress; 166 | SwiftOverrideMethodModel *model = [SwiftOverrideMethodModel new]; 167 | uintptr_t overrideTypeAddress = (methodAddress + methodType->OverrideClass - linkBase); 168 | model.overrideClass = overrideTypeAddress; 169 | model.overrideMethod = (methodAddress + sizeof(UInt32) + methodType->OverrideMethod - linkBase); 170 | model.method = (methodAddress + 2 * sizeof(UInt32) + methodType->Method - linkBase); 171 | model.overrideClassName = [self getTypeName:(overrideTypeAddress - exeHeader)]; 172 | [ovTable addObject:model]; 173 | methodLocation += sizeof(struct SwiftOverrideMethod); 174 | } 175 | } 176 | 177 | methodTableModel.vTable = vTable.copy; 178 | methodTableModel.overrideTable = ovTable.copy; 179 | 180 | } 181 | return methodTableModel; 182 | } 183 | 184 | + (NSString *)getTypeName:(uintptr_t)typeOffset { 185 | 186 | const struct segment_command_64 *linkedit = getsegbyname("__LINKEDIT"); 187 | //计算linkBase 188 | uintptr_t linkBase = linkedit->vmaddr-linkedit->fileoff; 189 | uintptr_t exeHeader = (uintptr_t)(&_mh_execute_header); 190 | uintptr_t typeAddress = exeHeader + typeOffset; 191 | 192 | //按SwiftType 结构去解析内存 193 | struct SwiftBaseType *baseType = (struct SwiftBaseType *)typeAddress; 194 | uintptr_t classNameOffset = typeOffset + baseType->Name + 8; 195 | char *className = (char *)(exeHeader + classNameOffset); 196 | NSString *name = [NSString stringWithFormat:@"%s",className]; 197 | uintptr_t parentOffset = typeOffset + 1 * 4 + baseType->Parent - linkBase; 198 | SwiftKind kind = SwiftKindUnknown; 199 | while (kind != SwiftKindModule) { 200 | 201 | uintptr_t parent = exeHeader + parentOffset; 202 | 203 | struct SwiftBaseType *parentType = (struct SwiftBaseType *)parent; 204 | kind = parentType->Flag; 205 | 206 | uintptr_t parentNameContent = parentType->Name; 207 | uintptr_t parentNameOffset = parentOffset + 2 * 4 + parentNameContent; 208 | 209 | char *parentName = (char *)(exeHeader + parentNameOffset); 210 | name = [NSString stringWithFormat:@"%s.%@",parentName,name]; 211 | 212 | uintptr_t parentOffsetContent = parentType->Parent - linkBase; 213 | parentOffset = parentOffset + 1 * 4 + parentOffsetContent; 214 | } 215 | 216 | return name; 217 | } 218 | 219 | #pragma mark Flag 220 | + (BOOL)hasVTable:(struct SwiftBaseType*)type{ 221 | if ((type->Flag & 0x80000000) == 0x80000000) {return YES;} 222 | return NO; 223 | } 224 | 225 | + (BOOL)hasOverrideTable:(struct SwiftBaseType*)type{ 226 | if ((type->Flag & 0x40000000) == 0x40000000) {return YES;} 227 | return NO; 228 | } 229 | 230 | + (BOOL)hasResilientSuperclass:(struct SwiftBaseType*)type{ 231 | if ((type->Flag & 0x20000000) == 0x20000000) {return YES;} 232 | return NO; 233 | } 234 | 235 | + (BOOL)isGenericType:(struct SwiftBaseType*)type{ 236 | if ( (type->Flag & 0x80 )) {return YES;} 237 | return NO; 238 | } 239 | 240 | + (BOOL)isGeneric:(struct SwiftType*)type{ 241 | if ( (type->Flag & 0x80 )) {return YES;} 242 | return NO; 243 | } 244 | 245 | + (BOOL)hasSingletonMetadataInitialization:(struct SwiftBaseType*)type{ 246 | if ( (type->Flag & 0x00010000 )) {return YES;} 247 | return NO; 248 | } 249 | 250 | + (SwiftMethodKind)getSwiftMethodKind:(struct SwiftMethod*)method{ 251 | SwiftMethodKind kind = (SwiftMethodKind)(method->Flag&SwiftMethodTypeKind); 252 | return kind; 253 | } 254 | 255 | + (SwiftMethodType)getSwiftMethodType:(struct SwiftMethod*)method{ 256 | SwiftMethodType type = SwiftMethodTypeKind; 257 | if ((method->Flag&SwiftMethodTypeInstance) == SwiftMethodTypeInstance) { 258 | type = SwiftMethodTypeInstance; 259 | }else if ((method->Flag&SwiftMethodTypeDynamic) == SwiftMethodTypeDynamic){ 260 | type = SwiftMethodTypeDynamic; 261 | }else if ((method->Flag&SwiftMethodTypeExtraDiscriminator) == SwiftMethodTypeExtraDiscriminator){ 262 | type = SwiftMethodTypeExtraDiscriminator; 263 | } 264 | return type; 265 | } 266 | 267 | + (SwiftKind)getSwiftType:(struct SwiftType*)type{ 268 | //读低五位判断类型 269 | if ((type->Flag & 0x1f) == SwiftKindClass) { 270 | return SwiftKindClass; 271 | }else if ((type->Flag & 0x3) == SwiftKindProtocol){ 272 | return SwiftKindProtocol; 273 | }else if((type->Flag & 0x1f) == SwiftKindStruct){ 274 | return SwiftKindStruct; 275 | }else if((type->Flag & 0x1f) == SwiftKindEnum){ 276 | return SwiftKindEnum; 277 | }else if((type->Flag & 0x0f) == SwiftKindModule){ 278 | return SwiftKindModule; 279 | } 280 | 281 | return SwiftKindUnknown; 282 | } 283 | 284 | + (short)addPlaceholderWithGeneric:(unsigned long long)typeOffset{ 285 | 286 | struct SwiftType* swiftType = (struct SwiftType* )((uintptr_t)(&_mh_execute_header) + typeOffset); 287 | 288 | if (![self isGeneric:swiftType]) { 289 | return 0; 290 | } 291 | //非class 不处理 292 | if ([self getSwiftType:swiftType] != SwiftKindClass) { 293 | return 0; 294 | } 295 | 296 | short paramsCount = 0; 297 | short requeireCount = 0; 298 | void *p0 = (void *)((uintptr_t)(&_mh_execute_header) + typeOffset + 13 * 4); 299 | void *p1 = (void *)((uintptr_t)(&_mh_execute_header) + typeOffset + 13 * 4 + 2); 300 | 301 | memcpy(¶msCount, p0, sizeof(short)); 302 | memcpy(¶msCount, p1, sizeof(short)); 303 | 304 | //4字节对齐 305 | short pandding = (unsigned)-paramsCount & 3; 306 | 307 | /** 308 | 309 | 16 = 4 + 4 + 2 + 2 + 2 + 2 310 | addMetadataInstantiationCache 4 311 | addMetadataInstantiationPattern 4 312 | GenericParamCount 2 313 | GenericRequirementCount 2 314 | GenericKeyArgumentCount 2 315 | GenericExtraArgumentCount 2 316 | */ 317 | return (16 + paramsCount + pandding + 3 * 4 * (requeireCount) + 4); 318 | } 319 | 320 | @end 321 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemoTests/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemoTests/SwiftDemoTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftDemoTests.swift 3 | // SwiftDemoTests 4 | // 5 | // Created by 邓竹立 on 2021/2/26. 6 | // 7 | 8 | import XCTest 9 | @testable import SwiftDemo 10 | 11 | class SwiftDemoTests: XCTestCase { 12 | 13 | override func setUpWithError() throws { 14 | // Put setup code here. This method is called before the invocation of each test method in the class. 15 | } 16 | 17 | override func tearDownWithError() throws { 18 | // Put teardown code here. This method is called after the invocation of each test method in the class. 19 | } 20 | 21 | func testExample() throws { 22 | // This is an example of a functional test case. 23 | // Use XCTAssert and related functions to verify your tests produce the correct results. 24 | } 25 | 26 | func testPerformanceExample() throws { 27 | // This is an example of a performance test case. 28 | self.measure { 29 | // Put the code you want to measure the time of here. 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemoUITests/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemoUITests/SwiftDemoUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftDemoUITests.swift 3 | // SwiftDemoUITests 4 | // 5 | // Created by 邓竹立 on 2021/2/26. 6 | // 7 | 8 | import XCTest 9 | 10 | class SwiftDemoUITests: XCTestCase { 11 | 12 | override func setUpWithError() throws { 13 | // Put setup code here. This method is called before the invocation of each test method in the class. 14 | 15 | // In UI tests it is usually best to stop immediately when a failure occurs. 16 | continueAfterFailure = false 17 | 18 | // 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. 19 | } 20 | 21 | override func tearDownWithError() throws { 22 | // Put teardown code here. This method is called after the invocation of each test method in the class. 23 | } 24 | 25 | func testExample() throws { 26 | // UI tests must launch the application that they test. 27 | let app = XCUIApplication() 28 | app.launch() 29 | 30 | // Use recording to get started writing UI tests. 31 | // Use XCTAssert and related functions to verify your tests produce the correct results. 32 | } 33 | 34 | func testLaunchPerformance() throws { 35 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) { 36 | // This measures how long it takes to launch your application. 37 | measure(metrics: [XCTApplicationLaunchMetric()]) { 38 | XCUIApplication().launch() 39 | } 40 | } 41 | } 42 | } 43 | --------------------------------------------------------------------------------