diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8164d74 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +dkVideoPlayer/dkVideoPlayer.xcodeproj/project.xcworkspace +dkVideoPlayer/dkVideoPlayer.xcodeproj/xcuserdata +dkVideoPlayer/Packages +dkvideoLoader/dkvideoLoader/TargetApp/ECAJIUZLO.app +dkvideoLoader/dkvideoLoader.xcodeproj/xcuserdata +dkvideoLoader/dkvideoLoader.xcodeproj/project.xcworkspace +LatestBuild diff --git a/01.PNG b/01.PNG new file mode 100644 index 0000000..04f6921 Binary files /dev/null and b/01.PNG differ diff --git a/02.PNG b/02.PNG new file mode 100644 index 0000000..cb679a0 Binary files /dev/null and b/02.PNG differ diff --git a/03.jpg b/03.jpg new file mode 100644 index 0000000..b4aaa27 Binary files /dev/null and b/03.jpg differ diff --git a/README.md b/README.md index ff7f32b..56ad484 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,45 @@ -# DKVideoPlayer -一款直播或视频类APP插件 +DKVideoPlayer +=== +一款可以获取视频类APP和直播类APP播放地址的插件。 + + **更多介绍[前往查看📲](iosre.com/t/%E4%BB%8A%E5%A4%A9%E5%85%A8%E5%9C%BA%E7%9A%84%E6%B6%88%E8%B4%B9%E7%94%B1%E8%B5%B5%E5%85%AC%E5%AD%90%E4%B9%B0%E5%8D%95%EF%BC%81/22005)** + +#### 可以做什么? +本项目支持大部分🔞视频类APP和直播类APP, + * [x] 获取播放地址直接播放视频。 + * [x] 解除直播录屏限制 + * [x] 获取直播rtmp地址 + * [x] 在原应用内播放限制视频 + * [x] 一键复制视频地址 + * [x] 自定义选择需要注入应用 + * [x] 一次安装多APP同时注入 + + #### 支持那些应用: + 大部分视频类APP和直播类APP,具体前往issue查看或添加 [前往查看📲](https://github.com/DKJone/DKVideoPlayer/issues/1) + +#### 安装方式(越狱): + * [x] [越狱安装📲](./dkVideoPlayer) + * [x] [非越狱安装📲](./dkvideoLoader) +#### 使用方法 +**非越狱跳过第1、2步** +1、在设置中找到 dkvideoPlayer 打开你需要注入的应用开关 + +| 设置 | 开关 | +|:-:|:-:| +|![设置](./01.PNG)|![开关](./02.PNG)| + +2、重新打开需要注入的应用,看到和系统辅助触控类似的小白点按钮表示注入成功 + +3、点击需要观看的视频或者直播间,点击小白点-解析视频即可打开自定义播放页面无限制播放直播或视频,并可截图或录屏、需要退出自定义播放器可以点击小白点-退出解析 +![解析](./03.jpg) + +4、复制视频地址:点击小白点-复制地址或者解析视频后点击最上方复制地址按钮 + +5、切换播放的服务器地址,仅对视频类应用有用,直播类服务器地址无法更换 + + + + + + + diff --git a/dkVideoPlayer/README.md b/dkVideoPlayer/README.md new file mode 100644 index 0000000..ebc26b9 --- /dev/null +++ b/dkVideoPlayer/README.md @@ -0,0 +1,55 @@ +DKVideoPlayer +=== +一款可以获取视频类APP和直播类APP播放地址的插件。 + + **更多介绍[前往查看📲](iosre.com/t/%E4%BB%8A%E5%A4%A9%E5%85%A8%E5%9C%BA%E7%9A%84%E6%B6%88%E8%B4%B9%E7%94%B1%E8%B5%B5%E5%85%AC%E5%AD%90%E4%B9%B0%E5%8D%95%EF%BC%81/22005)** + +#### 可以做什么? +本项目支持大部分🔞视频类APP和直播类APP, + * [x] 获取播放地址直接播放视频。 + * [x] 解除直播录屏限制 + * [x] 获取直播rtmp地址 + * [x] 在原应用内播放限制视频 + * [x] 一键复制视频地址 + * [x] 自定义选择需要注入应用 + * [x] 一次安装多APP同时注入 + + #### 支持那些应用: + 大部分视频类APP和直播类APP,具体前往issue查看或添加 [前往查看📲](https://github.com/DKJone/DKVideoPlayer/issues/1) + +#### 安装方式(越狱): +##### 一:源代码安装 + 下载本项目使用xcode安装到越狱手机,需要安装monkeyDev + +##### 二:添加越狱源安装 + 添加`https://dkjone.github.io`到Cydia或者sileo,选择dkVideoPlayer安装 + 注意:本插件越狱安装时需要依赖 `PreferenceLoader`和`AppList` ,请确保先安装了这两个依赖库 + +##### 三:下载deb文件安装 +[网盘下载 deb-0.1.0](https://url15.ctfile.com/f/24576815-863624277-4b1308?p=dkjone) + +#### 使用方法 +1、在设置中找到 dkvideoPlayer 打开你需要注入的应用开关 + +| 设置 | 开关 | +|:-:|:-:| +|![设置](../01.PNG)|![开关](../02.PNG)| + + + + +2、重新打开需要注入的应用,看到和系统辅助触控类似的小白点按钮表示注入成功 + +3、点击需要观看的视频或者直播间,点击小白点-解析视频即可打开自定义播放页面无限制播放直播或视频,并可截图或录屏、需要退出自定义播放器可以点击小白点-退出解析 +![解析](../03.jpg) + +4、复制视频地址:点击小白点-复制地址或者解析视频后点击最上方复制地址按钮 + +5、切换播放的服务器地址,仅对视频类应用有用,直播类服务器地址无法更换 + + + + + + + diff --git a/dkVideoPlayer/dkVideoPlayer.xcodeproj/project.pbxproj b/dkVideoPlayer/dkVideoPlayer.xcodeproj/project.pbxproj new file mode 100644 index 0000000..2ba6c7f --- /dev/null +++ b/dkVideoPlayer/dkVideoPlayer.xcodeproj/project.pbxproj @@ -0,0 +1,416 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + 117259B72A136235003E45D5 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 117259B62A136235003E45D5 /* UIKit.framework */; }; + 117259B92A136235003E45D5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 117259B82A136235003E45D5 /* Foundation.framework */; }; + 117259BB2A136235003E45D5 /* CydiaSubstrate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 117259BA2A136235003E45D5 /* CydiaSubstrate.framework */; }; + 117259C42A136235003E45D5 /* dkVideoPlayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 117259C32A136235003E45D5 /* dkVideoPlayer.mm */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 117259B32A136235003E45D5 /* dkVideoPlayer.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = dkVideoPlayer.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; + 117259B62A136235003E45D5 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 117259B82A136235003E45D5 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 117259BA2A136235003E45D5 /* CydiaSubstrate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CydiaSubstrate.framework; path = Library/Frameworks/CydiaSubstrate.framework; sourceTree = DEVELOPER_DIR; }; + 117259BF2A136235003E45D5 /* control */ = {isa = PBXFileReference; lastKnownFileType = text; path = control; sourceTree = ""; }; + 117259C12A136235003E45D5 /* dkVideoPlayer-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "dkVideoPlayer-Prefix.pch"; path = "../dkVideoPlayer-Prefix.pch"; sourceTree = ""; }; + 117259C22A136235003E45D5 /* dkVideoPlayer.xm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; path = dkVideoPlayer.xm; sourceTree = ""; }; + 117259C32A136235003E45D5 /* dkVideoPlayer.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = dkVideoPlayer.mm; sourceTree = ""; }; + 117259C82A136235003E45D5 /* dkVideoPlayer.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = dkVideoPlayer.plist; sourceTree = ""; }; + 11A65C432A1DAEDA00A60CBF /* info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = info.plist; sourceTree = ""; }; + 11A65D2F2A1DDB6100A60CBF /* icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon.png; sourceTree = ""; }; + 11A65D302A1DDB6100A60CBF /* icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon@2x.png"; sourceTree = ""; }; + 11A65D312A1DDB6100A60CBF /* icon@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon@3x.png"; sourceTree = ""; }; + 11A65D322A1DDB6100A60CBF /* dkVideoPlayer.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = dkVideoPlayer.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 117259AF2A136235003E45D5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 117259B72A136235003E45D5 /* UIKit.framework in Frameworks */, + 117259B92A136235003E45D5 /* Foundation.framework in Frameworks */, + 117259BB2A136235003E45D5 /* CydiaSubstrate.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 117259A82A136235003E45D5 = { + isa = PBXGroup; + children = ( + 117259BC2A136235003E45D5 /* dkVideoPlayer */, + 117259B52A136235003E45D5 /* Frameworks */, + 117259B42A136235003E45D5 /* Products */, + ); + sourceTree = ""; + }; + 117259B42A136235003E45D5 /* Products */ = { + isa = PBXGroup; + children = ( + 117259B32A136235003E45D5 /* dkVideoPlayer.dylib */, + ); + name = Products; + sourceTree = ""; + }; + 117259B52A136235003E45D5 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 117259B62A136235003E45D5 /* UIKit.framework */, + 117259B82A136235003E45D5 /* Foundation.framework */, + 117259BA2A136235003E45D5 /* CydiaSubstrate.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 117259BC2A136235003E45D5 /* dkVideoPlayer */ = { + isa = PBXGroup; + children = ( + 11A65C432A1DAEDA00A60CBF /* info.plist */, + 117259C22A136235003E45D5 /* dkVideoPlayer.xm */, + 117259C32A136235003E45D5 /* dkVideoPlayer.mm */, + 117259BD2A136235003E45D5 /* Package */, + 117259C02A136235003E45D5 /* Supporting Files */, + ); + path = dkVideoPlayer; + sourceTree = ""; + }; + 117259BD2A136235003E45D5 /* Package */ = { + isa = PBXGroup; + children = ( + 117259BE2A136235003E45D5 /* DEBIAN */, + 117259C52A136235003E45D5 /* Library */, + ); + path = Package; + sourceTree = ""; + }; + 117259BE2A136235003E45D5 /* DEBIAN */ = { + isa = PBXGroup; + children = ( + 117259BF2A136235003E45D5 /* control */, + ); + path = DEBIAN; + sourceTree = ""; + }; + 117259C02A136235003E45D5 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 117259C12A136235003E45D5 /* dkVideoPlayer-Prefix.pch */, + ); + path = "Supporting Files"; + sourceTree = ""; + }; + 117259C52A136235003E45D5 /* Library */ = { + isa = PBXGroup; + children = ( + 11A65D2D2A1DDB6100A60CBF /* PreferenceLoader */, + 117259C62A136235003E45D5 /* MobileSubstrate */, + ); + path = Library; + sourceTree = ""; + }; + 117259C62A136235003E45D5 /* MobileSubstrate */ = { + isa = PBXGroup; + children = ( + 117259C72A136235003E45D5 /* DynamicLibraries */, + ); + path = MobileSubstrate; + sourceTree = ""; + }; + 117259C72A136235003E45D5 /* DynamicLibraries */ = { + isa = PBXGroup; + children = ( + 117259C82A136235003E45D5 /* dkVideoPlayer.plist */, + ); + path = DynamicLibraries; + sourceTree = ""; + }; + 11A65D2D2A1DDB6100A60CBF /* PreferenceLoader */ = { + isa = PBXGroup; + children = ( + 11A65D2E2A1DDB6100A60CBF /* Preferences */, + ); + path = PreferenceLoader; + sourceTree = ""; + }; + 11A65D2E2A1DDB6100A60CBF /* Preferences */ = { + isa = PBXGroup; + children = ( + 11A65D2F2A1DDB6100A60CBF /* icon.png */, + 11A65D302A1DDB6100A60CBF /* icon@2x.png */, + 11A65D312A1DDB6100A60CBF /* icon@3x.png */, + 11A65D322A1DDB6100A60CBF /* dkVideoPlayer.plist */, + ); + path = Preferences; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 117259B02A136235003E45D5 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 117259B22A136235003E45D5 /* dkVideoPlayer */ = { + isa = PBXNativeTarget; + buildConfigurationList = 117259CB2A136235003E45D5 /* Build configuration list for PBXNativeTarget "dkVideoPlayer" */; + buildPhases = ( + 117259AD2A136235003E45D5 /* ShellScript */, + 117259AE2A136235003E45D5 /* Sources */, + 117259AF2A136235003E45D5 /* Frameworks */, + 117259B02A136235003E45D5 /* Headers */, + 117259B12A136235003E45D5 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = dkVideoPlayer; + productName = dkVideoPlayer; + productReference = 117259B32A136235003E45D5 /* dkVideoPlayer.dylib */; + productType = "com.apple.product-type.library.dynamic"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 117259A92A136235003E45D5 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastUpgradeCheck = 1420; + TargetAttributes = { + 117259B22A136235003E45D5 = { + CreatedOnToolsVersion = 14.2; + }; + }; + }; + buildConfigurationList = 117259AC2A136235003E45D5 /* Build configuration list for PBXProject "dkVideoPlayer" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 117259A82A136235003E45D5; + productRefGroup = 117259B42A136235003E45D5 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 117259B22A136235003E45D5 /* dkVideoPlayer */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXShellScriptBuildPhase section */ + 117259AD2A136235003E45D5 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/opt/MonkeyDev/bin/md --xcbp-logos"; + }; + 117259B12A136235003E45D5 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/opt/MonkeyDev/bin/md --xcbp"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 117259AE2A136235003E45D5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 117259C42A136235003E45D5 /* dkVideoPlayer.mm in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 117259C92A136235003E45D5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + EXCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES = "*.nib *.lproj *.gch (*) .DS_Store CVS .svn .git .hg *.xcodeproj *.xcode *.pbproj *.pbxproj"; + FRAMEWORK_SEARCH_PATHS = ( + "$(MonkeyDevPath)/frameworks/**", + "$(MonkeyDevTheosPath)/vendor/lib", + ); + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = "$(MonkeyDevTheosPath)/vendor/include/**"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LIBRARY_SEARCH_PATHS = "$(MonkeyDevTheosPath)/vendor/lib/**"; + MonkeyDevPath = /opt/MonkeyDev; + MonkeyDevTheosPath = /opt/theos; + OTHER_CFLAGS = "-DTHEOS_INSTANCE_NAME=\"\\\"dkVideoPlayer\\\"\""; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 117259CA2A136235003E45D5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + EXCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES = "*.nib *.lproj *.gch (*) .DS_Store CVS .svn .git .hg *.xcodeproj *.xcode *.pbproj *.pbxproj"; + FRAMEWORK_SEARCH_PATHS = ( + "$(MonkeyDevPath)/frameworks/**", + "$(MonkeyDevTheosPath)/vendor/lib", + ); + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = "$(MonkeyDevTheosPath)/vendor/include/**"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LIBRARY_SEARCH_PATHS = "$(MonkeyDevTheosPath)/vendor/lib/**"; + MonkeyDevPath = /opt/MonkeyDev; + MonkeyDevTheosPath = /opt/theos; + ONLY_ACTIVE_ARCH = YES; + OTHER_CFLAGS = "-DTHEOS_INSTANCE_NAME=\"\\\"dkVideoPlayer\\\"\""; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = NO; + }; + name = Debug; + }; + 117259CC2A136235003E45D5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_ARC = YES; + CODE_SIGNING_ALLOWED = NO; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = NL54V6A3P5; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "dkVideoPlayer/dkVideoPlayer-Prefix.pch"; + INFOPLIST_FILE = "$(SRCROOT)/dkVideoPlayer/info.plist"; + INSTALL_PATH = /Library/MobileSubstrate/DynamicLibraries; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MARKETING_VERSION = 0.0.1; + MonkeyDevBuildPackageOnAnyBuild = NO; + MonkeyDevClearUiCacheOnInstall = NO; + MonkeyDevCopyOnBuild = NO; + MonkeyDevDeviceIP = 127.0.0.1; + MonkeyDevDevicePassword = alpine; + MonkeyDevDevicePort = 2222; + MonkeyDevInstallOnAnyBuild = YES; + MonkeyDevInstallOnProfiling = YES; + MonkeyDevkillProcessOnInstall = SpringBoard; + PRODUCT_BUNDLE_IDENTIFIER = com.dkjone.dkVideoPlayer; + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTS_MACCATALYST = NO; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 117259CD2A136235003E45D5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_ARC = YES; + CODE_SIGNING_ALLOWED = NO; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = NL54V6A3P5; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "dkVideoPlayer/dkVideoPlayer-Prefix.pch"; + INFOPLIST_FILE = "$(SRCROOT)/dkVideoPlayer/info.plist"; + INSTALL_PATH = /Library/MobileSubstrate/DynamicLibraries; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MARKETING_VERSION = 0.0.1; + MonkeyDevBuildPackageOnAnyBuild = NO; + MonkeyDevClearUiCacheOnInstall = NO; + MonkeyDevCopyOnBuild = NO; + MonkeyDevDeviceIP = 127.0.0.1; + MonkeyDevDevicePassword = alpine; + MonkeyDevDevicePort = 2222; + MonkeyDevInstallOnAnyBuild = YES; + MonkeyDevInstallOnProfiling = YES; + MonkeyDevkillProcessOnInstall = SpringBoard; + PRODUCT_BUNDLE_IDENTIFIER = com.dkjone.dkVideoPlayer; + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTS_MACCATALYST = NO; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 117259AC2A136235003E45D5 /* Build configuration list for PBXProject "dkVideoPlayer" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 117259C92A136235003E45D5 /* Release */, + 117259CA2A136235003E45D5 /* Debug */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 117259CB2A136235003E45D5 /* Build configuration list for PBXNativeTarget "dkVideoPlayer" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 117259CC2A136235003E45D5 /* Release */, + 117259CD2A136235003E45D5 /* Debug */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 117259A92A136235003E45D5 /* Project object */; +} diff --git a/dkVideoPlayer/dkVideoPlayer/Package/DEBIAN/control b/dkVideoPlayer/dkVideoPlayer/Package/DEBIAN/control new file mode 100644 index 0000000..69246bf --- /dev/null +++ b/dkVideoPlayer/dkVideoPlayer/Package/DEBIAN/control @@ -0,0 +1,17 @@ +Package: com.dkjone.dkVideoPlayer +Name: dkVideoPlayer +Version: 0.1.0-1 +Description: +Section: System +Depends: firmware (>= 5.0), mobilesubstrate +Conflicts: +Replaces: +Priority: optional +Architecture: iphoneos-arm +Author: DKJone +dev: +Homepage: +Depiction: +Maintainer: +Icon: + diff --git a/dkVideoPlayer/dkVideoPlayer/Package/Library/Application Support/DKVideoLoader/libDKVideo.dylib b/dkVideoPlayer/dkVideoPlayer/Package/Library/Application Support/DKVideoLoader/libDKVideo.dylib new file mode 100755 index 0000000..ee19539 Binary files /dev/null and b/dkVideoPlayer/dkVideoPlayer/Package/Library/Application Support/DKVideoLoader/libDKVideo.dylib differ diff --git a/dkVideoPlayer/dkVideoPlayer/Package/Library/MobileSubstrate/DynamicLibraries/dkVideoPlayer.dylib b/dkVideoPlayer/dkVideoPlayer/Package/Library/MobileSubstrate/DynamicLibraries/dkVideoPlayer.dylib new file mode 100755 index 0000000..bba49fd Binary files /dev/null and b/dkVideoPlayer/dkVideoPlayer/Package/Library/MobileSubstrate/DynamicLibraries/dkVideoPlayer.dylib differ diff --git a/dkVideoPlayer/dkVideoPlayer/Package/Library/MobileSubstrate/DynamicLibraries/dkVideoPlayer.plist b/dkVideoPlayer/dkVideoPlayer/Package/Library/MobileSubstrate/DynamicLibraries/dkVideoPlayer.plist new file mode 100644 index 0000000..9211921 --- /dev/null +++ b/dkVideoPlayer/dkVideoPlayer/Package/Library/MobileSubstrate/DynamicLibraries/dkVideoPlayer.plist @@ -0,0 +1,13 @@ + + + + + Filter + + Bundles + + com.apple.UIKit + + + + diff --git a/dkVideoPlayer/dkVideoPlayer/Package/Library/PreferenceLoader/Preferences/dkVideoPlayer.plist b/dkVideoPlayer/dkVideoPlayer/Package/Library/PreferenceLoader/Preferences/dkVideoPlayer.plist new file mode 100644 index 0000000..0308e6c --- /dev/null +++ b/dkVideoPlayer/dkVideoPlayer/Package/Library/PreferenceLoader/Preferences/dkVideoPlayer.plist @@ -0,0 +1,30 @@ +entry = { + bundle = AppList; + cell = PSLinkCell; + icon = "/Library/PreferenceLoader/Preferences/icon.png"; + isController = 1; + label = DKVideoPlayer; + ALSettingsPath = "/var/mobile/Library/Preferences/com.dkjone.dkplayer.plist"; + ALSettingsKeyPrefix = "DKVideoEnable--"; + ALChangeNotification = "com.dkjone.dkplayer.settingschanged"; + ALSettingsDefaultValue = 0; + ALSectionDescriptors = ( + + { + title = "用户应用"; + predicate = "(isSystemApplication = FALSE)"; + "cell-class-name" = "ALSwitchCell"; + "icon-size" = 29; + "suppress-hidden-apps" = 1; + + }, + { + title = "越狱/系统 应用"; + predicate = "(isSystemApplication = TRUE)"; + "cell-class-name" = "ALSwitchCell"; + "icon-size" = 29; + "suppress-hidden-apps" = 1; + "footer-title" = "© buginux create for flexloader"; + } + ); +}; diff --git a/dkVideoPlayer/dkVideoPlayer/Package/Library/PreferenceLoader/Preferences/icon.png b/dkVideoPlayer/dkVideoPlayer/Package/Library/PreferenceLoader/Preferences/icon.png new file mode 100644 index 0000000..f1f49aa Binary files /dev/null and b/dkVideoPlayer/dkVideoPlayer/Package/Library/PreferenceLoader/Preferences/icon.png differ diff --git a/dkVideoPlayer/dkVideoPlayer/Package/Library/PreferenceLoader/Preferences/icon@2x.png b/dkVideoPlayer/dkVideoPlayer/Package/Library/PreferenceLoader/Preferences/icon@2x.png new file mode 100644 index 0000000..c0e068f Binary files /dev/null and b/dkVideoPlayer/dkVideoPlayer/Package/Library/PreferenceLoader/Preferences/icon@2x.png differ diff --git a/dkVideoPlayer/dkVideoPlayer/Package/Library/PreferenceLoader/Preferences/icon@3x.png b/dkVideoPlayer/dkVideoPlayer/Package/Library/PreferenceLoader/Preferences/icon@3x.png new file mode 100644 index 0000000..9b22710 Binary files /dev/null and b/dkVideoPlayer/dkVideoPlayer/Package/Library/PreferenceLoader/Preferences/icon@3x.png differ diff --git a/dkVideoPlayer/dkVideoPlayer/dkVideoPlayer-Prefix.pch b/dkVideoPlayer/dkVideoPlayer/dkVideoPlayer-Prefix.pch new file mode 100644 index 0000000..cb39fbf --- /dev/null +++ b/dkVideoPlayer/dkVideoPlayer/dkVideoPlayer-Prefix.pch @@ -0,0 +1,8 @@ +// +// Prefix header for all source files of the 'dkVideoPlayer' target in the 'dkVideoPlayer' project +// + +#ifdef __OBJC__ + #import + #import "/opt/theos/Prefix.pch" //path/to/theos/Prefix.pch +#endif diff --git a/dkVideoPlayer/dkVideoPlayer/dkVideoPlayer.mm b/dkVideoPlayer/dkVideoPlayer/dkVideoPlayer.mm new file mode 100644 index 0000000..7a53122 --- /dev/null +++ b/dkVideoPlayer/dkVideoPlayer/dkVideoPlayer.mm @@ -0,0 +1,64 @@ +#line 1 "/Users/zhudekun/mycode/test/AppHooker/dkVideoPlayer/dkVideoPlayer/dkVideoPlayer.xm" + + +#if TARGET_OS_SIMULATOR +#error Do not support the simulator, please use the real iPhone Device. +#endif + +#import +#import +#import + +@interface AssistiveTouch:UIWindow ++ (instancetype)shared; +@end + + +@interface DKVideoLoader: NSObject +@end + +@implementation DKVideoLoader + ++ (instancetype)sharedInstance { + static dispatch_once_t onceToken; + static DKVideoLoader *loader; + dispatch_once(&onceToken, ^{ + loader = [[DKVideoLoader alloc] init]; + }); + + return loader; +} + +- (void)show { + + [[objc_getClass("AssistiveTouch") shared] setHidden:NO]; +} + +@end + +static __attribute__((constructor)) void _logosLocalCtor_3b47fc20(int __unused argc, char __unused **argv, char __unused **envp) { + + + NSDictionary *pref = [NSDictionary dictionaryWithContentsOfFile:@"/var/mobile/Library/Preferences/com.dkjone.dkplayer.plist"]; + NSString *dylibPath = @"/Library/Application Support/DKVideoLoader/libDKVideo.dylib"; + + if (![[NSFileManager defaultManager] fileExistsAtPath:dylibPath]) { + NSLog(@"DKVideoLoader dylib file not found: %@", dylibPath); + return; + } + + NSString *keyPath = [NSString stringWithFormat:@"DKVideoEnable--%@", [[NSBundle mainBundle] bundleIdentifier]]; + if ([[pref objectForKey:keyPath] boolValue]) { + void *handle = dlopen([dylibPath UTF8String], RTLD_NOW); + if (handle == NULL) { + char *error = dlerror(); + return; + } + + [[NSNotificationCenter defaultCenter] addObserver:[DKVideoLoader sharedInstance] + selector:@selector(show) + name:UIApplicationDidBecomeActiveNotification + object:nil]; + } + +} diff --git a/dkVideoPlayer/dkVideoPlayer/dkVideoPlayer.xm b/dkVideoPlayer/dkVideoPlayer/dkVideoPlayer.xm new file mode 100644 index 0000000..4a441c3 --- /dev/null +++ b/dkVideoPlayer/dkVideoPlayer/dkVideoPlayer.xm @@ -0,0 +1,63 @@ +// See http://iphonedevwiki.net/index.php/Logos + +#if TARGET_OS_SIMULATOR +#error Do not support the simulator, please use the real iPhone Device. +#endif + +#import +#import +#import + +@interface AssistiveTouch:UIWindow ++ (instancetype)shared; +@end + + +@interface DKVideoLoader: NSObject +@end + +@implementation DKVideoLoader + ++ (instancetype)sharedInstance { + static dispatch_once_t onceToken; + static DKVideoLoader *loader; + dispatch_once(&onceToken, ^{ + loader = [[DKVideoLoader alloc] init]; + }); + + return loader; +} + +- (void)show { + + [[objc_getClass("AssistiveTouch") shared] setHidden:NO]; +} + +@end + +%ctor { + + + NSDictionary *pref = [NSDictionary dictionaryWithContentsOfFile:@"/var/mobile/Library/Preferences/com.dkjone.dkplayer.plist"]; + NSString *dylibPath = @"/Library/Application Support/DKVideoLoader/libDKVideo.dylib"; + + if (![[NSFileManager defaultManager] fileExistsAtPath:dylibPath]) { + NSLog(@"DKVideoLoader dylib file not found: %@", dylibPath); + return; + } + + NSString *keyPath = [NSString stringWithFormat:@"DKVideoEnable--%@", [[NSBundle mainBundle] bundleIdentifier]]; + if ([[pref objectForKey:keyPath] boolValue]) { + void *handle = dlopen([dylibPath UTF8String], RTLD_NOW); + if (handle == NULL) { + char *error = dlerror(); + return; + } + + [[NSNotificationCenter defaultCenter] addObserver:[DKVideoLoader sharedInstance] + selector:@selector(show) + name:UIApplicationDidBecomeActiveNotification + object:nil]; + } + +} diff --git a/dkVideoPlayer/dkVideoPlayer/info.plist b/dkVideoPlayer/dkVideoPlayer/info.plist new file mode 100644 index 0000000..47fad32 --- /dev/null +++ b/dkVideoPlayer/dkVideoPlayer/info.plist @@ -0,0 +1,8 @@ + + + + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + + diff --git a/dkvideoLoader/README.md b/dkvideoLoader/README.md new file mode 100644 index 0000000..30451f5 --- /dev/null +++ b/dkvideoLoader/README.md @@ -0,0 +1,39 @@ +DKVideoPlayer +=== +一款可以获取视频类APP和直播类APP播放地址的插件。 + + **更多介绍[前往查看📲](iosre.com/t/%E4%BB%8A%E5%A4%A9%E5%85%A8%E5%9C%BA%E7%9A%84%E6%B6%88%E8%B4%B9%E7%94%B1%E8%B5%B5%E5%85%AC%E5%AD%90%E4%B9%B0%E5%8D%95%EF%BC%81/22005)** + +#### 可以做什么? +本项目支持大部分🔞视频类APP和直播类APP, + * [x] 获取播放地址直接播放视频。 + * [x] 解除直播录屏限制 + * [x] 获取直播rtmp地址 + * [x] 在原应用内播放限制视频 + * [x] 一键复制视频地址 + + #### 支持那些应用: + 大部分视频类APP和直播类APP,具体前往issue查看或添加 [前往查看📲](https://github.com/DKJone/DKVideoPlayer/issues/1) + +#### 安装方式(非越狱): + +将下载已脱壳的应用放到'/dkvideoLoader/dkvideoLoader/TargetApp/'目录下该目录下有一个空白文件’put ipa or app here‘,和它放在同一文件夹下即可,修改项目BundleId及签名信息,选择真机设备运行即可 +其他方式可以参考[DKWechatHelper](https://github.com/DKJone/DKWechatHelper) +#### 使用方法 +**非越狱跳过第1、2步** +~~1、在设置中找到 dkvideoPlayer 打开你需要注入的应用开关~~ +~~2、重新打开需要注入的应用,看到和系统辅助触控类似的小白点按钮表示注入成功~~ + +3、点击需要观看的视频或者直播间,点击小白点-解析视频即可打开自定义播放页面无限制播放直播或视频,并可截图或录屏、需要退出自定义播放器可以点击小白点-退出解析 +![解析](../03.jpg) + +4、复制视频地址:点击小白点-复制地址或者解析视频后点击最上方复制地址按钮 + +5、切换播放的服务器地址,仅对视频类应用有用,直播类服务器地址无法更换 + + + + + + + diff --git a/dkvideoLoader/dkvideoLoader.xcodeproj/project.pbxproj b/dkvideoLoader/dkvideoLoader.xcodeproj/project.pbxproj new file mode 100644 index 0000000..24438cf --- /dev/null +++ b/dkvideoLoader/dkvideoLoader.xcodeproj/project.pbxproj @@ -0,0 +1,812 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + 11FB94512A28700A0050200A /* MDConfig.plist in Resources */ = {isa = PBXBuildFile; fileRef = 11FB94502A28700A0050200A /* MDConfig.plist */; }; + 11FB945B2A28700A0050200A /* libdkvideoLoaderDylib.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = 11FB945A2A28700A0050200A /* libdkvideoLoaderDylib.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 11FB94602A28700A0050200A /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 11FB945F2A28700A0050200A /* JavaScriptCore.framework */; }; + 11FB94622A28700A0050200A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 11FB94612A28700A0050200A /* Foundation.framework */; }; + 11FB94642A28700A0050200A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 11FB94632A28700A0050200A /* UIKit.framework */; }; + 11FB94692A28700A0050200A /* dkvideoLoaderDylib.mm in Sources */ = {isa = PBXBuildFile; fileRef = 11FB94682A28700A0050200A /* dkvideoLoaderDylib.mm */; }; + 11FB946C2A28700A0050200A /* MDConfigManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 11FB946B2A28700A0050200A /* MDConfigManager.h */; }; + 11FB946E2A28700A0050200A /* MDConfigManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 11FB946D2A28700A0050200A /* MDConfigManager.m */; }; + 11FB94702A28700A0050200A /* MDCycriptManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 11FB946F2A28700A0050200A /* MDCycriptManager.h */; }; + 11FB94722A28700A0050200A /* MDCycriptManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 11FB94712A28700A0050200A /* MDCycriptManager.m */; }; + 11FB94742A28700A0050200A /* MDMethodTrace.h in Headers */ = {isa = PBXBuildFile; fileRef = 11FB94732A28700A0050200A /* MDMethodTrace.h */; }; + 11FB94762A28700A0050200A /* MDMethodTrace.m in Sources */ = {isa = PBXBuildFile; fileRef = 11FB94752A28700A0050200A /* MDMethodTrace.m */; }; + 11FB94792A28700A0050200A /* a1a2-selectortramps-arm.s in Sources */ = {isa = PBXBuildFile; fileRef = 11FB94782A28700A0050200A /* a1a2-selectortramps-arm.s */; }; + 11FB947B2A28700A0050200A /* a1a2-selectortramps-arm64.s in Sources */ = {isa = PBXBuildFile; fileRef = 11FB947A2A28700A0050200A /* a1a2-selectortramps-arm64.s */; }; + 11FB947D2A28700A0050200A /* a1a2-selectortramps-i386.s in Sources */ = {isa = PBXBuildFile; fileRef = 11FB947C2A28700A0050200A /* a1a2-selectortramps-i386.s */; }; + 11FB947F2A28700A0050200A /* a1a2-selectortramps-x86_64.s in Sources */ = {isa = PBXBuildFile; fileRef = 11FB947E2A28700A0050200A /* a1a2-selectortramps-x86_64.s */; }; + 11FB94812A28700A0050200A /* a2a3-selectortramps-arm.s in Sources */ = {isa = PBXBuildFile; fileRef = 11FB94802A28700A0050200A /* a2a3-selectortramps-arm.s */; }; + 11FB94832A28700A0050200A /* a2a3-selectortramps-i386.s in Sources */ = {isa = PBXBuildFile; fileRef = 11FB94822A28700A0050200A /* a2a3-selectortramps-i386.s */; }; + 11FB94852A28700A0050200A /* a2a3-selectortramps-x86_64.s in Sources */ = {isa = PBXBuildFile; fileRef = 11FB94842A28700A0050200A /* a2a3-selectortramps-x86_64.s */; }; + 11FB94872A28700A0050200A /* OCMethodTrace.h in Headers */ = {isa = PBXBuildFile; fileRef = 11FB94862A28700A0050200A /* OCMethodTrace.h */; }; + 11FB94892A28700B0050200A /* OCMethodTrace.m in Sources */ = {isa = PBXBuildFile; fileRef = 11FB94882A28700A0050200A /* OCMethodTrace.m */; }; + 11FB948B2A28700B0050200A /* OCSelectorTrampolines.h in Headers */ = {isa = PBXBuildFile; fileRef = 11FB948A2A28700B0050200A /* OCSelectorTrampolines.h */; }; + 11FB948D2A28700B0050200A /* OCSelectorTrampolines.mm in Sources */ = {isa = PBXBuildFile; fileRef = 11FB948C2A28700B0050200A /* OCSelectorTrampolines.mm */; }; + 11FB94912A28700B0050200A /* LLDBTools.h in Headers */ = {isa = PBXBuildFile; fileRef = 11FB94902A28700B0050200A /* LLDBTools.h */; }; + 11FB94932A28700B0050200A /* LLDBTools.mm in Sources */ = {isa = PBXBuildFile; fileRef = 11FB94922A28700B0050200A /* LLDBTools.mm */; }; + 11FB94982A28700B0050200A /* AntiAntiDebug.m in Sources */ = {isa = PBXBuildFile; fileRef = 11FB94972A28700B0050200A /* AntiAntiDebug.m */; }; + 11FB949B2A28700B0050200A /* fishhook.c in Sources */ = {isa = PBXBuildFile; fileRef = 11FB949A2A28700B0050200A /* fishhook.c */; }; + 11FB949D2A28700B0050200A /* fishhook.h in Headers */ = {isa = PBXBuildFile; fileRef = 11FB949C2A28700B0050200A /* fishhook.h */; }; + 11FB949F2A28700B0050200A /* dkvideoLoaderDylib.h in Headers */ = {isa = PBXBuildFile; fileRef = 11FB949E2A28700B0050200A /* dkvideoLoaderDylib.h */; }; + 11FB94A12A28700B0050200A /* dkvideoLoaderDylib.m in Sources */ = {isa = PBXBuildFile; fileRef = 11FB94A02A28700B0050200A /* dkvideoLoaderDylib.m */; }; + 11FB94B52A288FDE0050200A /* libDKVideo.dylib in Resources */ = {isa = PBXBuildFile; fileRef = 11FB94B32A288F590050200A /* libDKVideo.dylib */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 11FB945C2A28700A0050200A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 11FB943E2A28700A0050200A /* Project object */; + proxyType = 1; + remoteGlobalIDString = 11FB94592A28700A0050200A; + remoteInfo = dkvideoLoaderDylib; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 11FB94462A28700A0050200A /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 11FB945B2A28700A0050200A /* libdkvideoLoaderDylib.dylib in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 11FB94492A28700A0050200A /* dkvideoLoader.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = dkvideoLoader.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 11FB944C2A28700A0050200A /* icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon.png; sourceTree = ""; }; + 11FB944E2A28700A0050200A /* quick-resign.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "quick-resign.sh"; sourceTree = ""; }; + 11FB94502A28700A0050200A /* MDConfig.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = MDConfig.plist; sourceTree = ""; }; + 11FB94532A28700A0050200A /* put ipa or app here */ = {isa = PBXFileReference; lastKnownFileType = text; path = "put ipa or app here"; sourceTree = ""; }; + 11FB94542A28700A0050200A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 11FB945A2A28700A0050200A /* libdkvideoLoaderDylib.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libdkvideoLoaderDylib.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; + 11FB945F2A28700A0050200A /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; + 11FB94612A28700A0050200A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 11FB94632A28700A0050200A /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 11FB94672A28700A0050200A /* dkvideoLoaderDylib.xm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; path = dkvideoLoaderDylib.xm; sourceTree = ""; }; + 11FB94682A28700A0050200A /* dkvideoLoaderDylib.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = dkvideoLoaderDylib.mm; sourceTree = ""; }; + 11FB946B2A28700A0050200A /* MDConfigManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MDConfigManager.h; sourceTree = ""; }; + 11FB946D2A28700A0050200A /* MDConfigManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MDConfigManager.m; sourceTree = ""; }; + 11FB946F2A28700A0050200A /* MDCycriptManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MDCycriptManager.h; sourceTree = ""; }; + 11FB94712A28700A0050200A /* MDCycriptManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MDCycriptManager.m; sourceTree = ""; }; + 11FB94732A28700A0050200A /* MDMethodTrace.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MDMethodTrace.h; sourceTree = ""; }; + 11FB94752A28700A0050200A /* MDMethodTrace.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MDMethodTrace.m; sourceTree = ""; }; + 11FB94782A28700A0050200A /* a1a2-selectortramps-arm.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = "a1a2-selectortramps-arm.s"; sourceTree = ""; }; + 11FB947A2A28700A0050200A /* a1a2-selectortramps-arm64.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = "a1a2-selectortramps-arm64.s"; sourceTree = ""; }; + 11FB947C2A28700A0050200A /* a1a2-selectortramps-i386.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = "a1a2-selectortramps-i386.s"; sourceTree = ""; }; + 11FB947E2A28700A0050200A /* a1a2-selectortramps-x86_64.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = "a1a2-selectortramps-x86_64.s"; sourceTree = ""; }; + 11FB94802A28700A0050200A /* a2a3-selectortramps-arm.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = "a2a3-selectortramps-arm.s"; sourceTree = ""; }; + 11FB94822A28700A0050200A /* a2a3-selectortramps-i386.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = "a2a3-selectortramps-i386.s"; sourceTree = ""; }; + 11FB94842A28700A0050200A /* a2a3-selectortramps-x86_64.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = "a2a3-selectortramps-x86_64.s"; sourceTree = ""; }; + 11FB94862A28700A0050200A /* OCMethodTrace.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OCMethodTrace.h; sourceTree = ""; }; + 11FB94882A28700A0050200A /* OCMethodTrace.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OCMethodTrace.m; sourceTree = ""; }; + 11FB948A2A28700B0050200A /* OCSelectorTrampolines.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OCSelectorTrampolines.h; sourceTree = ""; }; + 11FB948C2A28700B0050200A /* OCSelectorTrampolines.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = OCSelectorTrampolines.mm; sourceTree = ""; }; + 11FB948E2A28700B0050200A /* selectortramps.mac */ = {isa = PBXFileReference; lastKnownFileType = text; path = selectortramps.mac; sourceTree = ""; }; + 11FB94902A28700B0050200A /* LLDBTools.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LLDBTools.h; sourceTree = ""; }; + 11FB94922A28700B0050200A /* LLDBTools.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = LLDBTools.mm; sourceTree = ""; }; + 11FB94952A28700B0050200A /* dkvideoLoaderDylib-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "dkvideoLoaderDylib-Prefix.pch"; path = "../dkvideoLoaderDylib-Prefix.pch"; sourceTree = ""; }; + 11FB94972A28700B0050200A /* AntiAntiDebug.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AntiAntiDebug.m; sourceTree = ""; }; + 11FB949A2A28700B0050200A /* fishhook.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = fishhook.c; sourceTree = ""; }; + 11FB949C2A28700B0050200A /* fishhook.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = fishhook.h; sourceTree = ""; }; + 11FB949E2A28700B0050200A /* dkvideoLoaderDylib.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dkvideoLoaderDylib.h; sourceTree = ""; }; + 11FB94A02A28700B0050200A /* dkvideoLoaderDylib.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = dkvideoLoaderDylib.m; sourceTree = ""; }; + 11FB94B32A288F590050200A /* libDKVideo.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = libDKVideo.dylib; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 11FB94432A28700A0050200A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 11FB94572A28700A0050200A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 11FB94602A28700A0050200A /* JavaScriptCore.framework in Frameworks */, + 11FB94642A28700A0050200A /* UIKit.framework in Frameworks */, + 11FB94622A28700A0050200A /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 11FB943D2A28700A0050200A = { + isa = PBXGroup; + children = ( + 11FB944B2A28700A0050200A /* dkvideoLoader */, + 11FB94652A28700A0050200A /* dkvideoLoaderDylib */, + 11FB945E2A28700A0050200A /* Frameworks */, + 11FB944A2A28700A0050200A /* Products */, + ); + sourceTree = ""; + }; + 11FB944A2A28700A0050200A /* Products */ = { + isa = PBXGroup; + children = ( + 11FB94492A28700A0050200A /* dkvideoLoader.app */, + 11FB945A2A28700A0050200A /* libdkvideoLoaderDylib.dylib */, + ); + name = Products; + sourceTree = ""; + }; + 11FB944B2A28700A0050200A /* dkvideoLoader */ = { + isa = PBXGroup; + children = ( + 11FB944C2A28700A0050200A /* icon.png */, + 11FB94542A28700A0050200A /* Info.plist */, + 11FB944D2A28700A0050200A /* Scripts */, + 11FB944F2A28700A0050200A /* Config */, + 11FB94522A28700A0050200A /* TargetApp */, + ); + path = dkvideoLoader; + sourceTree = ""; + }; + 11FB944D2A28700A0050200A /* Scripts */ = { + isa = PBXGroup; + children = ( + 11FB944E2A28700A0050200A /* quick-resign.sh */, + ); + path = Scripts; + sourceTree = ""; + }; + 11FB944F2A28700A0050200A /* Config */ = { + isa = PBXGroup; + children = ( + 11FB94502A28700A0050200A /* MDConfig.plist */, + ); + path = Config; + sourceTree = ""; + }; + 11FB94522A28700A0050200A /* TargetApp */ = { + isa = PBXGroup; + children = ( + 11FB94532A28700A0050200A /* put ipa or app here */, + ); + path = TargetApp; + sourceTree = ""; + }; + 11FB945E2A28700A0050200A /* Frameworks */ = { + isa = PBXGroup; + children = ( + 11FB945F2A28700A0050200A /* JavaScriptCore.framework */, + 11FB94612A28700A0050200A /* Foundation.framework */, + 11FB94632A28700A0050200A /* UIKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 11FB94652A28700A0050200A /* dkvideoLoaderDylib */ = { + isa = PBXGroup; + children = ( + 11FB94B32A288F590050200A /* libDKVideo.dylib */, + 11FB949E2A28700B0050200A /* dkvideoLoaderDylib.h */, + 11FB94A02A28700B0050200A /* dkvideoLoaderDylib.m */, + 11FB94662A28700A0050200A /* Logos */, + 11FB946A2A28700A0050200A /* Config */, + 11FB94772A28700A0050200A /* Trace */, + 11FB948F2A28700B0050200A /* Tools */, + 11FB94962A28700B0050200A /* AntiAntiDebug */, + 11FB94992A28700B0050200A /* fishhook */, + 11FB94942A28700B0050200A /* Supporting Files */, + ); + path = dkvideoLoaderDylib; + sourceTree = ""; + }; + 11FB94662A28700A0050200A /* Logos */ = { + isa = PBXGroup; + children = ( + 11FB94672A28700A0050200A /* dkvideoLoaderDylib.xm */, + 11FB94682A28700A0050200A /* dkvideoLoaderDylib.mm */, + ); + path = Logos; + sourceTree = ""; + }; + 11FB946A2A28700A0050200A /* Config */ = { + isa = PBXGroup; + children = ( + 11FB946B2A28700A0050200A /* MDConfigManager.h */, + 11FB946D2A28700A0050200A /* MDConfigManager.m */, + 11FB946F2A28700A0050200A /* MDCycriptManager.h */, + 11FB94712A28700A0050200A /* MDCycriptManager.m */, + 11FB94732A28700A0050200A /* MDMethodTrace.h */, + 11FB94752A28700A0050200A /* MDMethodTrace.m */, + ); + path = Config; + sourceTree = ""; + }; + 11FB94772A28700A0050200A /* Trace */ = { + isa = PBXGroup; + children = ( + 11FB94782A28700A0050200A /* a1a2-selectortramps-arm.s */, + 11FB947A2A28700A0050200A /* a1a2-selectortramps-arm64.s */, + 11FB947C2A28700A0050200A /* a1a2-selectortramps-i386.s */, + 11FB947E2A28700A0050200A /* a1a2-selectortramps-x86_64.s */, + 11FB94802A28700A0050200A /* a2a3-selectortramps-arm.s */, + 11FB94822A28700A0050200A /* a2a3-selectortramps-i386.s */, + 11FB94842A28700A0050200A /* a2a3-selectortramps-x86_64.s */, + 11FB94862A28700A0050200A /* OCMethodTrace.h */, + 11FB94882A28700A0050200A /* OCMethodTrace.m */, + 11FB948A2A28700B0050200A /* OCSelectorTrampolines.h */, + 11FB948C2A28700B0050200A /* OCSelectorTrampolines.mm */, + 11FB948E2A28700B0050200A /* selectortramps.mac */, + ); + path = Trace; + sourceTree = ""; + }; + 11FB948F2A28700B0050200A /* Tools */ = { + isa = PBXGroup; + children = ( + 11FB94902A28700B0050200A /* LLDBTools.h */, + 11FB94922A28700B0050200A /* LLDBTools.mm */, + ); + path = Tools; + sourceTree = ""; + }; + 11FB94942A28700B0050200A /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 11FB94952A28700B0050200A /* dkvideoLoaderDylib-Prefix.pch */, + ); + path = "Supporting Files"; + sourceTree = ""; + }; + 11FB94962A28700B0050200A /* AntiAntiDebug */ = { + isa = PBXGroup; + children = ( + 11FB94972A28700B0050200A /* AntiAntiDebug.m */, + ); + path = AntiAntiDebug; + sourceTree = ""; + }; + 11FB94992A28700B0050200A /* fishhook */ = { + isa = PBXGroup; + children = ( + 11FB949A2A28700B0050200A /* fishhook.c */, + 11FB949C2A28700B0050200A /* fishhook.h */, + ); + path = fishhook; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 11FB94582A28700A0050200A /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 11FB94702A28700A0050200A /* MDCycriptManager.h in Headers */, + 11FB94742A28700A0050200A /* MDMethodTrace.h in Headers */, + 11FB949D2A28700B0050200A /* fishhook.h in Headers */, + 11FB949F2A28700B0050200A /* dkvideoLoaderDylib.h in Headers */, + 11FB94912A28700B0050200A /* LLDBTools.h in Headers */, + 11FB946C2A28700A0050200A /* MDConfigManager.h in Headers */, + 11FB948B2A28700B0050200A /* OCSelectorTrampolines.h in Headers */, + 11FB94872A28700A0050200A /* OCMethodTrace.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 11FB94482A28700A0050200A /* dkvideoLoader */ = { + isa = PBXNativeTarget; + buildConfigurationList = 11FB94A72A28700B0050200A /* Build configuration list for PBXNativeTarget "dkvideoLoader" */; + buildPhases = ( + 11FB94422A28700A0050200A /* Sources */, + 11FB94432A28700A0050200A /* Frameworks */, + 11FB94442A28700A0050200A /* ShellScript */, + 11FB94452A28700A0050200A /* Resources */, + 11FB94462A28700A0050200A /* CopyFiles */, + 11FB94472A28700A0050200A /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + 11FB945D2A28700A0050200A /* PBXTargetDependency */, + ); + name = dkvideoLoader; + productName = dkvideoLoader; + productReference = 11FB94492A28700A0050200A /* dkvideoLoader.app */; + productType = "com.apple.product-type.application"; + }; + 11FB94592A28700A0050200A /* dkvideoLoaderDylib */ = { + isa = PBXNativeTarget; + buildConfigurationList = 11FB94A42A28700B0050200A /* Build configuration list for PBXNativeTarget "dkvideoLoaderDylib" */; + buildPhases = ( + 11FB94552A28700A0050200A /* ShellScript */, + 11FB94562A28700A0050200A /* Sources */, + 11FB94572A28700A0050200A /* Frameworks */, + 11FB94582A28700A0050200A /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = dkvideoLoaderDylib; + productName = dkvideoLoaderDylib; + productReference = 11FB945A2A28700A0050200A /* libdkvideoLoaderDylib.dylib */; + productType = "com.apple.product-type.library.dynamic"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 11FB943E2A28700A0050200A /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastUpgradeCheck = 1420; + TargetAttributes = { + 11FB94482A28700A0050200A = { + CreatedOnToolsVersion = 14.2; + }; + 11FB94592A28700A0050200A = { + CreatedOnToolsVersion = 14.2; + }; + }; + }; + buildConfigurationList = 11FB94412A28700A0050200A /* Build configuration list for PBXProject "dkvideoLoader" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 11FB943D2A28700A0050200A; + productRefGroup = 11FB944A2A28700A0050200A /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 11FB94482A28700A0050200A /* dkvideoLoader */, + 11FB94592A28700A0050200A /* dkvideoLoaderDylib */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 11FB94452A28700A0050200A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 11FB94B52A288FDE0050200A /* libDKVideo.dylib in Resources */, + 11FB94512A28700A0050200A /* MDConfig.plist in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 11FB94442A28700A0050200A /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/opt/MonkeyDev/Tools/pack.sh\n"; + }; + 11FB94472A28700A0050200A /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/opt/MonkeyDev/Tools/pack.sh codesign"; + }; + 11FB94552A28700A0050200A /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/opt/MonkeyDev/bin/md --xcbp-logos"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 11FB94422A28700A0050200A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 11FB94562A28700A0050200A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 11FB94722A28700A0050200A /* MDCycriptManager.m in Sources */, + 11FB947B2A28700A0050200A /* a1a2-selectortramps-arm64.s in Sources */, + 11FB94792A28700A0050200A /* a1a2-selectortramps-arm.s in Sources */, + 11FB947F2A28700A0050200A /* a1a2-selectortramps-x86_64.s in Sources */, + 11FB94892A28700B0050200A /* OCMethodTrace.m in Sources */, + 11FB946E2A28700A0050200A /* MDConfigManager.m in Sources */, + 11FB949B2A28700B0050200A /* fishhook.c in Sources */, + 11FB94982A28700B0050200A /* AntiAntiDebug.m in Sources */, + 11FB948D2A28700B0050200A /* OCSelectorTrampolines.mm in Sources */, + 11FB947D2A28700A0050200A /* a1a2-selectortramps-i386.s in Sources */, + 11FB94832A28700A0050200A /* a2a3-selectortramps-i386.s in Sources */, + 11FB94812A28700A0050200A /* a2a3-selectortramps-arm.s in Sources */, + 11FB94692A28700A0050200A /* dkvideoLoaderDylib.mm in Sources */, + 11FB94A12A28700B0050200A /* dkvideoLoaderDylib.m in Sources */, + 11FB94932A28700B0050200A /* LLDBTools.mm in Sources */, + 11FB94852A28700A0050200A /* a2a3-selectortramps-x86_64.s in Sources */, + 11FB94762A28700A0050200A /* MDMethodTrace.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 11FB945D2A28700A0050200A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 11FB94592A28700A0050200A /* dkvideoLoaderDylib */; + targetProxy = 11FB945C2A28700A0050200A /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 11FB94A22A28700B0050200A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 11FB94A32A28700B0050200A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 11FB94A52A28700B0050200A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = NL54V6A3P5; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + ENABLE_BITCODE = NO; + EXCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES = "*.nib *.lproj *.gch (*) .DS_Store CVS .svn .git .hg *.xcodeproj *.xcode *.pbproj *.pbxproj"; + EXECUTABLE_PREFIX = lib; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(MonkeyDevPath)/Frameworks/**", + "$(MonkeyDevPath)/Librarys/**", + "$(MonkeyDevTheosPath)/vendor/lib", + ); + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "dkvideoLoaderDylib/dkvideoLoaderDylib-Prefix.pch"; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(MonkeyDevPath)/include", + "$(MonkeyDevTheosPath)/vendor/include/**", + ); + INSTALL_PATH = "@executable_path/Frameworks/libdkvideoLoaderDylib.dylib"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(MonkeyDevPath)/Frameworks", + "$(MonkeyDevTheosPath)/vendor/lib/**", + "$(PROJECT_DIR)/dkvideoLoaderDylib", + ); + MonkeyDevPath = /opt/MonkeyDev; + MonkeyDevTheosPath = /opt/theos; + OTHER_CFLAGS = ( + "$(inherited)", + "-DTHEOS_INSTANCE_NAME=\"\\\"dkvideoLoaderDylib\\\"\"", + ); + OTHER_LDFLAGS = ( + "$(inherited)", + "-weak_library", + "/usr/lib/libc++.dylib", + "-weak_library", + "/usr/lib/libstdc++.dylib", + "-weak_library", + "$(MonkeyDevPath)/Frameworks/libsubstrate.dylib", + "-lcycript", + "-framework", + RevealServer, + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = NO; + }; + name = Debug; + }; + 11FB94A62A28700B0050200A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = YES; + DEVELOPMENT_TEAM = NL54V6A3P5; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + ENABLE_BITCODE = NO; + EXCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES = "*.nib *.lproj *.gch (*) .DS_Store CVS .svn .git .hg *.xcodeproj *.xcode *.pbproj *.pbxproj"; + EXECUTABLE_PREFIX = lib; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(MonkeyDevPath)/Frameworks/**", + "$(MonkeyDevPath)/Librarys/**", + "$(MonkeyDevTheosPath)/vendor/lib", + ); + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "dkvideoLoaderDylib/dkvideoLoaderDylib-Prefix.pch"; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(MonkeyDevPath)/include", + "$(MonkeyDevTheosPath)/vendor/include/**", + ); + INSTALL_PATH = "@executable_path/Frameworks/libdkvideoLoaderDylib.dylib"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(MonkeyDevPath)/Frameworks", + "$(MonkeyDevTheosPath)/vendor/lib/**", + "$(PROJECT_DIR)/dkvideoLoaderDylib", + ); + MonkeyDevPath = /opt/MonkeyDev; + MonkeyDevTheosPath = /opt/theos; + OTHER_CFLAGS = ( + "$(inherited)", + "-DTHEOS_INSTANCE_NAME=\"\\\"dkvideoLoaderDylib\\\"\"", + ); + OTHER_LDFLAGS = ( + "$(inherited)", + "-weak_library", + "/usr/lib/libc++.dylib", + "-weak_library", + "/usr/lib/libstdc++.dylib", + "-weak_library", + "$(MonkeyDevPath)/Frameworks/libsubstrate.dylib", + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 11FB94A82A28700B0050200A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = NL54V6A3P5; + ENABLE_BITCODE = NO; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/dkvideoLoaderDylib", + ); + MARKETING_VERSION = 1.0; + MONKEYDEV_ADD_SUBSTRATE = YES; + MONKEYDEV_CLASS_DUMP = NO; + MONKEYDEV_DEFAULT_BUNDLEID = NO; + MONKEYDEV_INSERT_DYLIB = YES; + MONKEYDEV_RESTORE_SYMBOL = NO; + MONKEYDEV_TARGET_APP = Optional; + PODS_CONFIGURATION_BUILD_DIR = "$BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)"; + PODS_ROOT = "${SRCROOT}/Pods"; + PRODUCT_BUNDLE_IDENTIFIER = com.dkjone.dkvideoLoader; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 11FB94A92A28700B0050200A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = NL54V6A3P5; + ENABLE_BITCODE = NO; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/dkvideoLoaderDylib", + ); + MARKETING_VERSION = 1.0; + MONKEYDEV_ADD_SUBSTRATE = YES; + MONKEYDEV_CLASS_DUMP = NO; + MONKEYDEV_DEFAULT_BUNDLEID = NO; + MONKEYDEV_INSERT_DYLIB = YES; + MONKEYDEV_RESTORE_SYMBOL = NO; + MONKEYDEV_TARGET_APP = Optional; + PODS_CONFIGURATION_BUILD_DIR = "$BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)"; + PODS_ROOT = "${SRCROOT}/Pods"; + PRODUCT_BUNDLE_IDENTIFIER = com.dkjone.dkvideoLoader; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 11FB94412A28700A0050200A /* Build configuration list for PBXProject "dkvideoLoader" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 11FB94A22A28700B0050200A /* Debug */, + 11FB94A32A28700B0050200A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 11FB94A42A28700B0050200A /* Build configuration list for PBXNativeTarget "dkvideoLoaderDylib" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 11FB94A52A28700B0050200A /* Debug */, + 11FB94A62A28700B0050200A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 11FB94A72A28700B0050200A /* Build configuration list for PBXNativeTarget "dkvideoLoader" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 11FB94A82A28700B0050200A /* Debug */, + 11FB94A92A28700B0050200A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 11FB943E2A28700A0050200A /* Project object */; +} diff --git a/dkvideoLoader/dkvideoLoader/Config/MDConfig.plist b/dkvideoLoader/dkvideoLoader/Config/MDConfig.plist new file mode 100644 index 0000000..df9bacd --- /dev/null +++ b/dkvideoLoader/dkvideoLoader/Config/MDConfig.plist @@ -0,0 +1,208 @@ + + + + + MethodTrace + + LogLevel + 0 + LogWhen + 0 + LogRegexString + + TraceFlag + 2 + TraceObject + 0 + ClassRegexString + + CORE_CLASS_LIST + + MDConfigManager + + MDMethodTrace + + MDTraceClassInfo + + FastCoder + + NSManagedObject + + NSObject + + NSException + + NSTypesetter + + NSString + + NSCache + + NSPlaceholderString + + __NSCFString + + NSURL + + TraceMode + 0 + MethodBlackList + + isKindOfClass: + + + NSFont + + OS_object + + OS_xpc_object + + OS_dispatch_object + + OS_dispatch_queue + + NSSet + + NSOrderedSet + + __NSPlaceholderSet + + __NSPlaceholderOrderedSet + + NSMutableOrderedSet + + NSDictionary + + NSMutableDictionary + + __NSCFDictionary + + __NSDictionaryM + + __NSPlaceholderDictionary + + NSArray + + NSMutableArray + + __NSCFArray + + __NSArrayM + + __NSArrayI + + __NSPlaceholderArray + + NSDate + + __NSDate + + __NSPlaceholderDate + + NSNumber + + NSPlaceholderNumber + + NSPredicate + + NSRecursiveLock + + NSConcreteMapTable + + _UIPointVector + + NSConcreteHashTable + + FBSWorkspace + + FBSSerialQueue + + BSDescriptionBuilder + + FBSSceneImpl + + BSSettings + + FBSWorkspaceClient + + AVAudioSession + + + USER_CLASS_LIST + + BaseMsgContentViewController + + TraceMode + 1 + TraceFlag + 0 + MethodWhiteList + + MethodBlackList + + + CMessageMgr + + TraceMode + 2 + TraceFlag + 0 + MethodWhiteList + + AsyncOnAddMsg:MsgWrap: + onRevokeMsg: + + MethodBlackList + + + + + Cycript + + nslog + + LoadAtLaunch + + priority + 0 + content + NSLog = function() { var types = 'v', args = [], count = arguments.length; for (var i = 0; i != count; ++i) { types += '@'; args.push(arguments[i]); } new Functor(dlsym(RTLD_DEFAULT, "NSLog"), types).apply(null, args); } + + ms + + LoadAtLaunch + + priority + 1 + url + https://raw.githubusercontent.com/AloneMonkey/MDCycript/master/MS.cy + + hook + + LoadAtLaunch + + priority + 2 + content + try{ + var oldm = {}; + HookMessage(CustomViewController, @selector(showChangeLog:), function(log) { + NSLog("hooked by cycript!!!"); + return oldm->call(this,log); + }, oldm); +}catch(err){ + NSLog(err.toString()) +} + + md + + LoadAtLaunch + + priority + 3 + url + https://raw.githubusercontent.com/AloneMonkey/MDCycript/master/md.cy + + + + diff --git a/dkvideoLoader/dkvideoLoader/Info.plist b/dkvideoLoader/dkvideoLoader/Info.plist new file mode 100644 index 0000000..18478ed --- /dev/null +++ b/dkvideoLoader/dkvideoLoader/Info.plist @@ -0,0 +1,137 @@ + + + + + BuildMachineOSBuild + 21G531 + CFBundleDevelopmentRegion + en + CFBundleExecutable + ECAJIUZLO + CFBundleIconFiles + + dkvideoLoader/icon.png + + CFBundleIcons + + CFBundlePrimaryIcon + + CFBundleIconFiles + + AppIcon60x60 + + CFBundleIconName + AppIcon + + + CFBundleIcons~ipad + + CFBundlePrimaryIcon + + CFBundleIconFiles + + AppIcon60x60 + AppIcon76x76 + + CFBundleIconName + AppIcon + + + CFBundleIdentifier + com.dkjone.dkvideoLoader + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ECAJIUZLO + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0.8 + CFBundleSupportedPlatforms + + iPhoneOS + + CFBundleVersion + 5503 + DTAppStoreToolsBuild + 14E221 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 20C52 + DTPlatformName + iphoneos + DTPlatformVersion + 16.2 + DTSDKBuild + 20C52 + DTSDKName + iphoneos16.2 + DTXcode + 1420 + DTXcodeBuild + 14C18 + DTXcodeBuildDistribution + 14C18 + ITSDRMScheme + v2 + LSRequiresIPhoneOS + + MinimumOSVersion + 15.0 + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + NSAppleMusicUsageDescription + 当前应用想要访问媒体库 + NSCalendarsUsageDescription + 当前应用想要访问日历 + NSCameraUsageDescription + Access the camera to Take pictures to puzzle + NSContactsUsageDescription + 当前应用想要访问通讯录 + NSLocationAlwaysUsageDescription + 当前应用想要访问你的位置 + NSLocationWhenInUseUsageDescription + 当前应用想要访问你的位置 + NSMicrophoneUsageDescription + 当前应用想要访问麦克风 + NSMotionUsageDescription + 当前应用想要访问运动数据 + NSPhotoLibraryAddUsageDescription + 当前应用保存图片到相册 + NSPhotoLibraryUsageDescription + 当前应用想要访问相册 + NSSpeechRecognitionUsageDescription + 当前应用想要访问语言识别 + UIApplicationSupportsIndirectInputEvents + + UIDeviceFamily + + 1 + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + arm64 + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~iphone + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/dkvideoLoader/dkvideoLoader/Scripts/quick-resign.sh b/dkvideoLoader/dkvideoLoader/Scripts/quick-resign.sh new file mode 100755 index 0000000..c851be5 --- /dev/null +++ b/dkvideoLoader/dkvideoLoader/Scripts/quick-resign.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# Usage +# Must be an absolute path + +# ./quick-resign.sh [insert] "origin.ipa path" "resign.ipa path" + +INSERT_DYLIB=NO +INPUT_PATH=$1 +OUTPUT_PATH=$2 + +if [[ $1 == "insert" ]];then + INSERT_DYLIB=YES + INPUT_PATH=$2 + OUTPUT_PATH=$3 +fi + +if [[ ! $OUTPUT_PATH ]];then + OUTPUT_PATH=$PWD +fi + +cp -rf $INPUT_PATH ../TargetApp/ +cd ../../ +xcodebuild MONKEYDEV_INSERT_DYLIB=$INSERT_DYLIB | xcpretty +cd LatestBuild +./createIPA.command +cp -rf Target.ipa $OUTPUT_PATH +exit 0 \ No newline at end of file diff --git a/dkvideoLoader/dkvideoLoader/TargetApp/put ipa or app here b/dkvideoLoader/dkvideoLoader/TargetApp/put ipa or app here new file mode 100644 index 0000000..e69de29 diff --git a/dkvideoLoader/dkvideoLoader/icon.png b/dkvideoLoader/dkvideoLoader/icon.png new file mode 100644 index 0000000..7f323ec Binary files /dev/null and b/dkvideoLoader/dkvideoLoader/icon.png differ diff --git a/dkvideoLoader/dkvideoLoaderDylib/AntiAntiDebug/AntiAntiDebug.m b/dkvideoLoader/dkvideoLoaderDylib/AntiAntiDebug/AntiAntiDebug.m new file mode 100644 index 0000000..879578d --- /dev/null +++ b/dkvideoLoader/dkvideoLoaderDylib/AntiAntiDebug/AntiAntiDebug.m @@ -0,0 +1,108 @@ +// weibo: http://weibo.com/xiaoqing28 +// blog: http://www.alonemonkey.com +// +// AntiAntiDebug.m +// MonkeyDev +// +// Created by AloneMonkey on 2016/12/10. +// Copyright © 2017年 MonkeyDev. All rights reserved. +// + +#if TARGET_OS_SIMULATOR +#error Do not support the simulator, please use the real iPhone Device. +#endif + +#import "fishhook.h" +#import +#import + +typedef int (*ptrace_ptr_t)(int _request,pid_t _pid, caddr_t _addr,int _data); +typedef void* (*dlsym_ptr_t)(void * __handle, const char* __symbol); +typedef int (*syscall_ptr_t)(int, ...); +typedef int (*sysctl_ptr_t)(int *,u_int, void*, size_t*,void*, size_t); + + +static ptrace_ptr_t orig_ptrace = NULL; +static dlsym_ptr_t orig_dlsym = NULL; +static sysctl_ptr_t orig_sysctl = NULL; +static syscall_ptr_t orig_syscall = NULL; + +int my_ptrace(int _request, pid_t _pid, caddr_t _addr, int _data); +void* my_dlsym(void* __handle, const char* __symbol); +int my_sysctl(int * name, u_int namelen, void * info, size_t * infosize, void * newinfo, size_t newinfosize); +int my_syscall(int code, va_list args); + +int my_ptrace(int _request, pid_t _pid, caddr_t _addr, int _data){ + if(_request != 31){ + return orig_ptrace(_request,_pid,_addr,_data); + } + + NSLog(@"[AntiAntiDebug] - ptrace request is PT_DENY_ATTACH"); + + return 0; +} + +void* my_dlsym(void* __handle, const char* __symbol){ + if(strcmp(__symbol, "ptrace") != 0){ + return orig_dlsym(__handle, __symbol); + } + + NSLog(@"[AntiAntiDebug] - dlsym get ptrace symbol"); + + return my_ptrace; +} + +typedef struct kinfo_proc _kinfo_proc; + +int my_sysctl(int * name, u_int namelen, void * info, size_t * infosize, void * newinfo, size_t newinfosize){ + if(namelen == 4 && name[0] == CTL_KERN && name[1] == KERN_PROC && name[2] == KERN_PROC_PID && info && infosize && ((int)*infosize == sizeof(_kinfo_proc))){ + int ret = orig_sysctl(name, namelen, info, infosize, newinfo, newinfosize); + struct kinfo_proc *info_ptr = (struct kinfo_proc *)info; + if(info_ptr && (info_ptr->kp_proc.p_flag & P_TRACED) != 0){ + NSLog(@"[AntiAntiDebug] - sysctl query trace status."); + info_ptr->kp_proc.p_flag ^= P_TRACED; + if((info_ptr->kp_proc.p_flag & P_TRACED) == 0){ + NSLog(@"trace status reomve success!"); + } + } + return ret; + } + return orig_sysctl(name, namelen, info, infosize, newinfo, newinfosize); +} + +int my_syscall(int code, va_list args){ + int request; + va_list newArgs; + va_copy(newArgs, args); + if(code == 26){ +#ifdef __LP64__ + __asm__( + "ldr %w[result], [fp, #0x10]\n" + : [result] "=r" (request) + : + : + ); +#else + request = va_arg(args, int); +#endif + if(request == 31){ + NSLog(@"[AntiAntiDebug] - syscall call ptrace, and request is PT_DENY_ATTACH"); + return 0; + } + } + return orig_syscall(code, newArgs); +} + +__attribute__((constructor)) static void entry(){ + NSLog(@"[AntiAntiDebug Init]"); + + rebind_symbols((struct rebinding[1]){{"ptrace", my_ptrace, (void*)&orig_ptrace}},1); + + rebind_symbols((struct rebinding[1]){{"dlsym", my_dlsym, (void*)&orig_dlsym}},1); + + //some app will crash with _dyld_debugger_notification + // rebind_symbols((struct rebinding[1]){{"sysctl", my_sysctl, (void*)&orig_sysctl}},1); + + rebind_symbols((struct rebinding[1]){{"syscall", my_syscall, (void*)&orig_syscall}},1); +} + diff --git a/dkvideoLoader/dkvideoLoaderDylib/Config/MDConfigManager.h b/dkvideoLoader/dkvideoLoaderDylib/Config/MDConfigManager.h new file mode 100644 index 0000000..b33fa87 --- /dev/null +++ b/dkvideoLoader/dkvideoLoaderDylib/Config/MDConfigManager.h @@ -0,0 +1,85 @@ +// weibo: http://weibo.com/xiaoqing28 +// blog: http://www.alonemonkey.com +// +// MDConfigManager.h +// MonkeyDev +// +// Created by AloneMonkey on 2018/4/24. +// Copyright © 2018年 AloneMonkey. All rights reserved. +// + +#import + +#define MDCONFIG_CYCRIPT_KEY @"Cycript" +#define MDCONFIG_LOADATLAUNCH_KEY @"LoadAtLaunch" + +#define MDCONFIG_TRACE_KEY @"MethodTrace" +#define MDCONFIG_LOG_LEVEL_KEY @"LogLevel" +#define MDCONFIG_LOG_WHEN_KEY @"LogWhen" +#define MDCONFIG_LOG_REGEX_STRING_KEY @"LogRegexString" // 仅LogWhen=MDTraceLogWhenRegexString有效 +#define MDCONFIG_TRACE_FLAG_KEY @"TraceFlag" +#define MDCONFIG_TRACE_OBJECT_KEY @"TraceObject" +#define MDCONFIG_CLASS_REGEX_STRING_KEY @"ClassRegexString" // 仅TraceObject=MDTraceObjectRegexClass有效 +#define MDCONFIG_CORE_CLASS_LIST @"CORE_CLASS_LIST" +#define MDCONFIG_USER_CLASS_LIST @"USER_CLASS_LIST" +#define MDCONFIG_TRACE_MODE_KEY @"TraceMode" +#define MDCONFIG_METHOD_WHITE_LIST_KEY @"MethodWhiteList" +#define MDCONFIG_METHOD_BLACK_LIST_KEY @"MethodBlackList" + +// Trace日志级别 +typedef NS_ENUM(NSUInteger, MDTraceLogLevel) { + MDTraceLogLeveError = 0, // 错误 + MDTraceLogLeveDebug = 1, // 调试 + MDTraceLogLeveMax +}; + +// Trace日志输出时机 +typedef NS_ENUM(NSUInteger, MDTraceLogWhen) { + MDTraceLogWhenStartup = 0, // 启动即输出日志 + MDTraceLogWhenVolume = 1, // 根据音量键控制输出日志(增加音量:输出日志;降低音量:关闭日志;默认时关闭日志) + MDTraceLogWhenRegexString = 2, // 日志包含指定正则字符串才输出日志 + MDTraceLogWhenMax +}; + +// Trace控制位(尽量在该处扩展) +typedef NS_OPTIONS(NSUInteger, MDTraceFlag) { + MDTraceFlagDoesNotUseDescription = 1 << 0, // 跳过调用对象description方法,避免不正规的description实现导致递归 + MDTraceFlagDumpClassListInfo = 1 << 1, // 打印类列表信息,便于调试 + MDTraceFlagDumpClassMethod = 1 << 2, // 打印某个类的方法(不包括父类方法),便于调试 + MDTraceFlagDumpSuperClassMethod = 1 << 3, // 打印某个类的父类方法(包括递归父类的方法),便于调试 + MDTraceFlagMask = 0xF, + + MDTraceFlagDefault = 0, +}; + +// Trace对象 +typedef NS_ENUM(NSUInteger, MDTraceObject) { + // 屏蔽trace所有类 + MDTraceObjectNone = 0, + // trace引擎指定类的方法(仅测试验证使用),仅需要考虑CORE_CLASS_LIST + MDTraceObjectCoreClass = 1, + // trace用户指定类的方法,需要考虑USER_CLASS_LIST + "USER_CLASS_LIST和CORE_CLASS_LIST交集" + MDTraceObjectUserClass = 2, + // trace用户指定类 + 正则匹配类的方法,需要考虑USER_CLASS_LIST + "USER_CLASS_LIST和CORE_CLASS_LIST交集" + + // "匹配ClassRegexString的CLASS_LIST和CORE_CLASS_LIST交集" + MDTraceObjectRegexClass = 3, + + MDTraceObjectMax +}; + +// Trace模式 +typedef NS_ENUM(NSUInteger, MDTraceMode) { + MDTraceModeOff = 0, // 屏蔽trace方法 + MDTraceModeAll = 1, // trace所有方法 + MDTraceModeIncludeWhiteList = 2, // trace包含"白名单方法列表"的方法 + MDTraceModeExcludeBlackList = 3, // trace排除"黑名单方法列表"的方法 + MDTraceModeMax +}; + +@interface MDConfigManager : NSObject + ++ (instancetype)sharedInstance; + +- (NSDictionary*)readConfigByKey:(NSString*) key; + +@end diff --git a/dkvideoLoader/dkvideoLoaderDylib/Config/MDConfigManager.m b/dkvideoLoader/dkvideoLoaderDylib/Config/MDConfigManager.m new file mode 100644 index 0000000..58a1f4e --- /dev/null +++ b/dkvideoLoader/dkvideoLoaderDylib/Config/MDConfigManager.m @@ -0,0 +1,48 @@ +// weibo: http://weibo.com/xiaoqing28 +// blog: http://www.alonemonkey.com +// +// MDConfigManager.m +// MonkeyDev +// +// Created by AloneMonkey on 2018/4/24. +// Copyright © 2018年 AloneMonkey. All rights reserved. +// + +#define CONFIG_FILE_NAME @"MDConfig" + +#import "MDConfigManager.h" + +@implementation MDConfigManager{ + NSString* _filepath; +} + ++ (instancetype)sharedInstance{ + static MDConfigManager *sharedInstance = nil; + if (!sharedInstance){ + sharedInstance = [[MDConfigManager alloc] init]; + } + return sharedInstance; +} + +- (BOOL)isActive{ + _filepath = [[NSBundle mainBundle] pathForResource:CONFIG_FILE_NAME ofType:@"plist"]; + if(_filepath == nil){ + return NO; + } + return YES; +} + +- (NSDictionary*) readConfigByKey:(NSString*) key{ + if([self isActive]){ + NSDictionary* contentDict = [NSDictionary dictionaryWithContentsOfFile:_filepath]; + if([contentDict.allKeys containsObject:key]){ + return contentDict[key]; + }else{ + return nil; + } + }else{ + return nil; + } +} + +@end diff --git a/dkvideoLoader/dkvideoLoaderDylib/Config/MDCycriptManager.h b/dkvideoLoader/dkvideoLoaderDylib/Config/MDCycriptManager.h new file mode 100644 index 0000000..ff1e68c --- /dev/null +++ b/dkvideoLoader/dkvideoLoaderDylib/Config/MDCycriptManager.h @@ -0,0 +1,40 @@ +// weibo: http://weibo.com/xiaoqing28 +// blog: http://www.alonemonkey.com +// +// MDCycriptManager.h +// MonkeyDev +// +// Created by AloneMonkey on 2018/3/8. +// Copyright © 2018年 AloneMonkey. All rights reserved. +// + +#ifndef __OPTIMIZE__ + +#import + +#define PORT 6666 + +@interface MDCycriptManager : NSObject + ++ (instancetype)sharedInstance; + + +/** + Download script by config.plist + + @param update Force update of all scripts + */ +-(void)loadCycript:(BOOL) update; + +/** + eval javascript by cycript + + @param cycript javascript string + @param error error happened + @return eval result + */ +-(NSString*)evaluateCycript:(NSString*) cycript error:(NSError **) error; + +@end + +#endif \ No newline at end of file diff --git a/dkvideoLoader/dkvideoLoaderDylib/Config/MDCycriptManager.m b/dkvideoLoader/dkvideoLoaderDylib/Config/MDCycriptManager.m new file mode 100644 index 0000000..67a66d0 --- /dev/null +++ b/dkvideoLoader/dkvideoLoaderDylib/Config/MDCycriptManager.m @@ -0,0 +1,306 @@ +// weibo: http://weibo.com/xiaoqing28 +// blog: http://www.alonemonkey.com +// +// MDCycriptManager.m +// MonkeyDev +// +// Created by AloneMonkey on 2018/3/8. +// Copyright © 2018年 AloneMonkey. All rights reserved. +// + +#ifndef __OPTIMIZE__ + +#import "MDCycriptManager.h" +#import "MDConfigManager.h" +#import +#import +#import +#import +#import + +#define IOS_CELLULAR @"pdp_ip0" +#define IOS_WIFI @"en0" +#define IP_ADDR_IPv4 @"ipv4" +#define IP_ADDR_IPv6 @"ipv6" +#define MDLog(fmt, ...) NSLog((@"[Cycript] " fmt), ##__VA_ARGS__) + +extern JSGlobalContextRef CYGetJSContext(void); +extern void CydgetMemoryParse(const uint16_t **data, size_t *size); + +NSString * const CYErrorLineKey = @"CYErrorLineKey"; +NSString * const CYErrorNameKey = @"CYErrorNameKey"; +NSString * const CYErrorMessageKey = @"CYErrorMessageKey"; + +@interface MDSettingObject : NSObject + +@property (nonatomic, assign) NSInteger priority; +@property (nonatomic, copy) NSString* url; +@property (nonatomic, copy) NSString* content; +@property (nonatomic, assign) BOOL loadAtLaunch; + +-(instancetype)initWithDicationary:(NSDictionary*) dictionary; + +@end + +@implementation MDSettingObject + +-(instancetype)initWithDicationary:(NSDictionary *)dictionary{ + self = [super init]; + if(self){ + self.priority = [dictionary[@"priority"] integerValue]; + self.url = dictionary[@"url"]; + self.content = dictionary[@"content"]; + self.loadAtLaunch = [dictionary objectForKey:MDCONFIG_LOADATLAUNCH_KEY] && [dictionary[MDCONFIG_LOADATLAUNCH_KEY] boolValue]; + } + return self; +} + +@end + +@interface MDCycriptManager() + +@property (nonatomic, strong) NSDictionary* configItem; +@property (nonatomic, copy) NSString* cycriptDirectory; +@property (nonatomic, strong) NSMutableArray* downloading; +@property (nonatomic, strong) NSMutableDictionary* loadAtLaunchModules; + +@end + +@implementation MDCycriptManager + ++ (instancetype)sharedInstance{ + static MDCycriptManager *sharedInstance = nil; + if (!sharedInstance){ + sharedInstance = [[MDCycriptManager alloc] init]; + } + return sharedInstance; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + _loadAtLaunchModules = [NSMutableDictionary dictionary]; + _downloading = [NSMutableArray array]; + [self check]; + [self readConfigFile]; + } + return self; +} + +-(void)check{ + NSString* ip = [self getIPAddress]; + if(ip != nil){ + printf("\nDownload cycript(https://cydia.saurik.com/api/latest/3) then run: ./cycript -r %s:%d\n\n", [ip UTF8String], PORT); + }else{ + printf("\nPlease connect wifi before using cycript!\n\n"); + } + + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSString *documentsPath =[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES) firstObject]; + _cycriptDirectory = [documentsPath stringByAppendingPathComponent:@"cycript"]; + [fileManager createDirectoryAtPath:_cycriptDirectory withIntermediateDirectories:YES attributes:nil error:nil]; +} + +-(NSArray*)sortedArray:(NSDictionary*) dictionary{ + NSMutableArray* result = [NSMutableArray arrayWithCapacity:10]; + + NSArray* sortedArray = [dictionary.allKeys sortedArrayUsingComparator:^NSComparisonResult(NSNumber* _Nonnull number1, NSNumber* _Nonnull number2) { + if ([number1 integerValue] > [number2 integerValue]) + return NSOrderedDescending; + return NSOrderedAscending; + }]; + + for (NSNumber* item in sortedArray) { + [result addObject:dictionary[item]]; + } + + return [result copy]; +} + +-(void)readConfigFile{ + MDConfigManager * configManager = [MDConfigManager sharedInstance]; + _configItem = [configManager readConfigByKey:MDCONFIG_CYCRIPT_KEY]; +} + +-(void)loadCycript:(BOOL) update{ + NSFileManager *fileManager = [NSFileManager defaultManager]; + + if(_configItem && _configItem.count > 0){ + + BOOL download = NO; + + for (NSString* moduleName in _configItem.allKeys) { + MDSettingObject * item = [[MDSettingObject alloc] initWithDicationary:_configItem[moduleName]]; + NSString *fullPath = [[_cycriptDirectory stringByAppendingPathComponent:moduleName] stringByAppendingPathExtension:@"cy"]; + + if(item.url){ + if(![fileManager fileExistsAtPath:fullPath] || update){ + download = YES; + [self.downloading addObject:moduleName]; + [self downLoadUrl:item.url saveName:moduleName]; + } + } + + if(item.content){ + if(![fileManager fileExistsAtPath:fullPath] || update){ + NSString* writeContent = [NSString stringWithFormat:@"(function(exports) { %@ })(exports);", item.content]; + [writeContent writeToFile:fullPath atomically:YES encoding:NSUTF8StringEncoding error:nil]; + } + } + + if(item.loadAtLaunch){ + [_loadAtLaunchModules setObject:fullPath forKey:@(item.priority)]; + } + } + + if(!download){ + [self finishDownload]; + } + } +} + +-(void)finishDownload{ + MDLog(@"Finish download all script!"); + NSArray* sortedArray = [self sortedArray:_loadAtLaunchModules]; + for (NSString* fullPath in sortedArray) { + NSError* error; + [self evaluateCycript:[NSString stringWithFormat:@"require('%@');",fullPath] error:&error]; + if(error.code != 0){ + MDLog(@"%@", error.localizedDescription); + } + } +} + +-(void)downLoadUrl:(NSString*) urlString saveName:(NSString*) filename{ + __weak typeof(self) weakSelf = self; + NSURLSession *session = [NSURLSession sharedSession]; + NSURL *url = [NSURL URLWithString:urlString]; + NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:url completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) { + + if(error){ + MDLog(@"Failed download script [%@]: %@", filename, error.localizedDescription); + }else{ + NSString *fullPath = [[weakSelf.cycriptDirectory stringByAppendingPathComponent:filename] stringByAppendingPathExtension:@"cy"]; + [[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil]; + + MDLog(@"Successful download script [%@]", filename); + } + + [weakSelf.downloading removeObject:filename]; + + if(!weakSelf.downloading.count){ + [weakSelf finishDownload]; + } + }]; + [downloadTask resume]; +} + +-(NSString *)evaluateCycript:(NSString *)cycript error:(NSError *__autoreleasing *)error{ + NSString *resultString = nil; + + static pthread_mutex_t cycript_metex = PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_lock(&cycript_metex); { + JSGlobalContextRef context = CYGetJSContext(); + + size_t length = cycript.length; + unichar *buffer = malloc(length * sizeof(unichar)); + [cycript getCharacters:buffer range:NSMakeRange(0, length)]; + const uint16_t *characters = buffer; + CydgetMemoryParse(&characters, &length); + JSStringRef expression = JSStringCreateWithCharacters(characters, length); + + // Evaluate the Javascript + JSValueRef exception = NULL; + JSValueRef result = JSEvaluateScript(context, expression, NULL, NULL, 0, &exception); + JSStringRelease(expression); + + // If a result was returned, convert it into an NSString + if (result) { + JSStringRef string = JSValueToStringCopy(context, result, &exception); + if (string) { + resultString = (__bridge_transfer NSString *)JSStringCopyCFString(kCFAllocatorDefault, string); + JSStringRelease(string); + } + } + + // If an exception was thrown, convert it into an NSError + if (exception && error) { + JSObjectRef exceptionObject = JSValueToObject(context, exception, NULL); + + NSInteger line = (NSInteger)JSValueToNumber(context, JSObjectGetProperty(context, exceptionObject, JSStringCreateWithUTF8CString("line"), NULL), NULL); + JSStringRef string = JSValueToStringCopy(context, JSObjectGetProperty(context, exceptionObject, JSStringCreateWithUTF8CString("name"), NULL), NULL); + NSString *name = (__bridge_transfer NSString *)JSStringCopyCFString(kCFAllocatorDefault, string); + JSStringRelease(string); + string = JSValueToStringCopy(context, JSObjectGetProperty(context, exceptionObject, JSStringCreateWithUTF8CString("message"), NULL), NULL); + NSString *message = (__bridge_transfer NSString *)JSStringCopyCFString(kCFAllocatorDefault, string); + JSStringRelease(string); + string = JSValueToStringCopy(context, exception, NULL); + NSString *description = (__bridge_transfer NSString *)JSStringCopyCFString(kCFAllocatorDefault, string); + JSStringRelease(string); + + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + [userInfo setValue:@(line) forKey:CYErrorLineKey]; + [userInfo setValue:name forKey:CYErrorNameKey]; + [userInfo setValue:message forKey:CYErrorMessageKey]; + [userInfo setValue:description forKey:NSLocalizedDescriptionKey]; + *error = [NSError errorWithDomain:@"CYContextDomain" code:0 userInfo:userInfo]; + } + }pthread_mutex_unlock(&cycript_metex); + + return resultString; +} + +- (NSString *)getIPAddress{ + + NSDictionary *addresses = [self getIPAddresses]; + + if([addresses.allKeys containsObject:IOS_WIFI @"/" IP_ADDR_IPv4]){ + return addresses[IOS_WIFI @"/" IP_ADDR_IPv4]; + } + + return nil; +} + +- (NSDictionary *)getIPAddresses{ + NSMutableDictionary *addresses = [NSMutableDictionary dictionaryWithCapacity:8]; + + // retrieve the current interfaces - returns 0 on success + struct ifaddrs *interfaces; + if(!getifaddrs(&interfaces)) { + // Loop through linked list of interfaces + struct ifaddrs *interface; + for(interface=interfaces; interface; interface=interface->ifa_next) { + if(!(interface->ifa_flags & IFF_UP) /* || (interface->ifa_flags & IFF_LOOPBACK) */ ) { + continue; // deeply nested code harder to read + } + const struct sockaddr_in *addr = (const struct sockaddr_in*)interface->ifa_addr; + char addrBuf[ MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) ]; + if(addr && (addr->sin_family==AF_INET || addr->sin_family==AF_INET6)) { + NSString *name = [NSString stringWithUTF8String:interface->ifa_name]; + NSString *type; + if(addr->sin_family == AF_INET) { + if(inet_ntop(AF_INET, &addr->sin_addr, addrBuf, INET_ADDRSTRLEN)) { + type = IP_ADDR_IPv4; + } + } else { + const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*)interface->ifa_addr; + if(inet_ntop(AF_INET6, &addr6->sin6_addr, addrBuf, INET6_ADDRSTRLEN)) { + type = IP_ADDR_IPv6; + } + } + if(type) { + NSString *key = [NSString stringWithFormat:@"%@/%@", name, type]; + addresses[key] = [NSString stringWithUTF8String:addrBuf]; + } + } + } + // Free memory + freeifaddrs(interfaces); + } + return [addresses count] ? addresses : nil; +} + +@end + +#endif diff --git a/dkvideoLoader/dkvideoLoaderDylib/Config/MDMethodTrace.h b/dkvideoLoader/dkvideoLoaderDylib/Config/MDMethodTrace.h new file mode 100644 index 0000000..29e3610 --- /dev/null +++ b/dkvideoLoader/dkvideoLoaderDylib/Config/MDMethodTrace.h @@ -0,0 +1,30 @@ +// weibo: http://weibo.com/xiaoqing28 +// blog: http://www.alonemonkey.com +// +// MDMethodTrace.h +// MonkeyDev +// +// Created by AloneMonkey on 2017/9/7. +// Copyright © 2017年 AloneMonkey. All rights reserved. +// + +#ifndef MethodTrace_h +#define MethodTrace_h + +#define TRACE_README @"\n📚--------------------OCMethodTrace(Usage)-------------------📚\nhttps://github.com/omxcodec/OCMethodTrace/blob/master/README.md\n📚--------------------OCMethodTrace(Usage)-------------------📚" + +#import + +@interface MDMethodTrace : NSObject + ++ (instancetype)sharedInstance; + +- (void)addClassTrace:(NSString *) className; + +- (void)addClassTrace:(NSString *)className methodName:(NSString *)methodName; + +- (void)addClassTrace:(NSString *)className methodList:(NSArray *)methodList; + +@end + +#endif /* MethodTrace_h */ diff --git a/dkvideoLoader/dkvideoLoaderDylib/Config/MDMethodTrace.m b/dkvideoLoader/dkvideoLoaderDylib/Config/MDMethodTrace.m new file mode 100644 index 0000000..1034107 --- /dev/null +++ b/dkvideoLoader/dkvideoLoaderDylib/Config/MDMethodTrace.m @@ -0,0 +1,923 @@ +// weibo: http://weibo.com/xiaoqing28 +// blog: http://www.alonemonkey.com +// +// MDMethodTrace.m +// MonkeyDev +// +// Created by AloneMonkey on 2017/9/6. +// Copyright © 2017年 AloneMonkey. All rights reserved. +// + +#import "MDMethodTrace.h" +#import +#import +#import "MDConfigManager.h" +#import "OCMethodTrace.h" + +//#define USE_DDLOG // 使用外部日志系统,日志多的时候特别有用 +#ifdef USE_DDLOG +#import "CocoaLumberjack.h" +static const int ddLogLevel = DDLogLevelVerbose; +#define MDLog(fmt, ...) DDLogDebug((@"[MethodTrace] " fmt), ##__VA_ARGS__) +#else +//#define MDLog(fmt, ...) NSLog((@"[MethodTrace] " fmt), ##__VA_ARGS__) +#define MDLog(fmt, ...) printf("[MethodTrace] %s\n",[[NSString stringWithFormat:fmt, ##__VA_ARGS__] UTF8String]); +#endif + +#define SAFE_CHECK(_object, _type) (_type *)[[self class] safeCheck:_object class:[_type class]] +#define MDFatal(fmt, ...) [NSException raise:@"MDMethodTrace" format:fmt, ##__VA_ARGS__] + +// 指定ClassInfo源 +typedef NS_ENUM(NSUInteger, MDTraceSource) { + MDTraceSourceCore = 0, // 引擎指定(引擎指OCMethodTrace内部实现框架) + MDTraceSourceUser = 1, // 用户指定 + MDTraceSourceMerge = 2, // 引擎和用户合并 + MDTraceSourceMax +}; + +//////////////////////////////////////////////////////////////////////////////// +#pragma mark - Class Define + +@interface MDTraceClassInfo : NSObject + +@property (nonatomic, strong) NSString *name; // 类名 +@property (nonatomic, assign) MDTraceSource source; // 指定源 +@property (nonatomic, assign) MDTraceMode mode; // trace模式 +@property (nonatomic, assign) MDTraceFlag flag; // flag +@property (nonatomic, strong) NSMutableArray *methodList; // 黑名单或者白名单,根据mode决定 + +// 解析类配置,无key则加key,设置默认值,并校验值类型 ++ (instancetype)infoWithName:(NSString *)name source:(MDTraceSource)source config:(NSDictionary *)config; +// 根据类型返回引擎指定的默认ClassInfo ++ (instancetype)defaultCoreClassInfo:(NSString *)name; +// 根据类型返回用户指定的默认ClassInfo ++ (instancetype)defaultUserClassInfo:(NSString *)name; +// 安全检查 ++ (id)safeCheck:(id)content class:(Class)cls; +// 数组相减: arrayA - arrayB ++ (NSArray *)minusWithArrayA:(NSArray *)arrayA arrayB:(NSArray *)arrayB; +// 数组相加: arrayA + arrayB,可去重,相同元素只保留一个 ++ (NSArray *)unionWithArrayA:(NSArray *)arrayA arrayB:(NSArray *)arrayB; +// 合并引擎和用户ClassInfo,合并时core的优先级比user大,具体见函数内部实现 ++ (MDTraceClassInfo *)mergeInfoWithCoreInfo:(MDTraceClassInfo *)coreInfo userInfo:(MDTraceClassInfo *)userInfo; +// 合并引擎和用户config ++ (MDTraceClassInfo *)mergeInfoWithName:(NSString *)name coreConfig:(NSDictionary *)coreConfig userConfig:(NSDictionary *)userConfig; + +@end + +@interface MDMethodTrace () + +@property (nonatomic, strong) NSMutableDictionary *config; +@property (nonatomic, assign) MDTraceLogLevel logLevel; // 日志级别 +@property (nonatomic, assign) MDTraceLogWhen logWhen; // 日志输出时机 +@property (nonatomic, strong) NSString *logRegexString; // 日志正则匹配字符串,仅当logWhen=MDTraceLogWhenRegexString有效 +@property (nonatomic, assign) NSInteger numberOfPendingLog; // logRegexString匹配后,待输出afer日志个数 +@property (nonatomic, assign) CGFloat lastSystemVolume; // 上一次系统音量 +@property (nonatomic, assign) MDTraceFlag traceFlag; // 控制trace行为的一些特殊flag +@property (nonatomic, assign) MDTraceObject traceObject; // trace对象 +@property (nonatomic, strong) NSString *classRegexString; // 类正则匹配字符串 +@property (nonatomic, strong) NSMutableArray *coreClassInfoList; // 引擎类信息列表 +@property (nonatomic, strong) NSMutableArray *userClassInfoList; // 用户类信息列表 +@property (nonatomic, strong) NSMutableArray *regexClassInfoList; // 正则类信息列表 + +// 解析配置文件 +- (void)parseConfig:(NSDictionary *)config; + +@end + +//////////////////////////////////////////////////////////////////////////////// +#pragma mark - MDTraceClassInfo + +@implementation MDTraceClassInfo + +- (instancetype)init +{ + self = [super init]; + if (self) { + self.name = @"NoName"; + self.source = MDTraceSourceUser; + self.mode = MDTraceModeAll; + self.flag = MDTraceFlagDefault; + self.methodList = [NSMutableArray array]; + } + return self; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p name: %@ source: %tu mode: %tu flag: %tu methodList: %@>", + NSStringFromClass([self class]), self, _name, _source, _mode, _flag, _methodList]; +} + ++ (instancetype)infoWithName:(NSString *)name source:(MDTraceSource)source config:(NSDictionary *)config +{ + // 无对应字典说明用户没有指定类,不处理 + if (nil == config) { + return nil; + } + + MDTraceClassInfo *info = [[MDTraceClassInfo alloc] init]; + info.name = name; + info.source = source; + // 1 mode + info.mode = info.source == MDTraceSourceCore ? MDTraceModeOff: MDTraceModeAll; + if (![config valueForKey:MDCONFIG_TRACE_MODE_KEY]) { + // MDLog(@"Cannot find class %@ %@, set it to default %d", info.name, MDCONFIG_TRACE_MODE_KEY, (int)info.mode); + } else { + info.mode = [SAFE_CHECK(config[MDCONFIG_TRACE_MODE_KEY], NSNumber) integerValue]; + } + + // 2 flag + info.flag = MDTraceFlagDefault; + if (![config valueForKey:MDCONFIG_TRACE_FLAG_KEY]) { + // MDLog(@"Cannot find class %@ %@, set it to default %d", info.name, MDCONFIG_TRACE_FLAG_KEY, (int)info.flag); + } else { + info.flag = [SAFE_CHECK(config[MDCONFIG_TRACE_FLAG_KEY], NSNumber) integerValue]; + } + + // 3 whiteList + if ([config valueForKey:MDCONFIG_METHOD_WHITE_LIST_KEY]) { + id methodList = config[MDCONFIG_METHOD_WHITE_LIST_KEY]; + if (![methodList isKindOfClass:[NSArray class]]) { + MDFatal(@"Class %@ %@ should be array", info.name, MDCONFIG_METHOD_WHITE_LIST_KEY); + } else if (info.mode == MDTraceModeIncludeWhiteList) { + info.methodList = methodList; + } + } + + // 4 blackList + if ([config valueForKey:MDCONFIG_METHOD_BLACK_LIST_KEY]) { + id methodList = config[MDCONFIG_METHOD_BLACK_LIST_KEY]; + if (![methodList isKindOfClass:[NSArray class]]) { + MDFatal(@"Class %@ %@ should be array", info.name, MDCONFIG_METHOD_BLACK_LIST_KEY); + } else if (info.mode == MDTraceModeExcludeBlackList) { + info.methodList = methodList; + } + } + + return info; +} + ++ (instancetype)defaultCoreClassInfo:(NSString *)name +{ + MDTraceClassInfo *info = [[MDTraceClassInfo alloc] init]; + info.name = name; + info.source = MDTraceSourceCore; + info.mode = MDTraceModeOff; + return info; +} + ++ (instancetype)defaultUserClassInfo:(NSString *)name +{ + MDTraceClassInfo *info = [[MDTraceClassInfo alloc] init]; + info.name = name; + info.source = MDTraceSourceUser; + info.mode = MDTraceModeAll; + return info; +} + ++ (id)safeCheck:(id)content class:(Class)cls +{ + if ([content isKindOfClass:cls]) { + return content; + } + MDFatal(@"safeCheck failed, content(%@) should be class(%@) type", content, NSStringFromClass(cls)); + return nil; +} + ++ (NSArray *)minusWithArrayA:(NSArray *)arrayA arrayB:(NSArray *)arrayB +{ + NSMutableOrderedSet *setA = [NSMutableOrderedSet orderedSetWithArray:arrayA]; + NSMutableOrderedSet *setB = [NSMutableOrderedSet orderedSetWithArray:arrayB]; + [setA minusOrderedSet:setB]; + return [setA array]; +} + ++ (NSArray *)unionWithArrayA:(NSArray *)arrayA arrayB:(NSArray *)arrayB +{ + NSMutableOrderedSet *setA = [NSMutableOrderedSet orderedSetWithArray:arrayA]; + NSMutableOrderedSet *setB = [NSMutableOrderedSet orderedSetWithArray:arrayB]; + [setA unionOrderedSet:setB]; + return [setA array]; +} + +- (void)setSource:(MDTraceSource)source +{ + NSAssert(source >= MDTraceSourceCore && source < MDTraceSourceMax, @"invalid TraceSource"); + _source = source; +} + +- (void)setMode:(MDTraceMode)mode +{ + NSAssert(mode >= MDTraceModeOff && mode < MDTraceModeMax, @"invalid TraceMode"); + _mode = mode; +} + +- (void)setFlag:(MDTraceFlag)flag +{ + NSAssert(flag >= MDTraceModeOff && flag <= MDTraceFlagMask, @"invalid TraceFlag"); + _flag = flag; +} + +- (id)copyWithZone:(NSZone *)zone +{ + MDTraceClassInfo *info = [[self.class allocWithZone:zone] init]; + + info.name = self.name; + info.source = self.source; + info.mode = self.mode; + info.flag = self.flag; + info.methodList = [NSMutableArray arrayWithArray:self.methodList]; + + return info; +} + ++ (MDTraceClassInfo *)mergeInfoWithCoreInfo:(MDTraceClassInfo *)coreInfo userInfo:(MDTraceClassInfo *)userInfo +{ + if (nil == coreInfo && nil == userInfo) { + NSAssert(0, @"invalid info"); + return nil; + } + + MDTraceClassInfo *mergeInfo = nil; + if (nil != coreInfo && nil == userInfo) { + NSAssert(coreInfo.source == MDTraceSourceCore, @"invalid core source"); + mergeInfo = [coreInfo copy]; + } else if (nil == coreInfo && nil != userInfo) { + NSAssert(userInfo.source == MDTraceSourceUser, @"invalid user source"); + mergeInfo = [userInfo copy]; + } else { + NSAssert([coreInfo.name isEqualToString:userInfo.name], @"invalid name"); + NSAssert(coreInfo.source == MDTraceSourceCore, @"invalid core source"); + NSAssert(coreInfo.mode == MDTraceModeOff || coreInfo.mode == MDTraceModeExcludeBlackList, @"invalid core mode"); + NSAssert(userInfo.source == MDTraceSourceUser, @"invalid user source"); + + mergeInfo = [[MDTraceClassInfo alloc] init]; + mergeInfo.name = coreInfo.name; + mergeInfo.source = MDTraceSourceMerge; + mergeInfo.flag = coreInfo.flag | userInfo.flag; + // core优先级比user优先级高 + if (coreInfo.mode == MDTraceModeOff) { + // core关闭则无需关心user配置 + mergeInfo.mode = MDTraceModeOff; + } else if (coreInfo.mode == MDTraceModeExcludeBlackList) { + switch (userInfo.mode) { + case MDTraceModeOff: + // user关闭就不trace这个类 + mergeInfo.mode = MDTraceModeOff; + break; + case MDTraceModeAll: + // 排除core指定的黑名单 + mergeInfo.mode = MDTraceModeExcludeBlackList; + [mergeInfo.methodList addObjectsFromArray:coreInfo.methodList]; + break; + case MDTraceModeIncludeWhiteList: + // user白名单排除掉core黑名单 + mergeInfo.mode = MDTraceModeIncludeWhiteList; + [mergeInfo.methodList addObjectsFromArray:[[self class] minusWithArrayA:userInfo.methodList arrayB:coreInfo.methodList]]; + break; + case MDTraceModeExcludeBlackList: + // user黑名单加上core黑名单 + mergeInfo.mode = MDTraceModeExcludeBlackList; + [mergeInfo.methodList addObjectsFromArray:[[self class] unionWithArrayA:userInfo.methodList arrayB:coreInfo.methodList]]; + break; + default: + break; + } + } + } + + return mergeInfo; +} + ++ (MDTraceClassInfo *)mergeInfoWithName:(NSString *)name coreConfig:(NSDictionary *)coreConfig userConfig:(NSDictionary *)userConfig; +{ + MDTraceClassInfo *coreInfo = [MDTraceClassInfo infoWithName:name source:MDTraceSourceCore config:coreConfig]; + MDTraceClassInfo *userInfo = [MDTraceClassInfo infoWithName:name source:MDTraceSourceUser config:userConfig]; + return [MDTraceClassInfo mergeInfoWithCoreInfo:coreInfo userInfo:userInfo]; +} + +@end + +//////////////////////////////////////////////////////////////////////////////// +#pragma mark - MDMethodTrace + +@implementation MDMethodTrace + ++ (instancetype)sharedInstance { + static MDMethodTrace *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[MDMethodTrace alloc] init]; + }); + return sharedInstance; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + self.logLevel = MDTraceLogLeveDebug; + self.logWhen = MDTraceLogWhenStartup; + self.traceFlag = MDTraceFlagDefault; + self.traceObject = MDTraceObjectNone; + self.coreClassInfoList = [[NSMutableArray alloc] init]; + self.userClassInfoList = [[NSMutableArray alloc] init]; + self.regexClassInfoList = [[NSMutableArray alloc] init]; + } + return self; +} + +- (void)dealloc +{ +#if !TARGET_OS_SIMULATOR + [self removeVolumeObserver]; +#endif +} + +#pragma mark - Trace utils + ++ (NSString *)docPath +{ + return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; +} + +// 安全检查 ++ (id)safeCheck:(id)content class:(Class)cls +{ + if ([content isKindOfClass:cls]) { + return content; + } + MDFatal(@"safeCheck failed, content(%@) should be class(%@) type", content, NSStringFromClass(cls)); + return nil; +} + +// 正则匹配 optionss是否需要更多参数??? +// FIXME -[NSString rangeOfString:options:NSRegularExpressionSearch]在实际运行中会死循环,不太明白原因 ++ (BOOL)isMatchRegexString:(NSString *)regexString inputString:(NSString *)inputString +{ + NSError *error = NULL; + NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regexString options:NSRegularExpressionDotMatchesLineSeparators | NSRegularExpressionAnchorsMatchLines error:&error]; + NSTextCheckingResult *result = [regex firstMatchInString:inputString options:0 range:NSMakeRange(0, [inputString length])]; + return nil != result; +} + +// 获取object名称 ++ (NSString *)NSStringFromTraceObject:(MDTraceObject)traceObject +{ + NSString *name; + switch (traceObject) { + case MDTraceObjectNone: + name = @"未指定类"; + break; + case MDTraceObjectCoreClass: + name = @"引擎类"; + break; + case MDTraceObjectUserClass: + name = @"用户类"; + break; + case MDTraceObjectRegexClass: + name = @"正则类"; + break; + + default: + NSAssert1(0, @"Unkown trace object: %tu", traceObject); + break; + } + + return name; +} + +// 判断object是否属于测试模式 ++ (BOOL)isTestTraceObject:(MDTraceObject)traceObject +{ + return (traceObject == MDTraceObjectCoreClass); +} + +// 获取当前classInfoList +- (NSArray *)classInfoList +{ + if (self.traceObject == MDTraceObjectCoreClass) { + return self.coreClassInfoList; + } else if (self.traceObject == MDTraceObjectUserClass) { + return self.userClassInfoList; + } else if (self.traceObject == MDTraceObjectRegexClass) { + return self.regexClassInfoList; + } + return nil; +} + +// 查找某个类是否存在classInfoList中 +- (MDTraceClassInfo *)infoInClassInfoList:(NSString *)className +{ + for (MDTraceClassInfo *info in [self classInfoList]) { + if ([info.name isEqualToString:className]) { + return info; + } + } + return nil; +} + +// dump输出ClassListInfo +- (void)dumpClassListInfo +{ + if (!(self.traceFlag & MDTraceFlagDumpClassListInfo)) { + return; + } + + MDLog(@"Dump %@ class list info: ", [[self class] NSStringFromTraceObject:self.traceObject]); + MDLog(@"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + NSArray *classInfoList = [self classInfoList]; + for (int i = 0; i < classInfoList.count; i++) { + MDLog(@"ClassList[%05d]: %@", i, classInfoList[i]); + } + MDLog(@"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); +} + +// dump类所有方法信息 +- (void)dumpClassMethodInfo:(MDTraceClassInfo *)classInfo +{ + if (!(self.traceFlag & MDTraceFlagDumpClassMethod || classInfo.flag & MDTraceFlagDumpClassMethod)) { + return; + } + + MDLog(@"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + + Class cls = NSClassFromString(classInfo.name); + while (nil != cls) { + unsigned int numMethods = 0; + Method *methodList = class_copyMethodList(cls, &numMethods); + if (NULL != methodList) { + for (unsigned int i = 0; i < numMethods; i ++) { + MDLog(@"-Class[%@] method[%03d]: %@", cls, i, [[self class] methodInfo:methodList[i]]); + } + } + + Class metaClass = object_getClass(cls); + methodList = class_copyMethodList(metaClass, &numMethods); + if (NULL != methodList) { + for (unsigned int i = 0; i < numMethods; i ++) { + MDLog(@"+Class[%@] method[%03d]: %@", cls, i, [[self class] methodInfo:methodList[i]]); + } + } + + if (!(self.traceFlag & MDTraceFlagDumpSuperClassMethod || classInfo.flag & MDTraceFlagDumpSuperClassMethod)) { + break; + } + cls = [cls superclass]; + } + + MDLog(@"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); +} + +// 某方法信息 ++ (NSString *)methodInfo:(Method)method +{ + return [NSString stringWithFormat:@"name[%s] IMP[%p]", sel_getName(method_getName(method)), method_getImplementation(method)]; +} + +#pragma mark - Trace log + +// 初始化日志系统 +- (void)initLogger +{ +#ifdef USE_DDLOG + // 外部Lumberjack logger, 日志存放于目录"~/Library/Caches/Logs" + [DDLog addLogger:[DDTTYLogger sharedInstance]]; // TTY = Xcode 控制台 + // [[DDTTYLogger sharedInstance] setColorsEnabled:YES]; + // [DDLog addLogger:[DDASLLogger sharedInstance]]; // ASL = Apple System Logs 苹果系统日志 + + DDFileLogger *fileLogger = [[DDFileLogger alloc] init]; // 本地文件日志 + fileLogger.doNotReuseLogFiles = YES; + fileLogger.logFileManager.maximumNumberOfLogFiles = 1; // 永远创建一个文件,便于观察日志 + fileLogger.maximumFileSize = 0; + fileLogger.rollingFrequency = 0; + [DDLog addLogger:fileLogger]; +#endif + + // 内部logger + [[OCMethodTrace sharedInstance] setLogLevel:self.logLevel == MDTraceLogLeveError ? OMTLogLevelError : OMTLogLevelDebug]; + [[OCMethodTrace sharedInstance] setDelegate:self]; +} + +// trace开关 +- (void)enableTrace:(BOOL)enable +{ + if (!enable) { + [OCMethodTrace sharedInstance].disableTrace = YES; + } else { + if (self.logWhen == MDTraceLogWhenVolume) { +#if TARGET_OS_SIMULATOR + [OCMethodTrace sharedInstance].disableTrace = NO; + self.logWhen = MDTraceLogWhenStartup; + MDLog(@"Volume control log is not supported when simulator, reset logWhen to %tu", self.logWhen); +#else + self.lastSystemVolume = [[AVAudioSession sharedInstance] outputVolume]; + // 需要异步注册通知,否则无法工作 + dispatch_async(dispatch_get_main_queue(), ^{ + [self addVolumeObserver]; + }); +#endif + } else { + [OCMethodTrace sharedInstance].disableTrace = NO; + } + } +} + +#if !TARGET_OS_SIMULATOR +- (void)addVolumeObserver +{ + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(onSystemVolumeChanged:) name:@"AVSystemController_SystemVolumeDidChangeNotification" + object:nil]; + [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; +} + +- (void)removeVolumeObserver +{ + [[NSNotificationCenter defaultCenter] removeObserver:self + name:@"AVSystemController_SystemVolumeDidChangeNotification" + object:nil]; + [[UIApplication sharedApplication] endReceivingRemoteControlEvents]; +} + +- (void)onSystemVolumeChanged:(NSNotification *)notification +{ + NSString *category = notification.userInfo[@"AVSystemController_AudioCategoryNotificationParameter"]; + NSString *changeReason = notification.userInfo[@"AVSystemController_AudioVolumeChangeReasonNotificationParameter"]; + if (![category isEqualToString:@"Audio/Video"] || ![changeReason isEqualToString:@"ExplicitVolumeChange"]) { + return; + } + CGFloat volume = [[notification userInfo][@"AVSystemController_AudioVolumeNotificationParameter"] floatValue]; + [OCMethodTrace sharedInstance].disableTrace = volume < self.lastSystemVolume; // 音量升高触发日志输出 + self.lastSystemVolume = volume; +} +#endif + +#pragma mark - Trace parse config + +- (void)parseConfig:(NSDictionary *)config +{ + if (nil == config) { + return; + } + + MDLog(TRACE_README); + + self.config = [NSMutableDictionary dictionaryWithDictionary:config]; + self.logLevel = [SAFE_CHECK(self.config[MDCONFIG_LOG_LEVEL_KEY], NSNumber) unsignedIntegerValue]; + self.logWhen = [SAFE_CHECK(self.config[MDCONFIG_LOG_WHEN_KEY], NSNumber) unsignedIntegerValue]; + self.traceFlag = [SAFE_CHECK(self.config[MDCONFIG_TRACE_FLAG_KEY], NSNumber) unsignedIntegerValue]; + self.traceObject = [SAFE_CHECK(self.config[MDCONFIG_TRACE_OBJECT_KEY], NSNumber) unsignedIntegerValue]; + + MDLog(@"logLevel: %tu: logWhen: %tu traceFlag: %tu traceObject: %tu(%@%@)", + self.logLevel, self.logWhen, self.traceFlag, self.traceObject, + [[self class] NSStringFromTraceObject:self.traceObject], + [[self class] isTestTraceObject:self.traceObject] ? @"(仅测试验证使用,不建议开启)" : @""); + + // 检查配置有效性 + [self checkConfig]; + + // 初始化日志 + [self initLogger]; + + // 屏蔽trace输出。避免hook准备过程中导致的递归调用 + [self enableTrace:NO]; + + // 实际hook类的各种方法 + [self traceClassObject]; + + // 恢复trace输出 + [self enableTrace:YES]; +} + +- (void)checkConfig +{ + NSAssert(self.logLevel >= MDTraceLogLeveError && self.logLevel < MDTraceLogLeveMax, @"invalid loglevel"); + NSAssert(self.logWhen >= MDTraceLogWhenStartup && self.logWhen < MDTraceLogWhenMax, @"invalid logWhen"); + NSAssert(self.traceFlag >= 0 && self.traceFlag <= MDTraceFlagMask, @"invalid traceFlag"); + NSAssert(self.traceObject >= MDTraceObjectNone && self.traceObject < MDTraceObjectMax, @"invalid traceObject"); + + if (self.logWhen == MDTraceLogWhenRegexString) { + self.logRegexString = SAFE_CHECK(self.config[MDCONFIG_LOG_REGEX_STRING_KEY], NSString); + if (self.logRegexString.length == 0) { + MDFatal(@"LogRegexString is nil"); + } + MDLog(@"LogRegexString: %@", self.logRegexString); + } + + if (self.traceObject == MDTraceObjectRegexClass) { + self.classRegexString = SAFE_CHECK(self.config[MDCONFIG_CLASS_REGEX_STRING_KEY], NSString); + if (self.classRegexString.length == 0) { + MDFatal(@"ClassRegexString is nil"); + } + MDLog(@"ClassRegexString: %@", self.classRegexString); + } +} + +- (void)traceClassObject +{ + if (self.traceObject == MDTraceObjectNone) { + MDLog(@"Method Trace is disabled"); + return; + } + + [self parseClassListInfo]; + [self dumpClassListInfo]; + [self traceClassListInfo]; +} + +- (void)parseClassListInfo +{ + id object = nil; + NSDictionary *coreClassListDict = nil; + NSDictionary *userClassListDict = nil; + NSMutableArray *classList = [[NSMutableArray alloc] init]; + NSMutableArray *regexClassList = [[NSMutableArray alloc] init]; + + object = [self.config valueForKey:MDCONFIG_CORE_CLASS_LIST]; + if (nil != object) { + coreClassListDict = SAFE_CHECK(object, NSDictionary); + } + object = [self.config valueForKey:MDCONFIG_USER_CLASS_LIST]; + if (nil != object) { + userClassListDict = SAFE_CHECK(object, NSDictionary); + } + + // 1 获取真实存在的类 + int numberOfClasses = objc_getClassList(NULL, 0); + Class *tmpClassList = (Class *)malloc(sizeof(Class) * numberOfClasses); + if (NULL != tmpClassList) { + objc_getClassList(tmpClassList, numberOfClasses); + for (int i = 0; i < numberOfClasses; i++) { + NSString *className = NSStringFromClass(tmpClassList[i]); + [classList addObject:className]; + if (self.traceObject == MDTraceObjectRegexClass && [[self class] isMatchRegexString:self.classRegexString inputString:className]) { + // 多次匹配可能是重复类,需要去重 + if (![regexClassList containsObject:className]) { + [regexClassList addObject:className]; + } + } + } + free(tmpClassList); + } + + // 2 获取classInfo + if (self.traceObject == MDTraceObjectCoreClass) { + // 2.1 core + for (NSString *className in coreClassListDict.allKeys) { + if (![classList containsObject:className]) { + MDLog(@"Cannot find class %@", className); + continue; + } + + NSDictionary *coreConfig = coreClassListDict[className]; + MDTraceClassInfo *coreInfo = [MDTraceClassInfo infoWithName:className source:MDTraceSourceCore config:coreConfig]; + [self.coreClassInfoList addObject:coreInfo]; + } + } else if (self.traceObject == MDTraceObjectUserClass) { + // 2.2 user,注意,user需要跟core合并,优先级:core > user + for (NSString *className in userClassListDict.allKeys) { + if (![classList containsObject:className]) { + MDLog(@"Cannot find class %@", className); + continue; + } + + NSDictionary *coreConfig = coreClassListDict[className]; + NSDictionary *userConfig = userClassListDict[className]; + MDTraceClassInfo *mergeinfo = [MDTraceClassInfo mergeInfoWithName:className coreConfig:coreConfig userConfig:userConfig]; + [self.userClassInfoList addObject:mergeinfo]; + } + } else if (self.traceObject == MDTraceObjectRegexClass) { + // 2.3 regex, 优先级:core > user > regex + + // 2.3.1 user需要跟core合并,优先级:core > user + for (NSString *className in userClassListDict.allKeys) { + if (![classList containsObject:className]) { + MDLog(@"Cannot find class %@", className); + continue; + } + + NSDictionary *coreConfig = coreClassListDict[className]; + NSDictionary *userConfig = userClassListDict[className]; + MDTraceClassInfo *mergeinfo = [MDTraceClassInfo mergeInfoWithName:className coreConfig:coreConfig userConfig:userConfig]; + [self.regexClassInfoList addObject:mergeinfo]; + } + + // 2.3.2 regex需要跟core合并,优先级:core > regex。regex匹配的类可理解成更低优先级的user类 + NSDictionary *defaultUserConfig = [[NSDictionary alloc] init]; + for (NSString *className in regexClassList) { + if (nil == [self infoInClassInfoList:className]) { + NSDictionary *coreConfig = coreClassListDict[className]; + MDTraceClassInfo *mergeinfo = [MDTraceClassInfo mergeInfoWithName:className coreConfig:coreConfig userConfig:defaultUserConfig]; + [self.regexClassInfoList addObject:mergeinfo]; + } + } + } +} + +- (void)traceClassListInfo +{ + MDLog(@" "); + MDLog(@"////////////////////////////////////////////////////////////////////////////////"); + MDLog(@" "); + + NSArray *classInfoList = [self classInfoList]; + for (int i = 0; i < classInfoList.count; i++) { + MDTraceClassInfo *info = classInfoList[i]; + if (nil != objc_getClass([info.name UTF8String])) { + MDLog(@"ClassList[%05d]: %@", i, info.name); + [self traceClass:info]; + } else { + MDLog(@"Cannot find class %@", info.name); + } + } + + MDLog(@" "); + MDLog(@"////////////////////////////////////////////////////////////////////////////////"); + MDLog(@" "); +} + +- (void)traceClass:(MDTraceClassInfo *)classInfo +{ + if (nil == classInfo) { + return; + } + + [self dumpClassMethodInfo:classInfo]; + + if (classInfo.mode == MDTraceModeOff) { + } else if (classInfo.mode == MDTraceModeAll) { + [self addClassTrace:classInfo.name]; + } else if (classInfo.mode == MDTraceModeIncludeWhiteList) { + [self addClassTrace:classInfo.name methodList:classInfo.methodList white:YES]; + } else if (classInfo.mode == MDTraceModeExcludeBlackList) { + [self addClassTrace:classInfo.name methodList:classInfo.methodList white:NO]; + } + + [self dumpClassMethodInfo:classInfo]; +} + +#pragma mark - Trace method + +- (void)addClassTrace:(NSString *)className{ + [self addClassTrace:className methodList:nil]; +} + +- (void)addClassTrace:(NSString *)className methodName:(NSString *)methodName { + [self addClassTrace:className methodList:@[methodName]]; +} + +- (void)addClassTrace:(NSString *)className methodList:(NSArray*)methodList { + [self addClassTrace:className methodList:methodList white:YES]; +} + +- (void)addClassTrace:(NSString *)className methodList:(NSArray *)methodList white:(BOOL)white { + Class targetClass = objc_getClass([className UTF8String]); + if (targetClass != nil) { + [[OCMethodTrace sharedInstance] traceMethodWithClass:NSClassFromString(className) condition:^BOOL(SEL sel) { + if (methodList == nil || methodList.count == 0) { + return YES; + } + for (id object in methodList) { + NSString *methodName = SAFE_CHECK(object, NSString); + // 方法可以是正则表达式 + if ([[self class] isMatchRegexString:methodName inputString:NSStringFromSelector(sel)]) { + return white; + } + } + return !white; + } before:^(id target, Class cls, SEL sel, NSArray *args, int deep) { + NSString *selector = NSStringFromSelector(sel); + NSMutableString *selectorString = [NSMutableString new]; + if ([selector containsString:@":"]) { + NSArray *selectorArrary = [selector componentsSeparatedByString:@":"]; + selectorArrary = [selectorArrary filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"length > 0"]]; + for (int i = 0; i < selectorArrary.count; i++) { + [selectorString appendFormat:@"%@:%@ ", selectorArrary[i], args[i]]; + } + } else { + [selectorString appendString:selector]; + } + + NSMutableString *deepString = [NSMutableString new]; + for (int i = 0; i < deep; i++) { + [deepString appendString:@"-"]; + } + + // [obj class]则分两种情况: + // 1 当obj为实例对象时,[obj class]中class是实例方法:- (Class)class,返回的obj对象中的isa指针; + // 2 当obj为类对象(包括元类和根类以及根元类)时,调用的是类方法:+ (Class)class,返回的结果为其本身。 + NSString *prefix = target == [target class] ? @"+" : @"-"; + // target不是强引用,如果打印接口异步,可能未实际调用description就被释放了,所以提前获取desc,保证线程安全 + NSString *description = [self descriptionWithTarget:target class:cls selector:sel targetPosition:OMTTargetPositionBeforeSelf]; + NSString *logString = nil; + if ([target class] != [cls class]) { + // 如果是子类调用基类方法,则()内打印基类名 + logString = [NSString stringWithFormat:@"%@%@[%@(%@) %@]", deepString, prefix, description, NSStringFromClass(cls), selectorString]; + } else { + logString = [NSString stringWithFormat:@"%@%@[%@ %@]", deepString, prefix, description, selectorString]; + } + + if (self.logWhen == MDTraceLogWhenStartup || + self.logWhen == MDTraceLogWhenVolume || + (self.logWhen == MDTraceLogWhenRegexString && [[self class] isMatchRegexString:self.logRegexString inputString:logString])) { + self.numberOfPendingLog++; + MDLog(@"%@", logString); + } + } after:^(id target, Class cls, SEL sel, id ret, int deep, NSTimeInterval interval) { + // 因为多线程并发,numberOfPendingLog变量维护的输出状态有可能并不是那么准,但是打印调试可以容忍 + if (self.numberOfPendingLog > 0) { + self.numberOfPendingLog--; + NSMutableString *deepString = [NSMutableString new]; + for (int i = 0; i < deep; i++) { + [deepString appendString:@"-"]; + } + + NSString *prefix = target == [target class] ? @"+" : @"-"; + MDLog(@"%@%@ret:%@", deepString, prefix, ret); + } + }]; + } else { + MDLog(@"Canot find class %@", className); + } +} + +#pragma mark - OCMethodTraceDelegate + +- (NSString *)descriptionWithTarget:(id)target class:(Class)cls selector:(SEL)sel targetPosition:(OMTTargetPosition)targetPosition +{ + if (nil == target) { + return @"nil"; + } + + NSString *targetClassName = NSStringFromClass([target class]); + + // 全局跳过对象description方法 + if (self.traceFlag & MDTraceFlagDoesNotUseDescription) { + return [NSString stringWithFormat:@"<%@: %p>", targetClassName, target]; + } + + // 类跳过对象description方法,粒度更小一点 + MDTraceClassInfo *info = [self infoInClassInfoList:targetClassName]; + BOOL doesNotUseDescription = (nil != info && info.flag & MDTraceFlagDoesNotUseDescription); + if (!doesNotUseDescription) { + // 构造初始化函数特殊处理, 系统类初始化比较喜欢"_init"这样的方式 + NSString *selectorName = NSStringFromSelector(sel); + BOOL isAllocFunc = [selectorName hasPrefix:@"new"] || [selectorName hasPrefix:@"alloc"]; + BOOL maybeInitFunc = [selectorName hasPrefix:@"init"] || [selectorName hasPrefix:@"_init"]; + BOOL isDeallocFunc = [selectorName isEqualToString:@"dealloc"]; + if (isAllocFunc || maybeInitFunc) { + switch (targetPosition) { + case OMTTargetPositionBeforeSelf: + // 调用构造函数时,此时实例还没初始化完全,不能调用description + doesNotUseDescription = YES; + break; + case OMTTargetPositionBeforeArgument: + break; + case OMTTargetPositionAfterSelf: + case OMTTargetPositionAfterReturnValue: + if (isAllocFunc) { + doesNotUseDescription = YES; + } else if (maybeInitFunc) { + // 调用构造函数时,可能是调用父类的构造函数,此时实例还没初始化完全,不能调用description + if (![targetClassName isEqualToString:NSStringFromClass(cls)]) { + doesNotUseDescription = YES; + } + } + break; + + default: + break; + } + } else if (isDeallocFunc) { + // 析构函数所有只打印指针,因为dealloc after时,对象已被释放 + doesNotUseDescription = YES; + } + } + + return doesNotUseDescription ? [NSString stringWithFormat:@"<%@: %p>", targetClassName, target] : [target description]; +} + +- (void)log:(OMTLogLevel)level format:(NSString *)format, ... +{ + va_list args; + if (format) { + va_start(args, format); + NSString *message = [[NSString alloc] initWithFormat:format arguments:args]; + va_end(args); + + MDLog(@"%@", message); + } +} + +@end + +//////////////////////////////////////////////////////////////////////////////// +#pragma mark - Entry + +static __attribute__((constructor)) void entry() +{ + NSDictionary *config = [[MDConfigManager sharedInstance] readConfigByKey:MDCONFIG_TRACE_KEY]; + [[MDMethodTrace sharedInstance] parseConfig:config]; +} diff --git a/dkvideoLoader/dkvideoLoaderDylib/Logos/dkvideoLoaderDylib.mm b/dkvideoLoader/dkvideoLoaderDylib/Logos/dkvideoLoaderDylib.mm new file mode 100644 index 0000000..264c7d6 --- /dev/null +++ b/dkvideoLoader/dkvideoLoaderDylib/Logos/dkvideoLoaderDylib.mm @@ -0,0 +1,71 @@ +#line 1 "/Users/zhudekun/mycode/test/AppHooker/dkvideoLoader/dkvideoLoaderDylib/Logos/dkvideoLoaderDylib.xm" + + +#import +#import +#import + +@interface AssistiveTouch:UIWindow ++ (instancetype)shared; +@end + + +@interface DKVideoLoader: NSObject +@end + +@implementation DKVideoLoader + ++ (instancetype)sharedInstance { + static dispatch_once_t onceToken; + static DKVideoLoader *loader; + dispatch_once(&onceToken, ^{ + loader = [[DKVideoLoader alloc] init]; + }); + + return loader; +} + +- (void)show { + + [[objc_getClass("AssistiveTouch") shared] setHidden:NO]; +} + +@end + +static __attribute__((constructor)) void _logosLocalCtor_acb97b70(int __unused argc, char __unused **argv, char __unused **envp) { + + NSString* dylibPath = [NSBundle.mainBundle pathForResource:@"libDKVideo" ofType:@"dylib"]; + if (![[NSFileManager defaultManager] fileExistsAtPath:dylibPath]) { + NSLog(@"DKVideoLoader dylib file not found: %@", dylibPath); + return; + } + void *handle = dlopen([dylibPath UTF8String], RTLD_NOW); + if (handle == NULL) { + char *error = dlerror(); + return; + } + + + + + + + + + + + + + + + + + + + + + + + + +} diff --git a/dkvideoLoader/dkvideoLoaderDylib/Logos/dkvideoLoaderDylib.xm b/dkvideoLoader/dkvideoLoaderDylib/Logos/dkvideoLoaderDylib.xm new file mode 100644 index 0000000..2903ddb --- /dev/null +++ b/dkvideoLoader/dkvideoLoaderDylib/Logos/dkvideoLoaderDylib.xm @@ -0,0 +1,52 @@ +// See http://iphonedevwiki.net/index.php/Logos + +#import +#import +#import + +@interface AssistiveTouch:UIWindow ++ (instancetype)shared; +@end + + +@interface DKVideoLoader: NSObject +@end + +@implementation DKVideoLoader + ++ (instancetype)sharedInstance { + static dispatch_once_t onceToken; + static DKVideoLoader *loader; + dispatch_once(&onceToken, ^{ + loader = [[DKVideoLoader alloc] init]; + }); + + return loader; +} + +- (void)show { + + [[objc_getClass("AssistiveTouch") shared] setHidden:NO]; +} + +@end + +%ctor { + + NSString* dylibPath = [NSBundle.mainBundle pathForResource:@"libDKVideo" ofType:@"dylib"]; + if (![[NSFileManager defaultManager] fileExistsAtPath:dylibPath]) { + NSLog(@"DKVideoLoader dylib file not found: %@", dylibPath); + return; + } + void *handle = dlopen([dylibPath UTF8String], RTLD_NOW); + if (handle == NULL) { + char *error = dlerror(); + return; + } + [[NSNotificationCenter defaultCenter] addObserver:[DKVideoLoader sharedInstance] + selector:@selector(show) + name:UIApplicationDidBecomeActiveNotification + object:nil]; + + +} diff --git a/dkvideoLoader/dkvideoLoaderDylib/Tools/LLDBTools.h b/dkvideoLoader/dkvideoLoaderDylib/Tools/LLDBTools.h new file mode 100644 index 0000000..d11b63b --- /dev/null +++ b/dkvideoLoader/dkvideoLoaderDylib/Tools/LLDBTools.h @@ -0,0 +1,30 @@ +// weibo: http://weibo.com/xiaoqing28 +// blog: http://www.alonemonkey.com +// +// LLDBTools.h +// MonkeyDev +// +// Created by AloneMonkey on 2018/3/8. +// Copyright © 2018年 AloneMonkey. All rights reserved. +// + +#import +#import + +//(lldb) po pviews() + +NSString* pvc(void); + +NSString* pviews(void); + +NSString* pactions(vm_address_t address); + +NSString* pblock(vm_address_t address); + +NSString* methods(const char * classname); + +NSString* ivars(vm_address_t address); + +NSString* choose(const char* classname); + +NSString* vmmap(); diff --git a/dkvideoLoader/dkvideoLoaderDylib/Tools/LLDBTools.mm b/dkvideoLoader/dkvideoLoaderDylib/Tools/LLDBTools.mm new file mode 100644 index 0000000..5a245a1 --- /dev/null +++ b/dkvideoLoader/dkvideoLoaderDylib/Tools/LLDBTools.mm @@ -0,0 +1,432 @@ +// weibo: http://weibo.com/xiaoqing28 +// blog: http://www.alonemonkey.com +// +// LLDBTools.m +// MonkeyDev +// +// Created by AloneMonkey on 2018/3/8. +// Copyright © 2018年 AloneMonkey. All rights reserved. +// + +#pragma GCC diagnostic ignored "-Wundeclared-selector" + +#import "LLDBTools.h" +#import +#import +#import +#import +#import +#import + +enum { + BLOCK_HAS_COPY_DISPOSE = (1 << 25), + BLOCK_HAS_CTOR = (1 << 26), // helpers have C++ code + BLOCK_IS_GLOBAL = (1 << 28), + BLOCK_HAS_STRET = (1 << 29), // IFF BLOCK_HAS_SIGNATURE + BLOCK_HAS_SIGNATURE = (1 << 30), +}; + +struct Block_literal_1 { + void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock + int flags; + int reserved; + void (*invoke)(void *, ...); + struct Block_descriptor_1 { + unsigned long int reserved; // NULL + unsigned long int size; // sizeof(struct Block_literal_1) + // optional helper functions + void (*copy_helper)(void *dst, void *src); // IFF (1<<25) + void (*dispose_helper)(void *src); // IFF (1<<25) + // required ABI.2010.3.16 + const char *signature; // IFF (1<<30) + } *descriptor; + // imported variables +}; + +NSString* decode(NSString* code); +NSArray* choose_inner(const char * classname); +char * protection_bits_to_rwx (vm_prot_t p); +const char * unparse_inheritance (vm_inherit_t i); +char * behavior_to_text (vm_behavior_t b); + +NSString* decode(NSString* code){ + NSDictionary * encodeMap = @{ + @"c": @"char", + @"i": @"int", + @"s": @"short", + @"l": @"long", + @"q": @"long long", + + @"C": @"unsigned char", + @"I": @"unsigned int", + @"S": @"unsigned short", + @"L": @"unsigned long", + @"Q": @"unsigned long long", + + @"f": @"float", + @"d": @"double", + @"B": @"bool", + @"v": @"void", + @"*": @"char *", + @"@": @"id", + @"#": @"Class", + @":": @"SEL" + }; + + if(encodeMap[code]){ + return encodeMap[code]; + }else if([code characterAtIndex:0] == '@'){ + if([code characterAtIndex:1] == '?'){ + return code; + }else if([code characterAtIndex:2] == '<'){ + return [NSString stringWithFormat:@"id%@", [[code substringWithRange:NSMakeRange(2, code.length-3)] stringByReplacingOccurrencesOfString:@"><" withString:@", "]]; + }else{ + return [NSString stringWithFormat:@"%@ *", [code substringWithRange:NSMakeRange(2, code.length-3)]]; + } + }else if([code characterAtIndex:0] == '^'){ + return [NSString stringWithFormat:@"%@ *", decode([code substringFromIndex:1])]; + } + return code; +} + +NSString* pvc(){ + return [[[UIWindow performSelector:@selector(keyWindow)] performSelector:@selector(rootViewController)] performSelector:@selector(_printHierarchy)]; +} + +NSString* pviews(){ + return [[[UIApplication sharedApplication] keyWindow] performSelector:@selector(recursiveDescription)]; +} + +NSString* pactions(vm_address_t address){ + NSMutableString* result = [NSMutableString new]; + UIControl* control = (__bridge UIControl*)(void*)address; + NSArray* targets = [[control allTargets] allObjects]; + for (id item in targets) { + NSArray* actions = [control actionsForTarget:item forControlEvent:0]; + [result appendFormat:@"<%s: 0x%lx>: %@\n", object_getClassName(item), (unsigned long)item, [actions componentsJoinedByString:@","]]; + } + return result; +} + +NSString* pblock(vm_address_t address){ + struct Block_literal_1 real = *((struct Block_literal_1 *)(void*)address); + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + [dict setObject:[NSNumber numberWithLong:(long)real.invoke] forKey:@"invoke"]; + if (real.flags & BLOCK_HAS_SIGNATURE) { + char *signature; + if (real.flags & BLOCK_HAS_COPY_DISPOSE) { + signature = (char *)(real.descriptor)->signature; + } else { + signature = (char *)(real.descriptor)->copy_helper; + } + + NSMethodSignature *sig = [NSMethodSignature signatureWithObjCTypes:signature]; + NSMutableArray *types = [NSMutableArray array]; + + [types addObject:[NSString stringWithUTF8String:(char *)[sig methodReturnType]]]; + + for (NSUInteger i = 0; i < sig.numberOfArguments; i++) { + char *type = (char *)[sig getArgumentTypeAtIndex:i]; + [types addObject:[NSString stringWithUTF8String:type]]; + } + + [dict setObject:types forKey:@"signature"]; + } + + NSMutableArray* sigArr = dict[@"signature"]; + + if(!sigArr){ + return [NSString stringWithFormat:@"Imp: 0x%lx", [dict[@"invoke"] longValue]]; + }else{ + NSMutableString* sig = [NSMutableString stringWithFormat:@"%@ ^(", decode(sigArr[0])]; + for (int i = 2; i < sigArr.count; i++) { + if(i == sigArr.count - 1){ + [sig appendFormat:@"%@", decode(sigArr[i])]; + }else{ + [sig appendFormat:@"%@ ,", decode(sigArr[i])]; + } + } + [sig appendString:@");"]; + return [NSString stringWithFormat:@"Imp: 0x%lx Signature: %s", [dict[@"invoke"] longValue], [sig UTF8String]]; + } +} + +struct CYChoice { + std::set query_; + std::set results_; +}; + +struct CYObjectStruct { + Class isa_; +}; + +static void choose_(task_t task, void *baton, unsigned type, vm_range_t *ranges, unsigned count) { + CYChoice *choice(reinterpret_cast(baton)); + + for (unsigned i(0); i != count; ++i) { + vm_range_t &range(ranges[i]); + void *data(reinterpret_cast(range.address)); + size_t size(range.size); + + if (size < sizeof(CYObjectStruct)) + continue; + + uintptr_t *pointers(reinterpret_cast(data)); +#ifdef __arm64__ + Class isa = (__bridge Class)((void *)(pointers[0] & 0x1fffffff8)); +#else + Class isa =(__bridge Class)(void *)pointers[0]; +#endif + std::set::const_iterator result(choice->query_.find(isa)); + if (result == choice->query_.end()) + continue; + + size_t needed(class_getInstanceSize(*result)); + // XXX: if (size < needed) + + size_t boundary(496); +#ifdef __LP64__ + boundary *= 2; +#endif + if ((needed <= boundary && (needed + 15) / 16 * 16 != size) || (needed > boundary && (needed + 511) / 512 * 512 != size)) + continue; + choice->results_.insert((__bridge id)(data)); + } +} + +static Class *CYCopyClassList(size_t &size) { + size = objc_getClassList(NULL, 0); + Class *data(reinterpret_cast(malloc(sizeof(Class) * size))); + + for (;;) { + size_t writ(objc_getClassList(data, (int)size)); + if (writ <= size) { + size = writ; + return data; + } + + Class *copy(reinterpret_cast(realloc(data, sizeof(Class) * writ))); + if (copy == NULL) { + free(data); + return NULL; + } + + data = copy; + size = writ; + } +} + +static kern_return_t CYReadMemory(task_t task, vm_address_t address, vm_size_t size, void **data) { + *data = reinterpret_cast(address); + return KERN_SUCCESS; +} + +NSArray* choose_inner(const char * classname){ + + Class _class = NSClassFromString([NSString stringWithUTF8String:classname]); + + vm_address_t *zones = NULL; + unsigned size = 0; + //获取所有的zone信息 堆上的区域 + kern_return_t error = malloc_get_all_zones(mach_task_self(), &CYReadMemory, &zones, &size); + assert(error == KERN_SUCCESS); + + size_t number; + Class *classes(CYCopyClassList(number)); + assert(classes != NULL); + + CYChoice choice; + + //找到目标Class + for (size_t i(0); i != number; ++i) + for (Class current(classes[i]); current != Nil; current = class_getSuperclass(current)) + if (current == _class) { + choice.query_.insert(classes[i]); + break; + } + + for (unsigned i(0); i != size; ++i) { + const malloc_zone_t *zone(reinterpret_cast(zones[i])); + if (zone == NULL || zone->introspect == NULL) + continue; + + //枚举堆上的对象 + zone->introspect->enumerator(mach_task_self(), &choice, MALLOC_PTR_IN_USE_RANGE_TYPE, zones[i], &CYReadMemory, &choose_); + } + NSMutableArray * result = [[NSMutableArray alloc] init]; + + for (auto iter = choice.results_.begin(); iter != choice.results_.end(); iter++) { + [result addObject:(id)*iter]; + } + return result; +} + +NSString* choose(const char* classname){ + NSMutableString* result = [NSMutableString new]; + NSArray* results = choose_inner(classname); + [result appendFormat:@"Find %lu instance objects in memory!\n" , (unsigned long)results.count]; + for (id item in results) { + [result appendFormat:@"<%s: 0x%llx>\n", object_getClassName(item), (long long)item]; + } + return result; +} + +NSString* methods(const char * classname){ + return [objc_getClass(classname) performSelector:@selector(_shortMethodDescription)]; +} + +NSString* ivars(vm_address_t address){ + id target = (__bridge id)(void*)address; + return [target performSelector:@selector(_ivarDescription)]; +} + +char * protection_bits_to_rwx (vm_prot_t p){ + static char returned[4]; + + returned[0] = (p & VM_PROT_READ ? 'r' : '-'); + returned[1] = (p & VM_PROT_WRITE ? 'w' : '-'); + returned[2] = (p & VM_PROT_EXECUTE ? 'x' : '-'); + returned[3] = '\0'; + + // memory leak here. No biggy + return (strdup(returned)); +} + +const char * unparse_inheritance (vm_inherit_t i){ + switch (i){ + case VM_INHERIT_SHARE: + return "share"; + case VM_INHERIT_COPY: + return "copy"; + case VM_INHERIT_NONE: + return "none"; + default: + return "???"; + } +} + +char * behavior_to_text (vm_behavior_t b){ + switch (b){ + case VM_BEHAVIOR_DEFAULT: return((char*)"default"); + case VM_BEHAVIOR_RANDOM: return((char*)"random"); + case VM_BEHAVIOR_SEQUENTIAL: return((char*)"fwd-seq"); + case VM_BEHAVIOR_RSEQNTL: return((char*)"rev-seq"); + case VM_BEHAVIOR_WILLNEED: return((char*)"will-need"); + case VM_BEHAVIOR_DONTNEED: return((char*)"will-need"); + case VM_BEHAVIOR_FREE: return((char*)"free-nowb"); + case VM_BEHAVIOR_ZERO_WIRED_PAGES: return((char*)"zero-wire"); + case VM_BEHAVIOR_REUSABLE: return((char*)"reusable"); + case VM_BEHAVIOR_REUSE: return((char*)"reuse"); + case VM_BEHAVIOR_CAN_REUSE: return((char*)"canreuse"); + default: return ((char*)"?"); + } +} + +__BEGIN_DECLS + +extern kern_return_t mach_vm_region +( + vm_map_t target_task, + mach_vm_address_t *address, + mach_vm_size_t *size, + vm_region_flavor_t flavor, + vm_region_info_t info, + mach_msg_type_number_t *infoCnt, + mach_port_t *object_name + ); + +__END_DECLS + +NSString* vmmap(){ + vm_region_basic_info_data_t info, prev_info; + mach_vm_address_t address = 1, prev_address; + mach_vm_size_t size, prev_size; + mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64; + mach_port_t object_name; + + int nsubregions = 0; + kern_return_t kr = mach_vm_region(mach_task_self(), &address, &size, VM_REGION_BASIC_INFO, (vm_region_info_t)&info, &count, &object_name); + + NSMutableString* result = [[NSMutableString alloc] init]; + + if(kr != KERN_SUCCESS){ + [result appendFormat:@"mach_vm_region: Error %d - %s", kr, mach_error_string(kr)]; + return [result copy]; + } + + //保存之前查到的info + memcpy (&prev_info, &info, sizeof (vm_region_basic_info_data_t)); + prev_address = address; + prev_size = size; + nsubregions = 1; + + while (true) { + int print = 0, done = 0; + + address = prev_address + prev_size; + + if (address == 0){ + print = done = 1; + } + + if (!done){ + kr = mach_vm_region (mach_task_self(), &address, &size, VM_REGION_BASIC_INFO, (vm_region_info_t)&info, &count, &object_name); + + if (kr != KERN_SUCCESS){ + [result appendFormat:@"mach_vm_region failed for address %llu - Error: %x\n",address, (kr)]; + print = done = 1; + } + } + + //等于才是连续的内存,不等于才打印 + if (address != prev_address + prev_size) + print = 1; + + //或者权限信息改变了也打印 + if ((info.protection != prev_info.protection) + || (info.max_protection != prev_info.max_protection) + || (info.inheritance != prev_info.inheritance) + || (info.shared != prev_info.reserved) + || (info.reserved != prev_info.reserved)) + print = 1; + + if (print){ + char *print_size_unit = NULL; + + mach_vm_size_t print_size = prev_size; + if (print_size > 1024) { print_size /= 1024; print_size_unit = (char*)"K"; } + if (print_size > 1024) { print_size /= 1024; print_size_unit = (char*)"M"; } + if (print_size > 1024) { print_size /= 1024; print_size_unit = (char*)"G"; } + + [result appendFormat:@" %p-%p [%llu%s](%s/%s; %s, %s, %s) %s", + (void*)(prev_address), + (void*)(prev_address + prev_size), + print_size, + print_size_unit, + protection_bits_to_rwx (prev_info.protection), + protection_bits_to_rwx (prev_info.max_protection), + unparse_inheritance (prev_info.inheritance), + prev_info.shared ? "shared" : "private", + prev_info.reserved ? "reserved" : "not-reserved", + behavior_to_text (prev_info.behavior)]; + + if (nsubregions > 1) + [result appendFormat:@" (%d sub-regions)", nsubregions]; + + [result appendFormat:@"\n"]; + prev_address = address; + prev_size = size; + memcpy (&prev_info, &info, sizeof (vm_region_basic_info_data_t)); + nsubregions = 1; + }else{ + prev_size += size; + nsubregions++; + } + + if (done) + break; + } + return [result copy]; +} + + diff --git a/dkvideoLoader/dkvideoLoaderDylib/Trace/OCMethodTrace.h b/dkvideoLoader/dkvideoLoaderDylib/Trace/OCMethodTrace.h new file mode 100644 index 0000000..feda924 --- /dev/null +++ b/dkvideoLoader/dkvideoLoaderDylib/Trace/OCMethodTrace.h @@ -0,0 +1,89 @@ +/* + * OCMethodTrace.h + * OCMethodTrace + * + * https://github.com/omxcodec/OCMethodTrace.git + * + * Copyright (C) 2018 Michael Chen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +// 方法跟踪条件block +// @param sel 方法名 +typedef BOOL (^OMTConditionBlock)(SEL sel); + +// 方法调用前会调用该block +// @param target 跟踪目标对象 +// @param cls 调用方法所在的类(可以是target所在的类,也可以是target的父类) +// @param sel 方法名 +// @param args 参数列表 +// @param deep 调用层次 +typedef void (^OMTBeforeBlock)(id target, Class cls, SEL sel, NSArray *args, int deep); + +// 方法调用后会调用该block +// @param target 跟踪目标对象 +// @param cls 调用方法所在的类(可以是target所在的类,也可以是target的父类) +// @param sel 方法名 +// @param ret 返回值 +// @param deep 调用层次 +// @param interval 执行方法的ms耗时 +typedef void (^OMTAfterBlock)(id target, Class cls, SEL sel, id ret, int deep, NSTimeInterval interval); + +// target位置 +typedef NS_ENUM(NSUInteger, OMTTargetPosition) { + OMTTargetPositionBeforeSelf = 0, // before-调用者self + OMTTargetPositionBeforeArgument, // before-参数 + OMTTargetPositionAfterSelf, // after-调用者self + OMTTargetPositionAfterReturnValue, // after-返回值 + OMTTargetPositionMax, +}; + +// 日志级别 +typedef NS_ENUM(NSUInteger, OMTLogLevel) { + OMTLogLevelError = 0, + OMTLogLevelDebug, + OMTLogLevelMax, +}; + +@protocol OCMethodTraceDelegate + +@optional +// 获取target的description回调 +- (NSString *)descriptionWithTarget:(id)target class:(Class)cls selector:(SEL)sel targetPosition:(OMTTargetPosition)targetPosition; +// 日志回调 +- (void)log:(OMTLogLevel)level format:(NSString *)format, ... NS_FORMAT_FUNCTION(2,3); + +@end + +@interface OCMethodTrace : NSObject + +@property (nonatomic, assign) BOOL disableTrace; // 屏蔽before和after调用,hook完成后默认打开 +@property (nonatomic, weak) id delegate; // 回调 +@property (nonatomic, assign) OMTLogLevel logLevel; // 日志级别,默认OMTLogLevelDebug + ++ (OCMethodTrace *)sharedInstance; + +// 跟踪打印目标(实例或类)方法调用 +// @param cls 跟踪打印目标类 +// @param condition 判断是否跟踪方法的block +// @param before 被跟踪的方法调用前会调用该block +// @param after 被跟踪的方法调用后会调用该block +- (void)traceMethodWithClass:(Class)cls + condition:(OMTConditionBlock)condition + before:(OMTBeforeBlock)before + after:(OMTAfterBlock)after; + +@end diff --git a/dkvideoLoader/dkvideoLoaderDylib/Trace/OCMethodTrace.m b/dkvideoLoader/dkvideoLoaderDylib/Trace/OCMethodTrace.m new file mode 100644 index 0000000..7c5fa72 --- /dev/null +++ b/dkvideoLoader/dkvideoLoaderDylib/Trace/OCMethodTrace.m @@ -0,0 +1,1131 @@ +/* + * OCMethodTrace.m + * OCMethodTrace + * + * https://github.com/omxcodec/OCMethodTrace.git + * + * Copyright (C) 2018 Michael Chen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "OCMethodTrace.h" +#import +#import +#import +#import +#import +#import +#import "OCSelectorTrampolines.h" + +#define OMT_LOG(_level_, _fmt_, ...) do { \ + if ((_level_) <= [OCMethodTrace sharedInstance].logLevel) { \ + if ([OCMethodTrace sharedInstance].delegate && [[OCMethodTrace sharedInstance].delegate respondsToSelector:@selector(log:format:)]) { \ + [[OCMethodTrace sharedInstance].delegate log:OMTLogLevelDebug format:(_fmt_), ## __VA_ARGS__]; \ + } else { \ + NSLog((_fmt_), ## __VA_ARGS__); \ + } \ + } \ + } while(0) + +#define OMT_LOGE(_fmt_, ...) OMT_LOG(OMTLogLevelError, (_fmt_), ## __VA_ARGS__) +#define OMT_LOGD(_fmt_, ...) OMT_LOG(OMTLogLevelDebug, (_fmt_), ## __VA_ARGS__) + +static NSString *const OMTMessageTempPrefix = @"__OMTMessageTemp_"; +static NSString *const OMTMessageFinalPrefix = @"__OMTMessageFinal_"; +static NSString *const OMTBlockRunBeforeSelector = @"runBefore:"; +static NSString *const OMTBlockRunAfterSelector = @"runAfter:"; +static NSString *const OMTDescriptionWithTargetSelector = @"descriptionWithTarget:"; + +// trace位置 +typedef NS_ENUM(NSUInteger, OMTTracePosition) { + OMTTracePositionBefore = 1 << 0, // before + OMTTracePositionAfter = 1 << 1, // after +}; + +// 错误码,对内使用,便于调试 +typedef NS_ENUM(NSUInteger, OMTErrorCode) { + OMTErrorNoError, // NERR 没有错误 + OMTErrorSelectorPassThrough, // SPTH 透传不处理 + OMTErrorSelectorAlreadyHooked, // SAHK 已经hook过 + OMTErrorSelectorInUserBlacklist, // SIUB 在用户的黑名单里 + OMTErrorClassInSelfBlacklist, // CISB 在内部的类黑名单里 + OMTErrorSelectorInSelfBlacklist, // SISB 在内部的sel黑名单里 + OMTErrorSelectorUnsuppotedMethodSignature, // SUMS 无法支持的方法签名(导致crash的异常签名) + OMTErrorSelectorUnsuppotedEncodeType, // SUEY 无法支持的编码类型(局部无法识别的签名) + OMTErrorDoesNotRespondToMethod, // NMTD 无此method + OMTErrorDoesNotRespondToSelector, // NSEL 无此sel + OMTErrorDoesNotRespondToIMP, // NIMP 无此IMP + OMTErrorSwizzleMethodFailed, // SMDF 替换方法失败 +}; + +#define LOG_LEVEL_4_ERROR_CODE(_errorCode_) (((_errorCode_) >= OMTErrorSelectorUnsuppotedMethodSignature) ? OMTLogLevelError : OMTLogLevelDebug) + +//////////////////////////////////////////////////////////////////////////////// +#pragma mark - C Helper Define + +// 替换实例方法 +static void swizzle_instance_method(Class cls, SEL originSel, SEL newSel); +// 替换类方法 +static void swizzle_class_method(Class cls, SEL originSel, SEL newSel); + +// 是否支持某类型限定符 +static BOOL omt_isTypeQualifier(const char argumentType); +// 是否是struct类型 +static BOOL omt_isStructType(const char *argumentType); +// 获取struct类型名 +static NSString *omt_structName(const char *argumentType); +// 是否是union类型 +static BOOL omt_isUnionType(const char *argumentType); +// 获取union类型名 +static NSString *omt_unionName(const char *argumentType); +static BOOL isCGRect (const char *type); +static BOOL isCGPoint (const char *type); +static BOOL isCGSize (const char *type); +static BOOL isCGVector (const char *type); +static BOOL isUIOffset (const char *type); +static BOOL isUIEdgeInsets (const char *type); +static BOOL isCGAffineTransform(const char *type); + +//////////////////////////////////////////////////////////////////////////////// +#pragma mark - Class Define + +@interface OMTBlock : NSObject + +@property (nonatomic, strong) NSString *className; +@property (nonatomic, copy) OMTConditionBlock condition; +@property (nonatomic, copy) OMTBeforeBlock before; +@property (nonatomic, copy) OMTAfterBlock after; + +- (BOOL)runCondition:(SEL)sel; +- (void)runBefore:(id)target class:(Class)cls sel:(SEL)sel args:(NSArray *)args deep:(int)deep; +- (void)runAfter:(id)target class:(Class)cls sel:(SEL)sel ret:(id)ret deep:(int)deep interval:(NSTimeInterval)interval; + +@end + +@interface OMTMessageStub : NSObject + +@property (nonatomic, unsafe_unretained) id target; +@property (nonatomic, assign) SEL selector; + +- (instancetype)initWithTarget:(id)target selector:(SEL)aSelector; + +@end + +@interface NSObject (OCMethodTrace) + +// 类转发方法 ++ (id)omt_forwardingTargetForSelector:(SEL)aSelector; +// 实例转发方法 +- (id)omt_forwardingTargetForSelector:(SEL)aSelector; + +@end + +@interface NSInvocation (OCMethodTrace) + +// 获取原始的类名 +- (Class)omt_originClass; +// 获取原始的方法名 +- (SEL)omt_originSelector; +// 获取方法返回值 +- (id)omt_getReturnValue; +// 获取方法参数 +- (NSArray *)omt_getArguments; + +@end + +@interface OCMethodTrace() { + pthread_mutex_t _blockMutex; + pthread_mutex_t _deepMutex; +} + +@property (nonatomic, strong) NSArray *defaultClassBlackList; +@property (nonatomic, strong) NSArray *defaultMethodBlackList; +@property (nonatomic, strong) NSDictionary *supportedTypeDict; +@property (nonatomic, strong) NSDictionary *tracePositionDict; +@property (nonatomic, strong) NSMutableDictionary *blockCache; +@property (nonatomic, assign) int deep; + +// 初始化内部默认黑名单 +- (void)initDefaultClassBlackList; +- (void)initDefaultMethodBlackList; +// 初始化所支持类型编码的字典 +- (void)initSupportedTypeDict; +// 初始化trace位置字典 +- (void)initTracePositionDict; +// 根据错误码返回错误描述 ++ (NSString *)errorString:(OMTErrorCode)errorCode; +// 判断函数数组里任意函数是否存在递归循环调用 ++ (BOOL)detectInfiniteLoopAtSelectorArray:(NSArray *)selectorArray; +// 获取target的description +- (NSString *)descriptionWithTarget:(id)target class:(Class)cls selector:(SEL)sel targetPosition:(OMTTargetPosition)targetPosition; +// 判断类是否在内部默认黑名单中 +- (BOOL)isClassInBlackList:(NSString *)className; +// 判断方法是否在内部默认黑名单中 +- (BOOL)isSelectorInBlackList:(NSString *)methodName; +// 判断类型编码是否可以处理 +- (BOOL)isSupportedType:(NSString *)typeEncode; +// 获取方法名对应的trace位置 +- (OMTTracePosition)tracePosition:(NSString *)methodName; +// block相关 +- (void)setBlock:(OMTBlock *)block forKey:(NSString *)key; +- (OMTBlock *)blockforKey:(NSString *)key; +- (OMTBlock *)blockWithTarget:(id)target; +// 原子操作deep++,返回原值 +- (int)atomicAddDeep; +// 原子操作deep-- +- (void)atomicIncDeep; +// 根据条件跟踪目标类的方法 +- (void)traceMethodWithClass:(Class)cls condition:(OMTConditionBlock)condition; +// 判断方法是否支持跟踪 +- (OMTErrorCode)isTraceSupportedWithClass:(Class)cls method:(Method)method; +// 替换方法 +- (OMTErrorCode)swizzleMethodWithClass:(Class)cls selector:(SEL)selector; +// 转发实现 +- (void)omt_forwardInvocation:(NSInvocation *)invocation; + +@end + +//////////////////////////////////////////////////////////////////////////////// + +#pragma mark - C Helper + +static void swizzle_instance_method(Class cls, SEL originSel, SEL newSel) +{ + Method originMethod = class_getInstanceMethod(cls, originSel); + Method newMethod = class_getInstanceMethod(cls, newSel); + + if (class_addMethod(cls, originSel, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) { + class_replaceMethod(cls, newSel, method_getImplementation(originMethod), method_getTypeEncoding(originMethod)); + } else { + method_exchangeImplementations(originMethod, newMethod); + } +} + +static void swizzle_class_method(Class cls, SEL originSel, SEL newSel) +{ + Class metaClass = objc_getMetaClass([NSStringFromClass(cls) UTF8String]); + + Method originMethod = class_getInstanceMethod(metaClass, originSel); + Method newMethod = class_getInstanceMethod(metaClass, newSel); + + if (class_addMethod([metaClass class], originSel, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) { + class_replaceMethod([metaClass class], newSel, method_getImplementation(originMethod), method_getTypeEncoding(originMethod)); + } else { + method_exchangeImplementations(originMethod, newMethod); + } +} + +static BOOL omt_isTypeQualifier(const char argumentType) +{ + // Table 6-2 Objective-C method encodings + static const char supportedTypeQualifierList[] = { 'r', 'n', 'N', 'o', 'O', 'R', 'V' }; + static const size_t kNumSupportedTypeQualifier = sizeof(supportedTypeQualifierList) / sizeof(supportedTypeQualifierList[0]); + + size_t i; + for (i = 0; i < kNumSupportedTypeQualifier; i++) { + if (argumentType == supportedTypeQualifierList[i]) { + return YES; + } + } + return NO; +} + +static BOOL omt_isStructType(const char *argumentType) +{ + NSString *typeString = [NSString stringWithUTF8String:argumentType]; + return ([typeString hasPrefix:@"{"] && [typeString hasSuffix:@"}"]); +} + +static NSString *omt_structName(const char *argumentType) +{ + NSString *typeString = [NSString stringWithUTF8String:argumentType]; + NSUInteger start = [typeString rangeOfString:@"{"].location; + NSUInteger end = [typeString rangeOfString:@"="].location; + if (end > start) { + return [typeString substringWithRange:NSMakeRange(start + 1, end - start - 1)]; + } else { + return nil; + } +} + +static BOOL omt_isUnionType(const char *argumentType) +{ + NSString *typeString = [NSString stringWithUTF8String:argumentType]; + return ([typeString hasPrefix:@"("] && [typeString hasSuffix:@")"]); +} + +static NSString *omt_unionName(const char *argumentType) +{ + NSString *typeString = [NSString stringWithUTF8String:argumentType]; + NSUInteger start = [typeString rangeOfString:@"("].location; + NSUInteger end = [typeString rangeOfString:@"="].location; + if (end > start) { + return [typeString substringWithRange:NSMakeRange(start + 1, end - start - 1)]; + } else { + return nil; + } +} + +static BOOL isCGRect (const char *type) {return [omt_structName(type) isEqualToString:@"CGRect"];} +static BOOL isCGPoint (const char *type) {return [omt_structName(type) isEqualToString:@"CGPoint"];} +static BOOL isCGSize (const char *type) {return [omt_structName(type) isEqualToString:@"CGSize"];} +static BOOL isCGVector (const char *type) {return [omt_structName(type) isEqualToString:@"CGVector"];} +static BOOL isUIOffset (const char *type) {return [omt_structName(type) isEqualToString:@"UIOffset"];} +static BOOL isUIEdgeInsets (const char *type) {return [omt_structName(type) isEqualToString:@"UIEdgeInsets"];} +static BOOL isCGAffineTransform(const char *type) {return [omt_structName(type) isEqualToString:@"CGAffineTransform"];} + +//////////////////////////////////////////////////////////////////////////////// +#pragma mark - OCMethodTrace + +@implementation OCMethodTrace + +//////////////////////////////////////////////////////////////////////////////// + +#pragma mark - Public OCMethodTrace API + ++ (OCMethodTrace *)sharedInstance +{ + static OCMethodTrace *instance = nil; + static dispatch_once_t pred; + dispatch_once(&pred, ^{ + instance = [[OCMethodTrace alloc] init]; + }); + return instance; +} + +- (void)traceMethodWithClass:(Class)cls + condition:(OMTConditionBlock)condition + before:(OMTBeforeBlock)before + after:(OMTAfterBlock)after +{ +#ifndef DEBUG + return; +#endif + + // 黑名单的类不跟踪 + if ([self isClassInBlackList:NSStringFromClass(cls)]) { + OMT_LOG(OMTLogLevelDebug, @"[%@] trace class: %@", + [self.class errorString:OMTErrorClassInSelfBlacklist], + NSStringFromClass(cls)); + return; + } + + // 处理一个类被添加到blockCache多次的情况 + if (cls && ![self blockforKey:NSStringFromClass(cls)]) { + OMTBlock *block = [[OMTBlock alloc] init]; + block.className = NSStringFromClass(cls); + block.condition = condition; + block.before = before; + block.after = after; + [self setBlock:block forKey:block.className]; + } + + // 处理实例方法 + [self traceMethodWithClass:cls condition:condition]; + + // 处理类方法 + Class metaCls = object_getClass(cls); + if (class_isMetaClass(metaCls)) { + [self traceMethodWithClass:metaCls condition:condition]; + } +} + +//////////////////////////////////////////////////////////////////////////////// +#pragma mark - Private OCMethodTrace API + +- (instancetype)init +{ + self = [super init]; + if (self) { + // 参考ANYMethodLog的处理 + [self initDefaultClassBlackList]; + [self initDefaultMethodBlackList]; + [self initSupportedTypeDict]; + [self initTracePositionDict]; + + self.disableTrace = NO; + self.logLevel = OMTLogLevelDebug; + self.blockCache = [NSMutableDictionary dictionary]; + self.deep = 0; + + pthread_mutex_init(&_blockMutex, NULL); + pthread_mutex_init(&_deepMutex, NULL); + + } + return self; +} + +- (void)dealloc +{ + pthread_mutex_destroy(&_blockMutex); + pthread_mutex_destroy(&_deepMutex); +} + +- (void)initDefaultClassBlackList +{ + self.defaultClassBlackList = @[@"OCMethodTrace", + @"OMTBlock", + @"OMTMessageStub", + @"NSMethodSignature", + @"NSInvocation", + ]; +} + +- (void)initDefaultMethodBlackList +{ + self.defaultMethodBlackList = @[@".cxx_destruct", + @"_isDeallocating", + @"release", + @"autorelease", + @"recycle", + @"retain", + @"Retain", + @"_tryRetain", + @"copy", + @"copyWithZone:", + @"mutableCopyWithZone:", + @"nsis_descriptionOfVariable:", + @"respondsToSelector:", + @"class", + @"methodSignatureForSelector:", + @"allowsWeakReference", + @"retainWeakReference", + @"forwardInvocation:", + @"description", + @"sharedInstance", + @"SharedInstance", + @"getInstance", + @"GetInstance", + ]; +} + +- (void)initSupportedTypeDict +{ + // https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100-SW1 + + // Table 6-1 Objective-C type encodings + self.supportedTypeDict = @{[NSString stringWithUTF8String:@encode(char)] : @"(char)", + [NSString stringWithUTF8String:@encode(int)] : @"(int)", + [NSString stringWithUTF8String:@encode(short)] : @"(short)", + [NSString stringWithUTF8String:@encode(long)] : @"(long)", + [NSString stringWithUTF8String:@encode(long long)] : @"(long long)", + [NSString stringWithUTF8String:@encode(unsigned char)] : @"(unsigned char))", + [NSString stringWithUTF8String:@encode(unsigned int)] : @"(unsigned int)", + [NSString stringWithUTF8String:@encode(unsigned short)] : @"(unsigned short)", + [NSString stringWithUTF8String:@encode(unsigned long)] : @"(unsigned long)", + [NSString stringWithUTF8String:@encode(unsigned long long)] : @"(unsigned long long)", + [NSString stringWithUTF8String:@encode(float)] : @"(float)", + [NSString stringWithUTF8String:@encode(double)] : @"(double)", + [NSString stringWithUTF8String:@encode(BOOL)] : @"(BOOL)", + [NSString stringWithUTF8String:@encode(void)] : @"(void)", + [NSString stringWithUTF8String:@encode(char *)] : @"(char *)", + [NSString stringWithUTF8String:@encode(id)] : @"(id)", + [NSString stringWithUTF8String:@encode(Class)] : @"(Class)", + [NSString stringWithUTF8String:@encode(SEL)] : @"(SEL)", + [NSString stringWithUTF8String:@encode(CGRect)] : @"(CGRect)", + [NSString stringWithUTF8String:@encode(CGPoint)] : @"(CGPoint)", + [NSString stringWithUTF8String:@encode(CGSize)] : @"(CGSize)", + [NSString stringWithUTF8String:@encode(CGVector)] : @"(CGVector)", + [NSString stringWithUTF8String:@encode(CGAffineTransform)] : @"(CGAffineTransform)", + [NSString stringWithUTF8String:@encode(UIOffset)] : @"(UIOffset)", + [NSString stringWithUTF8String:@encode(UIEdgeInsets)] : @"(UIEdgeInsets)", + @"@?" : @"(block)", // block类型 + }; // 添加更多类型 +} + +- (void)initTracePositionDict +{ + // @interface NSObject + self.tracePositionDict = @{@"initialize" : @(OMTTracePositionBefore | OMTTracePositionAfter), + @"init" : @(OMTTracePositionBefore | OMTTracePositionAfter), + @"new" : @(OMTTracePositionBefore | OMTTracePositionAfter), + @"allocWithZone:" : @(OMTTracePositionBefore | OMTTracePositionAfter), + @"alloc" : @(OMTTracePositionBefore | OMTTracePositionAfter), + @"dealloc" : @(OMTTracePositionBefore), + @"finalize" : @(OMTTracePositionBefore), + }; // 添加更多类型 +} + ++ (NSString *)errorString:(OMTErrorCode)errorCode +{ + struct CodeToString { + OMTErrorCode errorCode; + const char *errorString; + }; + static const struct CodeToString kCodeToString[] = { + { OMTErrorNoError, "NERR" }, + { OMTErrorSelectorPassThrough, "SPTH" }, + { OMTErrorSelectorAlreadyHooked, "SAHK" }, + { OMTErrorSelectorInUserBlacklist, "SIUB" }, + { OMTErrorClassInSelfBlacklist, "CISB" }, + { OMTErrorSelectorInSelfBlacklist, "SISB" }, + { OMTErrorSelectorUnsuppotedMethodSignature,"SUMS" }, + { OMTErrorSelectorUnsuppotedEncodeType, "SUEY" }, + { OMTErrorDoesNotRespondToMethod, "NMTD" }, + { OMTErrorDoesNotRespondToSelector, "NSEL" }, + { OMTErrorDoesNotRespondToIMP, "NIMP" }, + { OMTErrorSwizzleMethodFailed, "SMDF" }, + }; + + static const size_t kNumCodeToString = sizeof(kCodeToString) / sizeof(kCodeToString[0]); + + size_t i; + for (i = 0; i < kNumCodeToString; i++) { + if (errorCode == kCodeToString[i].errorCode) { + break; + } + } + NSAssert(i != kNumCodeToString, @"Unknown errorCode???"); + + return [NSString stringWithUTF8String:kCodeToString[i].errorString]; +} + ++ (BOOL)detectInfiniteLoopAtSelectorArray:(NSArray *)selectorArray +{ + void *callstack[128]; + int frames = backtrace(callstack, 128); + char **strs = backtrace_symbols(callstack, frames); + + BOOL exists = NO; + // 跳过自身方法,所以从1开始 + for (int i = 1; i < frames && strs && !exists; i++) { + NSString *frame = [NSString stringWithUTF8String:strs[i]]; + // OMT_LOGD(@"frame[%d]: %@", i, frame); + for (NSString *selector in selectorArray) { + if ([frame containsString:selector]) { + exists = YES; + break; + } + } + } + if (strs) { + free(strs); + } + return exists; +} + +- (NSString *)descriptionWithTarget:(id)target class:(Class)cls selector:(SEL)sel targetPosition:(OMTTargetPosition)targetPosition +{ + if (nil != self.delegate && [self.delegate respondsToSelector:@selector(descriptionWithTarget:class:selector:targetPosition:)]) { + return [self.delegate descriptionWithTarget:target class:cls selector:sel targetPosition:targetPosition]; + } else { + return [target description]; + } +} + +- (BOOL)isClassInBlackList:(NSString *)className +{ + return [self.defaultClassBlackList containsObject:className]; +} + +- (BOOL)isSelectorInBlackList:(NSString *)methodName +{ + return [self.defaultMethodBlackList containsObject:methodName]; +} + +- (BOOL)isSupportedType:(NSString *)typeEncode +{ + return [self.supportedTypeDict.allKeys containsObject:typeEncode]; +} + +- (OMTTracePosition)tracePosition:(NSString *)methodName +{ + OMTTracePosition defaultPostion = OMTTracePositionBefore | OMTTracePositionAfter; + return [self.tracePositionDict.allKeys containsObject:methodName] ? [self.tracePositionDict[methodName] intValue]: defaultPostion; +} + +- (void)setBlock:(OMTBlock *)block forKey:(NSString *)key +{ + pthread_mutex_lock(&_blockMutex); + [self.blockCache setObject:block forKey:key]; + pthread_mutex_unlock(&_blockMutex); +} + +- (OMTBlock *)blockforKey:(NSString *)key +{ + pthread_mutex_lock(&_blockMutex); + OMTBlock *block = [self.blockCache objectForKey:key]; + pthread_mutex_unlock(&_blockMutex); + return block; +} + +- (OMTBlock *)blockWithTarget:(id)target +{ + pthread_mutex_lock(&_blockMutex); + Class cls = [target class]; + OMTBlock *block = [self.blockCache objectForKey:NSStringFromClass(cls)]; + while (nil == block) { + cls = [cls superclass]; + if (nil == cls) { + break; + } + block = [self.blockCache objectForKey:NSStringFromClass(cls)]; + } + pthread_mutex_unlock(&_blockMutex); + return block; +} + +- (int)atomicAddDeep +{ + pthread_mutex_lock(&_deepMutex); + int deep = _deep++; + pthread_mutex_unlock(&_deepMutex); + return deep; +} + +- (void)atomicIncDeep +{ + pthread_mutex_lock(&_deepMutex); + _deep--; + pthread_mutex_unlock(&_deepMutex); +} + +- (void)traceMethodWithClass:(Class)cls condition:(OMTConditionBlock)condition +{ + unsigned int outCount; + Method *methods = class_copyMethodList(cls, &outCount); + for (unsigned int i = 0; i < outCount; i++) { + Method method = *(methods + i); + SEL selector = method_getName(method); + + OMTErrorCode errorCode = [self isTraceSupportedWithClass:cls method:method]; + if (errorCode == OMTErrorNoError && condition) { + // 用户只有两种选择:跟踪,不跟踪 + if (!condition(selector)) { + errorCode = OMTErrorSelectorInUserBlacklist; + } + } + + if (errorCode == OMTErrorNoError) { + errorCode = [self swizzleMethodWithClass:cls selector:selector]; + } + + OMT_LOG(LOG_LEVEL_4_ERROR_CODE(errorCode), @"[%@] trace class: %@ method: %@ types: %s", + [self.class errorString:errorCode], + NSStringFromClass(cls), + NSStringFromSelector(selector), + method_getDescription(method)->types); + } + free(methods); +} + +- (OMTErrorCode)isTraceSupportedWithClass:(Class)cls method:(Method)method +{ + char returnTypeCString[1024]; + memset(returnTypeCString, 0, sizeof(returnTypeCString)); + method_getReturnType(method, returnTypeCString, sizeof(returnTypeCString)); + const char *returnType = returnTypeCString; + + + NSString *selectorName = NSStringFromSelector(method_getName(method)); + if ([selectorName hasPrefix:@"omt_"]) { + // 1 内部方法不处理 + return OMTErrorSelectorPassThrough; + } else if ([selectorName hasPrefix:OMTMessageFinalPrefix]) { + // 2 处理过的方法不处理 + return OMTErrorSelectorAlreadyHooked; + } + + // 3 内部黑名单中的方法不处理 + if ([self isSelectorInBlackList:selectorName]) { + return OMTErrorSelectorInSelfBlacklist; + } + + // 4 签名异常的方法不处理。模拟器下有一些奇葩的方法(系统方法居多)签名异常,会导致[NSMethodSignature signatureWithObjCTypes:] crash,所以需捕捉异常 + BOOL hasSignatureException = NO; + @try { + __unused NSMethodSignature *methodSignature = [NSMethodSignature signatureWithObjCTypes:method_getTypeEncoding(method)]; + } @catch (__unused NSException *e) { + hasSignatureException = YES; + } + if (hasSignatureException) { + return OMTErrorSelectorUnsuppotedMethodSignature; + } + + // 5 处理返回值类型 + // 跳过类型限定符 + if (omt_isTypeQualifier(returnType[0])) { + returnType++; + } + + // 支持指针类型 + if (returnType[0] != _C_PTR) { + // struct和union有可能无法解析,但是也通过,解释不出的用NSValue输出,便于打印函数调用链 + if (!(omt_isStructType(returnType) || omt_isUnionType(returnType))) { + if (![self isSupportedType:[NSString stringWithUTF8String:returnType]]) { + return OMTErrorSelectorUnsuppotedEncodeType; + } + } + } + + // 6 处理参数类型。需注意:发送消息时,第0个参数是self, 第1个参数是sel,第2个参数才是真正意义上的第一个方法参数,所以从2开始算 + for (int k = 2 ; k < method_getNumberOfArguments(method); k++) { + char argumentTypeCString[1024]; + memset(argumentTypeCString, 0, sizeof(argumentTypeCString)); + method_getArgumentType(method, k, argumentTypeCString, sizeof(argumentTypeCString)); + const char *argumentType = argumentTypeCString; + + // 跳过类型限定符 + if (omt_isTypeQualifier(argumentType[0])) { + argumentType++; + } + // 支持指针类型 + if (argumentType[0] == _C_PTR) { + continue; + } + + // struct和union有可能无法解析,但是也通过,解释不出的用NSValue输出,便于打印函数调用链 + if (!(omt_isStructType(argumentType) || omt_isUnionType(argumentType))) { + if (![self isSupportedType:[NSString stringWithUTF8String:argumentType]]) { + return OMTErrorSelectorUnsuppotedEncodeType; + } + } + } + + return OMTErrorNoError; +} + +- (OMTErrorCode)swizzleMethodWithClass:(Class)cls selector:(SEL)selector +{ + // 1 检查该selector是否已经hook过 + SEL newSelector = NSSelectorFromString([NSString stringWithFormat:@"%@%@->%@", + OMTMessageFinalPrefix, + NSStringFromClass(cls), + NSStringFromSelector(selector)]); + if (class_respondsToSelector(cls, newSelector)) { + return OMTErrorSelectorAlreadyHooked; + } + + // 2 原方法相关校验 + Method originMethod = class_getInstanceMethod(cls, selector); + if (!originMethod) { + return OMTErrorDoesNotRespondToMethod; + } + IMP originIMP = method_getImplementation(originMethod); + if (!originIMP) { + return OMTErrorDoesNotRespondToIMP; + } + const char *originTypes = method_getTypeEncoding(originMethod); + + // 3 转发:旧方法跳转到转发IMP + // 使用比较另类的"类与方法间隔符",如"->"。如果使用"_",有可能会导致冲突,如系统内部类"__CFNotification"就会异常 + SEL forwardingSEL = NSSelectorFromString([NSString stringWithFormat:@"%@%@->%@", + OMTMessageTempPrefix, + NSStringFromClass(cls), + NSStringFromSelector(selector)]); + IMP forwardingIMP = imp_implementationWithSelector(forwardingSEL, originTypes); + NSAssert(originIMP != forwardingIMP, @"originIMP != forwardingIMP"); + method_setImplementation(originMethod, forwardingIMP); + + // 4 还原:新SEL跳转回旧IMP + if (!class_addMethod(cls, newSelector, originIMP, originTypes)) { + return OMTErrorSwizzleMethodFailed; + } + + return OMTErrorNoError; +} + +- (void)omt_forwardInvocation:(NSInvocation *)invocation +{ + if (self.disableTrace) { + [invocation invoke]; + return; + } + + Class originClass = [invocation omt_originClass]; + SEL originSelector = [invocation omt_originSelector]; + // XXX 通过堆栈搜索递归调用会有挺大的性能损耗。但确实不知道怎么处理比较好,了解的麻烦知会email一下我 + // 其实主要是因为description调用,当遇到description则用加递归锁,直接跳过runBefore和runAfer,但是如果description内部有条件等待,可能会死锁. + BOOL disableTrace = [[self class] detectInfiniteLoopAtSelectorArray:@[OMTBlockRunBeforeSelector, + OMTBlockRunAfterSelector, + OMTDescriptionWithTargetSelector]]; + int deep = [self atomicAddDeep]; + + if (!disableTrace) { + OMTBlock *block = [self blockWithTarget:invocation.target]; + OMTTracePosition postion = [self tracePosition:NSStringFromSelector(originSelector)]; + NSDate *start; + + // 1 原方法调用前回调 + if (postion & OMTTracePositionBefore) { + [block runBefore:invocation.target class:originClass sel:originSelector args:[invocation omt_getArguments] deep:deep]; + } + if (postion & OMTTracePositionAfter) { + start = [NSDate date]; + } + + // 2 调用原方法 + [invocation invoke]; + + // 3 原方法调用后回调 + if (postion & OMTTracePositionAfter) { + NSTimeInterval interval = [[NSDate date] timeIntervalSinceDate:start]; + [block runAfter:invocation.target class:originClass sel:originSelector ret:[invocation omt_getReturnValue] deep:deep interval:interval]; + } + } else { + // 直接调用原方法 + [invocation invoke]; + } + + [self atomicIncDeep]; +} + +@end + +//////////////////////////////////////////////////////////////////////////////// +#pragma mark - OMTBlock + +@implementation OMTBlock + +- (BOOL)runCondition:(SEL)sel +{ + if (self.condition) { + return self.condition(sel); + } else { + return YES; + } +} + +- (void)runBefore:(id)target class:(Class)cls sel:(SEL)sel args:(NSArray *)args deep:(int)deep +{ + if (self.before) { + self.before(target, cls, sel, args, deep); + } +} + +- (void)runAfter:(id)target class:(Class)cls sel:(SEL)sel ret:(id)ret deep:(int)deep interval:(NSTimeInterval)interval +{ + if (self.after) { + self.after(target, cls, sel, ret, deep, interval); + } +} + +@end + +//////////////////////////////////////////////////////////////////////////////// +#pragma mark - OMTMessageStub + +@implementation OMTMessageStub + +- (instancetype)initWithTarget:(id)target selector:(SEL)aSelector +{ + self = [super init]; + if (self) { + self.target = target; + NSString *finalSelectorName = [NSStringFromSelector(aSelector) stringByReplacingOccurrencesOfString:OMTMessageTempPrefix withString:OMTMessageFinalPrefix]; + self.selector = NSSelectorFromString(finalSelectorName); + } + return self; +} + +- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector +{ + Method method = class_getInstanceMethod(object_getClass(self.target), self.selector); + if (NULL == method) { + OMT_LOGE(@"No Method, target: %@ selector: %@", self.target, NSStringFromSelector(self.selector)); + assert(NULL != method); + } + + const char *types = method_getTypeEncoding(method); + if (NULL == types) { + OMT_LOGE(@"No Types, target: %@ selector: %@", self.target, NSStringFromSelector(self.selector)); + assert(NULL != types); + } + + return [NSMethodSignature signatureWithObjCTypes:types]; +} + +- (void)forwardInvocation:(NSInvocation *)anInvocation +{ + anInvocation.target = self.target; + anInvocation.selector = self.selector; + + // 勿删,调试观察类名和方法名 + __unused const char *className = [NSStringFromClass([self.target class]) UTF8String]; + __unused const char *selectorName = [NSStringFromSelector(self.selector) UTF8String]; + + [[OCMethodTrace sharedInstance] omt_forwardInvocation:anInvocation]; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p target: %p selector: %@>", + NSStringFromClass([self class]), self, self.target, NSStringFromSelector(self.selector)]; +} + +@end + +//////////////////////////////////////////////////////////////////////////////// +#pragma mark - NSObject (OCMethodTrace) + +@implementation NSObject (OCMethodTrace) + ++ (void)load +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + swizzle_class_method([self class], @selector(forwardingTargetForSelector:), @selector(omt_forwardingTargetForSelector:)); + swizzle_instance_method([self class], @selector(forwardingTargetForSelector:), @selector(omt_forwardingTargetForSelector:)); + }); +} + ++ (id)omt_forwardingTargetForSelector:(SEL)aSelector +{ + if ([NSStringFromSelector(aSelector) hasPrefix:OMTMessageTempPrefix] && ![self isKindOfClass:[OMTMessageStub class]]) { + return [[OMTMessageStub alloc] initWithTarget:self selector:aSelector]; + } + return [self omt_forwardingTargetForSelector:aSelector]; +} + +- (id)omt_forwardingTargetForSelector:(SEL)aSelector +{ + if ([NSStringFromSelector(aSelector) hasPrefix:OMTMessageTempPrefix] && ![self isKindOfClass:[OMTMessageStub class]]) { + return [[OMTMessageStub alloc] initWithTarget:self selector:aSelector]; + } + return [self omt_forwardingTargetForSelector:aSelector]; +} + +@end + +//////////////////////////////////////////////////////////////////////////////// +#pragma mark - NSInvocation (OCMethodTrace) + +@implementation NSInvocation (OCMethodTrace) + +- (Class)omt_originClass +{ + NSString *finalSelectorName = [NSStringFromSelector(self.selector) stringByReplacingOccurrencesOfString:OMTMessageFinalPrefix withString:@""]; + NSUInteger location = [finalSelectorName rangeOfString:@"->"].location; + NSString *originClassName = [finalSelectorName substringWithRange:NSMakeRange(0, location)]; + return NSClassFromString(originClassName); +} + +- (SEL)omt_originSelector +{ + NSString *finalSelectorName = [NSStringFromSelector(self.selector) stringByReplacingOccurrencesOfString:OMTMessageFinalPrefix withString:@""]; + NSUInteger location = [finalSelectorName rangeOfString:@"->"].location; + NSString *originSelectorName = [finalSelectorName substringWithRange:NSMakeRange(location + 2, finalSelectorName.length - location - 2)]; + return NSSelectorFromString(originSelectorName); +} + +- (id)omt_getReturnValue +{ + const char *returnType = self.methodSignature.methodReturnType; + id ret = nil; + + // 跳过类型限定符 + if (omt_isTypeQualifier(returnType[0])) { + returnType++; + } + + // 基本类型 + #define GET_RETURN_VALUE(_type) \ + if (0 == strcmp(returnType, @encode(_type))) { \ + _type ret_temp; \ + [self getReturnValue:&ret_temp]; \ + ret = @(ret_temp); \ + } + + // 结构体类型 + #define GET_STRUCT_RETURN_VALUE(_type) \ + if (is##_type(returnType)) { \ + _type ret_temp; \ + [self getReturnValue:&ret_temp]; \ + ret = NSStringFrom##_type(ret_temp); \ + } + + if (omt_isStructType(returnType)) { + GET_STRUCT_RETURN_VALUE(CGRect) + else GET_STRUCT_RETURN_VALUE(CGPoint) + else GET_STRUCT_RETURN_VALUE(CGSize) + else GET_STRUCT_RETURN_VALUE(CGVector) + else GET_STRUCT_RETURN_VALUE(UIOffset) + else GET_STRUCT_RETURN_VALUE(UIEdgeInsets) + else GET_STRUCT_RETURN_VALUE(CGAffineTransform) + } + else if (omt_isUnionType(returnType)) { + // do nothing + } + else GET_RETURN_VALUE(char) + else GET_RETURN_VALUE(int) + else GET_RETURN_VALUE(short) + else GET_RETURN_VALUE(long) + else GET_RETURN_VALUE(long long) + else GET_RETURN_VALUE(unsigned char) + else GET_RETURN_VALUE(unsigned int) + else GET_RETURN_VALUE(unsigned short) + else GET_RETURN_VALUE(unsigned long) + else GET_RETURN_VALUE(unsigned long long) + else GET_RETURN_VALUE(float) + else GET_RETURN_VALUE(double) + else GET_RETURN_VALUE(BOOL) + else if (strcmp(returnType, @encode(void)) == 0) { + ret = @"void"; + } + else if (0 == strcmp(returnType, @encode(char *))) { + char *ret_temp; + [self getReturnValue:&ret_temp]; + ret = [NSString stringWithUTF8String:ret_temp ? ret_temp : "NULL"]; + } + else if (0 == strcmp(returnType, @encode(id))) { + __unsafe_unretained id ret_temp; + [self getReturnValue:&ret_temp]; + ret = [[OCMethodTrace sharedInstance] descriptionWithTarget:ret_temp class:[self omt_originClass] selector:[self omt_originSelector] targetPosition:OMTTargetPositionAfterReturnValue]; + } + else if (0 == strcmp(returnType, @encode(Class))) { + Class ret_temp; + [self getReturnValue:&ret_temp]; + ret = NSStringFromClass(ret_temp); + } + else if (0 == strcmp(returnType, @encode(SEL))) { + SEL ret_temp; + [self getReturnValue:&ret_temp]; + ret = NSStringFromSelector(ret_temp); + } + else if (0 == strcmp(returnType, "@?")) { // block + // 则模仿lldb bt堆栈打印形式,直接打印地址 + void *ret_temp; + [self getReturnValue:&ret_temp]; + ret = [NSString stringWithFormat:@"%p", ret_temp]; + } + else if (returnType[0] == _C_PTR) { + void *ret_temp; + [self getReturnValue:&ret_temp]; + if (0 == strcmp(returnType, @encode(CFStringRef))) { + ret = [NSString stringWithString:ret_temp ? (__bridge NSString *)ret_temp : @"NULL"]; // 深拷贝 + } + if (nil == ret) { + // 模仿lldb bt堆栈打印形式,直接打印地址 + ret = [NSString stringWithFormat:@"%p", ret_temp]; + } + } + + if (nil == ret) { + NSUInteger valueSize = 0; + NSGetSizeAndAlignment(returnType, &valueSize, NULL); + unsigned char valueBytes[valueSize]; + [self getReturnValue:valueBytes]; + ret = [NSValue valueWithBytes:valueBytes objCType:returnType]; + } + + return ret; +} + +- (NSArray *)omt_getArguments +{ + NSMethodSignature *methodSignature = [self methodSignature]; + NSMutableArray *argList = (methodSignature.numberOfArguments > 2 ? [NSMutableArray array] : nil); + for (NSUInteger i = 2; i < methodSignature.numberOfArguments; i++) { + const char *argumentType = [methodSignature getArgumentTypeAtIndex:i]; + id arg = nil; + + // 跳过类型限定符 + if (omt_isTypeQualifier(argumentType[0])) { + argumentType++; + } + + // 基本类型 + #define GET_ARGUMENT(_type) \ + if (0 == strcmp(argumentType, @encode(_type))) { \ + _type arg_temp; \ + [self getArgument:&arg_temp atIndex:i]; \ + arg = @(arg_temp); \ + } + + // 结构体类型 + #define GET_STRUCT_ARGUMENT(_type) \ + if (is##_type(argumentType)) { \ + _type arg_temp; \ + [self getArgument:&arg_temp atIndex:i]; \ + arg = NSStringFrom##_type(arg_temp); \ + } + + + if (omt_isStructType(argumentType)) { + GET_STRUCT_ARGUMENT(CGRect) + else GET_STRUCT_ARGUMENT(CGPoint) + else GET_STRUCT_ARGUMENT(CGSize) + else GET_STRUCT_ARGUMENT(CGVector) + else GET_STRUCT_ARGUMENT(UIOffset) + else GET_STRUCT_ARGUMENT(UIEdgeInsets) + else GET_STRUCT_ARGUMENT(CGAffineTransform) + } + else if (omt_isUnionType(argumentType)) { + // do nothing + } + else GET_ARGUMENT(char) + else GET_ARGUMENT(int) + else GET_ARGUMENT(short) + else GET_ARGUMENT(long) + else GET_ARGUMENT(long long) + else GET_ARGUMENT(unsigned char) + else GET_ARGUMENT(unsigned int) + else GET_ARGUMENT(unsigned short) + else GET_ARGUMENT(unsigned long) + else GET_ARGUMENT(unsigned long long) + else GET_ARGUMENT(float) + else GET_ARGUMENT(double) + else GET_ARGUMENT(BOOL) + else if (0 == strcmp(argumentType, @encode(char *))) { + char *arg_temp; + [self getArgument:&arg_temp atIndex:i]; + arg = [NSString stringWithUTF8String:arg_temp ? arg_temp : "NULL"]; + } + else if (0 == strcmp(argumentType, @encode(id))) { + __unsafe_unretained id arg_temp; + [self getArgument:&arg_temp atIndex:i]; + arg = [[OCMethodTrace sharedInstance] descriptionWithTarget:arg_temp class:[arg_temp class] selector:[self omt_originSelector] targetPosition:OMTTargetPositionBeforeArgument]; + } + else if (0 == strcmp(argumentType, @encode(Class))) { + Class arg_temp; + [self getArgument:&arg_temp atIndex:i]; + arg = NSStringFromClass(arg_temp); + } + else if (0 == strcmp(argumentType, @encode(SEL))) { + SEL arg_temp; + [self getArgument:&arg_temp atIndex:i]; + arg = NSStringFromSelector(arg_temp); + } + else if (0 == strcmp(argumentType, "@?")) { // block + // 则模仿lldb bt堆栈打印形式,直接打印地址 + void *arg_temp; + [self getArgument:&arg_temp atIndex:i]; + arg = [NSString stringWithFormat:@"%p", arg_temp]; + } + else if (argumentType[0] == _C_PTR) { + void *arg_temp; + [self getArgument:&arg_temp atIndex:i]; + if (0 == strcmp(argumentType, @encode(CFStringRef))) { + arg = [NSString stringWithString:arg_temp ? (__bridge NSString *)arg_temp : @"NULL"]; // 深拷贝 + } + if (nil == arg) { + // 则模仿lldb bt堆栈打印形式,直接打印地址 + arg = [NSString stringWithFormat:@"%p", arg_temp]; + } + } + + if (nil == arg) { + NSUInteger valueSize = 0; + NSGetSizeAndAlignment(argumentType, &valueSize, NULL); + unsigned char valueBytes[valueSize]; + [self getArgument:valueBytes atIndex:i]; + arg = [NSValue valueWithBytes:valueBytes objCType:argumentType]; + } + + [argList addObject:arg]; + } + return argList; +} + +@end diff --git a/dkvideoLoader/dkvideoLoaderDylib/Trace/OCSelectorTrampolines.h b/dkvideoLoader/dkvideoLoaderDylib/Trace/OCSelectorTrampolines.h new file mode 100644 index 0000000..e6b1b38 --- /dev/null +++ b/dkvideoLoader/dkvideoLoaderDylib/Trace/OCSelectorTrampolines.h @@ -0,0 +1,26 @@ +/* + * OCSelectorTrampolines.mm + * OCMethodTrace + * + * https://github.com/omxcodec/OCMethodTrace.git + * + * Copyright (C) 2018 Michael Chen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +FOUNDATION_EXTERN IMP imp_implementationWithSelector(SEL aSel, const char *signature); +FOUNDATION_EXTERN SEL imp_getSelector(IMP anImp); +FOUNDATION_EXTERN BOOL imp_removeSelector(IMP anImp); diff --git a/dkvideoLoader/dkvideoLoaderDylib/Trace/OCSelectorTrampolines.mm b/dkvideoLoader/dkvideoLoaderDylib/Trace/OCSelectorTrampolines.mm new file mode 100644 index 0000000..1c9180d --- /dev/null +++ b/dkvideoLoader/dkvideoLoaderDylib/Trace/OCSelectorTrampolines.mm @@ -0,0 +1,449 @@ +/* + * OCSelectorTrampolines.mm + * OCMethodTrace + * + * https://github.com/omxcodec/OCMethodTrace.git + * + * Copyright (C) 2018 Michael Chen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "OCSelectorTrampolines.h" +#import +#import +#import +#import + +// Define SUPPORT_STRET on architectures that need separate struct-return ABI. +#if defined(__arm64__) +# define SUPPORT_STRET 0 +#else +# define SUPPORT_STRET 1 +#endif + +#define _ost_fatal(fmt, ...) [NSException raise:@"OCSelectorTrampolines" format:fmt, ##__VA_ARGS__] + +// symbols defined in assembly files +// Don't use the symbols directly; they're thumb-biased on some ARM archs. +#define TRAMP(tramp) \ + static inline __unused uintptr_t tramp(void) { \ + extern void *_##tramp; \ + return ((uintptr_t)&_##tramp) & ~1UL; \ + } +// Scalar return +TRAMP(a1a2_selectorTrampHead); // trampoline header code +TRAMP(a1a2_firstSelectorTramp); // first trampoline +TRAMP(a1a2_selectorTrampEnd); // after the last trampoline + +#if SUPPORT_STRET +// Struct return +TRAMP(a2a3_selectorTrampHead); +TRAMP(a2a3_firstSelectorTramp); +TRAMP(a2a3_selectorTrampEnd); +#endif + +// argument mode identifier +typedef enum { + ReturnValueInRegisterArgumentMode, +#if SUPPORT_STRET + ReturnValueOnStackArgumentMode, +#endif + + ArgumentModeCount +} ArgumentMode; + + +// We must take care with our data layout on architectures that support +// multiple page sizes. +// +// The trampoline template in __TEXT is sized and aligned with PAGE_MAX_SIZE. +// On some platforms this requires additional linker flags. +// +// When we allocate a page pair, we use PAGE_MAX_SIZE size. +// This allows trampoline code to find its data by subtracting PAGE_MAX_SIZE. +// +// When we allocate a page pair, we use the process's page alignment. +// This simplifies allocation because we don't need to force greater than +// default alignment when running with small pages, but it also means +// the trampoline code MUST NOT look for its data by masking with PAGE_MAX_MASK. + +struct TrampolineSelectorPagePair +{ + IMP msgSend; // msg send hander + + TrampolineSelectorPagePair *nextPagePair; // linked list of all pages + TrampolineSelectorPagePair *nextAvailablePage; // linked list of pages with available slots + + uintptr_t nextAvailable; // index of next available slot, endIndex() if no more available + + // Payload data: selector and free list. + // Bytes parallel with trampoline header code are the fields above or unused + // uint8_t selectors[ PAGE_MAX_SIZE - sizeof(TrampolineSelectorPagePair) ] + + // Code: trampoline header followed by trampolines. + // uint8_t trampolines[PAGE_MAX_SIZE]; + + // Per-trampoline selector data format: + // initial value is 0 while page data is filled sequentially + // when filled, value is reference to selector + // when empty, value is index of next available slot OR 0 if never used yet + + union Payload { + SEL selector; + uintptr_t nextAvailable; // free list + }; + + static uintptr_t headerSize() { + return (uintptr_t) (a1a2_firstSelectorTramp() - a1a2_selectorTrampHead()); + } + + static uintptr_t slotSize() { + return 8; + } + + static uintptr_t startIndex() { + // headerSize is assumed to be slot-aligned + return headerSize() / slotSize(); + } + + static uintptr_t endIndex() { + return (uintptr_t)PAGE_MAX_SIZE / slotSize(); + } + + static bool validIndex(uintptr_t index) { + return (index >= startIndex() && index < endIndex()); + } + + Payload *payload(uintptr_t index) { + assert(validIndex(index)); + return (Payload *)((char *)this + index*slotSize()); + } + + IMP trampoline(uintptr_t index) { + assert(validIndex(index)); + char *imp = (char *)this + index*slotSize() + PAGE_MAX_SIZE; +#if __arm__ + imp++; // trampoline is Thumb instructions +#endif + return (IMP)imp; + } + + uintptr_t indexForTrampoline(IMP tramp) { + uintptr_t tramp0 = (uintptr_t)this + PAGE_MAX_SIZE; + uintptr_t start = tramp0 + headerSize(); + uintptr_t end = tramp0 + PAGE_MAX_SIZE; + uintptr_t address = (uintptr_t)tramp; + if (address >= start && address < end) { + return (uintptr_t)(address - tramp0) / slotSize(); + } + return 0; + } + + static void check() { + assert(TrampolineSelectorPagePair::slotSize() == 8); + assert(TrampolineSelectorPagePair::headerSize() >= sizeof(TrampolineSelectorPagePair)); + assert(TrampolineSelectorPagePair::headerSize() % TrampolineSelectorPagePair::slotSize() == 0); + + // _objc_inform("%p %p %p", a1a2_selectorTrampHead(), a1a2_firstSelectorTramp(), + // a1a2_selectorTrampEnd()); + assert(a1a2_selectorTrampHead() % PAGE_SIZE == 0); // not PAGE_MAX_SIZE + assert(a1a2_selectorTrampHead() + PAGE_MAX_SIZE == a1a2_selectorTrampEnd()); +#if SUPPORT_STRET + // _objc_inform("%p %p %p", a2a3_selectorTrampHead(), a2a3_firstSelectorTramp(), + // a2a3_selectorTrampEnd()); + assert(a2a3_selectorTrampHead() % PAGE_SIZE == 0); // not PAGE_MAX_SIZE + assert(a2a3_selectorTrampHead() + PAGE_MAX_SIZE == a2a3_selectorTrampEnd()); +#endif + +#if __arm__ + // make sure trampolines are Thumb + extern void *_a1a2_firstSelectorTramp; + extern void *_a2a3_firstSelectorTramp; + assert(((uintptr_t)&_a1a2_firstSelectorTramp) % 2 == 1); + assert(((uintptr_t)&_a2a3_firstSelectorTramp) % 2 == 1); +#endif + } + +}; + +// two sets of trampoline pages; one for stack returns and one for register returns +static TrampolineSelectorPagePair *headPagePairs[ArgumentModeCount]; + +#pragma mark Utility Functions + +static pthread_rwlock_t trampolinesLock = PTHREAD_RWLOCK_INITIALIZER; + +static inline void _lock() { + int err = pthread_rwlock_wrlock(&trampolinesLock); + if (err) _ost_fatal(@"pthread_rwlock_wrlock failed (%d)", err); +} + +static inline void _unlock() { + int err = pthread_rwlock_unlock(&trampolinesLock); + if (err) _ost_fatal(@"pthread_rwlock_unlock failed (%d)", err); +} + +static inline void _assert_locked() { +} + +#pragma mark Trampoline Management Functions +static TrampolineSelectorPagePair *_allocateTrampolinesAndData(ArgumentMode aMode) +{ + _assert_locked(); + + vm_address_t dataAddress; + + TrampolineSelectorPagePair::check(); + + TrampolineSelectorPagePair *headPagePair = headPagePairs[aMode]; + + assert(headPagePair == nil || headPagePair->nextAvailablePage == nil); + + kern_return_t result; + result = vm_allocate(mach_task_self(), &dataAddress, PAGE_MAX_SIZE * 2, + VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_FOUNDATION)); + if (result != KERN_SUCCESS) { + _ost_fatal(@"vm_allocate trampolines failed (%d)", result); + } + + vm_address_t codeAddress = dataAddress + PAGE_MAX_SIZE; + + uintptr_t codePage = NULL; + IMP sendImp = NULL; + switch(aMode) { + case ReturnValueInRegisterArgumentMode: + codePage = a1a2_selectorTrampHead(); + sendImp = objc_msgSend; + break; +#if SUPPORT_STRET + case ReturnValueOnStackArgumentMode: + codePage = a2a3_selectorTrampHead(); + sendImp = objc_msgSend_stret; + break; +#endif + default: + _ost_fatal(@"unknown return mode %d", (int)aMode); + break; + } + + vm_prot_t currentProtection, maxProtection; + result = vm_remap(mach_task_self(), &codeAddress, PAGE_MAX_SIZE, + 0, VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE, + mach_task_self(), codePage, TRUE, + ¤tProtection, &maxProtection, VM_INHERIT_SHARE); + if (result != KERN_SUCCESS) { + // vm_deallocate(mach_task_self(), dataAddress, PAGE_MAX_SIZE * 2); + _ost_fatal(@"vm_remap trampolines failed (%d)", result); + } + + TrampolineSelectorPagePair *pagePair = (TrampolineSelectorPagePair *) dataAddress; + pagePair->nextAvailable = pagePair->startIndex(); + pagePair->nextPagePair = nil; + pagePair->nextAvailablePage = nil; + pagePair->msgSend = sendImp; + + if (headPagePair) { + TrampolineSelectorPagePair *lastPagePair = headPagePair; + while(lastPagePair->nextPagePair) { + lastPagePair = lastPagePair->nextPagePair; + } + lastPagePair->nextPagePair = pagePair; + headPagePairs[aMode]->nextAvailablePage = pagePair; + } else { + headPagePairs[aMode] = pagePair; + } + + return pagePair; +} + +static TrampolineSelectorPagePair * +_getOrAllocatePagePairWithNextAvailable(ArgumentMode aMode) +{ + _assert_locked(); + + TrampolineSelectorPagePair *headPagePair = headPagePairs[aMode]; + + if (!headPagePair) + return _allocateTrampolinesAndData(aMode); + + // make sure head page is filled first + if (headPagePair->nextAvailable != headPagePair->endIndex()) + return headPagePair; + + if (headPagePair->nextAvailablePage) // check if there is a page w/a hole + return headPagePair->nextAvailablePage; + + return _allocateTrampolinesAndData(aMode); // tack on a new one +} + +static TrampolineSelectorPagePair * +_pageAndIndexContainingIMP(IMP anImp, uintptr_t *outIndex, + TrampolineSelectorPagePair **outHeadPagePair) +{ + _assert_locked(); + + for (int arg = 0; arg < ArgumentModeCount; arg++) { + for (TrampolineSelectorPagePair *pagePair = headPagePairs[arg]; + pagePair; + pagePair = pagePair->nextPagePair) + { + uintptr_t index = pagePair->indexForTrampoline(anImp); + if (index) { + if (outIndex) *outIndex = index; + if (outHeadPagePair) *outHeadPagePair = headPagePairs[arg]; + return pagePair; + } + } + } + + return nil; +} + +static ArgumentMode +_argumentModeForSignature(const char *signature) +{ + ArgumentMode aMode = ReturnValueInRegisterArgumentMode; + +#if SUPPORT_STRET + if (signature && signature[0] == '{') { + @try { + // In some cases that returns struct, we should use the '_stret' API: + // http://sealiesoftware.com/blog/archive/2008/10/30/objc_explain_objc_msgSend_stret.html + // NSMethodSignature knows the detail but has no API to return, we can only get the info from debugDescription. + NSMethodSignature *methodSignature = [NSMethodSignature signatureWithObjCTypes:signature]; + if ([methodSignature.debugDescription rangeOfString:@"is special struct return? YES"].location != NSNotFound) { + aMode = ReturnValueOnStackArgumentMode; + } + } @catch (__unused NSException *e) {} + } +#endif + + return aMode; +} + +#pragma mark Public API +IMP imp_implementationWithSelector(SEL aSel, const char *signature) +{ + IMP returnIMP; + + _lock(); + + ArgumentMode aMode = _argumentModeForSignature(signature); + + TrampolineSelectorPagePair *pagePair = + _getOrAllocatePagePairWithNextAvailable(aMode); + if (!headPagePairs[aMode]) + headPagePairs[aMode] = pagePair; + + uintptr_t index = pagePair->nextAvailable; + assert(index >= pagePair->startIndex() && index < pagePair->endIndex()); + TrampolineSelectorPagePair::Payload *payload = pagePair->payload(index); + + uintptr_t nextAvailableIndex = payload->nextAvailable; + if (nextAvailableIndex == 0) { + // First time through (unused slots are zero). Fill sequentially. + // If the page is now full this will now be endIndex(), handled below. + nextAvailableIndex = index + 1; + } + pagePair->nextAvailable = nextAvailableIndex; + if (nextAvailableIndex == pagePair->endIndex()) { + // PagePair is now full (free list or wilderness exhausted) + // Remove from available page linked list + TrampolineSelectorPagePair *iterator = headPagePairs[aMode]; + while(iterator && (iterator->nextAvailablePage != pagePair)) { + iterator = iterator->nextAvailablePage; + } + if (iterator) { + iterator->nextAvailablePage = pagePair->nextAvailablePage; + pagePair->nextAvailablePage = nil; + } + } + + payload->selector = aSel; + returnIMP = pagePair->trampoline(index); + + _unlock(); + + return returnIMP; +} + +SEL imp_getSelector(IMP anImp) { + uintptr_t index; + TrampolineSelectorPagePair *pagePair; + + if (!anImp) return nil; + + _lock(); + + pagePair = _pageAndIndexContainingIMP(anImp, &index, nil); + + if (!pagePair) { + _unlock(); + return nil; + } + + TrampolineSelectorPagePair::Payload *payload = pagePair->payload(index); + + if (payload->nextAvailable <= TrampolineSelectorPagePair::endIndex()) { + // unallocated + _unlock(); + return nil; + } + + _unlock(); + + return payload->selector; +} + +BOOL imp_removeSelector(IMP anImp) { + TrampolineSelectorPagePair *pagePair; + TrampolineSelectorPagePair *headPagePair; + uintptr_t index; + + if (!anImp) return NO; + + _lock(); + pagePair = _pageAndIndexContainingIMP(anImp, &index, &headPagePair); + + if (!pagePair) { + _unlock(); + return NO; + } + + TrampolineSelectorPagePair::Payload *payload = pagePair->payload(index); + + payload->nextAvailable = pagePair->nextAvailable; + pagePair->nextAvailable = index; + + // make sure this page is on available linked list + TrampolineSelectorPagePair *pagePairIterator = headPagePair; + + // see if page is the next available page for any existing pages + while (pagePairIterator->nextAvailablePage && + pagePairIterator->nextAvailablePage != pagePair) + { + pagePairIterator = pagePairIterator->nextAvailablePage; + } + + if (! pagePairIterator->nextAvailablePage) { + // if iteration stopped because nextAvail was nil + // add to end of list. + pagePairIterator->nextAvailablePage = pagePair; + pagePair->nextAvailablePage = nil; + } + + _unlock(); + + return YES; +} diff --git a/dkvideoLoader/dkvideoLoaderDylib/Trace/a1a2-selectortramps-arm.s b/dkvideoLoader/dkvideoLoaderDylib/Trace/a1a2-selectortramps-arm.s new file mode 100644 index 0000000..667fb82 --- /dev/null +++ b/dkvideoLoader/dkvideoLoaderDylib/Trace/a1a2-selectortramps-arm.s @@ -0,0 +1,166 @@ +/* + * a1a2-selectortramps-arm.s + * OCMethodTrace + * + * https://github.com/omxcodec/OCMethodTrace.git + * + * Copyright (C) 2018 Michael Chen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if __arm__ + +#include +#include + +.syntax unified + +.text + + .private_extern __a1a2_selectorTrampHead + .private_extern __a1a2_firstSelectorTramp + .private_extern __a1a2_selectorTrampEnd + +// Trampoline machinery assumes the trampolines are Thumb function pointers +#if !__thumb2__ +# error sorry +#endif + +.thumb +.thumb_func __a1a2_selectorTrampHead +.thumb_func __a1a2_firstSelectorTramp +.thumb_func __a1a2_selectorTrampEnd + +.align PAGE_MAX_SHIFT +__a1a2_selectorTrampHead: + // Trampoline's data is one page before the trampoline text. + // Also correct PC bias of 4 bytes. + // 1. selector + sub r12, #PAGE_MAX_SIZE + ldr r1, [r12, #-4] // selector -> _cmd + // 2. msgSend + mov r12, pc + sub r12, #PAGE_MAX_SIZE + ldr pc, [r12, #-12] // tail call msgSend + // not reached + nop + + // Align trampolines to 8 bytes +.align 3 + +.macro TrampolineEntry + mov r12, pc + b __a1a2_selectorTrampHead +.align 3 +.endmacro + +.macro TrampolineEntryX16 + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry +.endmacro + +.macro TrampolineEntryX256 + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 +.endmacro + +.private_extern __a1a2_firstSelectorTramp +__a1a2_firstSelectorTramp: + // 2048-3 trampolines to fill 16K page + TrampolineEntryX256 + TrampolineEntryX256 + TrampolineEntryX256 + TrampolineEntryX256 + + TrampolineEntryX256 + TrampolineEntryX256 + TrampolineEntryX256 + + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + + TrampolineEntry + // TrampolineEntry + // TrampolineEntry + // TrampolineEntry + +.private_extern __a1a2_selectorTrampEnd +__a1a2_selectorTrampEnd: + +#endif diff --git a/dkvideoLoader/dkvideoLoaderDylib/Trace/a1a2-selectortramps-arm64.s b/dkvideoLoader/dkvideoLoaderDylib/Trace/a1a2-selectortramps-arm64.s new file mode 100644 index 0000000..28b79a8 --- /dev/null +++ b/dkvideoLoader/dkvideoLoaderDylib/Trace/a1a2-selectortramps-arm64.s @@ -0,0 +1,156 @@ +/* + * a1a2-selectortramps-arm64.s + * OCMethodTrace + * + * https://github.com/omxcodec/OCMethodTrace.git + * + * Copyright (C) 2018 Michael Chen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if __arm64__ + +#include + +.text + + .private_extern __a1a2_selectorTrampHead + .private_extern __a1a2_firstSelectorTramp + .private_extern __a1a2_selectorTrampEnd + +msgSend: + .quad 0 + +.align PAGE_MAX_SHIFT +__a1a2_selectorTrampHead: +L_a1a2_selectorTrampHead: + // 1. selector + ldr x1, [x17] // selector -> _cmd + // 2. msgSend + adr x17, L_a1a2_selectorTrampHead + sub x17, x17, #PAGE_MAX_SIZE + ldr x16, [x17] + br x16 // tail call msgSend + + // pad up to TrampolineSelectorPagePair header size + nop + nop + nop + +.macro TrampolineEntry + // load address of trampoline data (one page before this instruction) + adr x17, -PAGE_MAX_SIZE + b L_a1a2_selectorTrampHead +.endmacro + +.macro TrampolineEntryX16 + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry +.endmacro + +.macro TrampolineEntryX256 + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 +.endmacro + +.align 3 +.private_extern __a1a2_firstSelectorTramp +__a1a2_firstSelectorTramp: + // 2048-4 trampolines to fill 16K page + TrampolineEntryX256 + TrampolineEntryX256 + TrampolineEntryX256 + TrampolineEntryX256 + + TrampolineEntryX256 + TrampolineEntryX256 + TrampolineEntryX256 + + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + + // TrampolineEntry + // TrampolineEntry + // TrampolineEntry + // TrampolineEntry + +.private_extern __a1a2_selectorTrampEnd +__a1a2_selectorTrampEnd: + +#endif diff --git a/dkvideoLoader/dkvideoLoaderDylib/Trace/a1a2-selectortramps-i386.s b/dkvideoLoader/dkvideoLoaderDylib/Trace/a1a2-selectortramps-i386.s new file mode 100644 index 0000000..71aa857 --- /dev/null +++ b/dkvideoLoader/dkvideoLoaderDylib/Trace/a1a2-selectortramps-i386.s @@ -0,0 +1,569 @@ +/* + * a1a2-selectortramps-i386.s + * OCMethodTrace + * + * https://github.com/omxcodec/OCMethodTrace.git + * + * Copyright (C) 2018 Michael Chen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef __i386__ + +#include +#include "selectortramps.mac" + +.text + .private_extern __a1a2_selectorTrampHead + .private_extern __a1a2_firstSelectorTramp + .private_extern __a1a2_nextSelectorTramp + .private_extern __a1a2_selectorTrampEnd + +.align PAGE_SHIFT +__a1a2_selectorTrampHead: + // 1. selector + popl %eax + andl $0xFFFFFFF8, %eax + subl $ PAGE_SIZE, %eax + movl (%eax), %ecx // selectorPtr -> ecx + movl %ecx, 8(%esp) // ecx -> _cmd + // 2. msgSend + INIT_PIC(__a1a2_selectorTrampHead) + PRELOAD(__a1a2_selectorTrampHead, __a1a2_selectorTrampHead) + subl $ PAGE_SIZE, LABEL_ADDR(__a1a2_selectorTrampHead, __a1a2_selectorTrampHead) + END_PIC() + jmp *0(%eax) // tail call msgSend + +.macro TrampolineEntry + call __a1a2_selectorTrampHead + nop + nop + nop +.endmacro + +.align 5 +__a1a2_firstSelectorTramp: + TrampolineEntry +__a1a2_nextSelectorTramp: // used to calculate size of each trampoline + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + // TrampolineEntry + // TrampolineEntry + // TrampolineEntry + // TrampolineEntry + +__a1a2_selectorTrampEnd: + +#endif diff --git a/dkvideoLoader/dkvideoLoaderDylib/Trace/a1a2-selectortramps-x86_64.s b/dkvideoLoader/dkvideoLoaderDylib/Trace/a1a2-selectortramps-x86_64.s new file mode 100644 index 0000000..4b57025 --- /dev/null +++ b/dkvideoLoader/dkvideoLoaderDylib/Trace/a1a2-selectortramps-x86_64.s @@ -0,0 +1,568 @@ +/* + * a1a2-selectortramps-x86_64.s + * OCMethodTrace + * + * https://github.com/omxcodec/OCMethodTrace.git + * + * Copyright (C) 2018 Michael Chen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef __x86_64__ + +#include +#include "selectortramps.mac" + + .text + .private_extern __a1a2_selectorTrampHead + .private_extern __a1a2_firstSelectorTramp + .private_extern __a1a2_nextSelectorTramp + .private_extern __a1a2_selectorTrampEnd + +.align PAGE_SHIFT +__a1a2_selectorTrampHead: + // 1. selector + popq %r10 + andq $0xFFFFFFFFFFFFFFF8, %r10 + subq $ PAGE_SIZE, %r10 + movq (%r10), %rsi // selector -> _cmd + // 2. msgSend + INIT_PIC(__a1a2_selectorTrampHead) + PRELOAD(__a1a2_selectorTrampHead, __a1a2_selectorTrampHead) + subq $ PAGE_SIZE, LABEL_ADDR(__a1a2_selectorTrampHead, __a1a2_selectorTrampHead) + END_PIC() + jmp *0(%r10) // tail call msgSend + +.macro TrampolineEntry + callq __a1a2_selectorTrampHead + nop + nop + nop +.endmacro + +.align 5 +__a1a2_firstSelectorTramp: + TrampolineEntry +__a1a2_nextSelectorTramp: + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + // TrampolineEntry + // TrampolineEntry + // TrampolineEntry + // TrampolineEntry + +__a1a2_selectorTrampEnd: + +#endif diff --git a/dkvideoLoader/dkvideoLoaderDylib/Trace/a2a3-selectortramps-arm.s b/dkvideoLoader/dkvideoLoaderDylib/Trace/a2a3-selectortramps-arm.s new file mode 100644 index 0000000..70f9a33 --- /dev/null +++ b/dkvideoLoader/dkvideoLoaderDylib/Trace/a2a3-selectortramps-arm.s @@ -0,0 +1,166 @@ +/* + * a2a3-selectortramps-arm.s + * OCMethodTrace + * + * https://github.com/omxcodec/OCMethodTrace.git + * + * Copyright (C) 2018 Michael Chen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if __arm__ + +#include +#include + +.syntax unified + +.text + + .private_extern __a2a3_selectorTrampHead + .private_extern __a2a3_firstSelectorTramp + .private_extern __a2a3_selectorTrampEnd + +// Trampoline machinery assumes the trampolines are Thumb function pointers +#if !__thumb2__ +# error sorry +#endif + +.thumb +.thumb_func __a2a3_selectorTrampHead +.thumb_func __a2a3_firstSelectorTramp +.thumb_func __a2a3_selectorTrampEnd + +.align PAGE_MAX_SHIFT +__a2a3_selectorTrampHead: + // Trampoline's data is one page before the trampoline text. + // Also correct PC bias of 4 bytes. + // 1. selector + sub r12, #PAGE_MAX_SIZE + ldr r2, [r12, #-4] // _cmd = selector + // 2. msgSend. Can't "ldr r12, msgSend", error: out of range pc-relative fixup value + mov r12, pc + sub r12, #PAGE_MAX_SIZE + ldr pc, [r12, #-12] + // not reached + nop + + // Align trampolines to 8 bytes +.align 3 + +.macro TrampolineEntry + mov r12, pc + b __a2a3_selectorTrampHead +.align 3 +.endmacro + +.macro TrampolineEntryX16 + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry +.endmacro + +.macro TrampolineEntryX256 + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 +.endmacro + +.private_extern __a2a3_firstSelectorTramp +__a2a3_firstSelectorTramp: + // 2048-2 trampolines to fill 16K page + TrampolineEntryX256 + TrampolineEntryX256 + TrampolineEntryX256 + TrampolineEntryX256 + + TrampolineEntryX256 + TrampolineEntryX256 + TrampolineEntryX256 + + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + + TrampolineEntryX16 + TrampolineEntryX16 + TrampolineEntryX16 + + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + + TrampolineEntry + // TrampolineEntry + // TrampolineEntry + // TrampolineEntry + +.private_extern __a2a3_selectorTrampEnd +__a2a3_selectorTrampEnd: + +#endif diff --git a/dkvideoLoader/dkvideoLoaderDylib/Trace/a2a3-selectortramps-i386.s b/dkvideoLoader/dkvideoLoaderDylib/Trace/a2a3-selectortramps-i386.s new file mode 100644 index 0000000..bbd9d0f --- /dev/null +++ b/dkvideoLoader/dkvideoLoaderDylib/Trace/a2a3-selectortramps-i386.s @@ -0,0 +1,569 @@ +/* + * a2a3-selectortramps-i386.s + * OCMethodTrace + * + * https://github.com/omxcodec/OCMethodTrace.git + * + * Copyright (C) 2018 Michael Chen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef __i386__ + +#include +#include "selectortramps.mac" + +.text + .private_extern __a2a3_selectorTrampHead + .private_extern __a2a3_firstSelectorTramp + .private_extern __a2a3_nextSelectorTramp + .private_extern __a2a3_selectorTrampEnd + +.align PAGE_SHIFT +__a2a3_selectorTrampHead: + // 1. selector + popl %eax + andl $0xFFFFFFF8, %eax + subl $ PAGE_SIZE, %eax + movl (%eax), %ecx // selectorPtr -> ecx + movl %ecx, 12(%esp) // ecx -> _cmd + // 2. msgSend + INIT_PIC(__a2a3_selectorTrampHead) + PRELOAD(__a2a3_selectorTrampHead, __a2a3_selectorTrampHead) + subl $ PAGE_SIZE, LABEL_ADDR(__a2a3_selectorTrampHead, __a2a3_selectorTrampHead) + END_PIC() + jmp *0(%eax) // tail call msgSend + +.macro TrampolineEntry + call __a2a3_selectorTrampHead + nop + nop + nop +.endmacro + +.align 5 +__a2a3_firstSelectorTramp: + TrampolineEntry +__a2a3_nextSelectorTramp: + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + // TrampolineEntry + // TrampolineEntry + // TrampolineEntry + // TrampolineEntry + +__a2a3_selectorTrampEnd: + +#endif diff --git a/dkvideoLoader/dkvideoLoaderDylib/Trace/a2a3-selectortramps-x86_64.s b/dkvideoLoader/dkvideoLoaderDylib/Trace/a2a3-selectortramps-x86_64.s new file mode 100644 index 0000000..adecbfd --- /dev/null +++ b/dkvideoLoader/dkvideoLoaderDylib/Trace/a2a3-selectortramps-x86_64.s @@ -0,0 +1,568 @@ +/* + * a2a3-selectortramps-x86_64.s + * OCMethodTrace + * + * https://github.com/omxcodec/OCMethodTrace.git + * + * Copyright (C) 2018 Michael Chen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef __x86_64__ + +#include +#include "selectortramps.mac" + + .text + .private_extern __a2a3_selectorTrampHead + .private_extern __a2a3_firstSelectorTramp + .private_extern __a2a3_nextSelectorTramp + .private_extern __a2a3_selectorTrampEnd + +.align PAGE_SHIFT +__a2a3_selectorTrampHead: + // 1. selector + popq %r10 + andq $0xFFFFFFFFFFFFFFF8, %r10 + subq $ PAGE_SIZE, %r10 + movq (%r10), %rdx // selector -> _cmd + // 2. msgSend + INIT_PIC(__a2a3_selectorTrampHead) + PRELOAD(__a2a3_selectorTrampHead, __a2a3_selectorTrampHead) + subq $ PAGE_SIZE, LABEL_ADDR(__a2a3_selectorTrampHead, __a2a3_selectorTrampHead) + END_PIC() + jmp *0(%r10) // tail call msgSend + +.macro TrampolineEntry + callq __a2a3_selectorTrampHead + nop + nop + nop +.endmacro + +.align 5 +__a2a3_firstSelectorTramp: + TrampolineEntry +__a2a3_nextSelectorTramp: + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + TrampolineEntry + // TrampolineEntry + // TrampolineEntry + // TrampolineEntry + // TrampolineEntry + +__a2a3_selectorTrampEnd: + +#endif diff --git a/dkvideoLoader/dkvideoLoaderDylib/Trace/selectortramps.mac b/dkvideoLoader/dkvideoLoaderDylib/Trace/selectortramps.mac new file mode 100644 index 0000000..3f1616a --- /dev/null +++ b/dkvideoLoader/dkvideoLoaderDylib/Trace/selectortramps.mac @@ -0,0 +1,38 @@ +/* + * selectortramps.mac + * OCMethodTrace + * + * https://github.com/omxcodec/OCMethodTrace.git + * + * Copyright (C) 2018 Michael Chen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef __x86_64__ + #define PRELOAD(x,f) movq x@GOTPCREL(%rip), %r10; + #define LABEL_ADDR(x,f) %r10 + #define LABEL_VALUE(x,f) (%r10) + #define INIT_PIC(f) + #define END_PIC(f) +#elif __i386__ + #define PRELOAD(x,f) leal x-L0## f ##$pb(%ebx), %eax; + #define LABEL_ADDR(x,f) %eax + #define LABEL_VALUE(x,f) (%eax) + #define INIT_PIC(x) \ + push %ebx; \ + call L0## x ##$pb; \ + L0## x ##$pb:; \ + pop %ebx; + #define END_PIC(x) pop %ebx +#endif diff --git a/dkvideoLoader/dkvideoLoaderDylib/dkvideoLoaderDylib-Prefix.pch b/dkvideoLoader/dkvideoLoaderDylib/dkvideoLoaderDylib-Prefix.pch new file mode 100644 index 0000000..cd09ac6 --- /dev/null +++ b/dkvideoLoader/dkvideoLoaderDylib/dkvideoLoaderDylib-Prefix.pch @@ -0,0 +1,8 @@ +// +// Prefix header for all source files of the 'dkvideoLoaderDylib' target in the 'dkvideoLoaderDylib' project +// + +#ifdef __OBJC__ + #import + #import "/opt/theos/Prefix.pch" //path/to/theos/Prefix.pch +#endif diff --git a/dkvideoLoader/dkvideoLoaderDylib/dkvideoLoaderDylib.h b/dkvideoLoader/dkvideoLoaderDylib/dkvideoLoaderDylib.h new file mode 100644 index 0000000..0a14f5b --- /dev/null +++ b/dkvideoLoader/dkvideoLoaderDylib/dkvideoLoaderDylib.h @@ -0,0 +1,14 @@ +// weibo: http://weibo.com/xiaoqing28 +// blog: http://www.alonemonkey.com +// +// dkvideoLoaderDylib.h +// dkvideoLoaderDylib +// +// Created by DDKJone on 2023/6/1. +// Copyright (c) 2023 ___ORGANIZATIONNAME___. All rights reserved. +// + +#import + +#define INSERT_SUCCESS_WELCOME " 🎉!!!congratulations!!!🎉\n👍----------------insert dylib success----------------👍\n" + diff --git a/dkvideoLoader/dkvideoLoaderDylib/dkvideoLoaderDylib.m b/dkvideoLoader/dkvideoLoaderDylib/dkvideoLoaderDylib.m new file mode 100644 index 0000000..5bc94e6 --- /dev/null +++ b/dkvideoLoader/dkvideoLoaderDylib/dkvideoLoaderDylib.m @@ -0,0 +1,37 @@ +// weibo: http://weibo.com/xiaoqing28 +// blog: http://www.alonemonkey.com +// +// dkvideoLoaderDylib.m +// dkvideoLoaderDylib +// +// Created by DKJone on 2023/6/1. +// Copyright (c) 2023 ___ORGANIZATIONNAME___. All rights reserved. +// + +#import "dkvideoLoaderDylib.h" +#import +#import +#import +#import + +CHConstructor{ + printf(INSERT_SUCCESS_WELCOME); + + [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidFinishLaunchingNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) { + +#ifndef __OPTIMIZE__ + CYListenServer(6666); + + MDCycriptManager* manager = [MDCycriptManager sharedInstance]; + [manager loadCycript:NO]; + + NSError* error; + NSString* result = [manager evaluateCycript:@"UIApp" error:&error]; + NSLog(@"result: %@", result); + if(error.code != 0){ + NSLog(@"error: %@", error.localizedDescription); + } +#endif + + }]; +} diff --git a/dkvideoLoader/dkvideoLoaderDylib/fishhook/fishhook.c b/dkvideoLoader/dkvideoLoaderDylib/fishhook/fishhook.c new file mode 100644 index 0000000..fb41e8e --- /dev/null +++ b/dkvideoLoader/dkvideoLoaderDylib/fishhook/fishhook.c @@ -0,0 +1,264 @@ +// Copyright (c) 2013, Facebook, Inc. +// All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name Facebook nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific +// prior written permission. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "fishhook.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __LP64__ +typedef struct mach_header_64 mach_header_t; +typedef struct segment_command_64 segment_command_t; +typedef struct section_64 section_t; +typedef struct nlist_64 nlist_t; +#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT_64 +#else +typedef struct mach_header mach_header_t; +typedef struct segment_command segment_command_t; +typedef struct section section_t; +typedef struct nlist nlist_t; +#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT +#endif + +#ifndef SEG_DATA_CONST +#define SEG_DATA_CONST "__DATA_CONST" +#endif + +struct rebindings_entry { + struct rebinding *rebindings; + size_t rebindings_nel; + struct rebindings_entry *next; +}; + +static struct rebindings_entry *_rebindings_head; + +static int prepend_rebindings(struct rebindings_entry **rebindings_head, + struct rebinding rebindings[], + size_t nel) { + struct rebindings_entry *new_entry = (struct rebindings_entry *) malloc(sizeof(struct rebindings_entry)); + if (!new_entry) { + return -1; + } + new_entry->rebindings = (struct rebinding *) malloc(sizeof(struct rebinding) * nel); + if (!new_entry->rebindings) { + free(new_entry); + return -1; + } + memcpy(new_entry->rebindings, rebindings, sizeof(struct rebinding) * nel); + new_entry->rebindings_nel = nel; + new_entry->next = *rebindings_head; + *rebindings_head = new_entry; + return 0; +} + +#if 0 +static int get_protection(void *addr, vm_prot_t *prot, vm_prot_t *max_prot) { + mach_port_t task = mach_task_self(); + vm_size_t size = 0; + vm_address_t address = (vm_address_t)addr; + memory_object_name_t object; +#ifdef __LP64__ + mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64; + vm_region_basic_info_data_64_t info; + kern_return_t info_ret = vm_region_64( + task, &address, &size, VM_REGION_BASIC_INFO_64, (vm_region_info_64_t)&info, &count, &object); +#else + mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT; + vm_region_basic_info_data_t info; + kern_return_t info_ret = vm_region(task, &address, &size, VM_REGION_BASIC_INFO, (vm_region_info_t)&info, &count, &object); +#endif + if (info_ret == KERN_SUCCESS) { + if (prot != NULL) + *prot = info.protection; + + if (max_prot != NULL) + *max_prot = info.max_protection; + + return 0; + } + + return -1; +} +#endif + +static void perform_rebinding_with_section(struct rebindings_entry *rebindings, + section_t *section, + intptr_t slide, + nlist_t *symtab, + char *strtab, + uint32_t *indirect_symtab) { + uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1; + void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr); + + for (uint i = 0; i < section->size / sizeof(void *); i++) { + uint32_t symtab_index = indirect_symbol_indices[i]; + if (symtab_index == INDIRECT_SYMBOL_ABS || symtab_index == INDIRECT_SYMBOL_LOCAL || + symtab_index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS)) { + continue; + } + uint32_t strtab_offset = symtab[symtab_index].n_un.n_strx; + char *symbol_name = strtab + strtab_offset; + bool symbol_name_longer_than_1 = symbol_name[0] && symbol_name[1]; + struct rebindings_entry *cur = rebindings; + while (cur) { + for (uint j = 0; j < cur->rebindings_nel; j++) { + if (symbol_name_longer_than_1 && strcmp(&symbol_name[1], cur->rebindings[j].name) == 0) { + kern_return_t err; + + if (cur->rebindings[j].replaced != NULL && indirect_symbol_bindings[i] != cur->rebindings[j].replacement) + *(cur->rebindings[j].replaced) = indirect_symbol_bindings[i]; + + /** + * 1. Moved the vm protection modifying codes to here to reduce the + * changing scope. + * 2. Adding VM_PROT_WRITE mode unconditionally because vm_region + * API on some iOS/Mac reports mismatch vm protection attributes. + * -- Lianfu Hao Jun 16th, 2021 + **/ + err = vm_protect (mach_task_self (), (uintptr_t)indirect_symbol_bindings, section->size, 0, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_COPY); + if (err == KERN_SUCCESS) { + /** + * Once we failed to change the vm protection, we + * MUST NOT continue the following write actions! + * iOS 15 has corrected the const segments prot. + * -- Lionfore Hao Jun 11th, 2021 + **/ + indirect_symbol_bindings[i] = cur->rebindings[j].replacement; + } + goto symbol_loop; + } + } + cur = cur->next; + } + symbol_loop:; + } +} + +static void rebind_symbols_for_image(struct rebindings_entry *rebindings, + const struct mach_header *header, + intptr_t slide) { + Dl_info info; + if (dladdr(header, &info) == 0) { + return; + } + + segment_command_t *cur_seg_cmd; + segment_command_t *linkedit_segment = NULL; + struct symtab_command* symtab_cmd = NULL; + struct dysymtab_command* dysymtab_cmd = NULL; + + uintptr_t cur = (uintptr_t)header + sizeof(mach_header_t); + for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { + cur_seg_cmd = (segment_command_t *)cur; + if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { + if (strcmp(cur_seg_cmd->segname, SEG_LINKEDIT) == 0) { + linkedit_segment = cur_seg_cmd; + } + } else if (cur_seg_cmd->cmd == LC_SYMTAB) { + symtab_cmd = (struct symtab_command*)cur_seg_cmd; + } else if (cur_seg_cmd->cmd == LC_DYSYMTAB) { + dysymtab_cmd = (struct dysymtab_command*)cur_seg_cmd; + } + } + + if (!symtab_cmd || !dysymtab_cmd || !linkedit_segment || + !dysymtab_cmd->nindirectsyms) { + return; + } + + // Find base symbol/string table addresses + uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff; + nlist_t *symtab = (nlist_t *)(linkedit_base + symtab_cmd->symoff); + char *strtab = (char *)(linkedit_base + symtab_cmd->stroff); + + // Get indirect symbol table (array of uint32_t indices into symbol table) + uint32_t *indirect_symtab = (uint32_t *)(linkedit_base + dysymtab_cmd->indirectsymoff); + + cur = (uintptr_t)header + sizeof(mach_header_t); + for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { + cur_seg_cmd = (segment_command_t *)cur; + if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { + if (strcmp(cur_seg_cmd->segname, SEG_DATA) != 0 && + strcmp(cur_seg_cmd->segname, SEG_DATA_CONST) != 0) { + continue; + } + for (uint j = 0; j < cur_seg_cmd->nsects; j++) { + section_t *sect = + (section_t *)(cur + sizeof(segment_command_t)) + j; + if ((sect->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS) { + perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab); + } + if ((sect->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS) { + perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab); + } + } + } + } +} + +static void _rebind_symbols_for_image(const struct mach_header *header, + intptr_t slide) { + rebind_symbols_for_image(_rebindings_head, header, slide); +} + +int rebind_symbols_image(void *header, + intptr_t slide, + struct rebinding rebindings[], + size_t rebindings_nel) { + struct rebindings_entry *rebindings_head = NULL; + int retval = prepend_rebindings(&rebindings_head, rebindings, rebindings_nel); + rebind_symbols_for_image(rebindings_head, (const struct mach_header *) header, slide); + if (rebindings_head) { + free(rebindings_head->rebindings); + } + free(rebindings_head); + return retval; +} + +int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel) { + int retval = prepend_rebindings(&_rebindings_head, rebindings, rebindings_nel); + if (retval < 0) { + return retval; + } + // If this was the first call, register callback for image additions (which is also invoked for + // existing images, otherwise, just run on existing images + if (!_rebindings_head->next) { + _dyld_register_func_for_add_image(_rebind_symbols_for_image); + } else { + uint32_t c = _dyld_image_count(); + for (uint32_t i = 0; i < c; i++) { + _rebind_symbols_for_image(_dyld_get_image_header(i), _dyld_get_image_vmaddr_slide(i)); + } + } + return retval; +} diff --git a/dkvideoLoader/dkvideoLoaderDylib/fishhook/fishhook.h b/dkvideoLoader/dkvideoLoaderDylib/fishhook/fishhook.h new file mode 100644 index 0000000..0d8e36a --- /dev/null +++ b/dkvideoLoader/dkvideoLoaderDylib/fishhook/fishhook.h @@ -0,0 +1,76 @@ +// Copyright (c) 2013, Facebook, Inc. +// All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name Facebook nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific +// prior written permission. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef fishhook_h +#define fishhook_h + +#include +#include + +#if !defined(FISHHOOK_EXPORT) +#define FISHHOOK_VISIBILITY __attribute__((visibility("hidden"))) +#else +#define FISHHOOK_VISIBILITY __attribute__((visibility("default"))) +#endif + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + +/* + * A structure representing a particular intended rebinding from a symbol + * name to its replacement + */ +struct rebinding { + const char *name; + void *replacement; + void **replaced; +}; + +/* + * For each rebinding in rebindings, rebinds references to external, indirect + * symbols with the specified name to instead point at replacement for each + * image in the calling process as well as for all future images that are loaded + * by the process. If rebind_functions is called more than once, the symbols to + * rebind are added to the existing list of rebindings, and if a given symbol + * is rebound more than once, the later rebinding will take precedence. + */ +FISHHOOK_VISIBILITY +int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel); + +/* + * Rebinds as above, but only in the specified image. The header should point + * to the mach-o header, the slide should be the slide offset. Others as above. + */ +FISHHOOK_VISIBILITY +int rebind_symbols_image(void *header, + intptr_t slide, + struct rebinding rebindings[], + size_t rebindings_nel); + +#ifdef __cplusplus +} +#endif //__cplusplus + +#endif //fishhook_h + diff --git a/dkvideoLoader/dkvideoLoaderDylib/libDKVideo.dylib b/dkvideoLoader/dkvideoLoaderDylib/libDKVideo.dylib new file mode 100755 index 0000000..ee19539 Binary files /dev/null and b/dkvideoLoader/dkvideoLoaderDylib/libDKVideo.dylib differ