├── .gitignore ├── framework ├── Stinger │ ├── Example │ │ ├── .gitkeep │ │ ├── Pods │ │ │ ├── Headers │ │ │ │ ├── Private │ │ │ │ │ ├── Aspects │ │ │ │ │ │ └── Aspects.h │ │ │ │ │ └── Stinger │ │ │ │ │ │ ├── ffi.h │ │ │ │ │ │ ├── STDefines.h │ │ │ │ │ │ ├── Stinger.h │ │ │ │ │ │ ├── STHookInfo.h │ │ │ │ │ │ ├── ffi_arm.h │ │ │ │ │ │ ├── ffi_i386.h │ │ │ │ │ │ ├── STHookInfoPool.h │ │ │ │ │ │ ├── StingerParams.h │ │ │ │ │ │ ├── ffi_arm64.h │ │ │ │ │ │ ├── ffi_x86_64.h │ │ │ │ │ │ ├── ffitarget.h │ │ │ │ │ │ ├── ffitarget_arm.h │ │ │ │ │ │ ├── STMethodSignature.h │ │ │ │ │ │ ├── ffitarget_arm64.h │ │ │ │ │ │ ├── ffitarget_i386.h │ │ │ │ │ │ └── ffitarget_x86_64.h │ │ │ │ └── Public │ │ │ │ │ ├── Aspects │ │ │ │ │ └── Aspects.h │ │ │ │ │ └── Stinger │ │ │ │ │ ├── Stinger.h │ │ │ │ │ ├── ffi.h │ │ │ │ │ ├── STDefines.h │ │ │ │ │ ├── STHookInfo.h │ │ │ │ │ ├── ffi_arm.h │ │ │ │ │ ├── ffi_i386.h │ │ │ │ │ ├── STHookInfoPool.h │ │ │ │ │ ├── StingerParams.h │ │ │ │ │ ├── ffi_arm64.h │ │ │ │ │ ├── ffi_x86_64.h │ │ │ │ │ ├── ffitarget.h │ │ │ │ │ ├── STMethodSignature.h │ │ │ │ │ ├── ffitarget_arm.h │ │ │ │ │ ├── ffitarget_arm64.h │ │ │ │ │ ├── ffitarget_i386.h │ │ │ │ │ └── ffitarget_x86_64.h │ │ │ ├── Target Support Files │ │ │ │ ├── Aspects │ │ │ │ │ ├── Aspects-dummy.m │ │ │ │ │ ├── Aspects-prefix.pch │ │ │ │ │ └── Aspects.xcconfig │ │ │ │ ├── Stinger │ │ │ │ │ ├── Stinger-dummy.m │ │ │ │ │ ├── Stinger-prefix.pch │ │ │ │ │ └── Stinger.xcconfig │ │ │ │ ├── Pods-Stinger_Tests │ │ │ │ │ ├── Pods-Stinger_Tests-dummy.m │ │ │ │ │ ├── Pods-Stinger_Tests-acknowledgements.markdown │ │ │ │ │ ├── Pods-Stinger_Tests.debug.xcconfig │ │ │ │ │ ├── Pods-Stinger_Tests.release.xcconfig │ │ │ │ │ └── Pods-Stinger_Tests-acknowledgements.plist │ │ │ │ └── Pods-Stinger_Example │ │ │ │ │ ├── Pods-Stinger_Example-dummy.m │ │ │ │ │ ├── Pods-Stinger_Example.debug.xcconfig │ │ │ │ │ ├── Pods-Stinger_Example.release.xcconfig │ │ │ │ │ ├── Pods-Stinger_Example-acknowledgements.markdown │ │ │ │ │ └── Pods-Stinger_Example-acknowledgements.plist │ │ │ ├── Manifest.lock │ │ │ ├── Local Podspecs │ │ │ │ └── Stinger.podspec.json │ │ │ └── Aspects │ │ │ │ ├── LICENSE │ │ │ │ ├── Aspects.h │ │ │ │ └── README.md │ │ ├── Stinger │ │ │ ├── en.lproj │ │ │ │ └── InfoPlist.strings │ │ │ ├── ASViewController.h │ │ │ ├── ASAppDelegate.h │ │ │ ├── Stinger-Prefix.pch │ │ │ ├── main.m │ │ │ ├── ASViewController.m │ │ │ ├── Stinger-Info.plist │ │ │ ├── Base.lproj │ │ │ │ ├── LaunchScreen.storyboard │ │ │ │ └── Main.storyboard │ │ │ ├── Images.xcassets │ │ │ │ └── AppIcon.appiconset │ │ │ │ │ └── Contents.json │ │ │ └── ASAppDelegate.m │ │ ├── Tests │ │ │ ├── en.lproj │ │ │ │ └── InfoPlist.strings │ │ │ ├── Tests-Prefix.pch │ │ │ ├── Tests-Info.plist │ │ │ ├── CompatibilityTests.m │ │ │ ├── MethodSignatureTests.m │ │ │ └── PerformanceTests.m │ │ ├── Podfile │ │ ├── Stinger.xcodeproj │ │ │ ├── project.xcworkspace │ │ │ │ └── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── xcbaselines │ │ │ │ └── 6003F5AD195388D20070C39A.xcbaseline │ │ │ │ │ ├── 99D3E204-67A8-4086-8B11-184B7F8D624D.plist │ │ │ │ │ └── Info.plist │ │ │ │ └── xcschemes │ │ │ │ └── Stinger-Example.xcscheme │ │ ├── Stinger.xcworkspace │ │ │ └── contents.xcworkspacedata │ │ └── Podfile.lock │ ├── Stinger │ │ ├── Assets │ │ │ └── .gitkeep │ │ └── Classes │ │ │ ├── libffi │ │ │ ├── libffi.a │ │ │ ├── ffi.h │ │ │ ├── ffitarget.h │ │ │ ├── ffitarget_arm64.h │ │ │ ├── ffitarget_arm.h │ │ │ ├── ffitarget_x86_64.h │ │ │ └── ffitarget_i386.h │ │ │ ├── STHookInfo.h │ │ │ ├── StingerParams.h │ │ │ ├── STHookInfoPool.h │ │ │ ├── STMethodSignature.h │ │ │ ├── STHookInfo.m │ │ │ ├── Stinger.h │ │ │ ├── StingerParams.m │ │ │ ├── STDefines.h │ │ │ ├── STMethodSignature.m │ │ │ └── Stinger.m │ ├── _Pods.xcodeproj │ ├── .gitattributes │ ├── .travis.yml │ ├── .gitignore │ ├── LICENSE │ ├── Stinger.podspec │ └── README_中文.md ├── Aspects │ ├── AspectsDemo │ │ ├── AspectsDemo │ │ │ ├── en.lproj │ │ │ │ └── InfoPlist.strings │ │ │ ├── AspectsAppDelegate.h │ │ │ ├── AspectsDemo-Prefix.pch │ │ │ ├── main.m │ │ │ ├── AspectsViewController.h │ │ │ ├── Images.xcassets │ │ │ │ ├── AppIcon.appiconset │ │ │ │ │ └── Contents.json │ │ │ │ └── LaunchImage.launchimage │ │ │ │ │ └── Contents.json │ │ │ ├── AspectsDemo-Info.plist │ │ │ ├── AspectsViewController.m │ │ │ ├── AspectsAppDelegate.m │ │ │ └── AspectsViewController.xib │ │ ├── AspectsDemoTests │ │ │ ├── en.lproj │ │ │ │ └── InfoPlist.strings │ │ │ └── AspectsDemoTests-Info.plist │ │ └── AspectsDemo.xcodeproj │ │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ └── AspectsDemo.xccheckout │ │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── AspectsDemo.xcscheme │ ├── AspectsDemoOSX │ │ ├── AspectsDemoOSX │ │ │ ├── en.lproj │ │ │ │ ├── InfoPlist.strings │ │ │ │ └── Credits.rtf │ │ │ ├── AspectsDemoOSX-Prefix.pch │ │ │ ├── main.m │ │ │ ├── AspectsAppDelegate.h │ │ │ ├── AspectsAppDelegate.m │ │ │ ├── Images.xcassets │ │ │ │ └── AppIcon.appiconset │ │ │ │ │ └── Contents.json │ │ │ └── AspectsDemoOSX-Info.plist │ │ ├── AspectsDemoOSXTests │ │ │ ├── en.lproj │ │ │ │ └── InfoPlist.strings │ │ │ └── AspectsDemoOSXTests-Info.plist │ │ └── AspectsDemoOSX.xcodeproj │ │ │ ├── project.xcworkspace │ │ │ └── xcshareddata │ │ │ │ └── AspectsDemoOSX.xccheckout │ │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── AspectsDemoOSX.xcscheme │ ├── stacktrace@2x.png │ ├── .gitignore │ ├── .travis.yml │ ├── Aspects.podspec │ ├── Info-watch.plist │ ├── Info.plist │ ├── LICENSE │ ├── Aspects.xcodeproj │ │ ├── project.xcworkspace │ │ │ └── xcshareddata │ │ │ │ └── Aspects.xccheckout │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── Aspects-Mac.xcscheme │ │ │ ├── Aspects-iOS.xcscheme │ │ │ └── Aspects-watchOS.xcscheme │ └── Aspects.h ├── fishhook │ ├── CODE_OF_CONDUCT.md │ ├── fishhook.podspec │ ├── CONTRIBUTING.md │ ├── LICENSE │ ├── fishhook.h │ └── README.md └── objc-msg-arm64 │ └── arm64下objc_msgSend汇编实现.md ├── notes ├── images │ ├── 配图1.jpeg │ ├── 21a4462309f79052f393b58007f3d7ca7acbd584.jpeg │ ├── 4d086e061d950a7b4d78bc7a01d162d9f2d3c93b.jpeg │ └── 7a899e510fb30f2457081ebdc395d143ac4b03f9.jpeg ├── aspects │ └── images │ │ ├── aspects_0.jpg │ │ └── aspects_1.jpg └── fishhook │ └── images │ ├── fishhook_0.png │ └── fishhook_1.png └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /framework/Stinger/Example/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /framework/Stinger/Stinger/Assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /framework/Stinger/_Pods.xcodeproj: -------------------------------------------------------------------------------- 1 | Example/Pods/Pods.xcodeproj -------------------------------------------------------------------------------- /framework/Stinger/.gitattributes: -------------------------------------------------------------------------------- 1 | *.* linguist-language=Objective-C 2 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Private/Aspects/Aspects.h: -------------------------------------------------------------------------------- 1 | ../../../Aspects/Aspects.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Public/Aspects/Aspects.h: -------------------------------------------------------------------------------- 1 | ../../../Aspects/Aspects.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Private/Stinger/ffi.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/libffi/ffi.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Public/Stinger/Stinger.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/Stinger.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Public/Stinger/ffi.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/libffi/ffi.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Private/Stinger/STDefines.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/STDefines.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Private/Stinger/Stinger.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/Stinger.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Public/Stinger/STDefines.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/STDefines.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Private/Stinger/STHookInfo.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/STHookInfo.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Private/Stinger/ffi_arm.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/libffi/ffi_arm.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Private/Stinger/ffi_i386.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/libffi/ffi_i386.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Public/Stinger/STHookInfo.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/STHookInfo.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Public/Stinger/ffi_arm.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/libffi/ffi_arm.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Public/Stinger/ffi_i386.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/libffi/ffi_i386.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Stinger/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Tests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /notes/images/配图1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonYHB/iOS-Framework-Analysis/HEAD/notes/images/配图1.jpeg -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Private/Stinger/STHookInfoPool.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/STHookInfoPool.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Private/Stinger/StingerParams.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/StingerParams.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Private/Stinger/ffi_arm64.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/libffi/ffi_arm64.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Private/Stinger/ffi_x86_64.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/libffi/ffi_x86_64.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Private/Stinger/ffitarget.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/libffi/ffitarget.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Public/Stinger/STHookInfoPool.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/STHookInfoPool.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Public/Stinger/StingerParams.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/StingerParams.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Public/Stinger/ffi_arm64.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/libffi/ffi_arm64.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Public/Stinger/ffi_x86_64.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/libffi/ffi_x86_64.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Public/Stinger/ffitarget.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/libffi/ffitarget.h -------------------------------------------------------------------------------- /framework/Aspects/AspectsDemo/AspectsDemo/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Private/Stinger/ffitarget_arm.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/libffi/ffitarget_arm.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Public/Stinger/STMethodSignature.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/STMethodSignature.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Public/Stinger/ffitarget_arm.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/libffi/ffitarget_arm.h -------------------------------------------------------------------------------- /framework/Aspects/AspectsDemo/AspectsDemoTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /framework/Aspects/AspectsDemoOSX/AspectsDemoOSX/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Private/Stinger/STMethodSignature.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/STMethodSignature.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Private/Stinger/ffitarget_arm64.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/libffi/ffitarget_arm64.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Private/Stinger/ffitarget_i386.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/libffi/ffitarget_i386.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Public/Stinger/ffitarget_arm64.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/libffi/ffitarget_arm64.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Public/Stinger/ffitarget_i386.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/libffi/ffitarget_i386.h -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Public/Stinger/ffitarget_x86_64.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/libffi/ffitarget_x86_64.h -------------------------------------------------------------------------------- /framework/Aspects/AspectsDemoOSX/AspectsDemoOSXTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Headers/Private/Stinger/ffitarget_x86_64.h: -------------------------------------------------------------------------------- 1 | ../../../../../Stinger/Classes/libffi/ffitarget_x86_64.h -------------------------------------------------------------------------------- /framework/Aspects/stacktrace@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonYHB/iOS-Framework-Analysis/HEAD/framework/Aspects/stacktrace@2x.png -------------------------------------------------------------------------------- /notes/aspects/images/aspects_0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonYHB/iOS-Framework-Analysis/HEAD/notes/aspects/images/aspects_0.jpg -------------------------------------------------------------------------------- /notes/aspects/images/aspects_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonYHB/iOS-Framework-Analysis/HEAD/notes/aspects/images/aspects_1.jpg -------------------------------------------------------------------------------- /notes/fishhook/images/fishhook_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonYHB/iOS-Framework-Analysis/HEAD/notes/fishhook/images/fishhook_0.png -------------------------------------------------------------------------------- /notes/fishhook/images/fishhook_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonYHB/iOS-Framework-Analysis/HEAD/notes/fishhook/images/fishhook_1.png -------------------------------------------------------------------------------- /framework/Stinger/Stinger/Classes/libffi/libffi.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonYHB/iOS-Framework-Analysis/HEAD/framework/Stinger/Stinger/Classes/libffi/libffi.a -------------------------------------------------------------------------------- /notes/images/21a4462309f79052f393b58007f3d7ca7acbd584.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonYHB/iOS-Framework-Analysis/HEAD/notes/images/21a4462309f79052f393b58007f3d7ca7acbd584.jpeg -------------------------------------------------------------------------------- /notes/images/4d086e061d950a7b4d78bc7a01d162d9f2d3c93b.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonYHB/iOS-Framework-Analysis/HEAD/notes/images/4d086e061d950a7b4d78bc7a01d162d9f2d3c93b.jpeg -------------------------------------------------------------------------------- /notes/images/7a899e510fb30f2457081ebdc395d143ac4b03f9.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonYHB/iOS-Framework-Analysis/HEAD/notes/images/7a899e510fb30f2457081ebdc395d143ac4b03f9.jpeg -------------------------------------------------------------------------------- /framework/Stinger/Example/Podfile: -------------------------------------------------------------------------------- 1 | target 'Stinger_Example' do 2 | pod 'Stinger', :path => '../' 3 | pod 'Aspects' 4 | target 'Stinger_Tests' do 5 | inherit! :search_paths 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Target Support Files/Aspects/Aspects-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Aspects : NSObject 3 | @end 4 | @implementation PodsDummy_Aspects 5 | @end 6 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Target Support Files/Stinger/Stinger-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Stinger : NSObject 3 | @end 4 | @implementation PodsDummy_Stinger 5 | @end 6 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Tests/Tests-Prefix.pch: -------------------------------------------------------------------------------- 1 | // The contents of this file are implicitly included at the beginning of every test case source file. 2 | 3 | #ifdef __OBJC__ 4 | 5 | //@import Kiwi; 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Stinger.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Target Support Files/Pods-Stinger_Tests/Pods-Stinger_Tests-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_Stinger_Tests : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_Stinger_Tests 5 | @end 6 | -------------------------------------------------------------------------------- /framework/Aspects/AspectsDemo/AspectsDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Target Support Files/Pods-Stinger_Tests/Pods-Stinger_Tests-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | Generated by CocoaPods - https://cocoapods.org 4 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Target Support Files/Pods-Stinger_Example/Pods-Stinger_Example-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_Stinger_Example : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_Stinger_Example 5 | @end 6 | -------------------------------------------------------------------------------- /framework/fishhook/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | Facebook has adopted a Code of Conduct that we expect project participants to adhere to. Please [read the full text](https://code.fb.com/codeofconduct) so that you can understand what actions will and will not be tolerated. -------------------------------------------------------------------------------- /framework/Aspects/AspectsDemoOSX/AspectsDemoOSX/AspectsDemoOSX-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #ifdef __OBJC__ 8 | #import 9 | #endif 10 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Target Support Files/Aspects/Aspects-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Target Support Files/Stinger/Stinger-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Stinger.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /framework/Stinger/Stinger/Classes/libffi/ffi.h: -------------------------------------------------------------------------------- 1 | #ifdef __arm64__ 2 | 3 | #include "ffi_arm64.h" 4 | 5 | 6 | #endif 7 | #ifdef __i386__ 8 | 9 | #include "ffi_i386.h" 10 | 11 | 12 | #endif 13 | #ifdef __arm__ 14 | 15 | #include "ffi_arm.h" 16 | 17 | 18 | #endif 19 | #ifdef __x86_64__ 20 | 21 | #include "ffi_x86_64.h" 22 | 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /framework/Aspects/.gitignore: -------------------------------------------------------------------------------- 1 | # CocoaPods 2 | # 3 | # We recommend against adding the Pods directory to your .gitignore. However 4 | # you should judge for yourself, the pros and cons are mentioned at: 5 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control? 6 | # 7 | # Pods/ 8 | 9 | .DS_Store 10 | xcuserdata -------------------------------------------------------------------------------- /framework/Aspects/AspectsDemoOSX/AspectsDemoOSX/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // AspectsDemoOSX 4 | // 5 | // Created by Ash Furrow on 2014-05-05. 6 | // Copyright (c) 2014 PSPDFKit GmbH. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, const char * argv[]) 12 | { 13 | return NSApplicationMain(argc, argv); 14 | } 15 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Stinger/ASViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASViewController.h 3 | // Stinger 4 | // 5 | // Created by Assuner on 12/05/2017. 6 | // Copyright (c) 2017 Assuner. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | typedef double (^testBlock)(double x, double y); 12 | 13 | @interface ASViewController : UIViewController 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /framework/Stinger/Stinger/Classes/libffi/ffitarget.h: -------------------------------------------------------------------------------- 1 | #ifdef __arm64__ 2 | 3 | #include "ffitarget_arm64.h" 4 | 5 | 6 | #endif 7 | #ifdef __i386__ 8 | 9 | #include "ffitarget_i386.h" 10 | 11 | 12 | #endif 13 | #ifdef __arm__ 14 | 15 | #include "ffitarget_arm.h" 16 | 17 | 18 | #endif 19 | #ifdef __x86_64__ 20 | 21 | #include "ffitarget_x86_64.h" 22 | 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Stinger/ASAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASAppDelegate.h 3 | // Stinger 4 | // 5 | // Created by Assuner-Lee on 12/05/2017. 6 | // Copyright (c) 2017 Assuner-Lee. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | @interface ASAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /framework/Stinger/Stinger/Classes/STHookInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // STHookInfo.h 3 | // Stinger 4 | // 5 | // Created by Assuner on 2018/1/9. 6 | // Copyright © 2018年 Assuner. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface STHookInfo : NSObject 13 | { 14 | @public 15 | id _block; 16 | } 17 | @end 18 | -------------------------------------------------------------------------------- /framework/Aspects/AspectsDemo/AspectsDemo/AspectsAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AspectsAppDelegate.h 3 | // AspectsDemo 4 | // 5 | // Created by Peter Steinberger on 03/05/14. 6 | // Copyright (c) 2014 PSPDFKit GmbH. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | @interface AspectsAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /framework/Aspects/AspectsDemoOSX/AspectsDemoOSX/AspectsAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AspectsAppDelegate.h 3 | // AspectsDemoOSX 4 | // 5 | // Created by Ash Furrow on 2014-05-05. 6 | // Copyright (c) 2014 PSPDFKit GmbH. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AspectsAppDelegate : NSObject 12 | 13 | @property (assign) IBOutlet NSWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Stinger/Stinger-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | @import UIKit; 15 | @import Foundation; 16 | #endif 17 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Stinger/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Stinger 4 | // 5 | // Created by Assuner-Lee on 12/05/2017. 6 | // Copyright (c) 2017 Assuner-Lee. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | #import "ASAppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) 13 | { 14 | @autoreleasepool { 15 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([ASAppDelegate class])); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /framework/Aspects/.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | script: 3 | - xcodebuild -project AspectsDemo/AspectsDemo.xcodeproj -scheme AspectsDemo -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO test 4 | - xcodebuild -project AspectsDemo/AspectsDemo.xcodeproj -scheme AspectsDemo -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPad Retina (64-bit),OS=8.1' test 5 | - xcodebuild -project AspectsDemoOSX/AspectsDemoOSX.xcodeproj -scheme AspectsDemoOSX test 6 | -------------------------------------------------------------------------------- /framework/Stinger/Stinger/Classes/StingerParams.h: -------------------------------------------------------------------------------- 1 | // 2 | // StingerParams.h 3 | // Stinger 4 | // 5 | // Created by Assuner on 2018/1/10. 6 | // Copyright © 2018年 Assuner. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | 13 | @interface StingerParams : NSObject 14 | - (instancetype)initWithType:(NSString *)types originalIMP:(IMP)imp sel:(SEL)sel args:(void **)args; 15 | @end 16 | -------------------------------------------------------------------------------- /framework/Aspects/AspectsDemo/AspectsDemo/AspectsDemo-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_3_0 10 | #warning "This project uses features only available in iOS SDK 3.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /framework/Aspects/AspectsDemo/AspectsDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // AspectsDemo 4 | // 5 | // Created by Peter Steinberger on 03/05/14. 6 | // Copyright (c) 2014 PSPDFKit GmbH. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "AspectsAppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AspectsAppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /framework/Aspects/AspectsDemo/AspectsDemo/AspectsViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // AspectsViewController.h 3 | // AspectsDemo 4 | // 5 | // Created by Peter Steinberger on 05/05/14. 6 | // Copyright (c) 2014 PSPDFKit GmbH. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AspectsViewController : UIViewController 12 | 13 | - (IBAction)buttonPressed:(id)sender; 14 | - (void)doNothing: (int)one; 15 | - (void)doObjectNothing: (NSDictionary *)dict andNum:(int)one; 16 | @end 17 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Aspects (1.4.1) 3 | - Stinger (0.2.8) 4 | 5 | DEPENDENCIES: 6 | - Aspects 7 | - Stinger (from `../`) 8 | 9 | SPEC REPOS: 10 | trunk: 11 | - Aspects 12 | 13 | EXTERNAL SOURCES: 14 | Stinger: 15 | :path: "../" 16 | 17 | SPEC CHECKSUMS: 18 | Aspects: 7595ba96a6727a58ebcbfc954497fc5d2fdde546 19 | Stinger: b32ad54b685dabf5a301b17e4b1f930b60204b62 20 | 21 | PODFILE CHECKSUM: 6df52b616ee208569510c4defb2313f601db9f5e 22 | 23 | COCOAPODS: 1.8.4 24 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Aspects (1.4.1) 3 | - Stinger (0.2.8) 4 | 5 | DEPENDENCIES: 6 | - Aspects 7 | - Stinger (from `../`) 8 | 9 | SPEC REPOS: 10 | trunk: 11 | - Aspects 12 | 13 | EXTERNAL SOURCES: 14 | Stinger: 15 | :path: "../" 16 | 17 | SPEC CHECKSUMS: 18 | Aspects: 7595ba96a6727a58ebcbfc954497fc5d2fdde546 19 | Stinger: b32ad54b685dabf5a301b17e4b1f930b60204b62 20 | 21 | PODFILE CHECKSUM: 6df52b616ee208569510c4defb2313f601db9f5e 22 | 23 | COCOAPODS: 1.8.4 24 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Target Support Files/Pods-Stinger_Tests/Pods-Stinger_Tests.debug.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Aspects" "${PODS_ROOT}/Headers/Public/Stinger" 3 | PODS_BUILD_DIR = ${BUILD_DIR} 4 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 5 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 6 | PODS_ROOT = ${SRCROOT}/Pods 7 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 8 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Target Support Files/Pods-Stinger_Tests/Pods-Stinger_Tests.release.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Aspects" "${PODS_ROOT}/Headers/Public/Stinger" 3 | PODS_BUILD_DIR = ${BUILD_DIR} 4 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 5 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 6 | PODS_ROOT = ${SRCROOT}/Pods 7 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 8 | -------------------------------------------------------------------------------- /framework/Stinger/.travis.yml: -------------------------------------------------------------------------------- 1 | # references: 2 | # * http://www.objc.io/issue-6/travis-ci.html 3 | # * https://github.com/supermarin/xcpretty#usage 4 | 5 | osx_image: xcode7.3 6 | language: objective-c 7 | # cache: cocoapods 8 | # podfile: Example/Podfile 9 | # before_install: 10 | # - gem install cocoapods # Since Travis is not always on latest version 11 | # - pod install --project-directory=Example 12 | script: 13 | - set -o pipefail && xcodebuild test -enableCodeCoverage YES -workspace Example/Stinger.xcworkspace -scheme Stinger-Example -sdk iphonesimulator9.3 ONLY_ACTIVE_ARCH=NO | xcpretty 14 | - pod lib lint 15 | -------------------------------------------------------------------------------- /framework/Aspects/AspectsDemoOSX/AspectsDemoOSX/en.lproj/Credits.rtf: -------------------------------------------------------------------------------- 1 | {\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;} 2 | {\colortbl;\red255\green255\blue255;} 3 | \paperw9840\paperh8400 4 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural 5 | 6 | \f0\b\fs24 \cf0 Engineering: 7 | \b0 \ 8 | Some people\ 9 | \ 10 | 11 | \b Human Interface Design: 12 | \b0 \ 13 | Some other people\ 14 | \ 15 | 16 | \b Testing: 17 | \b0 \ 18 | Hopefully not nobody\ 19 | \ 20 | 21 | \b Documentation: 22 | \b0 \ 23 | Whoever\ 24 | \ 25 | 26 | \b With special thanks to: 27 | \b0 \ 28 | Mom\ 29 | } 30 | -------------------------------------------------------------------------------- /framework/Stinger/Stinger/Classes/STHookInfoPool.h: -------------------------------------------------------------------------------- 1 | // 2 | // STHookInfoPool.h 3 | // Stinger 4 | // 5 | // Created by Assuner on 2018/1/9. 6 | // Copyright © 2018年 Assuner. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | extern NSString *st_getSignatureForBlock(id block); 13 | extern NSString * const STClassPrefix; 14 | extern void st_setHookInfoPool(id obj, SEL key, id infoPool); 15 | extern id st_getHookInfoPool(id obj, SEL key); 16 | 17 | static NSString * const STSelectorPrefix = @"st_sel"; 18 | 19 | @interface STHookInfoPool : NSObject 20 | @end 21 | -------------------------------------------------------------------------------- /framework/Stinger/Stinger/Classes/STMethodSignature.h: -------------------------------------------------------------------------------- 1 | // 2 | // STMethodSignature.h 3 | // Stinger 4 | // 5 | // Created by Assuner on 2018/1/9. 6 | // Copyright © 2018年 Assuner. All rights reserved. 7 | // TODO: can be optimized 8 | 9 | #import 10 | #import "ffi.h" 11 | 12 | @interface STMethodSignature : NSObject 13 | 14 | @property (nonatomic, readonly) NSString *types; 15 | @property (nonatomic, readonly) NSArray *argumentTypes; 16 | @property (nonatomic, readonly) NSString *returnType; 17 | 18 | - (instancetype)initWithObjCTypes:(NSString *)objCTypes; // type encoding of method or block 19 | 20 | ffi_type *st_ffiTypeWithType(NSString *type); 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /framework/Aspects/Aspects.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "Aspects" 3 | s.version = "1.4.1" 4 | s.summary = "Delightful, simple library for aspect oriented programming." 5 | s.homepage = "https://github.com/steipete/Aspects" 6 | s.license = { :type => 'MIT', :file => 'LICENSE' } 7 | s.author = { "Peter Steinberger" => "steipete@gmail.com" } 8 | s.ios.deployment_target = '6.0' 9 | s.osx.deployment_target = '10.7' 10 | s.source = { :git => "https://github.com/steipete/Aspects.git", :tag => "#{s.version}" } 11 | s.source_files = 'Aspects.{h,m}' 12 | s.requires_arc = true; 13 | s.social_media_url = "https://twitter.com/steipete" 14 | end 15 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Target Support Files/Aspects/Aspects.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Aspects 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Aspects" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Aspects" 4 | PODS_BUILD_DIR = ${BUILD_DIR} 5 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 6 | PODS_ROOT = ${SRCROOT} 7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/Aspects 8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 9 | SKIP_INSTALL = YES 10 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 11 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Target Support Files/Stinger/Stinger.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Stinger 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Stinger" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Stinger" 4 | PODS_BUILD_DIR = ${BUILD_DIR} 5 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 6 | PODS_ROOT = ${SRCROOT} 7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. 8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 9 | SKIP_INSTALL = YES 10 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 11 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Local Podspecs/Stinger.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Stinger", 3 | "version": "0.2.8", 4 | "summary": "Implementing HOOK & AOP using libffi for Objective-C.", 5 | "description": "TODO: Add long description of the pod here.", 6 | "homepage": "https://github.com/eleme/Stinger", 7 | "license": { 8 | "type": "MIT", 9 | "file": "LICENSE" 10 | }, 11 | "authors": { 12 | "Assuner-Lee": "yongguang.li@ele.me" 13 | }, 14 | "source": { 15 | "git": "https://github.com/eleme/Stinger.git", 16 | "tag": "0.2.8" 17 | }, 18 | "platforms": { 19 | "ios": "8.0" 20 | }, 21 | "source_files": "Stinger/Classes/**/*", 22 | "vendored_libraries": "Stinger/Classes/libffi/libffi.a" 23 | } 24 | -------------------------------------------------------------------------------- /framework/fishhook/fishhook.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |spec| 2 | spec.name = "fishhook" 3 | spec.version = "0.2" 4 | spec.license = { :type => "BSD", :file => "LICENSE" } 5 | spec.homepage = 'https://github.com/facebook/fishhook' 6 | spec.author = { "Facebook, Inc." => "https://github.com/facebook" } 7 | spec.summary = "A library that enables dynamically rebinding symbols in Mach-O binaries running on iOS." 8 | spec.source = { :git => "https://github.com/facebook/fishhook.git", :tag => '0.2'} 9 | spec.source_files = "fishhook.{h,c}" 10 | spec.social_media_url = 'https://twitter.com/fbOpenSource' 11 | 12 | spec.ios.deployment_target = '6.0' 13 | end 14 | -------------------------------------------------------------------------------- /framework/Aspects/AspectsDemoOSX/AspectsDemoOSX/AspectsAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AspectsAppDelegate.m 3 | // AspectsDemoOSX 4 | // 5 | // Created by Ash Furrow on 2014-05-05. 6 | // Copyright (c) 2014 PSPDFKit GmbH. All rights reserved. 7 | // 8 | 9 | #import "AspectsAppDelegate.h" 10 | #import "Aspects.h" 11 | 12 | @implementation AspectsAppDelegate 13 | 14 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification 15 | { 16 | // Ignore hooks when we are testing. 17 | if (!NSClassFromString(@"XCTestCase")) { 18 | [self.window aspect_hookSelector:@selector(displayIfNeeded) withOptions:0 usingBlock:^(id instance, NSArray *arguments) { 19 | NSLog(@"Window is displayed!"); 20 | } error:NULL]; 21 | } 22 | } 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /framework/Stinger/.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | 4 | # Xcode 5 | build/ 6 | *.pbxuser 7 | !default.pbxuser 8 | *.mode1v3 9 | !default.mode1v3 10 | *.mode2v3 11 | !default.mode2v3 12 | *.perspectivev3 13 | !default.perspectivev3 14 | xcuserdata/ 15 | *.xccheckout 16 | profile 17 | *.moved-aside 18 | DerivedData 19 | *.hmap 20 | *.ipa 21 | 22 | # Bundler 23 | .bundle 24 | 25 | Carthage 26 | # We recommend against adding the Pods directory to your .gitignore. However 27 | # you should judge for yourself, the pros and cons are mentioned at: 28 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 29 | # 30 | # Note: if you ignore the Pods directory, make sure to uncomment 31 | # `pod install` in .travis.yml 32 | # 33 | # Pods/ 34 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Target Support Files/Pods-Stinger_Example/Pods-Stinger_Example.debug.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Aspects" "${PODS_ROOT}/Headers/Public/Stinger" 3 | LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Aspects" "${PODS_CONFIGURATION_BUILD_DIR}/Stinger" "${PODS_ROOT}/../../Stinger/Classes/libffi" 4 | OTHER_LDFLAGS = $(inherited) -ObjC -l"Aspects" -l"Stinger" -l"ffi" 5 | PODS_BUILD_DIR = ${BUILD_DIR} 6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 8 | PODS_ROOT = ${SRCROOT}/Pods 9 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 10 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Target Support Files/Pods-Stinger_Example/Pods-Stinger_Example.release.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Aspects" "${PODS_ROOT}/Headers/Public/Stinger" 3 | LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Aspects" "${PODS_CONFIGURATION_BUILD_DIR}/Stinger" "${PODS_ROOT}/../../Stinger/Classes/libffi" 4 | OTHER_LDFLAGS = $(inherited) -ObjC -l"Aspects" -l"Stinger" -l"ffi" 5 | PODS_BUILD_DIR = ${BUILD_DIR} 6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 8 | PODS_ROOT = ${SRCROOT}/Pods 9 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 10 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Stinger.xcodeproj/xcshareddata/xcbaselines/6003F5AD195388D20070C39A.xcbaseline/99D3E204-67A8-4086-8B11-184B7F8D624D.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | classNames 6 | 7 | PerformanceTests 8 | 9 | testStingerHookMethodA2 10 | 11 | com.apple.XCTPerformanceMetric_WallClockTime 12 | 13 | baselineAverage 14 | 1.2167e-05 15 | baselineIntegrationDisplayName 16 | Local Baseline 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Tests/Tests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /framework/Aspects/AspectsDemo/AspectsDemoTests/AspectsDemoTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.pspdfkit.aspects.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /framework/Aspects/AspectsDemoOSX/AspectsDemoOSXTests/AspectsDemoOSXTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.pspdfkit.aspects.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /framework/Stinger/Stinger/Classes/STHookInfo.m: -------------------------------------------------------------------------------- 1 | // 2 | // STHookInfo.m 3 | // Stinger 4 | // 5 | // Created by Assuner on 2018/1/9. 6 | // Copyright © 2018年 Assuner. All rights reserved. 7 | // 8 | 9 | #import "STHookInfo.h" 10 | #import "STMethodSignature.h" 11 | 12 | @implementation STHookInfo 13 | 14 | @synthesize identifier = _identifier; 15 | @synthesize option = _option; 16 | @synthesize block = _block; 17 | 18 | + (instancetype)infoWithOption:(STOption)option withIdentifier:(STIdentifier)identifier withBlock:(id)block { 19 | NSAssert((option == 0 || option == 1 || option == 2), @"invalid STOption of %zd", option); 20 | NSParameterAssert(identifier); 21 | NSParameterAssert(block); 22 | 23 | STHookInfo *info = [[STHookInfo alloc] init]; 24 | info.option = option; 25 | info.identifier = identifier; 26 | info.block = block; 27 | return info; 28 | } 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /framework/Aspects/Info-watch.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Target Support Files/Pods-Stinger_Tests/Pods-Stinger_Tests-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Generated by CocoaPods - https://cocoapods.org 18 | Title 19 | 20 | Type 21 | PSGroupSpecifier 22 | 23 | 24 | StringsTable 25 | Acknowledgements 26 | Title 27 | Acknowledgements 28 | 29 | 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iOS-Framework-Analysis 2 | 🎉 iOS优秀第三方框架解析专栏...Doing... 3 | 4 | ## 介绍 5 | 6 | 众所周知,阅读优秀的框架源码是能快速提升自身 Coding 能力的方式之一,今年计划完成10篇框架源码解析,了解其设计思想及优秀的实现方式,构建更完善的知识体系。目前暂定的框架有 `fishhook` 、`Aspects`、`RxSwift` 等等,具体代码注释请[点击](/framework),解析文章会更新到 [我的掘金](https://juejin.im/user/58229b8ea0bb9f0058cd2738) ,欢迎关注一起成长。 7 | 8 | ## 框架目录 9 | 10 | - [fishhook解析](https://juejin.im/post/5e62275cf265da570e39ae46) 11 | Apple平台下老牌的C/C++函数Hook利器。 12 | 13 | - [Aspects解析](https://juejin.im/post/5e703f57e51d4526c3591b1a) 14 | iOS上优秀的AOP框架 15 | 16 | ## 版权声明 17 | 18 | * 所有原创文章(未进行特殊标识的均属于原创) 的著作权属于 **SimonYe**。 19 | * 所有转载文章(标题注明`[转]`的所有文章) 的著作权属于原作者。 20 | * 所有译文文章(标题注明`[译]`的所有文章) 的原文著作权属于原作者,译文著作权属于 **SimonYe**。 21 | 22 | #### 转载注意事项 23 | 24 | 除注明外,所有文章均采用 [Creative Commons BY-NC-ND 4.0(自由转载-保持署名-非商用-禁止演绎)](http://creativecommons.org/licenses/by-nc-nd/4.0/deed.zh)协议发布。 25 | 26 | 你可以在非商业的前提下免费转载,但同时你必须: 27 | 28 | * 保持文章原文,不作修改。 29 | * 明确署名,即至少注明 `作者:SimonYe` 字样以及文章的原始链接,且不得使用 `rel="nofollow"` 标记。 30 | * 商业用途请联系邮箱 `128526@qq.com` 或微信 `yhbxqc`。 31 | * 微信公众号转载一律不授权 `原创` 标志。 32 | -------------------------------------------------------------------------------- /framework/Aspects/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.pspdfkit.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.4.1 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSHumanReadableCopyright 24 | Copyright (c) 2014 Peter Steinberger. Licensed under the MIT license. 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /framework/Aspects/AspectsDemo/AspectsDemo/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "ipad", 20 | "size" : "29x29", 21 | "scale" : "1x" 22 | }, 23 | { 24 | "idiom" : "ipad", 25 | "size" : "29x29", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "ipad", 30 | "size" : "40x40", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "40x40", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "76x76", 41 | "scale" : "1x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "76x76", 46 | "scale" : "2x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } -------------------------------------------------------------------------------- /framework/Stinger/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Assuner-Lee 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /framework/Aspects/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2015 Peter Steinberger, steipete@gmail.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Aspects/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Peter Steinberger, steipete@gmail.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /framework/Aspects/AspectsDemoOSX/AspectsDemoOSX/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "size" : "16x16", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "size" : "16x16", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "size" : "32x32", 16 | "scale" : "1x" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "size" : "32x32", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "size" : "128x128", 26 | "scale" : "1x" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "size" : "128x128", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "size" : "256x256", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "size" : "256x256", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "size" : "512x512", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "size" : "512x512", 51 | "scale" : "2x" 52 | } 53 | ], 54 | "info" : { 55 | "version" : 1, 56 | "author" : "xcode" 57 | } 58 | } -------------------------------------------------------------------------------- /framework/Aspects/AspectsDemoOSX/AspectsDemoOSX/AspectsDemoOSX-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | com.pspdfkit.aspects.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSMinimumSystemVersion 26 | ${MACOSX_DEPLOYMENT_TARGET} 27 | NSHumanReadableCopyright 28 | Copyright © 2014 PSPDFKit GmbH. All rights reserved. 29 | NSMainNibFile 30 | MainMenu 31 | NSPrincipalClass 32 | NSApplication 33 | 34 | 35 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Stinger.xcodeproj/xcshareddata/xcbaselines/6003F5AD195388D20070C39A.xcbaseline/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | runDestinationsByUUID 6 | 7 | 99D3E204-67A8-4086-8B11-184B7F8D624D 8 | 9 | localComputer 10 | 11 | busSpeedInMHz 12 | 400 13 | cpuCount 14 | 1 15 | cpuKind 16 | 6-Core Intel Core i9 17 | cpuSpeedInMHz 18 | 2900 19 | logicalCPUCoresPerPackage 20 | 12 21 | modelCode 22 | MacBookPro15,1 23 | physicalCPUCoresPerPackage 24 | 6 25 | platformIdentifier 26 | com.apple.platform.macosx 27 | 28 | targetArchitecture 29 | x86_64 30 | targetDevice 31 | 32 | modelCode 33 | iPhone12,5 34 | platformIdentifier 35 | com.apple.platform.iphonesimulator 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /framework/fishhook/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to fishhook 2 | We want to make contributing to this project as easy and transparent as 3 | possible. 4 | 5 | ## Pull Requests 6 | We actively welcome your pull requests. 7 | 8 | 1. Fork the repo and create your branch from `master`. 9 | 2. If you've added code that should be tested, add tests. 10 | 3. If you've changed APIs, update the documentation. 11 | 4. Ensure the test suite passes. 12 | 5. Make sure your code lints. 13 | 6. If you haven't already, complete the Contributor License Agreement ("CLA"). 14 | 15 | ## Contributor License Agreement ("CLA") 16 | In order to accept your pull request, we need you to submit a CLA. You only need 17 | to do this once to work on any of Facebook's open source projects. 18 | 19 | Complete your CLA here: 20 | 21 | ## Issues 22 | We use GitHub issues to track public bugs. Please ensure your description is 23 | clear and has sufficient instructions to be able to reproduce the issue. 24 | 25 | Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe 26 | disclosure of security bugs. In those cases, please go through the process 27 | outlined on that page and do not file a public issue. 28 | 29 | ## License 30 | By contributing to fishhook, you agree that your contributions will be licensed 31 | under the LICENSE file in the root directory of this source tree. -------------------------------------------------------------------------------- /framework/Aspects/AspectsDemo/AspectsDemo/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "orientation" : "portrait", 20 | "idiom" : "ipad", 21 | "extent" : "full-screen", 22 | "minimum-system-version" : "7.0", 23 | "scale" : "1x" 24 | }, 25 | { 26 | "orientation" : "landscape", 27 | "idiom" : "ipad", 28 | "extent" : "full-screen", 29 | "minimum-system-version" : "7.0", 30 | "scale" : "1x" 31 | }, 32 | { 33 | "orientation" : "portrait", 34 | "idiom" : "ipad", 35 | "extent" : "full-screen", 36 | "minimum-system-version" : "7.0", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "orientation" : "landscape", 41 | "idiom" : "ipad", 42 | "extent" : "full-screen", 43 | "minimum-system-version" : "7.0", 44 | "scale" : "2x" 45 | } 46 | ], 47 | "info" : { 48 | "version" : 1, 49 | "author" : "xcode" 50 | } 51 | } -------------------------------------------------------------------------------- /framework/Stinger/Example/Stinger/ASViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ASViewController.m 3 | // Stinger 4 | // 5 | // Created by Assuner on 12/05/2017. 6 | // Copyright (c) 2017 Assuner. All rights reserved. 7 | // 8 | 9 | #import "ASViewController.h" 10 | #import 11 | #import 12 | 13 | @interface ASViewController () 14 | 15 | - (IBAction)test:(id)sender; 16 | 17 | @end 18 | 19 | @implementation ASViewController 20 | 21 | - (void)methodA { 22 | 23 | } 24 | 25 | - (void)setFrame:(CGRect)rect { 26 | 27 | } 28 | 29 | - (void)viewDidLoad { 30 | [super viewDidLoad]; 31 | [self.class st_hookInstanceMethod:@selector(methodA) option:STOptionBefore usingIdentifier:@"hook methodA before" withBlock:^(id params) { 32 | 33 | }]; 34 | [self.class st_hookInstanceMethod:@selector(methodA) option:STOptionAfter usingIdentifier:@"hook methodA after" withBlock:^(id params) { 35 | 36 | }]; 37 | 38 | // [self.class aspect_hookSelector:@selector(methodA) withOptions:AspectPositionBefore usingBlock:^(id params) { 39 | // 40 | // } error:nil]; 41 | // 42 | // [self.class aspect_hookSelector:@selector(methodA) withOptions:AspectPositionBefore usingBlock:^(id params) { 43 | // 44 | // } error:nil]; 45 | } 46 | 47 | - (IBAction)test:(id)sender { 48 | for (NSInteger i = 0; i < 1000000; i++) { 49 | [self methodA]; 50 | } 51 | NSLog(@"clicked!!"); 52 | } 53 | @end 54 | -------------------------------------------------------------------------------- /framework/Stinger/Stinger/Classes/Stinger.h: -------------------------------------------------------------------------------- 1 | // 2 | // Stinger.h 3 | // Stinger 4 | // 5 | // Created by Assuner on 2018/1/9. 6 | // Copyright © 2018年 Assuner. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | 13 | @interface NSObject (Stinger) 14 | 15 | #pragma mark - For specific class 16 | 17 | /* Adds a block of code before/instead/after the current 'sel'. 18 | * @param block. The first parameter will be `id`, followed by all parameters of the method. 19 | * @param STIdentifier. The string is a identifier for a specific hook. 20 | * @return hook result. 21 | */ 22 | + (STHookResult)st_hookInstanceMethod:(SEL)sel option:(STOption)option usingIdentifier:(STIdentifier)identifier withBlock:(id)block; 23 | + (STHookResult)st_hookClassMethod:(SEL)sel option:(STOption)option usingIdentifier:(STIdentifier)identifier withBlock:(id)block; 24 | 25 | /* 26 | * Get all hook identifiers for a specific key. 27 | */ 28 | + (NSArray *)st_allIdentifiersForKey:(SEL)key; 29 | 30 | /* 31 | * Remove a specific hook. 32 | */ 33 | + (BOOL)st_removeHookWithIdentifier:(STIdentifier)identifier forKey:(SEL)key; 34 | 35 | 36 | #pragma mark - For specific instance 37 | 38 | - (STHookResult)st_hookInstanceMethod:(SEL)sel option:(STOption)option usingIdentifier:(STIdentifier)identifier withBlock:(id)block; 39 | 40 | - (NSArray *)st_allIdentifiersForKey:(SEL)key; 41 | 42 | - (BOOL)st_removeHookWithIdentifier:(STIdentifier)identifier forKey:(SEL)key; 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /framework/fishhook/LICENSE: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, Facebook, Inc. 2 | // All rights reserved. 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // * Redistributions of source code must retain the above copyright notice, 6 | // this list of conditions and the following disclaimer. 7 | // * Redistributions in binary form must reproduce the above copyright notice, 8 | // this list of conditions and the following disclaimer in the documentation 9 | // and/or other materials provided with the distribution. 10 | // * Neither the name Facebook nor the names of its contributors may be used to 11 | // endorse or promote products derived from this software without specific 12 | // prior written permission. 13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 17 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /framework/Stinger/Stinger/Classes/StingerParams.m: -------------------------------------------------------------------------------- 1 | // 2 | // StingerParams.m 3 | // Stinger 4 | // 5 | // Created by Assuner on 2018/1/10. 6 | // Copyright © 2018年 Assuner. All rights reserved. 7 | // 8 | 9 | #import "StingerParams.h" 10 | 11 | @interface NSInvocation (STInvoke) 12 | - (void)invokeUsingIMP:(IMP)imp; 13 | @end 14 | 15 | @interface StingerParams () 16 | @property (nonatomic, strong) NSString *types; 17 | @property (nonatomic) SEL sel; 18 | @property (nonatomic) IMP originalIMP; 19 | @property (nonatomic) void **args; 20 | @end 21 | 22 | @implementation StingerParams 23 | 24 | - (instancetype)initWithType:(NSString *)types originalIMP:(IMP)imp sel:(SEL)sel args:(void **)args { 25 | if (self = [super init]) { 26 | _types = types; 27 | _sel = sel; 28 | _originalIMP = imp; 29 | _args = args; 30 | } 31 | return self; 32 | } 33 | 34 | - (id)slf { 35 | void **slfPointer = _args[0]; 36 | return (__bridge id)(*slfPointer); 37 | } 38 | 39 | - (SEL)sel { 40 | return _sel; 41 | } 42 | 43 | 44 | - (void)invokeAndGetOriginalRetValue:(void *)retLoc { 45 | NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:_types.UTF8String]; 46 | NSInteger count = signature.numberOfArguments; 47 | NSInvocation *originalInvocation = [NSInvocation invocationWithMethodSignature:signature]; 48 | for (int i = 0; i < count; i ++) { 49 | [originalInvocation setArgument:_args[i] atIndex:i]; 50 | } 51 | [originalInvocation invokeUsingIMP:_originalIMP]; 52 | if (originalInvocation.methodSignature.methodReturnLength && !(retLoc == NULL)) { 53 | [originalInvocation getReturnValue:retLoc]; 54 | } 55 | } 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /framework/Aspects/AspectsDemo/AspectsDemo/AspectsDemo-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.pspdfkit.aspects.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 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 | -------------------------------------------------------------------------------- /framework/Aspects/Aspects.xcodeproj/project.xcworkspace/xcshareddata/Aspects.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 4228F3E1-0517-43F3-919E-B521720D6F24 9 | IDESourceControlProjectName 10 | Aspects 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 8B3366FBF9699A8CCB764F44E854D1F695C54A83 14 | https://github.com/steipete/Aspects.git 15 | 16 | IDESourceControlProjectPath 17 | Aspects.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 8B3366FBF9699A8CCB764F44E854D1F695C54A83 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/steipete/Aspects.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | 8B3366FBF9699A8CCB764F44E854D1F695C54A83 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 8B3366FBF9699A8CCB764F44E854D1F695C54A83 36 | IDESourceControlWCCName 37 | Aspects 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /framework/Aspects/AspectsDemo/AspectsDemo.xcodeproj/project.xcworkspace/xcshareddata/AspectsDemo.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | AEBB4B3B-FCA8-4B2C-A364-473DA52FD1F1 9 | IDESourceControlProjectName 10 | AspectsDemo 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | BFDD7EB6-262A-4289-BF40-2E5B677EEC58 14 | https://github.com/steipete/Aspects.git 15 | 16 | IDESourceControlProjectPath 17 | AspectsDemo/AspectsDemo.xcodeproj/project.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | BFDD7EB6-262A-4289-BF40-2E5B677EEC58 21 | ../../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/steipete/Aspects.git 25 | IDESourceControlProjectVersion 26 | 110 27 | IDESourceControlProjectWCCIdentifier 28 | BFDD7EB6-262A-4289-BF40-2E5B677EEC58 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | BFDD7EB6-262A-4289-BF40-2E5B677EEC58 36 | IDESourceControlWCCName 37 | Aspects 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /framework/Aspects/AspectsDemoOSX/AspectsDemoOSX.xcodeproj/project.xcworkspace/xcshareddata/AspectsDemoOSX.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | BE9DB880-2611-435A-9782-57D047D30C1A 9 | IDESourceControlProjectName 10 | AspectsDemoOSX 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | BFDD7EB6-262A-4289-BF40-2E5B677EEC58 14 | https://github.com/steipete/Aspects.git 15 | 16 | IDESourceControlProjectPath 17 | AspectsDemoOSX/AspectsDemoOSX.xcodeproj/project.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | BFDD7EB6-262A-4289-BF40-2E5B677EEC58 21 | ../../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/steipete/Aspects.git 25 | IDESourceControlProjectVersion 26 | 110 27 | IDESourceControlProjectWCCIdentifier 28 | BFDD7EB6-262A-4289-BF40-2E5B677EEC58 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | BFDD7EB6-262A-4289-BF40-2E5B677EEC58 36 | IDESourceControlWCCName 37 | Aspects 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Stinger/Stinger-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | UISupportedInterfaceOrientations~ipad 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationPortraitUpsideDown 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /framework/Stinger/Stinger.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod lib lint Stinger.podspec' to ensure this is a 3 | # valid spec before submitting. 4 | # 5 | # Any lines starting with a # are optional, but their use is encouraged 6 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | s.name = 'Stinger' 11 | s.version = '0.2.8' 12 | s.summary = 'Implementing HOOK & AOP using libffi for Objective-C.' 13 | 14 | # This description is used to generate tags and improve search results. 15 | # * Think: What does it do? Why did you write it? What is the focus? 16 | # * Try to keep it short, snappy and to the point. 17 | # * Write the description between the DESC delimiters below. 18 | # * Finally, don't worry about the indent, CocoaPods strips it! 19 | 20 | s.description = <<-DESC 21 | TODO: Add long description of the pod here. 22 | DESC 23 | 24 | s.homepage = 'https://github.com/eleme/Stinger' 25 | # s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2' 26 | s.license = { :type => 'MIT', :file => 'LICENSE' } 27 | s.author = { 'Assuner-Lee' => 'yongguang.li@ele.me' } 28 | s.source = { :git => 'https://github.com/eleme/Stinger.git', :tag => s.version.to_s } 29 | # s.social_media_url = 'https://twitter.com/' 30 | 31 | s.ios.deployment_target = '8.0' 32 | 33 | s.source_files = 'Stinger/Classes/**/*' 34 | 35 | # s.resource_bundles = { 36 | # 'Stinger' => ['Stinger/Assets/*.png'] 37 | # } 38 | 39 | # s.public_header_files = 'Pod/Classes/**/*.h' 40 | # s.frameworks = 'UIKit', 'MapKit' 41 | # s.dependency 'AFNetworking', '~> 2.3' 42 | s.vendored_libraries = 'Stinger/Classes/libffi/libffi.a' 43 | 44 | end 45 | -------------------------------------------------------------------------------- /framework/Aspects/AspectsDemo/AspectsDemo/AspectsViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // AspectsViewController.m 3 | // AspectsDemo 4 | // 5 | // Created by Peter Steinberger on 05/05/14. 6 | // Copyright (c) 2014 PSPDFKit GmbH. All rights reserved. 7 | // 8 | 9 | #import "AspectsViewController.h" 10 | #import "Aspects.h" 11 | 12 | @implementation AspectsViewController 13 | 14 | - (IBAction)buttonPressed:(id)sender { 15 | UIViewController *testController = [[UIImagePickerController alloc] init]; 16 | 17 | testController.modalPresentationStyle = UIModalPresentationFormSheet; 18 | [self presentViewController:testController animated:YES completion:NULL]; 19 | 20 | // We are interested in being notified when the controller is being dismissed. 21 | [testController aspect_hookSelector:@selector(viewWillDisappear:) withOptions:0 usingBlock:^( BOOL animated, id info) { 22 | UIViewController *controller = [info instance]; 23 | if (controller.isBeingDismissed || controller.isMovingFromParentViewController) { 24 | [[[UIAlertView alloc] initWithTitle:@"Popped" message:@"Hello from Aspects" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"Ok", nil] show]; 25 | } 26 | } error:NULL]; 27 | 28 | // Hooking dealloc is delicate, only AspectPositionBefore will work here. 29 | [testController aspect_hookSelector:NSSelectorFromString(@"dealloc") withOptions:AspectPositionBefore usingBlock:^(id info) { 30 | NSLog(@"Controller is about to be deallocated: %@", [info instance]); 31 | } error:NULL]; 32 | } 33 | 34 | - (void)doNothing: (int)one{ 35 | NSLog(@"doNothing"); 36 | } 37 | 38 | -(void)viewDidLoad { 39 | [super viewDidLoad]; 40 | [self doObjectNothing:@{} andNum:1]; 41 | } 42 | 43 | - (void)doObjectNothing: (NSDictionary *)dict andNum:(int)one { 44 | 45 | } 46 | 47 | -(void)viewDidAppear:(BOOL)animated { 48 | [super viewDidAppear:animated]; 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Stinger/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 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Stinger/Images.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 | } -------------------------------------------------------------------------------- /framework/Stinger/Example/Stinger/ASAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // ASAppDelegate.m 3 | // Stinger 4 | // 5 | // Created by Assuner-Lee on 12/05/2017. 6 | // Copyright (c) 2017 Assuner-Lee. All rights reserved. 7 | // 8 | 9 | #import "ASAppDelegate.h" 10 | 11 | @implementation ASAppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 14 | { 15 | // Override point for customization after application launch. 16 | return YES; 17 | } 18 | 19 | - (void)applicationWillResignActive:(UIApplication *)application 20 | { 21 | // 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. 22 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 23 | } 24 | 25 | - (void)applicationDidEnterBackground:(UIApplication *)application 26 | { 27 | // 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. 28 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 29 | } 30 | 31 | - (void)applicationWillEnterForeground:(UIApplication *)application 32 | { 33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | - (void)applicationDidBecomeActive:(UIApplication *)application 37 | { 38 | // 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. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application 42 | { 43 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /framework/Stinger/Stinger/Classes/STDefines.h: -------------------------------------------------------------------------------- 1 | // 2 | // STDefines.h 3 | // Pods 4 | // 5 | // Created by 李永光 on 2019/12/11. 6 | // 7 | 8 | #ifndef STDefines_h 9 | #define STDefines_h 10 | 11 | typedef NSString *STIdentifier; 12 | typedef void *StingerIMP; 13 | 14 | 15 | #pragma mark - enum 16 | 17 | typedef NS_ENUM(NSInteger, STOption) { 18 | STOptionAfter = 0, // Called after the original implementation (default) 19 | STOptionInstead = 1, // Will replace the original implementation. 20 | STOptionBefore = 2, // Called before the original implementation. 21 | }; 22 | 23 | 24 | typedef NS_ENUM(NSInteger, STHookResult) { 25 | STHookResultSuccuss = 1, 26 | STHookResultErrorMethodNotFound = -1, 27 | STHookResultErrorBlockNotMatched = -2, 28 | STHookResultErrorIDExisted = -3, 29 | STHookResultOther = -4, 30 | }; 31 | 32 | 33 | #pragma mark - protocol 34 | 35 | @protocol STHookInfo 36 | @required 37 | @property (nonatomic, copy) id block; 38 | @property (nonatomic, assign) STOption option; 39 | @property (nonatomic, copy) STIdentifier identifier; 40 | 41 | @optional 42 | + (instancetype)infoWithOption:(STOption)option withIdentifier:(STIdentifier)identifier withBlock:(id)block; 43 | @end 44 | 45 | 46 | @protocol StingerParams 47 | @required 48 | - (id)slf; 49 | - (SEL)sel; 50 | - (void)invokeAndGetOriginalRetValue:(void *)retLoc; 51 | @end 52 | 53 | 54 | @protocol STHookInfoPool 55 | @required 56 | @property (nonatomic, strong, readonly) NSMutableArray> *beforeInfos; 57 | @property (nonatomic, strong, readonly) id insteadInfo; 58 | @property (nonatomic, strong, readonly) NSMutableArray> *afterInfos; 59 | @property (nonatomic, strong, readonly) NSMutableArray *identifiers; 60 | @property (nonatomic, copy) NSString *typeEncoding; 61 | @property (nonatomic) IMP originalIMP; 62 | @property (nonatomic) SEL sel; 63 | @property (nonatomic) StingerIMP stingerIMP; 64 | 65 | - (BOOL)addInfo:(id)info; 66 | - (BOOL)removeInfoForIdentifier:(STIdentifier)identifier; 67 | 68 | @optional 69 | @property (nonatomic, weak) Class hookedCls; 70 | @property (nonatomic, weak) Class statedCls; 71 | @property (nonatomic, assign) BOOL isInstanceHook; 72 | 73 | + (instancetype)poolWithTypeEncoding:(NSString *)typeEncoding originalIMP:(IMP)imp selector:(SEL)sel; 74 | @end 75 | 76 | 77 | #endif /* STDefines_h */ 78 | -------------------------------------------------------------------------------- /framework/Aspects/AspectsDemo/AspectsDemo/AspectsAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AspectsAppDelegate.m 3 | // AspectsDemo 4 | // 5 | // Created by Peter Steinberger on 03/05/14. 6 | // Copyright (c) 2014 PSPDFKit GmbH. All rights reserved. 7 | // 8 | 9 | #import "AspectsAppDelegate.h" 10 | #import "AspectsViewController.h" 11 | #import "Aspects.h" 12 | 13 | @implementation AspectsAppDelegate 14 | 15 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 16 | AspectsViewController *aspectsController = [AspectsViewController new]; 17 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 18 | self.window.backgroundColor = [UIColor whiteColor]; 19 | self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:aspectsController]; 20 | [self.window makeKeyAndVisible]; 21 | 22 | // Ignore hooks when we are testing. 23 | if (!NSClassFromString(@"XCTestCase")) { 24 | 25 | [AspectsViewController aspect_hookSelector:@selector(viewWillLayoutSubviews) withOptions:AspectPositionInstead usingBlock:^{ 26 | NSLog(@"Hooked testClassMethod"); 27 | } error:NULL]; 28 | 29 | // 30 | // [aspectsController aspect_hookSelector:@selector(buttonPressed:) withOptions:0 usingBlock:^(id info, id sender) { 31 | // NSLog(@"Button was pressed by: %@", sender); 32 | // } error:NULL]; 33 | 34 | // [aspectsController aspect_hookSelector:@selector(viewWillLayoutSubviews) withOptions:0 usingBlock:^{ 35 | // NSLog(@"Controller is layouting!"); 36 | // } error:NULL]; 37 | 38 | // [aspectsController aspect_hookSelector:@selector(doNothing:) withOptions:0 usingBlock:^(id info, id num){ 39 | // NSLog(@"doNothing is hook!"); 40 | // } error:NULL]; 41 | 42 | // [aspectsController aspect_hookSelector:@selector(viewWillAppear:) withOptions:AspectPositionInstead usingBlock:^(id info, id sender) { 43 | // NSLog(@"doNothing is hook!"); 44 | // } error:NULL]; 45 | 46 | [aspectsController aspect_hookSelector:@selector(doObjectNothing:andNum:) withOptions:AspectPositionInstead usingBlock:^(id info, id sender, int num) { 47 | NSLog(@"doNothing is hook!"); 48 | } error:NULL]; 49 | 50 | 51 | 52 | } 53 | 54 | return YES; 55 | } 56 | 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Target Support Files/Pods-Stinger_Example/Pods-Stinger_Example-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## Aspects 5 | 6 | The MIT License (MIT) 7 | 8 | Copyright (c) 2014 Peter Steinberger, steipete@gmail.com 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in all 18 | copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | SOFTWARE. 27 | 28 | ## Stinger 29 | 30 | Copyright (c) 2017 Assuner-Lee 31 | 32 | Permission is hereby granted, free of charge, to any person obtaining a copy 33 | of this software and associated documentation files (the "Software"), to deal 34 | in the Software without restriction, including without limitation the rights 35 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 36 | copies of the Software, and to permit persons to whom the Software is 37 | furnished to do so, subject to the following conditions: 38 | 39 | The above copyright notice and this permission notice shall be included in 40 | all copies or substantial portions of the Software. 41 | 42 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 43 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 44 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 45 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 46 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 47 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 48 | THE SOFTWARE. 49 | 50 | Generated by CocoaPods - https://cocoapods.org 51 | -------------------------------------------------------------------------------- /framework/Stinger/Stinger/Classes/libffi/ffitarget_arm64.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | ``Software''), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 21 | 22 | #ifndef LIBFFI_TARGET_H 23 | #define LIBFFI_TARGET_H 24 | 25 | #ifndef LIBFFI_H 26 | #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." 27 | #endif 28 | 29 | #ifndef LIBFFI_ASM 30 | #ifdef __ILP32__ 31 | #define FFI_SIZEOF_ARG 8 32 | #define FFI_SIZEOF_JAVA_RAW 4 33 | typedef unsigned long long ffi_arg; 34 | typedef signed long long ffi_sarg; 35 | #else 36 | typedef unsigned long ffi_arg; 37 | typedef signed long ffi_sarg; 38 | #endif 39 | 40 | typedef enum ffi_abi 41 | { 42 | FFI_FIRST_ABI = 0, 43 | FFI_SYSV, 44 | FFI_LAST_ABI, 45 | FFI_DEFAULT_ABI = FFI_SYSV 46 | } ffi_abi; 47 | #endif 48 | 49 | /* ---- Definitions for closures ----------------------------------------- */ 50 | 51 | #define FFI_CLOSURES 1 52 | #define FFI_NATIVE_RAW_API 0 53 | 54 | #if defined (FFI_EXEC_TRAMPOLINE_TABLE) && FFI_EXEC_TRAMPOLINE_TABLE 55 | 56 | #ifdef __MACH__ 57 | #define FFI_TRAMPOLINE_SIZE 16 58 | #define FFI_TRAMPOLINE_CLOSURE_OFFSET 16 59 | #else 60 | #error "No trampoline table implementation" 61 | #endif 62 | 63 | #else 64 | #define FFI_TRAMPOLINE_SIZE 24 65 | #define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE 66 | #endif 67 | 68 | /* ---- Internal ---- */ 69 | 70 | #if defined (__APPLE__) 71 | #define FFI_TARGET_SPECIFIC_VARIADIC 72 | #define FFI_EXTRA_CIF_FIELDS unsigned aarch64_nfixedargs 73 | #else 74 | /* iOS reserves x18 for the system. Disable Go closures until 75 | a new static chain is chosen. */ 76 | #define FFI_GO_CLOSURES 1 77 | #endif 78 | 79 | #define FFI_TARGET_HAS_COMPLEX_TYPE 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /framework/Stinger/Stinger/Classes/libffi/ffitarget_arm.h: -------------------------------------------------------------------------------- 1 | /* -----------------------------------------------------------------*-C-*- 2 | ffitarget.h - Copyright (c) 2012 Anthony Green 3 | Copyright (c) 2010 CodeSourcery 4 | Copyright (c) 1996-2003 Red Hat, Inc. 5 | 6 | Target configuration macros for ARM. 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining 9 | a copy of this software and associated documentation files (the 10 | ``Software''), to deal in the Software without restriction, including 11 | without limitation the rights to use, copy, modify, merge, publish, 12 | distribute, sublicense, and/or sell copies of the Software, and to 13 | permit persons to whom the Software is furnished to do so, subject to 14 | the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included 17 | in all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, 20 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 23 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 | DEALINGS IN THE SOFTWARE. 27 | 28 | ----------------------------------------------------------------------- */ 29 | 30 | #ifndef LIBFFI_TARGET_H 31 | #define LIBFFI_TARGET_H 32 | 33 | #ifndef LIBFFI_H 34 | #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." 35 | #endif 36 | 37 | #ifndef LIBFFI_ASM 38 | typedef unsigned long ffi_arg; 39 | typedef signed long ffi_sarg; 40 | 41 | typedef enum ffi_abi { 42 | FFI_FIRST_ABI = 0, 43 | FFI_SYSV, 44 | FFI_VFP, 45 | FFI_LAST_ABI, 46 | #ifdef __ARM_PCS_VFP 47 | FFI_DEFAULT_ABI = FFI_VFP, 48 | #else 49 | FFI_DEFAULT_ABI = FFI_SYSV, 50 | #endif 51 | } ffi_abi; 52 | #endif 53 | 54 | #define FFI_EXTRA_CIF_FIELDS \ 55 | int vfp_used; \ 56 | unsigned short vfp_reg_free, vfp_nargs; \ 57 | signed char vfp_args[16] \ 58 | 59 | #define FFI_TARGET_SPECIFIC_VARIADIC 60 | #define FFI_TARGET_HAS_COMPLEX_TYPE 61 | 62 | /* ---- Definitions for closures ----------------------------------------- */ 63 | 64 | #define FFI_CLOSURES 1 65 | #define FFI_GO_CLOSURES 1 66 | #define FFI_NATIVE_RAW_API 0 67 | 68 | #if defined (FFI_EXEC_TRAMPOLINE_TABLE) && FFI_EXEC_TRAMPOLINE_TABLE 69 | 70 | #ifdef __MACH__ 71 | #define FFI_TRAMPOLINE_SIZE 12 72 | #define FFI_TRAMPOLINE_CLOSURE_OFFSET 8 73 | #else 74 | #error "No trampoline table implementation" 75 | #endif 76 | 77 | #else 78 | #define FFI_TRAMPOLINE_SIZE 12 79 | #define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE 80 | #endif 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /framework/Aspects/Aspects.xcodeproj/xcshareddata/xcschemes/Aspects-Mac.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 60 | 61 | 67 | 68 | 69 | 70 | 72 | 73 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /framework/Aspects/Aspects.xcodeproj/xcshareddata/xcschemes/Aspects-iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 60 | 61 | 67 | 68 | 69 | 70 | 72 | 73 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /framework/Aspects/AspectsDemo/AspectsDemo/AspectsViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /framework/Aspects/Aspects.xcodeproj/xcshareddata/xcschemes/Aspects-watchOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /framework/fishhook/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; // 被hook的函数名 46 | void *replacement; // 替换的函数指针(IMP) 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 | // 参数分别是结构体rebinding数组和数组元素个数 60 | int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel); 61 | 62 | /* 63 | * Rebinds as above, but only in the specified image. The header should point 64 | * to the mach-o header, the slide should be the slide offset. Others as above. 65 | */ 66 | FISHHOOK_VISIBILITY 67 | // 在指定的image中进行替换,header为该镜像的header,slider为偏移量,其他如上。 68 | int rebind_symbols_image(void *header, 69 | intptr_t slide, 70 | struct rebinding rebindings[], 71 | size_t rebindings_nel); 72 | 73 | #ifdef __cplusplus 74 | } 75 | #endif //__cplusplus 76 | 77 | #endif //fishhook_h 78 | 79 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Target Support Files/Pods-Stinger_Example/Pods-Stinger_Example-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | The MIT License (MIT) 18 | 19 | Copyright (c) 2014 Peter Steinberger, steipete@gmail.com 20 | 21 | Permission is hereby granted, free of charge, to any person obtaining a copy 22 | of this software and associated documentation files (the "Software"), to deal 23 | in the Software without restriction, including without limitation the rights 24 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 25 | copies of the Software, and to permit persons to whom the Software is 26 | furnished to do so, subject to the following conditions: 27 | 28 | The above copyright notice and this permission notice shall be included in all 29 | copies or substantial portions of the Software. 30 | 31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 32 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 33 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 34 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 35 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 36 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 37 | SOFTWARE. 38 | License 39 | MIT 40 | Title 41 | Aspects 42 | Type 43 | PSGroupSpecifier 44 | 45 | 46 | FooterText 47 | Copyright (c) 2017 Assuner-Lee <yongguang.li@ele.me> 48 | 49 | Permission is hereby granted, free of charge, to any person obtaining a copy 50 | of this software and associated documentation files (the "Software"), to deal 51 | in the Software without restriction, including without limitation the rights 52 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 53 | copies of the Software, and to permit persons to whom the Software is 54 | furnished to do so, subject to the following conditions: 55 | 56 | The above copyright notice and this permission notice shall be included in 57 | all copies or substantial portions of the Software. 58 | 59 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 60 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 61 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 62 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 63 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 64 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 65 | THE SOFTWARE. 66 | 67 | License 68 | MIT 69 | Title 70 | Stinger 71 | Type 72 | PSGroupSpecifier 73 | 74 | 75 | FooterText 76 | Generated by CocoaPods - https://cocoapods.org 77 | Title 78 | 79 | Type 80 | PSGroupSpecifier 81 | 82 | 83 | StringsTable 84 | Acknowledgements 85 | Title 86 | Acknowledgements 87 | 88 | 89 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Stinger/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 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Aspects/Aspects.h: -------------------------------------------------------------------------------- 1 | // 2 | // Aspects.h 3 | // Aspects - A delightful, simple library for aspect oriented programming. 4 | // 5 | // Copyright (c) 2014 Peter Steinberger. Licensed under the MIT license. 6 | // 7 | 8 | #import 9 | 10 | typedef NS_OPTIONS(NSUInteger, AspectOptions) { 11 | AspectPositionAfter = 0, /// Called after the original implementation (default) 12 | AspectPositionInstead = 1, /// Will replace the original implementation. 13 | AspectPositionBefore = 2, /// Called before the original implementation. 14 | 15 | AspectOptionAutomaticRemoval = 1 << 3 /// Will remove the hook after the first execution. 16 | }; 17 | 18 | /// Opaque Aspect Token that allows to deregister the hook. 19 | @protocol AspectToken 20 | 21 | /// Deregisters an aspect. 22 | /// @return YES if deregistration is successful, otherwise NO. 23 | - (BOOL)remove; 24 | 25 | @end 26 | 27 | /// The AspectInfo protocol is the first parameter of our block syntax. 28 | @protocol AspectInfo 29 | 30 | /// The instance that is currently hooked. 31 | - (id)instance; 32 | 33 | /// The original invocation of the hooked method. 34 | - (NSInvocation *)originalInvocation; 35 | 36 | /// All method arguments, boxed. This is lazily evaluated. 37 | - (NSArray *)arguments; 38 | 39 | @end 40 | 41 | /** 42 | Aspects uses Objective-C message forwarding to hook into messages. This will create some overhead. Don't add aspects to methods that are called a lot. Aspects is meant for view/controller code that is not called a 1000 times per second. 43 | 44 | Adding aspects returns an opaque token which can be used to deregister again. All calls are thread safe. 45 | */ 46 | @interface NSObject (Aspects) 47 | 48 | /// Adds a block of code before/instead/after the current `selector` for a specific class. 49 | /// 50 | /// @param block Aspects replicates the type signature of the method being hooked. 51 | /// The first parameter will be `id`, followed by all parameters of the method. 52 | /// These parameters are optional and will be filled to match the block signature. 53 | /// You can even use an empty block, or one that simple gets `id`. 54 | /// 55 | /// @note Hooking static methods is not supported. 56 | /// @return A token which allows to later deregister the aspect. 57 | + (id)aspect_hookSelector:(SEL)selector 58 | withOptions:(AspectOptions)options 59 | usingBlock:(id)block 60 | error:(NSError **)error; 61 | 62 | /// Adds a block of code before/instead/after the current `selector` for a specific instance. 63 | - (id)aspect_hookSelector:(SEL)selector 64 | withOptions:(AspectOptions)options 65 | usingBlock:(id)block 66 | error:(NSError **)error; 67 | 68 | @end 69 | 70 | 71 | typedef NS_ENUM(NSUInteger, AspectErrorCode) { 72 | AspectErrorSelectorBlacklisted, /// Selectors like release, retain, autorelease are blacklisted. 73 | AspectErrorDoesNotRespondToSelector, /// Selector could not be found. 74 | AspectErrorSelectorDeallocPosition, /// When hooking dealloc, only AspectPositionBefore is allowed. 75 | AspectErrorSelectorAlreadyHookedInClassHierarchy, /// Statically hooking the same method in subclasses is not allowed. 76 | AspectErrorFailedToAllocateClassPair, /// The runtime failed creating a class pair. 77 | AspectErrorMissingBlockSignature, /// The block misses compile time signature info and can't be called. 78 | AspectErrorIncompatibleBlockSignature, /// The block signature does not match the method or is too large. 79 | 80 | AspectErrorRemoveObjectAlreadyDeallocated = 100 /// (for removing) The object hooked is already deallocated. 81 | }; 82 | 83 | extern NSString *const AspectErrorDomain; 84 | -------------------------------------------------------------------------------- /framework/Aspects/AspectsDemoOSX/AspectsDemoOSX.xcodeproj/xcshareddata/xcschemes/AspectsDemoOSX.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 61 | 62 | 68 | 69 | 70 | 71 | 72 | 73 | 79 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /framework/Aspects/Aspects.h: -------------------------------------------------------------------------------- 1 | // 2 | // Aspects.h 3 | // Aspects - A delightful, simple library for aspect oriented programming. 4 | // 5 | // Copyright (c) 2014 Peter Steinberger. Licensed under the MIT license. 6 | // 7 | 8 | #import 9 | 10 | typedef NS_OPTIONS(NSUInteger, AspectOptions) { 11 | AspectPositionAfter = 0, /// Called after the original implementation (default) 12 | AspectPositionInstead = 1, /// Will replace the original implementation. 13 | AspectPositionBefore = 2, /// Called before the original implementation. 14 | 15 | AspectOptionAutomaticRemoval = 1 << 3 /// Will remove the hook after the first execution. 16 | }; 17 | 18 | /// Opaque Aspect Token that allows to deregister the hook. 19 | /// 用于注销Hook 20 | @protocol AspectToken 21 | 22 | /// Deregisters an aspect. 23 | /// @return YES if deregistration is successful, otherwise NO. 24 | - (BOOL)remove; 25 | 26 | @end 27 | 28 | /// The AspectInfo protocol is the first parameter of our block syntax. 29 | /// 主要是所Hook方法的信息,用于校验block兼容性,后续触发block时会作为block的首个参数 30 | @protocol AspectInfo 31 | 32 | /// The instance that is currently hooked. 33 | - (id)instance; 34 | 35 | /// The original invocation of the hooked method. 36 | - (NSInvocation *)originalInvocation; 37 | 38 | /// All method arguments, boxed. This is lazily evaluated. 39 | - (NSArray *)arguments; 40 | 41 | @end 42 | 43 | /** 44 | Aspects uses Objective-C message forwarding to hook into messages. This will create some overhead. Don't add aspects to methods that are called a lot. Aspects is meant for view/controller code that is not called a 1000 times per second. 45 | 46 | Adding aspects returns an opaque token which can be used to deregister again. All calls are thread safe. 47 | */ 48 | /// 注释说明Aspects利用消息转发机制l来Hook消息,是存在性能开销的,不要在频繁调用的方法里去使用Aspects,主要用在view/controller的代码中 49 | @interface NSObject (Aspects) 50 | 51 | 52 | /// @param block Aspects replicates the type signature of the method being hooked. 53 | /// The first parameter will be `id`, followed by all parameters of the method. 54 | /// These parameters are optional and will be filled to match the block signature. 55 | /// You can even use an empty block, or one that simple gets `id`. 56 | /// 57 | /// @note Hooking static methods is not supported. 58 | /// @return A token which allows to later deregister the aspect. 59 | /// 在调用指定类的某个方法之前/过程中/之后执行一段block代码 60 | /// block的第一个参数固定为id`, 所以要Hook的方法如果有参数,则第一个参数必须为对象,否则在比对签名时或校验不过 61 | + (id)aspect_hookSelector:(SEL)selector 62 | withOptions:(AspectOptions)options 63 | usingBlock:(id)block 64 | error:(NSError **)error; 65 | 66 | /// Adds a block of code before/instead/after the current `selector` for a specific instance. 67 | - (id)aspect_hookSelector:(SEL)selector 68 | withOptions:(AspectOptions)options 69 | usingBlock:(id)block 70 | error:(NSError **)error; 71 | 72 | @end 73 | 74 | 75 | typedef NS_ENUM(NSUInteger, AspectErrorCode) { 76 | AspectErrorSelectorBlacklisted, /// Selectors like release, retain, autorelease are blacklisted. 77 | AspectErrorDoesNotRespondToSelector, /// Selector could not be found. 78 | AspectErrorSelectorDeallocPosition, /// When hooking dealloc, only AspectPositionBefore is allowed. 79 | AspectErrorSelectorAlreadyHookedInClassHierarchy, /// Statically hooking the same method in subclasses is not allowed. 80 | AspectErrorFailedToAllocateClassPair, /// The runtime failed creating a class pair. 81 | AspectErrorMissingBlockSignature, /// The block misses compile time signature info and can't be called. 82 | AspectErrorIncompatibleBlockSignature, /// The block signature does not match the method or is too large. 83 | 84 | AspectErrorRemoveObjectAlreadyDeallocated = 100 /// (for removing) The object hooked is already deallocated. 85 | }; 86 | 87 | extern NSString *const AspectErrorDomain; 88 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Stinger.xcodeproj/xcshareddata/xcschemes/Stinger-Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 38 | 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 | -------------------------------------------------------------------------------- /framework/Aspects/AspectsDemo/AspectsDemo.xcodeproj/xcshareddata/xcschemes/AspectsDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 61 | 62 | 68 | 69 | 70 | 71 | 75 | 76 | 77 | 78 | 84 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /framework/fishhook/README.md: -------------------------------------------------------------------------------- 1 | # fishhook 2 | 3 | __fishhook__ is a very simple library that enables dynamically rebinding symbols in Mach-O binaries running on iOS in the simulator and on device. This provides functionality that is similar to using [`DYLD_INTERPOSE`][interpose] on OS X. At Facebook, we've found it useful as a way to hook calls in libSystem for debugging/tracing purposes (for example, auditing for double-close issues with file descriptors). 4 | 5 | [interpose]: http://opensource.apple.com/source/dyld/dyld-210.2.3/include/mach-o/dyld-interposing.h "" 6 | 7 | ## Usage 8 | 9 | Once you add `fishhook.h`/`fishhook.c` to your project, you can rebind symbols as follows: 10 | ```Objective-C 11 | #import 12 | 13 | #import 14 | 15 | #import "AppDelegate.h" 16 | #import "fishhook.h" 17 | 18 | static int (*orig_close)(int); 19 | static int (*orig_open)(const char *, int, ...); 20 | 21 | int my_close(int fd) { 22 | printf("Calling real close(%d)\n", fd); 23 | return orig_close(fd); 24 | } 25 | 26 | int my_open(const char *path, int oflag, ...) { 27 | va_list ap = {0}; 28 | mode_t mode = 0; 29 | 30 | if ((oflag & O_CREAT) != 0) { 31 | // mode only applies to O_CREAT 32 | va_start(ap, oflag); 33 | mode = va_arg(ap, int); 34 | va_end(ap); 35 | printf("Calling real open('%s', %d, %d)\n", path, oflag, mode); 36 | return orig_open(path, oflag, mode); 37 | } else { 38 | printf("Calling real open('%s', %d)\n", path, oflag); 39 | return orig_open(path, oflag, mode); 40 | } 41 | } 42 | 43 | int main(int argc, char * argv[]) 44 | { 45 | @autoreleasepool { 46 | rebind_symbols((struct rebinding[2]){{"close", my_close, (void *)&orig_close}, {"open", my_open, (void *)&orig_open}}, 2); 47 | 48 | // Open our own binary and print out first 4 bytes (which is the same 49 | // for all Mach-O binaries on a given architecture) 50 | int fd = open(argv[0], O_RDONLY); 51 | uint32_t magic_number = 0; 52 | read(fd, &magic_number, 4); 53 | printf("Mach-O Magic Number: %x \n", magic_number); 54 | close(fd); 55 | 56 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 57 | } 58 | } 59 | ``` 60 | ### Sample output 61 | ``` 62 | Calling real open('/var/mobile/Applications/161DA598-5B83-41F5-8A44-675491AF6A2C/Test.app/Test', 0) 63 | Mach-O Magic Number: feedface 64 | Calling real close(3) 65 | ... 66 | ``` 67 | 68 | ## How it works 69 | 70 | `dyld` binds lazy and non-lazy symbols by updating pointers in particular sections of the `__DATA` segment of a Mach-O binary. __fishhook__ re-binds these symbols by determining the locations to update for each of the symbol names passed to `rebind_symbols` and then writing out the corresponding replacements. 71 | 72 | For a given image, the `__DATA` segment may contain two sections that are relevant for dynamic symbol bindings: `__nl_symbol_ptr` and `__la_symbol_ptr`. `__nl_symbol_ptr` is an array of pointers to non-lazily bound data (these are bound at the time a library is loaded) and `__la_symbol_ptr` is an array of pointers to imported functions that is generally filled by a routine called `dyld_stub_binder` during the first call to that symbol (it's also possible to tell `dyld` to bind these at launch). In order to find the name of the symbol that corresponds to a particular location in one of these sections, we have to jump through several layers of indirection. For the two relevant sections, the section headers (`struct section`s from ``) provide an offset (in the `reserved1` field) into what is known as the indirect symbol table. The indirect symbol table, which is located in the `__LINKEDIT` segment of the binary, is just an array of indexes into the symbol table (also in `__LINKEDIT`) whose order is identical to that of the pointers in the non-lazy and lazy symbol sections. So, given `struct section nl_symbol_ptr`, the corresponding index in the symbol table of the first address in that section is `indirect_symbol_table[nl_symbol_ptr->reserved1]`. The symbol table itself is an array of `struct nlist`s (see ``), and each `nlist` contains an index into the string table in `__LINKEDIT` which where the actual symbol names are stored. So, for each pointer `__nl_symbol_ptr` and `__la_symbol_ptr`, we are able to find the corresponding symbol and then the corresponding string to compare against the requested symbol names, and if there is a match, we replace the pointer in the section with the replacement. 73 | 74 | The process of looking up the name of a given entry in the lazy or non-lazy pointer tables looks like this: 75 | ![Visual explanation](http://i.imgur.com/HVXqHCz.png) -------------------------------------------------------------------------------- /framework/Stinger/Stinger/Classes/libffi/ffitarget_x86_64.h: -------------------------------------------------------------------------------- 1 | /* -----------------------------------------------------------------*-C-*- 2 | ffitarget.h - Copyright (c) 2012, 2014 Anthony Green 3 | Copyright (c) 1996-2003, 2010 Red Hat, Inc. 4 | Copyright (C) 2008 Free Software Foundation, Inc. 5 | 6 | Target configuration macros for x86 and x86-64. 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining 9 | a copy of this software and associated documentation files (the 10 | ``Software''), to deal in the Software without restriction, including 11 | without limitation the rights to use, copy, modify, merge, publish, 12 | distribute, sublicense, and/or sell copies of the Software, and to 13 | permit persons to whom the Software is furnished to do so, subject to 14 | the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included 17 | in all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, 20 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 23 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 | DEALINGS IN THE SOFTWARE. 27 | 28 | ----------------------------------------------------------------------- */ 29 | 30 | #ifndef LIBFFI_TARGET_H 31 | #define LIBFFI_TARGET_H 32 | 33 | #ifndef LIBFFI_H 34 | #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." 35 | #endif 36 | 37 | /* ---- System specific configurations ----------------------------------- */ 38 | 39 | /* For code common to all platforms on x86 and x86_64. */ 40 | #define X86_ANY 41 | 42 | #if defined (X86_64) && defined (__i386__) 43 | #undef X86_64 44 | #define X86 45 | #endif 46 | 47 | #ifdef X86_WIN64 48 | #define FFI_SIZEOF_ARG 8 49 | #define USE_BUILTIN_FFS 0 /* not yet implemented in mingw-64 */ 50 | #endif 51 | 52 | #define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION 53 | #ifndef _MSC_VER 54 | #define FFI_TARGET_HAS_COMPLEX_TYPE 55 | #endif 56 | 57 | /* ---- Generic type definitions ----------------------------------------- */ 58 | 59 | #ifndef LIBFFI_ASM 60 | #ifdef X86_WIN64 61 | #ifdef _MSC_VER 62 | typedef unsigned __int64 ffi_arg; 63 | typedef __int64 ffi_sarg; 64 | #else 65 | typedef unsigned long long ffi_arg; 66 | typedef long long ffi_sarg; 67 | #endif 68 | #else 69 | #if defined __x86_64__ && defined __ILP32__ 70 | #define FFI_SIZEOF_ARG 8 71 | #define FFI_SIZEOF_JAVA_RAW 4 72 | typedef unsigned long long ffi_arg; 73 | typedef long long ffi_sarg; 74 | #else 75 | typedef unsigned long ffi_arg; 76 | typedef signed long ffi_sarg; 77 | #endif 78 | #endif 79 | 80 | typedef enum ffi_abi { 81 | #if defined(X86_WIN64) 82 | FFI_FIRST_ABI = 0, 83 | FFI_WIN64, 84 | FFI_LAST_ABI, 85 | FFI_DEFAULT_ABI = FFI_WIN64 86 | 87 | #elif defined(X86_64) || (defined (__x86_64__) && defined (X86_DARWIN)) 88 | FFI_FIRST_ABI = 1, 89 | FFI_UNIX64, 90 | FFI_WIN64, 91 | FFI_EFI64 = FFI_WIN64, 92 | FFI_LAST_ABI, 93 | FFI_DEFAULT_ABI = FFI_UNIX64 94 | 95 | #elif defined(X86_WIN32) 96 | FFI_FIRST_ABI = 0, 97 | FFI_SYSV = 1, 98 | FFI_STDCALL = 2, 99 | FFI_THISCALL = 3, 100 | FFI_FASTCALL = 4, 101 | FFI_MS_CDECL = 5, 102 | FFI_PASCAL = 6, 103 | FFI_REGISTER = 7, 104 | FFI_LAST_ABI, 105 | FFI_DEFAULT_ABI = FFI_MS_CDECL 106 | #else 107 | FFI_FIRST_ABI = 0, 108 | FFI_SYSV = 1, 109 | FFI_THISCALL = 3, 110 | FFI_FASTCALL = 4, 111 | FFI_STDCALL = 5, 112 | FFI_PASCAL = 6, 113 | FFI_REGISTER = 7, 114 | FFI_MS_CDECL = 8, 115 | FFI_LAST_ABI, 116 | FFI_DEFAULT_ABI = FFI_SYSV 117 | #endif 118 | } ffi_abi; 119 | #endif 120 | 121 | /* ---- Definitions for closures ----------------------------------------- */ 122 | 123 | #define FFI_CLOSURES 1 124 | #define FFI_GO_CLOSURES 1 125 | 126 | #define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1) 127 | #define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2) 128 | #define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3) 129 | #define FFI_TYPE_MS_STRUCT (FFI_TYPE_LAST + 4) 130 | 131 | #if defined (X86_64) || defined(X86_WIN64) \ 132 | || (defined (__x86_64__) && defined (X86_DARWIN)) 133 | # define FFI_TRAMPOLINE_SIZE 24 134 | # define FFI_NATIVE_RAW_API 0 135 | #else 136 | # define FFI_TRAMPOLINE_SIZE 12 137 | # define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ 138 | #endif 139 | 140 | #endif 141 | 142 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Tests/CompatibilityTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // CompatibilityTests.m 3 | // Stinger_Tests 4 | // 5 | // Created by 李永光 on 2019/12/13. 6 | // Copyright © 2019 Assuner-Lee. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | 13 | @interface TestClassD : NSObject 14 | - (void)methodA; 15 | - (void)methodB; 16 | - (void)methodC; 17 | - (void)methodD; 18 | @end 19 | 20 | static NSString *TestClassD_string = @""; 21 | 22 | @implementation TestClassD 23 | 24 | - (void)methodA { 25 | TestClassD_string = [TestClassD_string stringByAppendingFormat:@"original methodA called--"]; 26 | } 27 | 28 | - (void)methodB { 29 | TestClassD_string = [TestClassD_string stringByAppendingFormat:@"original methodB called--"]; 30 | } 31 | 32 | - (void)methodC { 33 | TestClassD_string = [TestClassD_string stringByAppendingFormat:@"original methodC called--"]; 34 | } 35 | 36 | - (void)methodD { 37 | TestClassD_string = [TestClassD_string stringByAppendingFormat:@"original methodD called--"]; 38 | } 39 | 40 | @end 41 | 42 | @interface CompatibilityTests : XCTestCase 43 | 44 | @end 45 | 46 | @implementation CompatibilityTests 47 | 48 | 49 | - (void)testMethodA { 50 | TestClassD *object1 = [TestClassD new]; 51 | NSString *result = nil; 52 | [TestClassD st_hookInstanceMethod:@selector(methodA) option:STOptionAfter usingIdentifier:@"hook methodA after1" withBlock:^(id params) { 53 | TestClassD_string = [TestClassD_string stringByAppendingFormat:@"Stinger methodA after1 called--"]; 54 | }]; 55 | 56 | [TestClassD aspect_hookSelector:@selector(methodA) withOptions:AspectPositionAfter usingBlock:^(id params) { 57 | TestClassD_string = [TestClassD_string stringByAppendingFormat:@"Aspect methodA after1 called--"]; 58 | } error:nil]; 59 | 60 | TestClassD_string = @""; 61 | [object1 methodA]; 62 | result = @"original methodA called--Stinger methodA after1 called--Aspect methodA after1 called--"; 63 | XCTAssertTrue([TestClassD_string isEqualToString:result], @"should be equal"); 64 | } 65 | 66 | - (void)testMerhodB { 67 | TestClassD *object1 = [TestClassD new]; 68 | NSString *result = nil; 69 | 70 | [TestClassD aspect_hookSelector:@selector(methodB) withOptions:AspectPositionAfter usingBlock:^(id params) { 71 | TestClassD_string = [TestClassD_string stringByAppendingFormat:@"Aspect methodB after1 called--"]; 72 | } error:nil]; 73 | 74 | [TestClassD st_hookInstanceMethod:@selector(methodB) option:STOptionAfter usingIdentifier:@"hook methodB after1" withBlock:^(id params) { 75 | TestClassD_string = [TestClassD_string stringByAppendingFormat:@"Stinger methodB after1 called--"]; 76 | }]; 77 | 78 | TestClassD_string = @""; 79 | [object1 methodB]; 80 | result = @"original methodB called--Aspect methodB after1 called--Stinger methodB after1 called--"; 81 | XCTAssertTrue([TestClassD_string isEqualToString:result], @"should be equal"); 82 | } 83 | 84 | 85 | - (void)testMethodC { 86 | TestClassD *object1 = [TestClassD new]; 87 | NSString *result = nil; 88 | [object1 st_hookInstanceMethod:@selector(methodC) option:STOptionAfter usingIdentifier:@"hook methodC after1" withBlock:^(id params) { 89 | TestClassD_string = [TestClassD_string stringByAppendingFormat:@"Stinger methodC after1 called--"]; 90 | }]; 91 | 92 | [object1 aspect_hookSelector:@selector(methodC) withOptions:AspectPositionAfter usingBlock:^(id params) { 93 | TestClassD_string = [TestClassD_string stringByAppendingFormat:@"Aspect methodC after1 called--"]; 94 | } error:nil]; 95 | 96 | TestClassD_string = @""; 97 | [object1 methodC]; 98 | result = @"original methodC called--Stinger methodC after1 called--Aspect methodC after1 called--"; 99 | XCTAssertTrue([TestClassD_string isEqualToString:result], @"should be equal"); 100 | } 101 | 102 | - (void)testMerhodD { 103 | TestClassD *object1 = [TestClassD new]; 104 | NSString *result = nil; 105 | 106 | [object1 aspect_hookSelector:@selector(methodD) withOptions:AspectPositionAfter usingBlock:^(id params) { 107 | TestClassD_string = [TestClassD_string stringByAppendingFormat:@"Aspect methodD after1 called--"]; 108 | } error:nil]; 109 | 110 | [object1 st_hookInstanceMethod:@selector(methodD) option:STOptionAfter usingIdentifier:@"hook methodD after1" withBlock:^(id params) { 111 | TestClassD_string = [TestClassD_string stringByAppendingFormat:@"Stinger methodD after1 called--"]; 112 | }]; 113 | 114 | TestClassD_string = @""; 115 | [object1 methodD]; 116 | result = @"original methodD called--Aspect methodD after1 called--Stinger methodD after1 called--"; 117 | XCTAssertTrue([TestClassD_string isEqualToString:result], @"should be equal"); 118 | } 119 | 120 | 121 | @end 122 | -------------------------------------------------------------------------------- /framework/Stinger/Stinger/Classes/libffi/ffitarget_i386.h: -------------------------------------------------------------------------------- 1 | #ifdef __i386__ 2 | 3 | /* -----------------------------------------------------------------*-C-*- 4 | ffitarget.h - Copyright (c) 2012, 2014 Anthony Green 5 | Copyright (c) 1996-2003, 2010 Red Hat, Inc. 6 | Copyright (C) 2008 Free Software Foundation, Inc. 7 | 8 | Target configuration macros for x86 and x86-64. 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining 11 | a copy of this software and associated documentation files (the 12 | ``Software''), to deal in the Software without restriction, including 13 | without limitation the rights to use, copy, modify, merge, publish, 14 | distribute, sublicense, and/or sell copies of the Software, and to 15 | permit persons to whom the Software is furnished to do so, subject to 16 | the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included 19 | in all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, 22 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 25 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 26 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 28 | DEALINGS IN THE SOFTWARE. 29 | 30 | ----------------------------------------------------------------------- */ 31 | 32 | #ifndef LIBFFI_TARGET_H 33 | #define LIBFFI_TARGET_H 34 | 35 | #ifndef LIBFFI_H 36 | #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." 37 | #endif 38 | 39 | /* ---- System specific configurations ----------------------------------- */ 40 | 41 | /* For code common to all platforms on x86 and x86_64. */ 42 | #define X86_ANY 43 | 44 | #if defined (X86_64) && defined (__i386__) 45 | #undef X86_64 46 | #define X86 47 | #endif 48 | 49 | #ifdef X86_WIN64 50 | #define FFI_SIZEOF_ARG 8 51 | #define USE_BUILTIN_FFS 0 /* not yet implemented in mingw-64 */ 52 | #endif 53 | 54 | #define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION 55 | #define FFI_TARGET_HAS_COMPLEX_TYPE 56 | 57 | /* ---- Generic type definitions ----------------------------------------- */ 58 | 59 | #ifndef LIBFFI_ASM 60 | #ifdef X86_WIN64 61 | #ifdef _MSC_VER 62 | typedef unsigned __int64 ffi_arg; 63 | typedef __int64 ffi_sarg; 64 | #else 65 | typedef unsigned long long ffi_arg; 66 | typedef long long ffi_sarg; 67 | #endif 68 | #else 69 | #if defined __x86_64__ && defined __ILP32__ 70 | #define FFI_SIZEOF_ARG 8 71 | #define FFI_SIZEOF_JAVA_RAW 4 72 | typedef unsigned long long ffi_arg; 73 | typedef long long ffi_sarg; 74 | #else 75 | typedef unsigned long ffi_arg; 76 | typedef signed long ffi_sarg; 77 | #endif 78 | #endif 79 | 80 | typedef enum ffi_abi { 81 | FFI_FIRST_ABI = 0, 82 | 83 | /* ---- Intel x86 Win32 ---------- */ 84 | #ifdef X86_WIN32 85 | FFI_SYSV, 86 | FFI_STDCALL, 87 | FFI_THISCALL, 88 | FFI_FASTCALL, 89 | FFI_MS_CDECL, 90 | FFI_PASCAL, 91 | FFI_REGISTER, 92 | FFI_LAST_ABI, 93 | #ifdef _MSC_VER 94 | FFI_DEFAULT_ABI = FFI_MS_CDECL 95 | #else 96 | FFI_DEFAULT_ABI = FFI_SYSV 97 | #endif 98 | 99 | #elif defined(X86_WIN64) 100 | FFI_WIN64, 101 | FFI_LAST_ABI, 102 | FFI_DEFAULT_ABI = FFI_WIN64 103 | 104 | #else 105 | /* ---- Intel x86 and AMD x86-64 - */ 106 | FFI_SYSV, 107 | FFI_UNIX64, /* Unix variants all use the same ABI for x86-64 */ 108 | FFI_THISCALL, 109 | FFI_FASTCALL, 110 | FFI_STDCALL, 111 | FFI_PASCAL, 112 | FFI_REGISTER, 113 | FFI_LAST_ABI, 114 | #if defined(__i386__) || defined(__i386) 115 | FFI_DEFAULT_ABI = FFI_SYSV 116 | #else 117 | FFI_DEFAULT_ABI = FFI_UNIX64 118 | #endif 119 | #endif 120 | } ffi_abi; 121 | #endif 122 | 123 | /* ---- Definitions for closures ----------------------------------------- */ 124 | 125 | #define FFI_CLOSURES 1 126 | #define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1) 127 | #define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2) 128 | #define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3) 129 | #define FFI_TYPE_MS_STRUCT (FFI_TYPE_LAST + 4) 130 | 131 | #if defined (X86_64) || (defined (__x86_64__) && defined (X86_DARWIN)) 132 | #define FFI_TRAMPOLINE_SIZE 24 133 | #define FFI_NATIVE_RAW_API 0 134 | #else 135 | #ifdef X86_WIN32 136 | #define FFI_TRAMPOLINE_SIZE 52 137 | #else 138 | #ifdef X86_WIN64 139 | #define FFI_TRAMPOLINE_SIZE 29 140 | #define FFI_NATIVE_RAW_API 0 141 | #define FFI_NO_RAW_API 1 142 | #else 143 | #define FFI_TRAMPOLINE_SIZE 10 144 | #endif 145 | #endif 146 | #ifndef X86_WIN64 147 | #define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ 148 | #endif 149 | #endif 150 | 151 | #endif 152 | 153 | 154 | 155 | #endif -------------------------------------------------------------------------------- /framework/objc-msg-arm64/arm64下objc_msgSend汇编实现.md: -------------------------------------------------------------------------------- 1 | 0x18378c420 <+0>: cmp x0, #0x0 ; =0x0 2 | 0x18378c424 <+4>: b.le 0x18378c48c ; <+108> 3 | // x0->self #0x0->0 将self于0进行有符号比较(cmp),如果self不大于0(b.le:判断小于等于并跳转)则跳转到0x18378c48c 4 | 0x18378c428 <+8>: ldr x13, [x0] 5 | // 将x0存放的self的isa地址加载到x13寄存器中。(ldr:将存储器地址 所指地址处连续的4个字节(1个字)的数据传送到目的寄存器中) 6 | 0x18378c42c <+12>: and x16, x13, #0xffffffff8 7 | // 将isa和#0xffffffff8进行按位与(and)运算,并将结果存到x13中。(arm64架构使用non-pointer isa技术,isa字段除了包含指向Class信息,还存储了其他信息,例如引用计算等,进行按位与计算去除低位的冗余信息,最终得到Class的地址) 8 | 0x18378c430 <+16>: ldp x10, x11, [x16, #0x10] 9 | // 将Class地址偏移16字节(#0x10)后,向后取2个8字节分别放入x10和x11寄存器中,其中x10存放_buckets哈希桶,x11的高32位存放_occupied,低32位存放_mask。(ldp:与ldr类似,都是取值指令,可以连续取多个) 10 | 0x18378c434 <+20>: and w12, w1, w11 11 | // 将x1存放的_cmd的低32位信息和x11存放的低32位_mask信息进行按位与(相当于_cmd%table_size)得到哈希桶中的索引,并保存到x12的低32位中。(x1->寄存器的全部64位值,w1->寄存器的低32位值) 12 | 0x18378c438 <+24>: add x12, x10, x12, lsl #4 13 | // 将x12中的索引值左移4位(lsl #4),得到16位的索引值后(哈希桶中的bucket都是16位),与x10存放的哈希桶首地址相加(add)得到对应bucket地址存入x12中。 14 | 0x18378c43c <+28>: ldp x9, x17, [x12] 15 | // 将x12中bucket对应的2个8字节信息存放到x9和x17中,bucket是由selector和IMP两部分组成,x9存放selector,x17存放IMP 16 | 0x18378c440 <+32>: cmp x9, x1 17 | 0x18378c444 <+36>: b.ne 0x18378c44c ; <+44> 18 | // 将x1和x9存放的selector进行比较,如果不相同(b.ne)则跳转到0x18378c44c执行 19 | 0x18378c448 <+40>: br x17 20 | // 跳转(br)到x17存放的IMP执行具体代码。(**此时objc_msgSend处理最快的路径已经结束,既方法调用已经被缓存到哈希桶中,找到在对应的哈希桶中位置并执行) 21 | 0x18378c44c <+44>: cbz x9, 0x18378c720 ; _objc_msgSend_uncached 22 | // x1和x9存放的selector不相同时会执行到该执行,判断x9是否为0(cbz),为0则跳转到0x18378c720(对应代码为_objc_msgSend_uncached)。x9为0时表示对应的selector没有被缓存到哈希桶中,需要跳转到_objc_msgSend_uncached去执行没有缓存的查找方法(C函数)。 23 | 0x18378c450 <+48>: cmp x12, x10 24 | 0x18378c454 <+52>: b.eq 0x18378c460 ; <+64> 25 | // 将当前x12中的bucket地址与x10中的哈希桶首地址进行比较,如果相同则跳转到0x18378c460,从表位进行反向查询,不相同说明不是在表头,继续往下执行 26 | 0x18378c458 <+56>: ldp x9, x17, [x12, #-0x10]! 27 | 0x18378c45c <+60>: b 0x18378c440 ; <+32> 28 | // 往后偏移16位(#-0x10)x12中的bucket(#-0x10)得到新的bucket写入x12中(!),并存放到x9(selector)和x17(IMP)中。 29 | // 接着跳回0x18378c440循环执行x1和x9比较等操作,直到找到匹配项、bucket为空或回到哈希桶的表头 30 | 0x18378c460 <+64>: add x12, x12, w11, uxtw #4 31 | // 当找到匹配项或回到哈希桶的表头会执行到该指令,此时x12为最新的bucket地址,将w11左移4位(uxtw #4)后和x12相加得到哈希桶表尾地址,并将表尾地址存放到x12中 32 | 0x18378c464 <+68>: ldp x9, x17, [x12] 33 | // 将表位的bucket信息存储到x9和x17中 34 | 0x18378c468 <+72>: cmp x9, x1 35 | 0x18378c46c <+76>: b.ne 0x18378c474 ; <+84> 36 | 0x18378c470 <+80>: br x17 37 | // 比较x1和x9的selector是否相同,不相同则跳转到0x18378c474,相同则跳到x17的IMP位置执行 38 | 0x18378c474 <+84>: cbz x9, 0x18378c720 ; _objc_msgSend_uncached 39 | // 同0x18378c44c,判断x9是否为0,为0则执行_objc_msgSend_uncached 40 | 0x18378c478 <+88>: cmp x12, x10 41 | 0x18378c47c <+92>: b.eq 0x18378c488 ; <+104> 42 | // 判断x12与x10地址是否相同,相同则说明已循环完整个哈希桶,没有找到对应的bucket,跳转到0x18378c488 43 | 0x18378c480 <+96>: ldp x9, x17, [x12, #-0x10]! 44 | 0x18378c484 <+100>: b 0x18378c468 ; <+72> 45 | // 与0x18378c458指令相同,将bucket往后偏移16位后跳转0x18378c468,循环匹配bucket 46 | 0x18378c488 <+104>: b 0x18378c720 ; _objc_msgSend_uncached 47 | // 该指令会出现在内存损坏,既有索引值却找不到对应的bucket 48 | //-----------至此,前半部分在哈希桶中循环查找selector结束----- 49 | 0x18378c48c <+108>: b.eq 0x18378c4c4 ; <+164> 50 | // 开头0x18378c424执行后,self不大于0时会执行该指令,其中小于0则为标记指针(Tagged Pointer),等于0位nil。该指令判断是否等于nil,为nil为跳转到0x18378c4c4。 51 | 0x18378c490 <+112>: mov x10, #-0x1000000000000000 52 | // 将#-0x1000000000000000(高4位为1,其他为0的整型值)写入x10寄存器,用于作为提取self标记为的掩码 53 | 0x18378c494 <+116>: cmp x0, x10 54 | 0x18378c498 <+120>: b.hs 0x18378c4b0 ; <+144> 55 | // 比较x0中的self和x10中的掩码,如果self大于等于(h.hs)掩码,意味self的高4位也都为1,说明是自定义扩展的Tagged Pointer类型对象,第52-59位存储了Tagged Pointer类数组的索引值,跳转到0x18378c4b0处理,否则是系统自带的Tagged Pointer类型对象,高4位存储了Tagged Pointer类数组的索引值,继续往下执行 56 | 0x18378c49c <+124>: adrp x10, _objc_debug_taggedpointer_classes@PAGE 57 | 0x18378c4a0 <+128>: add x10, x10, _objc_debug_taggedpointer_classes@PAGEOFF 58 | // adrp和add指令用于加载tagged pointer主表(_objc_debug_taggedpointer_classes@PAG)到x10中,因为 ARM64 上的指针是 64 位宽,而指令只有 32 位宽,所以需要采用类 RISC 标准技术通过两个指令来加载符号地址。adrp 指令加载高 32 位信息然后再通过 add 指令将其与低 32 位进行求和。 59 | 0x18378c4a4 <+132>: lsr x11, x0, #60 60 | // 将x0右移(lsr)60位置得到存储在self高4位的索引值,并保存到x11中。 61 | 0x18378c4a8 <+136>: ldr x16, [x10, x11, lsl #3] 62 | // 通过x10的表头地址加上索引值(x11<<3)获取指针的类信息存储到x16中 63 | 0x18378c4ac <+140>: b 0x18378c430 ; <+16> 64 | // 跳转回0x18378c430进行方法查询处理 65 | 0x18378c4b0 <+144>: adrp x10, _objc_debug_taggedpointer_ext_classes@PAGE 66 | 0x18378c4b4 <+148>: add x10, x10, _objc_debug_taggedpointer_ext_classes@PAGEOFF 67 | // 该指令是0x18378c498中self为展的Tagged Pointer类型对象处理,此时与上面加载主表操作类似,加载拓展表 68 | 0x18378c4b8 <+152>: ubfx x11, x0, #52, #8 69 | // 提取self第52位~59位存储到x11中。 70 | 0x18378c4bc <+156>: ldr x16, [x10, x11, lsl #3] 71 | // 通过x10的表头地址加上索引值(x11<<3)获取指针的类信息存储到x16中 72 | 0x18378c4c0 <+160>: b 0x18378c430 ; <+16> 73 | // 跳转回0x18378c430进行方法查询处理 74 | 75 | 0x18378c4c4 <+164>: mov x1, #0x0 76 | 0x18378c4c8 <+168>: movi d0, #0000000000000000 77 | 0x18378c4cc <+172>: movi d1, #0000000000000000 78 | 0x18378c4d0 <+176>: movi d2, #0000000000000000 79 | 0x18378c4d4 <+180>: movi d3, #0000000000000000 80 | 0x18378c4d8 <+184>: ret 81 | // self为nil的处理指令,在arm64下,函数整型的返回值会存在x0,x1中,而浮点数的返回值存在v1-v3中,由于不知道函数的调用者需要什么类型,因此会将上述寄存器都清空,x0已经是0了,因此不需要清空。 82 | 0x18378c4dc <+188>: nop 83 | -------------------------------------------------------------------------------- /framework/Stinger/README_中文.md: -------------------------------------------------------------------------------- 1 | ![](https://github.com/Assuner-Lee/resource/blob/master/Stinger-2.jpg) 2 | [![CI Status](http://img.shields.io/travis/Assuner-Lee/Stinger.svg?style=flat)](https://travis-ci.org/Assuner-Lee/Stinger) 3 | [![Version](https://img.shields.io/cocoapods/v/Stinger.svg?style=flat)](http://cocoapods.org/pods/Stinger) 4 | [![License](https://img.shields.io/cocoapods/l/Stinger.svg?style=flat)](http://cocoapods.org/pods/Stinger) 5 | [![Platform](https://img.shields.io/cocoapods/p/Stinger.svg?style=flat)](http://cocoapods.org/pods/Stinger) 6 | 7 | 8 | Stinger是一个实现Objective-C AOP功能的库,有着良好的兼容性。你可以使用它在原方法的 前/替换/后位置插入(或替换)代码,实现起来比常规的方法交换更容易和灵活。**Stinger使用了libffi,没有使用OC的消息转发**。从消息发送到切面代码执行完毕,Stinger比Aspects快20倍,请参阅和运行这个`test case`。 [PerformanceTests](https://github.com/eleme/Stinger/blob/master/Example/Tests/PerformanceTests.m) 9 | 10 | Stinger 对NSObject做了以下方法扩展: 11 | 12 | ```objc 13 | typedef NSString *STIdentifier; 14 | 15 | typedef NS_ENUM(NSInteger, STOption) { 16 | STOptionAfter = 0, // 在原方法后调用(默认) 17 | STOptionInstead = 1, // 替换原实现 18 | STOptionBefore = 2, // 在原方法前调用 19 | }; 20 | 21 | typedef NS_ENUM(NSInteger, STHookResult) { 22 | STHookResultSuccuss = 1, 23 | STHookResultErrorMethodNotFound = -1, 24 | STHookResultErrorBlockNotMatched = -2, 25 | STHookResultErrorIDExisted = -3, 26 | STHookResultOther = -4, 27 | }; 28 | 29 | @interface NSObject (Stinger) 30 | 31 | #pragma mark - For specific class 32 | 33 | /* 在方法前后以block增加代码或替换. 34 | * @param block. block的第一个参数必须为 `id`, 后面跟着原方法的参数(如果原方法有返回值,选项为替换,则block也必须有返回值)。 35 | * @param STIdentifier. 标识特定hook的一个字符串,同一个对象的同一个方法的hook标识不能重复,可以使用此标识去帮助移除hook。 36 | * @return hook结果. 37 | */ 38 | + (STHookResult)st_hookInstanceMethod:(SEL)sel option:(STOption)option usingIdentifier:(STIdentifier)identifier withBlock:(id)block; 39 | + (STHookResult)st_hookClassMethod:(SEL)sel option:(STOption)option usingIdentifier:(STIdentifier)identifier withBlock:(id)block; 40 | 41 | /* 42 | * 获得这个sel下的所有hook标识。 43 | */ 44 | + (NSArray *)st_allIdentifiersForKey:(SEL)key; 45 | 46 | /* 47 | * 移除一个hook. 48 | */ 49 | + (BOOL)st_removeHookWithIdentifier:(STIdentifier)identifier forKey:(SEL)key; 50 | 51 | 52 | #pragma mark - For specific instance 53 | 54 | - (STHookResult)st_hookInstanceMethod:(SEL)sel option:(STOption)option usingIdentifier:(STIdentifier)identifier withBlock:(id)block; 55 | 56 | - (NSArray *)st_allIdentifiersForKey:(SEL)key; 57 | 58 | - (BOOL)st_removeHookWithIdentifier:(STIdentifier)identifier forKey:(SEL)key; 59 | 60 | @end 61 | ``` 62 | 63 | STIdentifier是一个hook的标识,它可以用来帮助移除Hook。 64 | 65 | Stinger使用libffi及解析方法签名构建壳函数,替换原方法实现以感知方法调用和捕获参数;使用同一cif模板及函数指针直接执行原实现和所有切面block。 66 | 67 | Stinger不使用消息转发指针替换原实现,hook兼容性更好;调用方法不经过消息转发过程,执行原实现及切面代码过程中无手动构建invocation等,效率更高。 68 | 69 | Stinger会匹配block的参数,第一个参数必须为`id`。 70 | 71 | ## How to use Stinger 72 | ### For specific class 73 | ```objc 74 | @interface ASViewController : UIViewController 75 | 76 | - (void)print1:(NSString *)s; 77 | - (NSString *)print2:(NSString *)s; 78 | + (void)class_print:(NSString *)s; 79 | 80 | @end 81 | 82 | ``` 83 | 84 | #### Using Stinger with void return types 85 | 86 | ```objc 87 | @implementation ASViewController (hook) 88 | 89 | + (void)load { 90 | /* 91 | * hook class method @selector(class_print:) 92 | */ 93 | [self st_hookClassMethod:@selector(class_print:) option:STOptionBefore usingIdentifier:@"hook_class_print_before" withBlock:^(id params, NSString *s) { 94 | NSLog(@"---before class_print: %@", s); 95 | }]; 96 | 97 | /* 98 | * hook @selector(print1:) 99 | */ 100 | [self st_hookInstanceMethod:@selector(print1:) option:STOptionBefore usingIdentifier:@"hook_print1_before1" withBlock:^(id params, NSString *s) { 101 | NSLog(@"---before1 print1: %@", s); 102 | }]; 103 | 104 | ``` 105 | 106 | #### Using Stinger with non-void return types 107 | 108 | ```objc 109 | @implementation ASViewController (hook) 110 | 111 | + (void)load { 112 | __block NSString *oldRet, *newRet; 113 | [self st_hookInstanceMethod:@selector(print2:) option:STOptionInstead usingIdentifier:@"hook_print2_instead" withBlock:^NSString * (id params, NSString *s) { 114 | [params invokeAndGetOriginalRetValue:&oldRet]; 115 | newRet = [oldRet stringByAppendingString:@" ++ new-st_instead"]; 116 | NSLog(@"---instead print2 old ret: (%@) / new ret: (%@)", oldRet, newRet); 117 | return newRet; 118 | }]; 119 | } 120 | @end 121 | 122 | ``` 123 | ### For specific instance 124 | ```objc 125 | // For specific instance 126 | @implementation ASViewController 127 | - (void)viewDidLoad { 128 | [super viewDidLoad]; 129 | [self st_hookInstanceMethod:@selector(print3:) option:STOptionAfter usingIdentifier:@"hook_print3_after1" withBlock:^(id params, NSString *s) { 130 | NSLog(@"---instance after print3: %@", s); 131 | }]; 132 | } 133 | @end 134 | 135 | ``` 136 | 137 | ## 性能测试 138 | [亮剑: Stinger到底能比Aspects快多少](https://juejin.im/post/5df5dcbc6fb9a0166138ff23) 139 | 140 | ## Credits 141 | 利用libffi, 可以使用(`ffi_prep_closure_loc`)创建和原方法有着相同参数和返回值的壳函数。可以在ffi_function(`void (*fun)(ffi_cif*,void*,void**,void*)`) 中得到所有的参数和调用所有的切面代码及原函数。 142 | 143 | ## Installation 144 | 145 | Stinger is available through [CocoaPods](http://cocoapods.org). To install 146 | it, simply add the following line to your Podfile: 147 | 148 | ```ruby 149 | pod 'Stinger' 150 | ``` 151 | 152 | ## Author 153 | 154 | Assuner-Lee, assuner@foxmail.com 155 | 156 | ## Release note 157 | | version | note | 158 | | ------ | ------ | 159 | | 0.1.1 | 初始化 | 160 | | 0.2.0 | 支持hook特定实例对象| 161 | | 0.2.1 | 提升了与使用消息转发hook方式的兼容性,如aspects, rac等| 162 | | 0.2.2 | 修掉一些Bug.| 163 | | 0.2.3 | 修掉一些Bug.| 164 | | 0.2.4 | 解决实例对象Hook的一个crash.| 165 | | 0.2.5 | 更正libffi版本.| 166 | | 0.2.6 | 支持结构体.| 167 | | 0.2.7 | 提升性能.| 168 | | 0.2.8 | 进一步提升实例对象hook的性能.| 169 | 170 | ## License 171 | 172 | Stinger is available under the MIT license. See the LICENSE file for more info. 173 | 174 | -------------------------------------------------------------------------------- /framework/Stinger/Stinger/Classes/STMethodSignature.m: -------------------------------------------------------------------------------- 1 | // 2 | // STMethodSignature.m 3 | // Stinger 4 | // 5 | // Created by Assuner on 2018/1/9. 6 | // Copyright © 2018年 Assuner. All rights reserved. 7 | // 8 | 9 | #import "STMethodSignature.h" 10 | 11 | @implementation STMethodSignature { 12 | NSString *_typeNames; 13 | NSMutableArray *_argumentTypes; 14 | NSString *_returnType; 15 | NSString *_types; 16 | } 17 | 18 | - (instancetype)initWithObjCTypes:(NSString *)objCTypes { 19 | self = [super init]; 20 | if (self) { 21 | _types = objCTypes; 22 | [self _genarateTypes]; 23 | } 24 | return self; 25 | } 26 | 27 | - (NSArray *)argumentTypes { 28 | return _argumentTypes; 29 | } 30 | 31 | - (NSString *)types { 32 | return _types; 33 | } 34 | 35 | - (NSString *)returnType { 36 | return _returnType; 37 | } 38 | 39 | ffi_type *st_ffiTypeWithType(NSString *type) { 40 | return _st_ffiTypeWithType(type.UTF8String); 41 | } 42 | 43 | 44 | #pragma mark - Private 45 | 46 | /* 47 | * sel: v24@0:8@16 -> v,@,:,@ 48 | * block: v24@?0@\"\"8@\"NSString\"16 -> v,@?,@,@ 49 | */ 50 | - (void)_genarateTypes { 51 | _argumentTypes = [[NSMutableArray alloc] init]; 52 | NSInteger descNum1 = 0; // num of '\"' in signature type encoding 53 | NSInteger descNum2 = 0; // num of '<' in block signature type encoding 54 | NSInteger descNum3 = 0; // num of '{' in signature type encoding 55 | NSInteger structBLoc = 0; // loc of '{' in signature type encoding 56 | NSInteger structELoc = 0; // loc of '}' in signature type encoding 57 | BOOL skipNext; 58 | NSString *arg; 59 | NSMutableArray *argArray = [NSMutableArray array]; 60 | 61 | for (int i = 0; i < _types.length; i ++) { 62 | unichar c = [_types characterAtIndex:i]; 63 | skipNext = NO; 64 | arg = nil; 65 | 66 | if (c == '\"') ++descNum1; 67 | if ((descNum1 % 2) != 0 || c == '\"' || isdigit(c)) { 68 | continue; 69 | } 70 | 71 | 72 | if (c == '<') ++descNum2; 73 | if (descNum2 > 0) { 74 | if (c == '>') { 75 | --descNum2; 76 | } 77 | continue; 78 | } 79 | 80 | 81 | if (c == '{') { 82 | if (descNum3 == 0) { 83 | structBLoc = i; 84 | } 85 | ++descNum3; 86 | } 87 | if (descNum3 > 0) { 88 | if (c == '}') { 89 | --descNum3; 90 | if (descNum3 == 0) { 91 | structELoc = i; 92 | arg = [_types substringWithRange:NSMakeRange(structBLoc, structELoc - structBLoc + 1)]; 93 | structBLoc = 0; 94 | structELoc = 0; 95 | } 96 | } 97 | 98 | if (descNum3 > 0) { 99 | continue; 100 | } 101 | } 102 | 103 | 104 | if (!arg) { 105 | if (c == '^') { 106 | skipNext = YES; 107 | arg = [_types substringWithRange:NSMakeRange(i, 2)]; 108 | } else if (c == '?') { 109 | // @? is block 110 | arg = [_types substringWithRange:NSMakeRange(i - 1, 2)]; 111 | [argArray removeLastObject]; 112 | } else { 113 | arg = [_types substringWithRange:NSMakeRange(i, 1)]; 114 | } 115 | } 116 | 117 | if (arg) { 118 | [argArray addObject:arg]; 119 | } 120 | if (skipNext) i++; 121 | } 122 | 123 | if (argArray.count > 1) { 124 | _returnType = argArray.firstObject; 125 | [argArray removeObjectAtIndex:0]; 126 | _argumentTypes = argArray; 127 | } 128 | } 129 | 130 | 131 | NS_INLINE ffi_type *_st_ffiTypeWithType(const char *c) { 132 | switch (c[0]) { 133 | case 'v': 134 | return &ffi_type_void; 135 | case 'c': 136 | return &ffi_type_schar; 137 | case 'C': 138 | return &ffi_type_uchar; 139 | case 's': 140 | return &ffi_type_sshort; 141 | case 'S': 142 | return &ffi_type_ushort; 143 | case 'i': 144 | return &ffi_type_sint; 145 | case 'I': 146 | return &ffi_type_uint; 147 | case 'l': 148 | return &ffi_type_slong; 149 | case 'L': 150 | return &ffi_type_ulong; 151 | case 'q': 152 | return &ffi_type_sint64; 153 | case 'Q': 154 | return &ffi_type_uint64; 155 | case 'f': 156 | return &ffi_type_float; 157 | case 'd': 158 | return &ffi_type_double; 159 | case 'F': 160 | #if CGFLOAT_IS_DOUBLE 161 | return &ffi_type_double; 162 | #else 163 | return &ffi_type_float; 164 | #endif 165 | case 'B': 166 | return &ffi_type_uint8; 167 | case '^': 168 | return &ffi_type_pointer; 169 | case '@': 170 | return &ffi_type_pointer; 171 | case '#': 172 | return &ffi_type_pointer; 173 | case ':': 174 | return &ffi_type_pointer; 175 | case '{': { 176 | // http://www.chiark.greenend.org.uk/doc/libffi-dev/html/Type-Example.html 177 | ffi_type *type = malloc(sizeof(ffi_type)); 178 | type->type = FFI_TYPE_STRUCT; 179 | NSUInteger size = 0; 180 | NSUInteger alignment = 0; 181 | NSGetSizeAndAlignment(c, &size, &alignment); 182 | type->alignment = alignment; 183 | type->size = size; 184 | while (c[0] != '=') ++c; ++c; 185 | 186 | NSPointerArray *pointArray = [NSPointerArray pointerArrayWithOptions:NSPointerFunctionsOpaqueMemory]; 187 | while (c[0] != '}') { 188 | ffi_type *elementType = NULL; 189 | elementType = _st_ffiTypeWithType(c); 190 | if (elementType) { 191 | [pointArray addPointer:elementType]; 192 | c = NSGetSizeAndAlignment(c, NULL, NULL); 193 | } else { 194 | return NULL; 195 | } 196 | } 197 | NSInteger count = pointArray.count; 198 | ffi_type **types = malloc(sizeof(ffi_type *) * (count + 1)); 199 | for (NSInteger i = 0; i < count; i++) { 200 | types[i] = [pointArray pointerAtIndex:i]; 201 | } 202 | types[count] = NULL; // terminated element is NULL 203 | 204 | type->elements = types; 205 | return type; 206 | } 207 | } 208 | return NULL; 209 | } 210 | 211 | @end 212 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Tests/MethodSignatureTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // MethodSignatureTests.m 3 | // Stinger_Tests 4 | // 5 | // Created by 李永光 on 2019/12/5. 6 | // Copyright © 2019 Assuner-Lee. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | #import 13 | 14 | @interface MethodSignatureTests : XCTestCase 15 | @end 16 | 17 | NSString *getTpyeEncoding(Class cls, SEL sel) { 18 | Method m = class_getInstanceMethod(cls, sel); 19 | const char * typeEncoding = method_getTypeEncoding(m); 20 | return [NSString stringWithUTF8String:typeEncoding]; 21 | } 22 | 23 | BOOL stringArrayIsEqual(NSArray *a, NSArray *b) { 24 | BOOL result = YES; 25 | if (a.count == b.count) { 26 | for (NSInteger i = 0; i < a.count; i++) { 27 | if (![a[i] isEqualToString:b[i]]) { 28 | result = NO; 29 | } 30 | } 31 | } else { 32 | result = NO; 33 | } 34 | return result; 35 | } 36 | 37 | @implementation MethodSignatureTests 38 | 39 | #define GET_TYPE_ENCODING(sel) getTpyeEncoding(self.class, @selector(sel)) 40 | - (void)testSignatureForMethod { 41 | STMethodSignature *st_signature; 42 | BOOL pass; 43 | 44 | st_signature = [[STMethodSignature alloc] initWithObjCTypes:GET_TYPE_ENCODING(methodA)]; 45 | XCTAssertTrue([st_signature.types isEqualToString:GET_TYPE_ENCODING(methodA)], @"should equal"); 46 | pass = [st_signature.returnType isEqualToString:@"v"] && stringArrayIsEqual(st_signature.argumentTypes, @[@"@", @":"]); 47 | XCTAssertTrue(pass, @"should equal"); 48 | 49 | st_signature = [[STMethodSignature alloc] initWithObjCTypes:GET_TYPE_ENCODING(methodB:)]; 50 | pass = [st_signature.returnType isEqualToString:@"@"] && stringArrayIsEqual(st_signature.argumentTypes, @[@"@", @":", @"@"]); 51 | XCTAssertTrue(pass, @"should equal"); 52 | 53 | st_signature = [[STMethodSignature alloc] initWithObjCTypes:GET_TYPE_ENCODING(methodC:)]; 54 | pass = [st_signature.returnType isEqualToString:@"v"] && stringArrayIsEqual(st_signature.argumentTypes, @[@"@", @":", @"@?"]); 55 | XCTAssertTrue(pass, @"should equal"); 56 | 57 | st_signature = [[STMethodSignature alloc] initWithObjCTypes:GET_TYPE_ENCODING(methodD:)]; 58 | pass = [st_signature.returnType isEqualToString:@"v"] && stringArrayIsEqual(st_signature.argumentTypes, @[@"@", @":", @"@?"]); 59 | XCTAssertTrue(pass, @"should equal"); 60 | 61 | st_signature = [[STMethodSignature alloc] initWithObjCTypes:GET_TYPE_ENCODING(methodE:)]; 62 | pass = [st_signature.returnType isEqualToString:@"{CGPoint=dd}"] && stringArrayIsEqual(st_signature.argumentTypes, @[@"@", @":", @"q"]); 63 | XCTAssertTrue(pass, @"should equal"); 64 | 65 | 66 | st_signature = [[STMethodSignature alloc] initWithObjCTypes:GET_TYPE_ENCODING(methodF:)]; 67 | pass = [st_signature.returnType isEqualToString:@"{CGRect={CGPoint=dd}{CGSize=dd}}"] && stringArrayIsEqual(st_signature.argumentTypes, @[@"@", @":", @"{CGRect={CGPoint=dd}{CGSize=dd}}"]); 68 | XCTAssertTrue(pass, @"should equal"); 69 | } 70 | 71 | 72 | - (void)testSignatureForBlock { 73 | STMethodSignature *st_signature; 74 | BOOL pass; 75 | 76 | id block = ^{ 77 | 78 | }; 79 | st_signature = [[STMethodSignature alloc] initWithObjCTypes:st_getSignatureForBlock(block)]; 80 | pass = [st_signature.returnType isEqualToString:@"v"] && stringArrayIsEqual(st_signature.argumentTypes, @[@"@?"]); 81 | XCTAssertTrue(pass, @"should equal"); 82 | 83 | 84 | block = ^NSString *(NSString *str){ 85 | return @"xxx"; 86 | }; 87 | st_signature = [[STMethodSignature alloc] initWithObjCTypes:st_getSignatureForBlock(block)]; 88 | pass = [st_signature.returnType isEqualToString:@"@"] && stringArrayIsEqual(st_signature.argumentTypes, @[@"@?", @"@"]); 89 | XCTAssertTrue(pass, @"should equal"); 90 | 91 | block = ^NSInteger (int a, float b) { 92 | return a+b; 93 | }; 94 | st_signature = [[STMethodSignature alloc] initWithObjCTypes:st_getSignatureForBlock(block)]; 95 | pass = [st_signature.returnType isEqualToString:@"q"] && stringArrayIsEqual(st_signature.argumentTypes, @[@"@?", @"i", @"f"]); 96 | XCTAssertTrue(pass, @"should equal"); 97 | 98 | block = ^NSInteger (id object) { 99 | return 1; 100 | }; 101 | st_signature = [[STMethodSignature alloc] initWithObjCTypes:st_getSignatureForBlock(block)]; 102 | pass = [st_signature.returnType isEqualToString:@"q"] && stringArrayIsEqual(st_signature.argumentTypes, @[@"@?", @"@"]); 103 | XCTAssertTrue(pass, @"should equal"); 104 | 105 | 106 | block = ^NSUInteger (void(^aBlock)(NSString *)) { 107 | return 1; 108 | }; 109 | st_signature = [[STMethodSignature alloc] initWithObjCTypes:st_getSignatureForBlock(block)]; 110 | pass = [st_signature.returnType isEqualToString:@"Q"] && stringArrayIsEqual(st_signature.argumentTypes, @[@"@?", @"@?"]); 111 | XCTAssertTrue(pass, @"should equal"); 112 | 113 | block = ^NSUInteger (void(^aBlock)(void(^blockParams)(NSString *x))) { 114 | return 1; 115 | }; 116 | st_signature = [[STMethodSignature alloc] initWithObjCTypes:st_getSignatureForBlock(block)]; 117 | pass = [st_signature.returnType isEqualToString:@"Q"] && stringArrayIsEqual(st_signature.argumentTypes, @[@"@?", @"@?"]); 118 | XCTAssertTrue(pass, @"should equal"); 119 | 120 | block = ^NSUInteger (void(^aBlock)(void(^blockParams)(NSString *x))) { 121 | return 1; 122 | }; 123 | st_signature = [[STMethodSignature alloc] initWithObjCTypes:st_getSignatureForBlock(block)]; 124 | pass = [st_signature.returnType isEqualToString:@"Q"] && stringArrayIsEqual(st_signature.argumentTypes, @[@"@?", @"@?"]); 125 | XCTAssertTrue(pass, @"should equal"); 126 | 127 | block = ^NSUInteger (CGPoint point) { 128 | return 1; 129 | }; 130 | st_signature = [[STMethodSignature alloc] initWithObjCTypes:st_getSignatureForBlock(block)]; 131 | pass = [st_signature.returnType isEqualToString:@"Q"] && stringArrayIsEqual(st_signature.argumentTypes, @[@"@?", @"{CGPoint=dd}"]); 132 | XCTAssertTrue(pass, @"should equal"); 133 | 134 | block = ^CGRect (CGPoint point) { 135 | return CGRectMake(1, 2, 3, 4); 136 | }; 137 | st_signature = [[STMethodSignature alloc] initWithObjCTypes:st_getSignatureForBlock(block)]; 138 | pass = [st_signature.returnType isEqualToString:@"{CGRect={CGPoint=dd}{CGSize=dd}}"] && stringArrayIsEqual(st_signature.argumentTypes, @[@"@?", @"{CGPoint=dd}"]); 139 | XCTAssertTrue(pass, @"should equal"); 140 | 141 | block = ^CGRect (CGRect rect) { 142 | return CGRectMake(1, 2, 3, 4); 143 | }; 144 | st_signature = [[STMethodSignature alloc] initWithObjCTypes:st_getSignatureForBlock(block)]; 145 | pass = [st_signature.returnType isEqualToString:@"{CGRect={CGPoint=dd}{CGSize=dd}}"] && stringArrayIsEqual(st_signature.argumentTypes, @[@"@?", @"{CGRect={CGPoint=dd}{CGSize=dd}}"]); 146 | XCTAssertTrue(pass, @"should equal"); 147 | 148 | block = ^NSUInteger (void *pointer) { 149 | return 1; 150 | }; 151 | st_signature = [[STMethodSignature alloc] initWithObjCTypes:st_getSignatureForBlock(block)]; 152 | pass = [st_signature.returnType isEqualToString:@"Q"] && stringArrayIsEqual(st_signature.argumentTypes, @[@"@?", @"^v"]); 153 | XCTAssertTrue(pass, @"should equal"); 154 | 155 | block = ^NSUInteger (SEL sel) { 156 | return 1; 157 | }; 158 | st_signature = [[STMethodSignature alloc] initWithObjCTypes:st_getSignatureForBlock(block)]; 159 | pass = [st_signature.returnType isEqualToString:@"Q"] && stringArrayIsEqual(st_signature.argumentTypes, @[@"@?", @":"]); 160 | XCTAssertTrue(pass, @"should equal"); 161 | } 162 | 163 | 164 | 165 | #pragma mark - Example method 166 | 167 | - (void)methodA { 168 | 169 | } 170 | 171 | - (NSString *)methodB:(NSString *)str { 172 | return @"xxx"; 173 | } 174 | 175 | - (void)methodC:(void(^)(void))block { 176 | 177 | } 178 | 179 | - (void)methodD:(NSString *(^)(void(^aBlock)(NSString *str)))block { 180 | 181 | } 182 | 183 | - (CGPoint)methodE:(NSInteger)num { 184 | return CGPointZero; 185 | } 186 | 187 | - (CGRect)methodF:(CGRect)rect { 188 | return CGRectZero; 189 | } 190 | 191 | @end 192 | -------------------------------------------------------------------------------- /framework/Stinger/Stinger/Classes/Stinger.m: -------------------------------------------------------------------------------- 1 | // 2 | // Stinger.m 3 | // Stinger 4 | // 5 | // Created by Assuner on 2018/1/9. 6 | // Copyright © 2018年 Assuner. All rights reserved. 7 | // 8 | 9 | #import "Stinger.h" 10 | #import 11 | #import "STHookInfo.h" 12 | #import "STHookInfoPool.h" 13 | #import "STMethodSignature.h" 14 | 15 | static void *STSubClassKey = &STSubClassKey; 16 | 17 | @implementation NSObject (Stinger) 18 | 19 | #pragma mark - For specific class 20 | 21 | + (STHookResult)st_hookInstanceMethod:(SEL)sel option:(STOption)option usingIdentifier:(STIdentifier)identifier withBlock:(id)block { 22 | return hookMethod(self, sel, option, identifier, block); 23 | } 24 | 25 | + (STHookResult)st_hookClassMethod:(SEL)sel option:(STOption)option usingIdentifier:(STIdentifier)identifier withBlock:(id)block { 26 | return hookMethod(object_getClass(self), sel, option, identifier, block); 27 | } 28 | 29 | + (NSArray *)st_allIdentifiersForKey:(SEL)key { 30 | NSMutableArray *mArray = [[NSMutableArray alloc] init]; 31 | @synchronized(self) { 32 | [mArray addObjectsFromArray:getAllIdentifiers(self, key)]; 33 | [mArray addObjectsFromArray:getAllIdentifiers(object_getClass(self), key)]; 34 | } 35 | return [mArray copy]; 36 | } 37 | 38 | + (BOOL)st_removeHookWithIdentifier:(STIdentifier)identifier forKey:(SEL)key { 39 | BOOL hasRemoved = NO; 40 | @synchronized(self) { 41 | id infoPool = st_getHookInfoPool(self, key); 42 | if ([infoPool removeInfoForIdentifier:identifier]) { 43 | hasRemoved = YES; 44 | } 45 | infoPool = st_getHookInfoPool(object_getClass(self), key); 46 | if ([infoPool removeInfoForIdentifier:identifier]) { 47 | hasRemoved = YES; 48 | } 49 | } 50 | return hasRemoved; 51 | } 52 | 53 | #pragma mark - For specific instance 54 | 55 | - (STHookResult)st_hookInstanceMethod:(SEL)sel option:(STOption)option usingIdentifier:(STIdentifier)identifier withBlock:(id)block { 56 | @synchronized(self) { 57 | Class stSubClass = getSTSubClass(self); 58 | if (!stSubClass) return STHookResultOther; 59 | 60 | STHookResult hookMethodResult = hookMethod(stSubClass, sel, option, identifier, block); 61 | if (hookMethodResult != STHookResultSuccuss) return hookMethodResult; 62 | if (!objc_getAssociatedObject(self, STSubClassKey)) { 63 | object_setClass(self, stSubClass); 64 | objc_setAssociatedObject(self, STSubClassKey, stSubClass, OBJC_ASSOCIATION_ASSIGN); 65 | } 66 | 67 | id instanceHookInfoPool = st_getHookInfoPool(self, sel); 68 | if (!instanceHookInfoPool) { 69 | instanceHookInfoPool = [STHookInfoPool poolWithTypeEncoding:nil originalIMP:NULL selector:sel]; 70 | st_setHookInfoPool(self, sel, instanceHookInfoPool); 71 | } 72 | 73 | STHookInfo *instanceHookInfo = [STHookInfo infoWithOption:option withIdentifier:identifier withBlock:block]; 74 | return [instanceHookInfoPool addInfo:instanceHookInfo] ? STHookResultSuccuss : STHookResultErrorIDExisted; 75 | } 76 | } 77 | 78 | - (NSArray *)st_allIdentifiersForKey:(SEL)key { 79 | @synchronized(self) { 80 | return getAllIdentifiers(self, key); 81 | } 82 | } 83 | 84 | - (BOOL)st_removeHookWithIdentifier:(STIdentifier)identifier forKey:(SEL)key { 85 | BOOL hasRemoved = NO; 86 | @synchronized(self) { 87 | id infoPool = st_getHookInfoPool(self, key); 88 | hasRemoved = [infoPool removeInfoForIdentifier:identifier]; 89 | return hasRemoved; 90 | } 91 | } 92 | 93 | #pragma mark - inline functions 94 | 95 | NS_INLINE STHookResult hookMethod(Class hookedCls, SEL sel, STOption option, STIdentifier identifier, id block) { 96 | NSCParameterAssert(hookedCls); 97 | NSCParameterAssert(sel); 98 | NSCParameterAssert(option == 0 || option == 1 || option == 2); 99 | NSCParameterAssert(identifier); 100 | NSCParameterAssert(block); 101 | Method m = class_getInstanceMethod(hookedCls, sel); 102 | NSCAssert(m, @"SEL (%@) doesn't has a imp in Class (%@) originally", NSStringFromSelector(sel), hookedCls); 103 | if (!m) return STHookResultErrorMethodNotFound; 104 | const char * typeEncoding = method_getTypeEncoding(m); 105 | STMethodSignature *methodSignature = [[STMethodSignature alloc] initWithObjCTypes:[NSString stringWithUTF8String:typeEncoding]]; 106 | STMethodSignature *blockSignature = [[STMethodSignature alloc] initWithObjCTypes:st_getSignatureForBlock(block)]; 107 | if (!isMatched(methodSignature, blockSignature, option, hookedCls, sel, identifier)) { 108 | return STHookResultErrorBlockNotMatched; 109 | } 110 | 111 | IMP originalImp = method_getImplementation(m); 112 | @synchronized(hookedCls) { 113 | id hookInfoPool = st_getHookInfoPool(hookedCls, sel); 114 | if (!hookInfoPool) { 115 | hookInfoPool = [STHookInfoPool poolWithTypeEncoding:[NSString stringWithUTF8String:typeEncoding] originalIMP:NULL selector:sel]; 116 | hookInfoPool.hookedCls = hookedCls; 117 | hookInfoPool.statedCls = [hookedCls class]; 118 | 119 | IMP stingerIMP = [hookInfoPool stingerIMP]; 120 | hookInfoPool.originalIMP = originalImp; 121 | if (!class_addMethod(hookedCls, sel, stingerIMP, typeEncoding)) { 122 | class_replaceMethod(hookedCls, sel, stingerIMP, typeEncoding); 123 | } 124 | 125 | st_setHookInfoPool(hookedCls, sel, hookInfoPool); 126 | } 127 | 128 | if ([NSStringFromClass(hookedCls) hasPrefix:STClassPrefix]) { 129 | return STHookResultSuccuss; 130 | } else { 131 | STHookInfo *hookInfo = [STHookInfo infoWithOption:option withIdentifier:identifier withBlock:block]; 132 | return [hookInfoPool addInfo:hookInfo] ? STHookResultSuccuss : STHookResultErrorIDExisted; 133 | } 134 | } 135 | } 136 | 137 | NS_INLINE Class getSTSubClass(id object) { 138 | NSCParameterAssert(object); 139 | Class stSubClass = objc_getAssociatedObject(object, STSubClassKey); 140 | if (stSubClass) return stSubClass; 141 | 142 | Class isaClass = object_getClass(object); 143 | NSString *isaClassName = NSStringFromClass(isaClass); 144 | const char *subclassName = [STClassPrefix stringByAppendingString:isaClassName].UTF8String; 145 | stSubClass = objc_getClass(subclassName); 146 | if (!stSubClass) { 147 | stSubClass = objc_allocateClassPair(isaClass, subclassName, 0); 148 | NSCAssert(stSubClass, @"Class %s allocate failed!", subclassName); 149 | if (!stSubClass) return nil; 150 | 151 | objc_registerClassPair(stSubClass); 152 | Class realClass = [object class]; 153 | hookGetClassMessage(stSubClass, realClass); 154 | hookGetClassMessage(object_getClass(stSubClass), realClass); 155 | } 156 | return stSubClass; 157 | } 158 | 159 | 160 | NS_INLINE void hookGetClassMessage(Class class, Class retClass) { 161 | Method method = class_getInstanceMethod(class, @selector(class)); 162 | IMP newIMP = imp_implementationWithBlock(^(id self) { 163 | return retClass; 164 | }); 165 | class_replaceMethod(class, @selector(class), newIMP, method_getTypeEncoding(method)); 166 | } 167 | 168 | NS_INLINE NSArray * getAllIdentifiers(id obj, SEL key) { 169 | NSCParameterAssert(obj); 170 | NSCParameterAssert(key); 171 | id infoPool = st_getHookInfoPool(obj, key); 172 | return infoPool.identifiers; 173 | } 174 | 175 | 176 | NS_INLINE BOOL isMatched(STMethodSignature *methodSignature, STMethodSignature *blockSignature, STOption option, Class cls, SEL sel, NSString *identifier) { 177 | //argument count 178 | if (methodSignature.argumentTypes.count != blockSignature.argumentTypes.count) { 179 | NSCAssert(NO, @"count of arguments isn't equal. Class: (%@), SEL: (%@), Identifier: (%@)", cls, NSStringFromSelector(sel), identifier); 180 | return NO; 181 | }; 182 | // loc 1 should be id. 183 | if (![blockSignature.argumentTypes[1] isEqualToString:@"@"]) { 184 | NSCAssert(NO, @"argument 1 should be object type. Class: (%@), SEL: (%@), Identifier: (%@)", cls, NSStringFromSelector(sel), identifier); 185 | return NO; 186 | } 187 | // from loc 2. 188 | for (NSInteger i = 2; i < methodSignature.argumentTypes.count; i++) { 189 | if (![blockSignature.argumentTypes[i] isEqualToString:methodSignature.argumentTypes[i]]) { 190 | NSCAssert(NO, @"argument (%zd) type isn't equal. Class: (%@), SEL: (%@), Identifier: (%@)", i, cls, NSStringFromSelector(sel), identifier); 191 | return NO; 192 | } 193 | } 194 | // when STOptionInstead, returnType 195 | if (option == STOptionInstead && ![blockSignature.returnType isEqualToString:methodSignature.returnType]) { 196 | NSCAssert(NO, @"return type isn't equal. Class: (%@), SEL: (%@), Identifier: (%@)", cls, NSStringFromSelector(sel), identifier); 197 | return NO; 198 | } 199 | 200 | return YES; 201 | } 202 | 203 | @end 204 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Tests/PerformanceTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // PerformanceTests.m 3 | // Stinger_Tests 4 | // 5 | // Created by 李永光 on 2019/12/11. 6 | // Copyright © 2019 Assuner-Lee. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | 13 | @interface TestClassC : NSObject 14 | - (void)methodBeforeA; 15 | - (void)methodA; 16 | - (void)methodAfterA; 17 | 18 | - (void)methodA1; 19 | - (void)methodB1; 20 | 21 | - (void)methodA2; 22 | - (void)methodB2; 23 | 24 | - (void)methodA3:(NSString *)str num:(double)num rect:(CGRect)rect; 25 | - (void)methodB3:(NSString *)str num:(double)num rect:(CGRect)rect; 26 | 27 | - (NSString *)methodA4; 28 | - (NSString *)methodB4; 29 | 30 | - (NSString *)methodA5:(NSString *)str num:(double)num rect:(CGRect)rect; 31 | - (NSString *)methodB5:(NSString *)str num:(double)num rect:(CGRect)rect; 32 | 33 | 34 | 35 | - (NSString *)methodC:(NSString *)str; 36 | - (NSString *)methodD:(NSString *)str; 37 | @end 38 | 39 | @implementation TestClassC 40 | 41 | - (void)methodBeforeA { 42 | } 43 | 44 | - (void)methodA { 45 | } 46 | 47 | - (void)methodAfterA { 48 | } 49 | 50 | 51 | - (void)methodA1 { 52 | } 53 | 54 | - (void)methodB1 { 55 | } 56 | 57 | 58 | - (void)methodA2 { 59 | } 60 | 61 | - (void)methodB2 { 62 | } 63 | 64 | 65 | - (void)methodA3:(NSString *)str num:(double)num rect:(CGRect)rect { 66 | 67 | } 68 | 69 | - (void)methodB3:(NSString *)str num:(double)num rect:(CGRect)rect { 70 | 71 | } 72 | 73 | - (NSString *)methodA4 { 74 | return @""; 75 | } 76 | 77 | - (NSString *)methodB4 { 78 | return @""; 79 | } 80 | 81 | - (NSString *)methodA5:(NSString *)str num:(double)num rect:(CGRect)rect { 82 | return @""; 83 | } 84 | 85 | - (NSString *)methodB5:(NSString *)str num:(double)num rect:(CGRect)rect { 86 | return @""; 87 | } 88 | 89 | - (NSString *)methodC:(NSString *)str { 90 | return [str stringByAppendingFormat:@"xx"]; 91 | } 92 | 93 | - (NSString *)methodD:(NSString *)str { 94 | return [str stringByAppendingFormat:@"xx"]; 95 | } 96 | 97 | @end 98 | 99 | @interface PerformanceTests : XCTestCase 100 | 101 | @end 102 | 103 | 104 | @implementation PerformanceTests 105 | 106 | 107 | - (void)testaBlankMethod { 108 | [self measureBlock:^{ 109 | for (NSInteger i = 0; i < 1000000; i++) { 110 | 111 | } 112 | }]; 113 | } 114 | 115 | - (void)testMethodA { 116 | TestClassC *object1 = [TestClassC new]; 117 | [self measureBlock:^{ 118 | for (NSInteger i = 0; i < 1000000; i++) { 119 | [object1 methodBeforeA]; 120 | [object1 methodA]; 121 | [object1 methodAfterA]; 122 | } 123 | }]; 124 | } 125 | 126 | - (void)testStingerHookMethodA1 { 127 | [TestClassC st_hookInstanceMethod:@selector(methodA1) option:STOptionBefore usingIdentifier:@"hook methodA1 before" withBlock:^(id params) { 128 | }]; 129 | [TestClassC st_hookInstanceMethod:@selector(methodA1) option:STOptionAfter usingIdentifier:@"hook methodA1 After" withBlock:^(id params) { 130 | }]; 131 | 132 | TestClassC *object1 = [TestClassC new]; 133 | [self measureBlock:^{ 134 | for (NSInteger i = 0; i < 1000000; i++) { 135 | [object1 methodA1]; 136 | } 137 | }]; 138 | } 139 | 140 | - (void)testAspectHookMethodB1 { 141 | [TestClassC aspect_hookSelector:@selector(methodB1) withOptions:AspectPositionBefore usingBlock:^(id params) { 142 | } error:nil]; 143 | [TestClassC aspect_hookSelector:@selector(methodB1) withOptions:AspectPositionAfter usingBlock:^(id params) { 144 | } error:nil]; 145 | 146 | TestClassC *object1 = [TestClassC new]; 147 | [self measureBlock:^{ 148 | for (NSInteger i = 0; i < 1000000; i++) { 149 | [object1 methodB1]; 150 | } 151 | }]; 152 | } 153 | 154 | - (void)testStingerHookMethodA2 { 155 | TestClassC *object1 = [TestClassC new]; 156 | [object1 st_hookInstanceMethod:@selector(methodA2) option:STOptionBefore usingIdentifier:@"hook methodA2 before" withBlock:^(id params) { 157 | }]; 158 | [object1 st_hookInstanceMethod:@selector(methodA2) option:STOptionAfter usingIdentifier:@"hook methodA2 After" withBlock:^(id params) { 159 | }]; 160 | 161 | [self measureBlock:^{ 162 | for (NSInteger i = 0; i < 1000000; i++) { 163 | [object1 methodA2]; 164 | } 165 | }]; 166 | } 167 | 168 | - (void)testAspectHookMethodB2 { 169 | TestClassC *object1 = [TestClassC new]; 170 | [object1 aspect_hookSelector:@selector(methodB2) withOptions:AspectPositionBefore usingBlock:^(id params) { 171 | } error:nil]; 172 | [object1 aspect_hookSelector:@selector(methodB2) withOptions:AspectPositionAfter usingBlock:^(id params) { 173 | } error:nil]; 174 | 175 | [self measureBlock:^{ 176 | for (NSInteger i = 0; i < 1000000; i++) { 177 | [object1 methodB2]; 178 | } 179 | }]; 180 | } 181 | 182 | 183 | - (void)testOne { 184 | [self measureBlock:^{ 185 | for (NSInteger i = 0; i < 1000000; i++) { 186 | NSString *str = @""; 187 | double num = 0.1; 188 | CGRect rect = CGRectMake(1, 1, 1.1, 1.1); 189 | } 190 | }]; 191 | } 192 | 193 | 194 | - (void)testMethodA3 { 195 | [TestClassC st_hookInstanceMethod:@selector(methodA3:num:rect:) option:STOptionBefore usingIdentifier:@"hook methodA3 before" withBlock:^(id params, NSString *str, double num, CGRect rect) { 196 | }]; 197 | [TestClassC st_hookInstanceMethod:@selector(methodA3:num:rect:) option:STOptionAfter usingIdentifier:@"hook methodA3 After" withBlock:^(id params, NSString *str, double num, CGRect rect) { 198 | }]; 199 | 200 | TestClassC *object1 = [TestClassC new]; 201 | NSString *str = @""; 202 | double num = 0.1; 203 | CGRect rect = CGRectMake(1, 1, 1.1, 1.1); 204 | [self measureBlock:^{ 205 | for (NSInteger i = 0; i < 1000000; i++) { 206 | [object1 methodA3:str num:num rect:rect]; 207 | } 208 | }]; 209 | } 210 | 211 | 212 | 213 | - (void)testMethodB3 { 214 | [TestClassC aspect_hookSelector:@selector(methodB3:num:rect:) withOptions:AspectPositionBefore usingBlock:^(id params, NSString *str, double num, CGRect rect) { 215 | } error:nil]; 216 | [TestClassC aspect_hookSelector:@selector(methodB3:num:rect:) withOptions:AspectPositionAfter usingBlock:^(id params, NSString *str, double num, CGRect rect) { 217 | } error:nil]; 218 | 219 | TestClassC *object1 = [TestClassC new]; 220 | NSString *str = @""; 221 | double num = 0.1; 222 | CGRect rect = CGRectMake(1, 1, 1.1, 1.1); 223 | [self measureBlock:^{ 224 | for (NSInteger i = 0; i < 1000000; i++) { 225 | [object1 methodB3:str num:num rect:rect]; 226 | } 227 | }]; 228 | } 229 | 230 | 231 | - (void)testMethodA4 { 232 | [TestClassC st_hookInstanceMethod:@selector(methodA4) option:STOptionBefore usingIdentifier:@"hook methodA4 before" withBlock:^(id params) { 233 | }]; 234 | [TestClassC st_hookInstanceMethod:@selector(methodA4) option:STOptionAfter usingIdentifier:@"hook methodA4 After" withBlock:^(id params) { 235 | }]; 236 | 237 | TestClassC *object1 = [TestClassC new]; 238 | [self measureBlock:^{ 239 | for (NSInteger i = 0; i < 1000000; i++) { 240 | [object1 methodA4]; 241 | } 242 | }]; 243 | } 244 | 245 | 246 | - (void)testMethodB4 { 247 | [TestClassC aspect_hookSelector:@selector(methodB4) withOptions:AspectPositionBefore usingBlock:^(id params) { 248 | } error:nil]; 249 | [TestClassC aspect_hookSelector:@selector(methodB4) withOptions:AspectPositionAfter usingBlock:^(id params) { 250 | } error:nil]; 251 | 252 | TestClassC *object1 = [TestClassC new]; 253 | [self measureBlock:^{ 254 | for (NSInteger i = 0; i < 1000000; i++) { 255 | [object1 methodB4]; 256 | } 257 | }]; 258 | } 259 | 260 | 261 | - (void)testMethodA5 { 262 | [TestClassC st_hookInstanceMethod:@selector(methodA5:num:rect:) option:STOptionBefore usingIdentifier:@"hook methodA5 before" withBlock:^(id params, NSString *str, double num, CGRect rect) { 263 | }]; 264 | [TestClassC st_hookInstanceMethod:@selector(methodA5:num:rect:) option:STOptionAfter usingIdentifier:@"hook methodA5 After" withBlock:^(id params, NSString *str, double num, CGRect rect) { 265 | }]; 266 | 267 | TestClassC *object1 = [TestClassC new]; 268 | NSString *str = @""; 269 | double num = 0.1; 270 | CGRect rect = CGRectMake(1, 1, 1.1, 1.1); 271 | [self measureBlock:^{ 272 | for (NSInteger i = 0; i < 1000000; i++) { 273 | [object1 methodA5:str num:num rect:rect]; 274 | } 275 | }]; 276 | } 277 | 278 | 279 | - (void)testMethodB5 { 280 | [TestClassC aspect_hookSelector:@selector(methodB5:num:rect:) withOptions:AspectPositionBefore usingBlock:^(id params, NSString *str, double num, CGRect rect) { 281 | } error:nil]; 282 | [TestClassC aspect_hookSelector:@selector(methodB5:num:rect:) withOptions:AspectPositionAfter usingBlock:^(id params, NSString *str, double num, CGRect rect) { 283 | } error:nil]; 284 | 285 | TestClassC *object1 = [TestClassC new]; 286 | NSString *str = @""; 287 | double num = 0.1; 288 | CGRect rect = CGRectMake(1, 1, 1.1, 1.1); 289 | [self measureBlock:^{ 290 | for (NSInteger i = 0; i < 1000000; i++) { 291 | [object1 methodB5:str num:num rect:rect]; 292 | } 293 | }]; 294 | } 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | - (void)testStingerHookMethodC { 304 | TestClassC *object1 = [TestClassC new]; 305 | __block NSString *oldRet, *ret; 306 | [TestClassC st_hookInstanceMethod:@selector(methodC:) option:STOptionInstead usingIdentifier:@"hook methodC instead" withBlock:^NSString *(id params, NSString *str) { 307 | [params invokeAndGetOriginalRetValue:&oldRet]; 308 | ret = [oldRet stringByAppendingFormat:@"++"]; 309 | return ret; 310 | }]; 311 | 312 | __block NSString *result; 313 | [self measureBlock:^{ 314 | for (NSInteger i = 0; i < 1000000; i++) { 315 | result = [object1 methodC:@""]; 316 | } 317 | }]; 318 | } 319 | 320 | - (void)testAspectHookMethodD { 321 | __block NSString *oldRet, *ret; 322 | [TestClassC aspect_hookSelector:@selector(methodD:) withOptions:AspectPositionInstead usingBlock:^(id params, NSString *str) { 323 | [params.originalInvocation invoke]; 324 | [params.originalInvocation getReturnValue:&oldRet]; 325 | ret = [oldRet stringByAppendingFormat:@"++"]; 326 | [params.originalInvocation setReturnValue:&ret]; 327 | } error:nil]; 328 | 329 | TestClassC *object1 = [TestClassC new]; 330 | __block NSString *result; 331 | [self measureBlock:^{ 332 | for (NSInteger i = 0; i < 1000000; i++) { 333 | result = [object1 methodD:@""]; 334 | } 335 | }]; 336 | } 337 | @end 338 | -------------------------------------------------------------------------------- /framework/Stinger/Example/Pods/Aspects/README.md: -------------------------------------------------------------------------------- 1 | Aspects v1.4.1 [![Build Status](https://travis-ci.org/steipete/Aspects.svg?branch=master)](https://travis-ci.org/steipete/Aspects) 2 | ============== 3 | 4 | Delightful, simple library for aspect oriented programming by [@steipete](http://twitter.com/steipete). 5 | 6 | **Think of Aspects as method swizzling on steroids. It allows you to add code to existing methods per class or per instance**, whilst thinking of the insertion point e.g. before/instead/after. Aspects automatically deals with calling super and is easier to use than regular method swizzling. 7 | 8 | This is stable and used in hundreds of apps since it's part of [PSPDFKit, an iOS PDF framework that ships with apps like Dropbox or Evernote](http://pspdfkit.com), and now I finally made it open source. 9 | 10 | Aspects extends `NSObject` with the following methods: 11 | 12 | ``` objc 13 | /// Adds a block of code before/instead/after the current `selector` for a specific class. 14 | /// 15 | /// @param block Aspects replicates the type signature of the method being hooked. 16 | /// The first parameter will be `id`, followed by all parameters of the method. 17 | /// These parameters are optional and will be filled to match the block signature. 18 | /// You can even use an empty block, or one that simple gets `id`. 19 | /// 20 | /// @note Hooking static methods is not supported. 21 | /// @return A token which allows to later deregister the aspect. 22 | + (id)aspect_hookSelector:(SEL)selector 23 | withOptions:(AspectOptions)options 24 | usingBlock:(id)block 25 | error:(NSError **)error; 26 | 27 | /// Adds a block of code before/instead/after the current `selector` for a specific instance. 28 | - (id)aspect_hookSelector:(SEL)selector 29 | withOptions:(AspectOptions)options 30 | usingBlock:(id)block 31 | error:(NSError **)error; 32 | 33 | /// Deregister an aspect. 34 | /// @return YES if deregistration is successful, otherwise NO. 35 | id aspect = ...; 36 | [aspect remove]; 37 | ``` 38 | 39 | Adding aspects returns an opaque token of type `AspectToken` which can be used to deregister again. All calls are thread-safe. 40 | 41 | Aspects uses Objective-C message forwarding to hook into messages. This will create some overhead. Don't add aspects to methods that are called a lot. Aspects is meant for view/controller code that is not called 1000 times per second. 42 | 43 | Aspects calls and matches block arguments. Blocks without arguments are supported as well. The first block argument will be of type `id`. 44 | 45 | When to use Aspects 46 | ------------------- 47 | Aspect-oritented programming (AOP) is used to encapsulate "cross-cutting" concerns. These are the kind of requirements that *cut-accross* many modules in your system, and so cannot be encapsulated using normal Object Oriented programming. Some examples of these kinds of requirements: 48 | 49 | * *Whenever* a user invokes a method on the service client, security should be checked. 50 | * *Whenever* a useer interacts with the store, a genius suggestion should be presented, based on their interaction. 51 | * *All* calls should be logged. 52 | 53 | If we implemented the above requirements using regular OO there'd be some drawbacks: 54 | 55 | 56 | Good OO says a class should have a single responsibility, however adding on extra *cross-cutting* requirements means a class that is taking on other responsibilites. For example you might have a **StoreClient** that supposed to be all about making purchases from an online store. Add in some cross-cutting requirements and it might also have to take on the roles of logging, security and recommendations. This is not great: 57 | 58 | * Our StoreClient is now harder to understand and maintain. 59 | * These cross-cutting requirements are duplicated and spreading throughout our app. 60 | 61 | AOP lets us modularize these cross-cutting requirements, and then cleanly identify all of the places they should be applied. As shown in the examples above cross-cutting requirements can be eithe technical or business focused in nature. 62 | 63 | ## Here are some concrete examples: 64 | 65 | 66 | Aspects can be used to **dynamically add logging** for debug builds only: 67 | 68 | ``` objc 69 | [UIViewController aspect_hookSelector:@selector(viewWillAppear:) withOptions:AspectPositionAfter usingBlock:^(id aspectInfo, BOOL animated) { 70 | NSLog(@"View Controller %@ will appear animated: %tu", aspectInfo.instance, animated); 71 | } error:NULL]; 72 | ``` 73 | 74 | ------------------- 75 | It can be used to greatly simplify your analytics setup: 76 | https://github.com/orta/ARAnalytics 77 | 78 | ------------------- 79 | You can check if methods are really being called in your test cases: 80 | ``` objc 81 | - (void)testExample { 82 | TestClass *testClass = [TestClass new]; 83 | TestClass *testClass2 = [TestClass new]; 84 | 85 | __block BOOL testCallCalled = NO; 86 | [testClass aspect_hookSelector:@selector(testCall) withOptions:AspectPositionAfter usingBlock:^{ 87 | testCallCalled = YES; 88 | } error:NULL]; 89 | 90 | [testClass2 testCallAndExecuteBlock:^{ 91 | [testClass testCall]; 92 | } error:NULL]; 93 | XCTAssertTrue(testCallCalled, @"Calling testCallAndExecuteBlock must call testCall"); 94 | } 95 | ``` 96 | ------------------- 97 | It can be really useful for debugging. Here I was curious when exactly the tap gesture changed state: 98 | 99 | ``` objc 100 | [_singleTapGesture aspect_hookSelector:@selector(setState:) withOptions:AspectPositionAfter usingBlock:^(id aspectInfo) { 101 | NSLog(@"%@: %@", aspectInfo.instance, aspectInfo.arguments); 102 | } error:NULL]; 103 | ``` 104 | 105 | ------------------- 106 | Another convenient use case is adding handlers for classes that you don't own. I've written it for use in [PSPDFKit](http://pspdfkit.com), where we require notifications when a view controller is being dismissed modally. This includes UIKit view controllers like `MFMailComposeViewController` or `UIImagePickerController`. We could have created subclasses for each of these controllers, but this would be quite a lot of unnecessary code. Aspects gives you a simpler solution for this problem: 107 | 108 | ``` objc 109 | @implementation UIViewController (DismissActionHook) 110 | 111 | // Will add a dismiss action once the controller gets dismissed. 112 | - (void)pspdf_addWillDismissAction:(void (^)(void))action { 113 | PSPDFAssert(action != NULL); 114 | 115 | [self aspect_hookSelector:@selector(viewWillDisappear:) withOptions:AspectPositionAfter usingBlock:^(id aspectInfo) { 116 | if ([aspectInfo.instance isBeingDismissed]) { 117 | action(); 118 | } 119 | } error:NULL]; 120 | } 121 | 122 | @end 123 | ``` 124 | 125 | Debugging 126 | --------- 127 | Aspects identifies itself nicely in the stack trace, so it's easy to see if a method has been hooked: 128 | 129 | 130 | 131 | Using Aspects with non-void return types 132 | ---------------------------------------- 133 | 134 | You can use the invocation object to customize the return value: 135 | 136 | ``` objc 137 | [PSPDFDrawView aspect_hookSelector:@selector(shouldProcessTouches:withEvent:) withOptions:AspectPositionInstead usingBlock:^(id info, NSSet *touches, UIEvent *event) { 138 | // Call original implementation. 139 | BOOL processTouches; 140 | NSInvocation *invocation = info.originalInvocation; 141 | [invocation invoke]; 142 | [invocation getReturnValue:&processTouches]; 143 | 144 | if (processTouches) { 145 | processTouches = pspdf_stylusShouldProcessTouches(touches, event); 146 | [invocation setReturnValue:&processTouches]; 147 | } 148 | } error:NULL]; 149 | ``` 150 | 151 | Installation 152 | ------------ 153 | The simplest option is to use `pod "Aspects"`. 154 | 155 | You can also add the two files `Aspects.h/m`. There are no further requirements. 156 | 157 | Compatibility and Limitations 158 | ----------------------------- 159 | Aspects uses quite some runtime trickery to achieve what it does. You can mostly mix this with regular method swizzling. 160 | 161 | An important limitation is that for class-based hooking, a method can only be hooked once within the subclass hierarchy. [See #2](https://github.com/steipete/Aspects/issues/2) 162 | This does not apply for objects that are hooked. Aspects creates a dynamic subclass here and has full control. 163 | 164 | KVO works if observers are created after your calls `aspect_hookSelector:` It most likely will crash the other way around. 165 | Still looking for workarounds here - any help apprechiated. 166 | 167 | Because of ugly implementation details on the ObjC runtime, methods that return unions that also contain structs might not work correctly unless this code runs on the arm64 runtime. 168 | 169 | Credits 170 | ------- 171 | The idea to use `_objc_msgForward` and parts of the `NSInvocation` argument selection is from the excellent [ReactiveCocoa](https://github.com/ReactiveCocoa/ReactiveCocoa) from the GitHub guys. [This article](http://codeshaker.blogspot.co.at/2012/01/aop-delivered.html) explains how it works under the hood. 172 | 173 | 174 | Supported iOS & SDK Versions 175 | ----------------------------- 176 | 177 | * Aspects requires ARC. 178 | * Aspects is tested with iOS 6+ and OS X 10.7 or higher. 179 | 180 | License 181 | ------- 182 | MIT licensed, Copyright (c) 2014 Peter Steinberger, steipete@gmail.com, [@steipete](http://twitter.com/steipete) 183 | 184 | 185 | Release Notes 186 | ----------------- 187 | 188 | Version 1.4.1 189 | 190 | - Rename error codes. 191 | 192 | Version 1.4.0 193 | 194 | - Add support for block signatures that match method signatures. (thanks to @nickynick) 195 | 196 | Version 1.3.1 197 | 198 | - Add support for OS X 10.7 or higher. (thanks to @ashfurrow) 199 | 200 | Version 1.3.0 201 | 202 | - Add automatic deregistration. 203 | - Checks if the selector exists before trying to hook. 204 | - Improved dealloc hooking. (no more unsafe_unretained needed) 205 | - Better examples. 206 | - Always log errors. 207 | 208 | Version 1.2.0 209 | 210 | - Adds error parameter. 211 | - Improvements in subclassing registration tracking. 212 | 213 | Version 1.1.0 214 | 215 | - Renamed the files from NSObject+Aspects.m/h to just Aspects.m/h. 216 | - Removing now works via calling `remove` on the aspect token. 217 | - Allow hooking dealloc. 218 | - Fixes infinite loop if the same method is hooked for multiple classes. Hooking will only work for one class in the hierarchy. 219 | - Additional checks to prevent things like hooking retain/release/autorelease or forwardInvocation: 220 | - The original implementation of forwardInvocation is now correctly preserved. 221 | - Classes are properly cleaned up and restored to the original state after the last hook is deregistered. 222 | - Lots and lots of new test cases! 223 | 224 | Version 1.0.1 225 | 226 | - Minor tweaks and documentation improvements. 227 | 228 | Version 1.0.0 229 | 230 | - Initial release 231 | --------------------------------------------------------------------------------