├── .gitignore ├── AppEnvCheck.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── AppEnvCheck ├── Info.plist ├── defs.h ├── fishHookCheck.h ├── fishHookCheck.m ├── fishhook.c ├── fishhook.h ├── inlineHookCheck.h ├── inlineHookCheck.m ├── main.m ├── uncacheModules.h └── uncacheModules.m └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | AppEnvCheck.xcodeproj/project.xcworkspace/xcuserdata 2 | AppEnvCheck.xcodeproj/xcuserdata 3 | -------------------------------------------------------------------------------- /AppEnvCheck.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1E27BAA62160A98C0052DE31 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E27BAA52160A98C0052DE31 /* main.m */; }; 11 | 1E59D999216C8F0700193741 /* uncacheModules.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E59D997216C8F0700193741 /* uncacheModules.m */; }; 12 | 1EADCBAC216B796C00545C86 /* inlineHookCheck.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EADCBAB216B796C00545C86 /* inlineHookCheck.m */; }; 13 | 1EADCBAF216B799500545C86 /* fishHookCheck.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EADCBAE216B799500545C86 /* fishHookCheck.m */; }; 14 | 1EEFD819216AF33400A77230 /* fishhook.c in Sources */ = {isa = PBXBuildFile; fileRef = 1EEFD817216AF33300A77230 /* fishhook.c */; }; 15 | /* End PBXBuildFile section */ 16 | 17 | /* Begin PBXFileReference section */ 18 | 1E27BA932160A9790052DE31 /* AppEnvCheck.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AppEnvCheck.app; sourceTree = BUILT_PRODUCTS_DIR; }; 19 | 1E27BAA42160A98C0052DE31 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 20 | 1E27BAA52160A98C0052DE31 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 21 | 1E27BAAC2160AA3F0052DE31 /* defs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = defs.h; sourceTree = ""; }; 22 | 1E59D997216C8F0700193741 /* uncacheModules.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = uncacheModules.m; sourceTree = ""; }; 23 | 1E59D998216C8F0700193741 /* uncacheModules.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = uncacheModules.h; sourceTree = ""; }; 24 | 1EADCBAA216B794A00545C86 /* inlineHookCheck.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = inlineHookCheck.h; sourceTree = ""; }; 25 | 1EADCBAB216B796C00545C86 /* inlineHookCheck.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = inlineHookCheck.m; sourceTree = ""; }; 26 | 1EADCBAD216B799500545C86 /* fishHookCheck.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fishHookCheck.h; sourceTree = ""; }; 27 | 1EADCBAE216B799500545C86 /* fishHookCheck.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = fishHookCheck.m; sourceTree = ""; }; 28 | 1EADCBB1216B7BC400545C86 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; 29 | 1EADCBD9216B802900545C86 /* readme.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = readme.md; sourceTree = ""; }; 30 | 1EEFD817216AF33300A77230 /* fishhook.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fishhook.c; sourceTree = ""; }; 31 | 1EEFD818216AF33300A77230 /* fishhook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fishhook.h; sourceTree = ""; }; 32 | /* End PBXFileReference section */ 33 | 34 | /* Begin PBXFrameworksBuildPhase section */ 35 | 1E27BA902160A9790052DE31 /* Frameworks */ = { 36 | isa = PBXFrameworksBuildPhase; 37 | buildActionMask = 2147483647; 38 | files = ( 39 | ); 40 | runOnlyForDeploymentPostprocessing = 0; 41 | }; 42 | /* End PBXFrameworksBuildPhase section */ 43 | 44 | /* Begin PBXGroup section */ 45 | 1E27BA8A2160A9780052DE31 = { 46 | isa = PBXGroup; 47 | children = ( 48 | 1EADCBD9216B802900545C86 /* readme.md */, 49 | 1E27BA952160A9790052DE31 /* AppEnvCheck */, 50 | 1E27BA942160A9790052DE31 /* Products */, 51 | 1EADCBB0216B7BC300545C86 /* Frameworks */, 52 | ); 53 | sourceTree = ""; 54 | }; 55 | 1E27BA942160A9790052DE31 /* Products */ = { 56 | isa = PBXGroup; 57 | children = ( 58 | 1E27BA932160A9790052DE31 /* AppEnvCheck.app */, 59 | ); 60 | name = Products; 61 | sourceTree = ""; 62 | }; 63 | 1E27BA952160A9790052DE31 /* AppEnvCheck */ = { 64 | isa = PBXGroup; 65 | children = ( 66 | 1E27BAA42160A98C0052DE31 /* Info.plist */, 67 | 1E27BAAC2160AA3F0052DE31 /* defs.h */, 68 | 1E27BAA52160A98C0052DE31 /* main.m */, 69 | 1EEFD818216AF33300A77230 /* fishhook.h */, 70 | 1EEFD817216AF33300A77230 /* fishhook.c */, 71 | 1EADCBAA216B794A00545C86 /* inlineHookCheck.h */, 72 | 1EADCBAB216B796C00545C86 /* inlineHookCheck.m */, 73 | 1EADCBAD216B799500545C86 /* fishHookCheck.h */, 74 | 1EADCBAE216B799500545C86 /* fishHookCheck.m */, 75 | 1E59D998216C8F0700193741 /* uncacheModules.h */, 76 | 1E59D997216C8F0700193741 /* uncacheModules.m */, 77 | ); 78 | path = AppEnvCheck; 79 | sourceTree = ""; 80 | }; 81 | 1EADCBB0216B7BC300545C86 /* Frameworks */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | 1EADCBB1216B7BC400545C86 /* CoreFoundation.framework */, 85 | ); 86 | name = Frameworks; 87 | sourceTree = ""; 88 | }; 89 | /* End PBXGroup section */ 90 | 91 | /* Begin PBXNativeTarget section */ 92 | 1E27BA922160A9790052DE31 /* AppEnvCheck */ = { 93 | isa = PBXNativeTarget; 94 | buildConfigurationList = 1E27BAA92160A98C0052DE31 /* Build configuration list for PBXNativeTarget "AppEnvCheck" */; 95 | buildPhases = ( 96 | 1E27BA8F2160A9790052DE31 /* Sources */, 97 | 1E27BA902160A9790052DE31 /* Frameworks */, 98 | 1E27BA912160A9790052DE31 /* Resources */, 99 | ); 100 | buildRules = ( 101 | ); 102 | dependencies = ( 103 | ); 104 | name = AppEnvCheck; 105 | productName = AppEnvCheck; 106 | productReference = 1E27BA932160A9790052DE31 /* AppEnvCheck.app */; 107 | productType = "com.apple.product-type.application"; 108 | }; 109 | /* End PBXNativeTarget section */ 110 | 111 | /* Begin PBXProject section */ 112 | 1E27BA8B2160A9780052DE31 /* Project object */ = { 113 | isa = PBXProject; 114 | attributes = { 115 | LastUpgradeCheck = 0940; 116 | ORGANIZATIONNAME = liaogang; 117 | TargetAttributes = { 118 | 1E27BA922160A9790052DE31 = { 119 | CreatedOnToolsVersion = 9.4.1; 120 | }; 121 | }; 122 | }; 123 | buildConfigurationList = 1E27BA8E2160A9780052DE31 /* Build configuration list for PBXProject "AppEnvCheck" */; 124 | compatibilityVersion = "Xcode 9.3"; 125 | developmentRegion = en; 126 | hasScannedForEncodings = 0; 127 | knownRegions = ( 128 | en, 129 | Base, 130 | ); 131 | mainGroup = 1E27BA8A2160A9780052DE31; 132 | productRefGroup = 1E27BA942160A9790052DE31 /* Products */; 133 | projectDirPath = ""; 134 | projectRoot = ""; 135 | targets = ( 136 | 1E27BA922160A9790052DE31 /* AppEnvCheck */, 137 | ); 138 | }; 139 | /* End PBXProject section */ 140 | 141 | /* Begin PBXResourcesBuildPhase section */ 142 | 1E27BA912160A9790052DE31 /* Resources */ = { 143 | isa = PBXResourcesBuildPhase; 144 | buildActionMask = 2147483647; 145 | files = ( 146 | ); 147 | runOnlyForDeploymentPostprocessing = 0; 148 | }; 149 | /* End PBXResourcesBuildPhase section */ 150 | 151 | /* Begin PBXSourcesBuildPhase section */ 152 | 1E27BA8F2160A9790052DE31 /* Sources */ = { 153 | isa = PBXSourcesBuildPhase; 154 | buildActionMask = 2147483647; 155 | files = ( 156 | 1E59D999216C8F0700193741 /* uncacheModules.m in Sources */, 157 | 1EEFD819216AF33400A77230 /* fishhook.c in Sources */, 158 | 1EADCBAC216B796C00545C86 /* inlineHookCheck.m in Sources */, 159 | 1E27BAA62160A98C0052DE31 /* main.m in Sources */, 160 | 1EADCBAF216B799500545C86 /* fishHookCheck.m in Sources */, 161 | ); 162 | runOnlyForDeploymentPostprocessing = 0; 163 | }; 164 | /* End PBXSourcesBuildPhase section */ 165 | 166 | /* Begin XCBuildConfiguration section */ 167 | 1E27BAA72160A98C0052DE31 /* Debug */ = { 168 | isa = XCBuildConfiguration; 169 | buildSettings = { 170 | ALWAYS_SEARCH_USER_PATHS = NO; 171 | CLANG_ANALYZER_NONNULL = YES; 172 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 173 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 174 | CLANG_CXX_LIBRARY = "libc++"; 175 | CLANG_ENABLE_MODULES = YES; 176 | CLANG_ENABLE_OBJC_ARC = YES; 177 | CLANG_ENABLE_OBJC_WEAK = YES; 178 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 179 | CLANG_WARN_BOOL_CONVERSION = YES; 180 | CLANG_WARN_COMMA = YES; 181 | CLANG_WARN_CONSTANT_CONVERSION = YES; 182 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 183 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 184 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 185 | CLANG_WARN_EMPTY_BODY = YES; 186 | CLANG_WARN_ENUM_CONVERSION = YES; 187 | CLANG_WARN_INFINITE_RECURSION = YES; 188 | CLANG_WARN_INT_CONVERSION = YES; 189 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 190 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 191 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 192 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 193 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 194 | CLANG_WARN_STRICT_PROTOTYPES = YES; 195 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 196 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 197 | CLANG_WARN_UNREACHABLE_CODE = YES; 198 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 199 | CODE_SIGN_IDENTITY = "iPhone Developer"; 200 | COPY_PHASE_STRIP = NO; 201 | DEBUG_INFORMATION_FORMAT = dwarf; 202 | ENABLE_STRICT_OBJC_MSGSEND = YES; 203 | ENABLE_TESTABILITY = YES; 204 | GCC_C_LANGUAGE_STANDARD = gnu11; 205 | GCC_DYNAMIC_NO_PIC = NO; 206 | GCC_NO_COMMON_BLOCKS = YES; 207 | GCC_OPTIMIZATION_LEVEL = 0; 208 | GCC_PREPROCESSOR_DEFINITIONS = ( 209 | "DEBUG=1", 210 | "$(inherited)", 211 | ); 212 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 213 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 214 | GCC_WARN_UNDECLARED_SELECTOR = YES; 215 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 216 | GCC_WARN_UNUSED_FUNCTION = YES; 217 | GCC_WARN_UNUSED_VARIABLE = YES; 218 | IPHONEOS_DEPLOYMENT_TARGET = 11.4; 219 | MTL_ENABLE_DEBUG_INFO = YES; 220 | ONLY_ACTIVE_ARCH = YES; 221 | SDKROOT = iphoneos; 222 | }; 223 | name = Debug; 224 | }; 225 | 1E27BAA82160A98C0052DE31 /* Release */ = { 226 | isa = XCBuildConfiguration; 227 | buildSettings = { 228 | ALWAYS_SEARCH_USER_PATHS = NO; 229 | CLANG_ANALYZER_NONNULL = YES; 230 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 231 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 232 | CLANG_CXX_LIBRARY = "libc++"; 233 | CLANG_ENABLE_MODULES = YES; 234 | CLANG_ENABLE_OBJC_ARC = YES; 235 | CLANG_ENABLE_OBJC_WEAK = YES; 236 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 237 | CLANG_WARN_BOOL_CONVERSION = YES; 238 | CLANG_WARN_COMMA = YES; 239 | CLANG_WARN_CONSTANT_CONVERSION = YES; 240 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 241 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 242 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 243 | CLANG_WARN_EMPTY_BODY = YES; 244 | CLANG_WARN_ENUM_CONVERSION = YES; 245 | CLANG_WARN_INFINITE_RECURSION = YES; 246 | CLANG_WARN_INT_CONVERSION = YES; 247 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 248 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 249 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 250 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 251 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 252 | CLANG_WARN_STRICT_PROTOTYPES = YES; 253 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 254 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 255 | CLANG_WARN_UNREACHABLE_CODE = YES; 256 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 257 | CODE_SIGN_IDENTITY = "iPhone Developer"; 258 | COPY_PHASE_STRIP = NO; 259 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 260 | ENABLE_NS_ASSERTIONS = NO; 261 | ENABLE_STRICT_OBJC_MSGSEND = YES; 262 | GCC_C_LANGUAGE_STANDARD = gnu11; 263 | GCC_NO_COMMON_BLOCKS = YES; 264 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 265 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 266 | GCC_WARN_UNDECLARED_SELECTOR = YES; 267 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 268 | GCC_WARN_UNUSED_FUNCTION = YES; 269 | GCC_WARN_UNUSED_VARIABLE = YES; 270 | IPHONEOS_DEPLOYMENT_TARGET = 11.4; 271 | MTL_ENABLE_DEBUG_INFO = NO; 272 | SDKROOT = iphoneos; 273 | VALIDATE_PRODUCT = YES; 274 | }; 275 | name = Release; 276 | }; 277 | 1E27BAAA2160A98C0052DE31 /* Debug */ = { 278 | isa = XCBuildConfiguration; 279 | buildSettings = { 280 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 281 | CODE_SIGN_STYLE = Automatic; 282 | DEVELOPMENT_TEAM = 2439H5NX36; 283 | INFOPLIST_FILE = AppEnvCheck/Info.plist; 284 | IPHONEOS_DEPLOYMENT_TARGET = 9.1; 285 | LD_RUNPATH_SEARCH_PATHS = ( 286 | "$(inherited)", 287 | "@executable_path/Frameworks", 288 | ); 289 | PRODUCT_BUNDLE_IDENTIFIER = com.abyun.AppEnvCheck; 290 | PRODUCT_NAME = "$(TARGET_NAME)"; 291 | TARGETED_DEVICE_FAMILY = "1,2"; 292 | }; 293 | name = Debug; 294 | }; 295 | 1E27BAAB2160A98C0052DE31 /* Release */ = { 296 | isa = XCBuildConfiguration; 297 | buildSettings = { 298 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 299 | CODE_SIGN_STYLE = Automatic; 300 | DEVELOPMENT_TEAM = 2439H5NX36; 301 | INFOPLIST_FILE = AppEnvCheck/Info.plist; 302 | IPHONEOS_DEPLOYMENT_TARGET = 9.1; 303 | LD_RUNPATH_SEARCH_PATHS = ( 304 | "$(inherited)", 305 | "@executable_path/Frameworks", 306 | ); 307 | PRODUCT_BUNDLE_IDENTIFIER = com.abyun.AppEnvCheck; 308 | PRODUCT_NAME = "$(TARGET_NAME)"; 309 | TARGETED_DEVICE_FAMILY = "1,2"; 310 | }; 311 | name = Release; 312 | }; 313 | /* End XCBuildConfiguration section */ 314 | 315 | /* Begin XCConfigurationList section */ 316 | 1E27BA8E2160A9780052DE31 /* Build configuration list for PBXProject "AppEnvCheck" */ = { 317 | isa = XCConfigurationList; 318 | buildConfigurations = ( 319 | 1E27BAA72160A98C0052DE31 /* Debug */, 320 | 1E27BAA82160A98C0052DE31 /* Release */, 321 | ); 322 | defaultConfigurationIsVisible = 0; 323 | defaultConfigurationName = Release; 324 | }; 325 | 1E27BAA92160A98C0052DE31 /* Build configuration list for PBXNativeTarget "AppEnvCheck" */ = { 326 | isa = XCConfigurationList; 327 | buildConfigurations = ( 328 | 1E27BAAA2160A98C0052DE31 /* Debug */, 329 | 1E27BAAB2160A98C0052DE31 /* Release */, 330 | ); 331 | defaultConfigurationIsVisible = 0; 332 | defaultConfigurationName = Release; 333 | }; 334 | /* End XCConfigurationList section */ 335 | }; 336 | rootObject = 1E27BA8B2160A9780052DE31 /* Project object */; 337 | } 338 | -------------------------------------------------------------------------------- /AppEnvCheck.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AppEnvCheck.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /AppEnvCheck/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | NSAppTransportSecurity 45 | 46 | NSAllowsArbitraryLoads 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /AppEnvCheck/defs.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | This file contains definitions used by the Hex-Rays decompiler output. 4 | It has type definitions and convenience macros to make the 5 | output more readable. 6 | 7 | Copyright (c) 2007-2017 Hex-Rays 8 | 9 | */ 10 | 11 | #ifndef HEXRAYS_DEFS_H 12 | #define HEXRAYS_DEFS_H 13 | 14 | #if defined(__GNUC__) 15 | typedef long long ll; 16 | typedef unsigned long long ull; 17 | #define __int64 long long 18 | #define __int32 int 19 | #define __int16 short 20 | #define __int8 char 21 | #define MAKELL(num) num ## LL 22 | #define FMT_64 "ll" 23 | #elif defined(_MSC_VER) 24 | typedef __int64 ll; 25 | typedef unsigned __int64 ull; 26 | #define MAKELL(num) num ## i64 27 | #define FMT_64 "I64" 28 | #elif defined (__BORLANDC__) 29 | typedef __int64 ll; 30 | typedef unsigned __int64 ull; 31 | #define MAKELL(num) num ## i64 32 | #define FMT_64 "L" 33 | #else 34 | #error "unknown compiler" 35 | #endif 36 | typedef unsigned int uint; 37 | typedef unsigned char uchar; 38 | typedef unsigned short ushort; 39 | typedef unsigned long ulong; 40 | 41 | typedef char int8; 42 | typedef signed char sint8; 43 | typedef unsigned char uint8; 44 | typedef short int16; 45 | typedef signed short sint16; 46 | typedef unsigned short uint16; 47 | typedef int int32; 48 | typedef signed int sint32; 49 | typedef unsigned int uint32; 50 | typedef ll int64; 51 | typedef ll sint64; 52 | typedef ull uint64; 53 | 54 | // Partially defined types. They are used when the decompiler does not know 55 | // anything about the type except its size. 56 | #define _BYTE uint8 57 | #define _WORD uint16 58 | #define _DWORD uint32 59 | #define _QWORD uint64 60 | #if !defined(_MSC_VER) 61 | #define _LONGLONG __int128 62 | #endif 63 | 64 | // Non-standard boolean types. They are used when the decompiler can not use 65 | // the standard "bool" type because of the size mistmatch but the possible 66 | // values are only 0 and 1. See also 'BOOL' type below. 67 | typedef int8 _BOOL1; 68 | typedef int16 _BOOL2; 69 | typedef int32 _BOOL4; 70 | 71 | #ifndef _WINDOWS_ 72 | typedef int8 BYTE; 73 | typedef int16 WORD; 74 | typedef int32 DWORD; 75 | typedef int32 LONG; 76 | typedef int BOOL; // uppercase BOOL is usually 4 bytes 77 | #endif 78 | typedef int64 QWORD; 79 | #ifndef __cplusplus 80 | //typedef int bool; // we want to use bool in our C programs 81 | #endif 82 | 83 | #define __pure // pure function: always returns the same value, has no 84 | // side effects 85 | 86 | // Non-returning function 87 | #if defined(__GNUC__) 88 | #define __noreturn __attribute__((noreturn)) 89 | #else 90 | #define __noreturn __declspec(noreturn) 91 | #endif 92 | 93 | 94 | #ifndef NULL 95 | #define NULL 0 96 | #endif 97 | 98 | // Some convenience macros to make partial accesses nicer 99 | #define LAST_IND(x,part_type) (sizeof(x)/sizeof(part_type) - 1) 100 | #if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN 101 | # define LOW_IND(x,part_type) LAST_IND(x,part_type) 102 | # define HIGH_IND(x,part_type) 0 103 | #else 104 | # define HIGH_IND(x,part_type) LAST_IND(x,part_type) 105 | # define LOW_IND(x,part_type) 0 106 | #endif 107 | // first unsigned macros: 108 | #define BYTEn(x, n) (*((_BYTE*)&(x)+n)) 109 | #define WORDn(x, n) (*((_WORD*)&(x)+n)) 110 | #define DWORDn(x, n) (*((_DWORD*)&(x)+n)) 111 | 112 | #define LOBYTE(x) BYTEn(x,LOW_IND(x,_BYTE)) 113 | #define LOWORD(x) WORDn(x,LOW_IND(x,_WORD)) 114 | #define LODWORD(x) DWORDn(x,LOW_IND(x,_DWORD)) 115 | #define HIBYTE(x) BYTEn(x,HIGH_IND(x,_BYTE)) 116 | #define HIWORD(x) WORDn(x,HIGH_IND(x,_WORD)) 117 | #define HIDWORD(x) DWORDn(x,HIGH_IND(x,_DWORD)) 118 | #define BYTE1(x) BYTEn(x, 1) // byte 1 (counting from 0) 119 | #define BYTE2(x) BYTEn(x, 2) 120 | #define BYTE3(x) BYTEn(x, 3) 121 | #define BYTE4(x) BYTEn(x, 4) 122 | #define BYTE5(x) BYTEn(x, 5) 123 | #define BYTE6(x) BYTEn(x, 6) 124 | #define BYTE7(x) BYTEn(x, 7) 125 | #define BYTE8(x) BYTEn(x, 8) 126 | #define BYTE9(x) BYTEn(x, 9) 127 | #define BYTE10(x) BYTEn(x, 10) 128 | #define BYTE11(x) BYTEn(x, 11) 129 | #define BYTE12(x) BYTEn(x, 12) 130 | #define BYTE13(x) BYTEn(x, 13) 131 | #define BYTE14(x) BYTEn(x, 14) 132 | #define BYTE15(x) BYTEn(x, 15) 133 | #define WORD1(x) WORDn(x, 1) 134 | #define WORD2(x) WORDn(x, 2) // third word of the object, unsigned 135 | #define WORD3(x) WORDn(x, 3) 136 | #define WORD4(x) WORDn(x, 4) 137 | #define WORD5(x) WORDn(x, 5) 138 | #define WORD6(x) WORDn(x, 6) 139 | #define WORD7(x) WORDn(x, 7) 140 | 141 | // now signed macros (the same but with sign extension) 142 | #define SBYTEn(x, n) (*((int8*)&(x)+n)) 143 | #define SWORDn(x, n) (*((int16*)&(x)+n)) 144 | #define SDWORDn(x, n) (*((int32*)&(x)+n)) 145 | 146 | #define SLOBYTE(x) SBYTEn(x,LOW_IND(x,int8)) 147 | #define SLOWORD(x) SWORDn(x,LOW_IND(x,int16)) 148 | #define SLODWORD(x) SDWORDn(x,LOW_IND(x,int32)) 149 | #define SHIBYTE(x) SBYTEn(x,HIGH_IND(x,int8)) 150 | #define SHIWORD(x) SWORDn(x,HIGH_IND(x,int16)) 151 | #define SHIDWORD(x) SDWORDn(x,HIGH_IND(x,int32)) 152 | #define SBYTE1(x) SBYTEn(x, 1) 153 | #define SBYTE2(x) SBYTEn(x, 2) 154 | #define SBYTE3(x) SBYTEn(x, 3) 155 | #define SBYTE4(x) SBYTEn(x, 4) 156 | #define SBYTE5(x) SBYTEn(x, 5) 157 | #define SBYTE6(x) SBYTEn(x, 6) 158 | #define SBYTE7(x) SBYTEn(x, 7) 159 | #define SBYTE8(x) SBYTEn(x, 8) 160 | #define SBYTE9(x) SBYTEn(x, 9) 161 | #define SBYTE10(x) SBYTEn(x, 10) 162 | #define SBYTE11(x) SBYTEn(x, 11) 163 | #define SBYTE12(x) SBYTEn(x, 12) 164 | #define SBYTE13(x) SBYTEn(x, 13) 165 | #define SBYTE14(x) SBYTEn(x, 14) 166 | #define SBYTE15(x) SBYTEn(x, 15) 167 | #define SWORD1(x) SWORDn(x, 1) 168 | #define SWORD2(x) SWORDn(x, 2) 169 | #define SWORD3(x) SWORDn(x, 3) 170 | #define SWORD4(x) SWORDn(x, 4) 171 | #define SWORD5(x) SWORDn(x, 5) 172 | #define SWORD6(x) SWORDn(x, 6) 173 | #define SWORD7(x) SWORDn(x, 7) 174 | 175 | 176 | // Helper functions to represent some assembly instructions. 177 | 178 | #ifdef __cplusplus 179 | 180 | // compile time assertion 181 | #define __CASSERT_N0__(l) COMPILE_TIME_ASSERT_ ## l 182 | #define __CASSERT_N1__(l) __CASSERT_N0__(l) 183 | #define CASSERT(cnd) typedef char __CASSERT_N1__(__LINE__) [(cnd) ? 1 : -1] 184 | 185 | // check that unsigned multiplication does not overflow 186 | template bool is_mul_ok(T count, T elsize) 187 | { 188 | CASSERT((T)(-1) > 0); // make sure T is unsigned 189 | if ( elsize == 0 || count == 0 ) 190 | return true; 191 | return count <= ((T)(-1)) / elsize; 192 | } 193 | 194 | // multiplication that saturates (yields the biggest value) instead of overflowing 195 | // such a construct is useful in "operator new[]" 196 | template bool saturated_mul(T count, T elsize) 197 | { 198 | return is_mul_ok(count, elsize) ? count * elsize : T(-1); 199 | } 200 | 201 | #include // for size_t 202 | 203 | // memcpy() with determined behavoir: it always copies 204 | // from the start to the end of the buffer 205 | // note: it copies byte by byte, so it is not equivalent to, for example, rep movsd 206 | inline void *qmemcpy(void *dst, const void *src, size_t cnt) 207 | { 208 | char *out = (char *)dst; 209 | const char *in = (const char *)src; 210 | while ( cnt > 0 ) 211 | { 212 | *out++ = *in++; 213 | --cnt; 214 | } 215 | return dst; 216 | } 217 | 218 | // Generate a reference to pair of operands 219 | template int16 __PAIR__( int8 high, T low) { return ((( int16)high) << sizeof(high)*8) | uint8(low); } 220 | template int32 __PAIR__( int16 high, T low) { return ((( int32)high) << sizeof(high)*8) | uint16(low); } 221 | template int64 __PAIR__( int32 high, T low) { return ((( int64)high) << sizeof(high)*8) | uint32(low); } 222 | template uint16 __PAIR__(uint8 high, T low) { return (((uint16)high) << sizeof(high)*8) | uint8(low); } 223 | template uint32 __PAIR__(uint16 high, T low) { return (((uint32)high) << sizeof(high)*8) | uint16(low); } 224 | template uint64 __PAIR__(uint32 high, T low) { return (((uint64)high) << sizeof(high)*8) | uint32(low); } 225 | 226 | // rotate left 227 | template T __ROL__(T value, int count) 228 | { 229 | const uint nbits = sizeof(T) * 8; 230 | 231 | if ( count > 0 ) 232 | { 233 | count %= nbits; 234 | T high = value >> (nbits - count); 235 | if ( T(-1) < 0 ) // signed value 236 | high &= ~((T(-1) << count)); 237 | value <<= count; 238 | value |= high; 239 | } 240 | else 241 | { 242 | count = -count % nbits; 243 | T low = value << (nbits - count); 244 | value >>= count; 245 | value |= low; 246 | } 247 | return value; 248 | } 249 | 250 | inline uint8 __ROL1__(uint8 value, int count) { return __ROL__((uint8)value, count); } 251 | inline uint16 __ROL2__(uint16 value, int count) { return __ROL__((uint16)value, count); } 252 | inline uint32 __ROL4__(uint32 value, int count) { return __ROL__((uint32)value, count); } 253 | inline uint64 __ROL8__(uint64 value, int count) { return __ROL__((uint64)value, count); } 254 | inline uint8 __ROR1__(uint8 value, int count) { return __ROL__((uint8)value, -count); } 255 | inline uint16 __ROR2__(uint16 value, int count) { return __ROL__((uint16)value, -count); } 256 | inline uint32 __ROR4__(uint32 value, int count) { return __ROL__((uint32)value, -count); } 257 | inline uint64 __ROR8__(uint64 value, int count) { return __ROL__((uint64)value, -count); } 258 | 259 | // carry flag of left shift 260 | template int8 __MKCSHL__(T value, uint count) 261 | { 262 | const uint nbits = sizeof(T) * 8; 263 | count %= nbits; 264 | 265 | return (value >> (nbits-count)) & 1; 266 | } 267 | 268 | // carry flag of right shift 269 | template int8 __MKCSHR__(T value, uint count) 270 | { 271 | return (value >> (count-1)) & 1; 272 | } 273 | 274 | // sign flag 275 | template int8 __SETS__(T x) 276 | { 277 | if ( sizeof(T) == 1 ) 278 | return int8(x) < 0; 279 | if ( sizeof(T) == 2 ) 280 | return int16(x) < 0; 281 | if ( sizeof(T) == 4 ) 282 | return int32(x) < 0; 283 | return int64(x) < 0; 284 | } 285 | 286 | // overflow flag of subtraction (x-y) 287 | template int8 __OFSUB__(T x, U y) 288 | { 289 | if ( sizeof(T) < sizeof(U) ) 290 | { 291 | U x2 = x; 292 | int8 sx = __SETS__(x2); 293 | return (sx ^ __SETS__(y)) & (sx ^ __SETS__(x2-y)); 294 | } 295 | else 296 | { 297 | T y2 = y; 298 | int8 sx = __SETS__(x); 299 | return (sx ^ __SETS__(y2)) & (sx ^ __SETS__(x-y2)); 300 | } 301 | } 302 | 303 | // overflow flag of addition (x+y) 304 | template int8 __OFADD__(T x, U y) 305 | { 306 | if ( sizeof(T) < sizeof(U) ) 307 | { 308 | U x2 = x; 309 | int8 sx = __SETS__(x2); 310 | return ((1 ^ sx) ^ __SETS__(y)) & (sx ^ __SETS__(x2+y)); 311 | } 312 | else 313 | { 314 | T y2 = y; 315 | int8 sx = __SETS__(x); 316 | return ((1 ^ sx) ^ __SETS__(y2)) & (sx ^ __SETS__(x+y2)); 317 | } 318 | } 319 | 320 | // carry flag of subtraction (x-y) 321 | template int8 __CFSUB__(T x, U y) 322 | { 323 | int size = sizeof(T) > sizeof(U) ? sizeof(T) : sizeof(U); 324 | if ( size == 1 ) 325 | return uint8(x) < uint8(y); 326 | if ( size == 2 ) 327 | return uint16(x) < uint16(y); 328 | if ( size == 4 ) 329 | return uint32(x) < uint32(y); 330 | return uint64(x) < uint64(y); 331 | } 332 | 333 | // carry flag of addition (x+y) 334 | template int8 __CFADD__(T x, U y) 335 | { 336 | int size = sizeof(T) > sizeof(U) ? sizeof(T) : sizeof(U); 337 | if ( size == 1 ) 338 | return uint8(x) > uint8(x+y); 339 | if ( size == 2 ) 340 | return uint16(x) > uint16(x+y); 341 | if ( size == 4 ) 342 | return uint32(x) > uint32(x+y); 343 | return uint64(x) > uint64(x+y); 344 | } 345 | 346 | #else 347 | // The following definition is not quite correct because it always returns 348 | // uint64. The above C++ functions are good, though. 349 | #define __PAIR__(high, low) (((uint64)(high)<>y) 355 | #define __CFADD__(x, y) invalid_operation // Generate carry flag for (x+y) 356 | #define __CFSUB__(x, y) invalid_operation // Generate carry flag for (x-y) 357 | #define __OFADD__(x, y) invalid_operation // Generate overflow flag for (x+y) 358 | #define __OFSUB__(x, y) invalid_operation // Generate overflow flag for (x-y) 359 | #endif 360 | 361 | // No definition for rcl/rcr because the carry flag is unknown 362 | #define __RCL__(x, y) invalid_operation // Rotate left thru carry 363 | #define __RCR__(x, y) invalid_operation // Rotate right thru carry 364 | #define __MKCRCL__(x, y) invalid_operation // Generate carry flag for a RCL 365 | #define __MKCRCR__(x, y) invalid_operation // Generate carry flag for a RCR 366 | #define __SETP__(x, y) invalid_operation // Generate parity flag for (x-y) 367 | 368 | // In the decompilation listing there are some objects declarared as _UNKNOWN 369 | // because we could not determine their types. Since the C compiler does not 370 | // accept void item declarations, we replace them by anything of our choice, 371 | // for example a char: 372 | 373 | #define _UNKNOWN char 374 | 375 | #ifdef _MSC_VER 376 | #define snprintf _snprintf 377 | #define vsnprintf _vsnprintf 378 | #endif 379 | 380 | #endif // HEXRAYS_DEFS_H 381 | -------------------------------------------------------------------------------- /AppEnvCheck/fishHookCheck.h: -------------------------------------------------------------------------------- 1 | // 2 | // inlineHookCheck.h 3 | // AppEnvCheck 4 | // 5 | // Created by liaogang on 2018/10/8. 6 | // Copyright © 2018年 liaogang. All rights reserved. 7 | // 8 | 9 | #ifndef fishHookCheck_h 10 | #define fishHookCheck_h 11 | 12 | void test_fish_hook(); 13 | 14 | #endif /* inlineHookCheck_h */ 15 | -------------------------------------------------------------------------------- /AppEnvCheck/fishHookCheck.m: -------------------------------------------------------------------------------- 1 | // 2 | // inlineHookCheck.h 3 | // AppEnvCheck 4 | // 5 | // Created by liaogang on 2018/10/8. 6 | // Copyright © 2018年 liaogang. All rights reserved. 7 | // 8 | 9 | #import "fishHookCheck.h" 10 | #import "fishhook.h" 11 | #import "defs.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #import 20 | #import 21 | #import 22 | #import 23 | #import 24 | #import 25 | 26 | 27 | 28 | 29 | typedef struct HookNode { 30 | void* beg; 31 | void* end; 32 | BYTE index; 33 | struct HookNode *next; //+32 34 | } HookNode; 35 | 36 | 37 | static struct HookNode *rootNode = NULL; 38 | 39 | 40 | 41 | /* 42 | 检测传入的函数地址是不是位于(_TEXT,__text)之中, 43 | 如果在说明是自己实现的伪函数,则位于(_TEXT,__text)之中 44 | 如果是系统的原函数,则位于 (__DATAl,a_symbol_ptr)里的 45 | */ 46 | BOOL inMachOSegTEXT(void *funcAddr) 47 | { 48 | BOOL inTEXT = FALSE; 49 | struct HookNode *node; 50 | for ( node = rootNode; node; node = node->next ) { 51 | 52 | if (funcAddr > node->beg && funcAddr < node->end) { 53 | inTEXT = TRUE; 54 | break; 55 | } 56 | 57 | } 58 | 59 | return inTEXT; 60 | } 61 | 62 | BOOL fishHooked(void *funcAddr) 63 | { 64 | return inMachOSegTEXT(funcAddr); 65 | } 66 | 67 | void find_mach0_file_text_seg_range( struct mach_header_64 *header , __int64 *begin, _QWORD *end) 68 | { 69 | if( header->ncmds ) 70 | { 71 | __int64 vmaddr = 0; 72 | int cmdIndex = 0; 73 | 74 | void *loadCmd = header + 1 ; 75 | struct segment_command_64 *sc = (struct segment_command_64 *)loadCmd; 76 | 77 | 78 | while ( TRUE ) 79 | { 80 | if ( sc->cmd == LC_SEGMENT_64 ) // value == 0x19 // is segment? 81 | { 82 | if ( !vmaddr ) 83 | { 84 | bool a = sc->fileoff; 85 | bool b = !sc->filesize; 86 | bool aa = a || b ; 87 | 88 | if( aa ) 89 | vmaddr = 0; 90 | else 91 | { 92 | vmaddr = (__int64)header - sc->vmaddr; 93 | } 94 | } 95 | 96 | 97 | if( strcmp(sc->segname, "__TEXT") == 0 ) 98 | { 99 | break; 100 | } 101 | 102 | } 103 | 104 | 105 | sc = (struct segment_command_64*)((BYTE*)sc + sc->cmdsize); 106 | 107 | if ( ++cmdIndex >= header->ncmds ) 108 | return ; 109 | } 110 | 111 | 112 | __int64 v10 = sc->fileoff + (__int64)header; 113 | 114 | *begin = v10; 115 | *end = v10 + (_QWORD)sc->filesize; 116 | 117 | } 118 | 119 | } 120 | 121 | 122 | void _prepare_root() 123 | { 124 | rootNode = malloc(sizeof(HookNode)); 125 | bzero(rootNode, sizeof(HookNode)); 126 | } 127 | 128 | 129 | void prepare_fish_hook_check() 130 | { 131 | _prepare_root(); 132 | 133 | 134 | integer_t task_info_out[TASK_DYLD_INFO_COUNT]; 135 | mach_msg_type_number_t task_info_outCnt = TASK_DYLD_INFO_COUNT; 136 | if( task_info( mach_task_self_ , TASK_DYLD_INFO , task_info_out, &task_info_outCnt) == KERN_SUCCESS ) 137 | { 138 | struct task_dyld_info dyld_info = *(struct task_dyld_info*)(void*)(task_info_out); 139 | struct dyld_all_image_infos* infos = (struct dyld_all_image_infos *) dyld_info.all_image_info_addr; 140 | struct dyld_uuid_info* pUuid_info = (struct dyld_uuid_info*) infos->uuidArray; //v4 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | struct HookNode *curr; 150 | struct HookNode *i; 151 | struct HookNode *next; 152 | 153 | curr = rootNode; 154 | 155 | 156 | if ( infos->uuidArrayCount ) 157 | { 158 | unsigned __int64 index = 1; 159 | 160 | for ( i = rootNode ; ; ) 161 | { 162 | const struct mach_header_64 *header = (const struct mach_header_64 *)pUuid_info->imageLoadAddress; 163 | 164 | curr->index = (signed __int64)(index - 1) > 1; 165 | 166 | 167 | QWORD v11; 168 | __int64 v12; 169 | find_mach0_file_text_seg_range(header, &v12, &v11); 170 | i->beg = v12; 171 | i->end = v11; 172 | 173 | 174 | next = i->next; 175 | if ( next == NULL ) 176 | { 177 | next = malloc(sizeof(struct HookNode)); 178 | bzero(next, sizeof(struct HookNode)); 179 | i->next = next; 180 | } 181 | 182 | 183 | if ( index >= infos->uuidArrayCount ) 184 | break; 185 | 186 | pUuid_info = pUuid_info + 1; 187 | curr = rootNode; 188 | ++index; 189 | i = next; 190 | } 191 | 192 | 193 | curr = next; 194 | } 195 | 196 | } 197 | 198 | } 199 | 200 | 201 | 202 | 203 | 204 | char *(*getenv0)(const char *); 205 | char *getenv1(const char *arg) 206 | { 207 | printf("my getenv\n"); 208 | return NULL; 209 | } 210 | 211 | 212 | static int (*orig_open)(const char *, int, ...); 213 | int new_open(const char *path, int oflag, ...) { 214 | printf("my open\n"); 215 | return 0; 216 | } 217 | 218 | void checkSomeFunc() 219 | { 220 | BOOL hooked; 221 | 222 | hooked = fishHooked( &open); 223 | printf("open hooked: %d\n",hooked); 224 | 225 | hooked = fishHooked( &dladdr); 226 | printf("dladdr hooked: %d\n",hooked); 227 | 228 | hooked = fishHooked( &read); 229 | printf("read hooked: %d\n",hooked); 230 | 231 | hooked = fishHooked( &getenv); 232 | printf("getenv hooked: %d\n",hooked); 233 | } 234 | 235 | void test_fish_hook() 236 | { 237 | printf("---fish hook check---\n"); 238 | 239 | prepare_fish_hook_check(); 240 | 241 | 242 | checkSomeFunc(); 243 | 244 | { 245 | struct rebinding open_rebinding = { "getenv", (void*)getenv1, (void **)&getenv0 }; 246 | rebind_symbols((struct rebinding[1]){open_rebinding}, 1); 247 | } 248 | 249 | { 250 | struct rebinding open_rebinding = { "open", (void*)new_open, (void **)&orig_open }; 251 | rebind_symbols((struct rebinding[1]){open_rebinding}, 1); 252 | } 253 | 254 | 255 | open("/var/mobile/Media/a.txt", 'r'); 256 | getenv("DYLD_INSERT_LIBRARY"); 257 | 258 | 259 | checkSomeFunc(); 260 | 261 | } 262 | -------------------------------------------------------------------------------- /AppEnvCheck/fishhook.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, Facebook, Inc. 2 | // All rights reserved. 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // * Redistributions of source code must retain the above copyright notice, 6 | // this list of conditions and the following disclaimer. 7 | // * Redistributions in binary form must reproduce the above copyright notice, 8 | // this list of conditions and the following disclaimer in the documentation 9 | // and/or other materials provided with the distribution. 10 | // * Neither the name Facebook nor the names of its contributors may be used to 11 | // endorse or promote products derived from this software without specific 12 | // prior written permission. 13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 17 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | #include "fishhook.h" 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #ifdef __LP64__ 35 | typedef struct mach_header_64 mach_header_t; 36 | typedef struct segment_command_64 segment_command_t; 37 | typedef struct section_64 section_t; 38 | typedef struct nlist_64 nlist_t; 39 | #define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT_64 40 | #else 41 | typedef struct mach_header mach_header_t; 42 | typedef struct segment_command segment_command_t; 43 | typedef struct section section_t; 44 | typedef struct nlist nlist_t; 45 | #define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT 46 | #endif 47 | 48 | #ifndef SEG_DATA_CONST 49 | #define SEG_DATA_CONST "__DATA_CONST" 50 | #endif 51 | 52 | struct rebindings_entry { 53 | struct rebinding *rebindings; 54 | size_t rebindings_nel; 55 | struct rebindings_entry *next; 56 | }; 57 | 58 | static struct rebindings_entry *_rebindings_head; 59 | 60 | static int prepend_rebindings(struct rebindings_entry **rebindings_head, 61 | struct rebinding rebindings[], 62 | size_t nel) { 63 | struct rebindings_entry *new_entry = (struct rebindings_entry *) malloc(sizeof(struct rebindings_entry)); 64 | if (!new_entry) { 65 | return -1; 66 | } 67 | new_entry->rebindings = (struct rebinding *) malloc(sizeof(struct rebinding) * nel); 68 | if (!new_entry->rebindings) { 69 | free(new_entry); 70 | return -1; 71 | } 72 | memcpy(new_entry->rebindings, rebindings, sizeof(struct rebinding) * nel); 73 | new_entry->rebindings_nel = nel; 74 | new_entry->next = *rebindings_head; 75 | *rebindings_head = new_entry; 76 | return 0; 77 | } 78 | 79 | static void perform_rebinding_with_section(struct rebindings_entry *rebindings, 80 | section_t *section, 81 | intptr_t slide, 82 | nlist_t *symtab, 83 | char *strtab, 84 | uint32_t *indirect_symtab) { 85 | uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1; 86 | void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr); 87 | for (uint i = 0; i < section->size / sizeof(void *); i++) { 88 | uint32_t symtab_index = indirect_symbol_indices[i]; 89 | if (symtab_index == INDIRECT_SYMBOL_ABS || symtab_index == INDIRECT_SYMBOL_LOCAL || 90 | symtab_index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS)) { 91 | continue; 92 | } 93 | uint32_t strtab_offset = symtab[symtab_index].n_un.n_strx; 94 | char *symbol_name = strtab + strtab_offset; 95 | bool symbol_name_longer_than_1 = symbol_name[0] && symbol_name[1]; 96 | struct rebindings_entry *cur = rebindings; 97 | while (cur) { 98 | for (uint j = 0; j < cur->rebindings_nel; j++) { 99 | if (symbol_name_longer_than_1 && 100 | strcmp(&symbol_name[1], cur->rebindings[j].name) == 0) { 101 | if (cur->rebindings[j].replaced != NULL && 102 | indirect_symbol_bindings[i] != cur->rebindings[j].replacement) { 103 | *(cur->rebindings[j].replaced) = indirect_symbol_bindings[i]; 104 | } 105 | indirect_symbol_bindings[i] = cur->rebindings[j].replacement; 106 | goto symbol_loop; 107 | } 108 | } 109 | cur = cur->next; 110 | } 111 | symbol_loop:; 112 | } 113 | } 114 | 115 | static void rebind_symbols_for_image(struct rebindings_entry *rebindings, 116 | const struct mach_header *header, 117 | intptr_t slide) { 118 | Dl_info info; 119 | if (dladdr(header, &info) == 0) { 120 | return; 121 | } 122 | 123 | segment_command_t *cur_seg_cmd; 124 | segment_command_t *linkedit_segment = NULL; 125 | struct symtab_command* symtab_cmd = NULL; 126 | struct dysymtab_command* dysymtab_cmd = NULL; 127 | 128 | uintptr_t cur = (uintptr_t)header + sizeof(mach_header_t); 129 | for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { 130 | cur_seg_cmd = (segment_command_t *)cur; 131 | if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { 132 | if (strcmp(cur_seg_cmd->segname, SEG_LINKEDIT) == 0) { 133 | linkedit_segment = cur_seg_cmd; 134 | } 135 | } else if (cur_seg_cmd->cmd == LC_SYMTAB) { 136 | symtab_cmd = (struct symtab_command*)cur_seg_cmd; 137 | } else if (cur_seg_cmd->cmd == LC_DYSYMTAB) { 138 | dysymtab_cmd = (struct dysymtab_command*)cur_seg_cmd; 139 | } 140 | } 141 | 142 | if (!symtab_cmd || !dysymtab_cmd || !linkedit_segment || 143 | !dysymtab_cmd->nindirectsyms) { 144 | return; 145 | } 146 | 147 | // Find base symbol/string table addresses 148 | uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff; 149 | nlist_t *symtab = (nlist_t *)(linkedit_base + symtab_cmd->symoff); 150 | char *strtab = (char *)(linkedit_base + symtab_cmd->stroff); 151 | 152 | // Get indirect symbol table (array of uint32_t indices into symbol table) 153 | uint32_t *indirect_symtab = (uint32_t *)(linkedit_base + dysymtab_cmd->indirectsymoff); 154 | 155 | cur = (uintptr_t)header + sizeof(mach_header_t); 156 | for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { 157 | cur_seg_cmd = (segment_command_t *)cur; 158 | if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { 159 | if (strcmp(cur_seg_cmd->segname, SEG_DATA) != 0 && 160 | strcmp(cur_seg_cmd->segname, SEG_DATA_CONST) != 0) { 161 | continue; 162 | } 163 | for (uint j = 0; j < cur_seg_cmd->nsects; j++) { 164 | section_t *sect = 165 | (section_t *)(cur + sizeof(segment_command_t)) + j; 166 | if ((sect->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS) { 167 | perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab); 168 | } 169 | if ((sect->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS) { 170 | perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab); 171 | } 172 | } 173 | } 174 | } 175 | } 176 | 177 | static void _rebind_symbols_for_image(const struct mach_header *header, 178 | intptr_t slide) { 179 | rebind_symbols_for_image(_rebindings_head, header, slide); 180 | } 181 | 182 | int rebind_symbols_image(void *header, 183 | intptr_t slide, 184 | struct rebinding rebindings[], 185 | size_t rebindings_nel) { 186 | struct rebindings_entry *rebindings_head = NULL; 187 | int retval = prepend_rebindings(&rebindings_head, rebindings, rebindings_nel); 188 | rebind_symbols_for_image(rebindings_head, (const struct mach_header *) header, slide); 189 | if (rebindings_head) { 190 | free(rebindings_head->rebindings); 191 | } 192 | free(rebindings_head); 193 | return retval; 194 | } 195 | 196 | int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel) { 197 | int retval = prepend_rebindings(&_rebindings_head, rebindings, rebindings_nel); 198 | if (retval < 0) { 199 | return retval; 200 | } 201 | // If this was the first call, register callback for image additions (which is also invoked for 202 | // existing images, otherwise, just run on existing images 203 | if (!_rebindings_head->next) { 204 | _dyld_register_func_for_add_image(_rebind_symbols_for_image); 205 | } else { 206 | uint32_t c = _dyld_image_count(); 207 | for (uint32_t i = 0; i < c; i++) { 208 | _rebind_symbols_for_image(_dyld_get_image_header(i), _dyld_get_image_vmaddr_slide(i)); 209 | } 210 | } 211 | return retval; 212 | } 213 | -------------------------------------------------------------------------------- /AppEnvCheck/fishhook.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, Facebook, Inc. 2 | // All rights reserved. 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // * Redistributions of source code must retain the above copyright notice, 6 | // this list of conditions and the following disclaimer. 7 | // * Redistributions in binary form must reproduce the above copyright notice, 8 | // this list of conditions and the following disclaimer in the documentation 9 | // and/or other materials provided with the distribution. 10 | // * Neither the name Facebook nor the names of its contributors may be used to 11 | // endorse or promote products derived from this software without specific 12 | // prior written permission. 13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 17 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | #ifndef fishhook_h 25 | #define fishhook_h 26 | 27 | #include 28 | #include 29 | 30 | #if !defined(FISHHOOK_EXPORT) 31 | #define FISHHOOK_VISIBILITY __attribute__((visibility("hidden"))) 32 | #else 33 | #define FISHHOOK_VISIBILITY __attribute__((visibility("default"))) 34 | #endif 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif //__cplusplus 39 | 40 | /* 41 | * A structure representing a particular intended rebinding from a symbol 42 | * name to its replacement 43 | */ 44 | struct rebinding { 45 | const char *name; 46 | void *replacement; 47 | void **replaced; 48 | }; 49 | 50 | /* 51 | * For each rebinding in rebindings, rebinds references to external, indirect 52 | * symbols with the specified name to instead point at replacement for each 53 | * image in the calling process as well as for all future images that are loaded 54 | * by the process. If rebind_functions is called more than once, the symbols to 55 | * rebind are added to the existing list of rebindings, and if a given symbol 56 | * is rebound more than once, the later rebinding will take precedence. 57 | */ 58 | FISHHOOK_VISIBILITY 59 | int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel); 60 | 61 | /* 62 | * Rebinds as above, but only in the specified image. The header should point 63 | * to the mach-o header, the slide should be the slide offset. Others as above. 64 | */ 65 | FISHHOOK_VISIBILITY 66 | int rebind_symbols_image(void *header, 67 | intptr_t slide, 68 | struct rebinding rebindings[], 69 | size_t rebindings_nel); 70 | 71 | #ifdef __cplusplus 72 | } 73 | #endif //__cplusplus 74 | 75 | #endif //fishhook_h 76 | 77 | -------------------------------------------------------------------------------- /AppEnvCheck/inlineHookCheck.h: -------------------------------------------------------------------------------- 1 | // 2 | // inlineHookCheck.h 3 | // AppEnvCheck 4 | // 5 | // Created by liaogang on 2018/10/8. 6 | // Copyright © 2018年 liaogang. All rights reserved. 7 | // 8 | 9 | #ifndef inlineHookCheck_h 10 | #define inlineHookCheck_h 11 | 12 | void test_inline_hook_check(); 13 | 14 | #endif /* inlineHookCheck_h */ 15 | -------------------------------------------------------------------------------- /AppEnvCheck/inlineHookCheck.m: -------------------------------------------------------------------------------- 1 | // 2 | // inlineHookCheck.h 3 | // AppEnvCheck 4 | // 5 | // Created by liaogang on 2018/10/8. 6 | // Copyright © 2018年 liaogang. All rights reserved. 7 | // 8 | #import "inlineHookCheck.h" 9 | #import "defs.h" 10 | #import 11 | #import 12 | #import 13 | #import 14 | #import 15 | 16 | 17 | int inline_hook_check(__int64 a1) 18 | { 19 | const _DWORD magic0 = 0x058000050;//arm64的跳转指令 20 | const _DWORD magic1 = 0x0d61f0200; 21 | 22 | const _DWORD magic2 = 0x058000051; 23 | const _DWORD magic3 = 0x0d61f0220; 24 | 25 | 26 | int v5; 27 | int v6; 28 | int v7; 29 | 30 | v5 = *(_DWORD *)(a1 + 4); 31 | 32 | if ( *(_DWORD *)a1 == magic0 ) 33 | v6 = (v5 == magic1); 34 | else 35 | v6 = 0; 36 | 37 | 38 | if ( !v6 ) 39 | { 40 | v7 = *(_DWORD *)a1 == magic2 ? v5 == magic3 : 0; 41 | if ( !v7 ) 42 | return 0; 43 | } 44 | 45 | 46 | if ( !*(_QWORD *)(a1 + 8) ) 47 | return 0; 48 | 49 | return 1; 50 | } 51 | 52 | 53 | 54 | void test_inline_hook_check() 55 | { 56 | printf("\n\n\n---inline hook check---\n"); 57 | int hooked; 58 | 59 | hooked = inline_hook_check( &open); 60 | printf("open hooked: %d\n",hooked); 61 | 62 | hooked = inline_hook_check( &dladdr); 63 | printf("dladdr hooked: %d\n",hooked); 64 | 65 | hooked = inline_hook_check( &read); 66 | printf("read hooked: %d\n",hooked); 67 | 68 | hooked = inline_hook_check( &getenv); 69 | printf("getenv hooked: %d\n",hooked); 70 | 71 | hooked = inline_hook_check( &getchar); 72 | printf("getchar hooked: %d\n",hooked); 73 | 74 | } 75 | -------------------------------------------------------------------------------- /AppEnvCheck/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // AppEnvCheck 4 | // 5 | // Created by liaogang on 2018/9/30. 6 | // Copyright © 2018年 liaogang. All rights reserved. 7 | // 8 | 9 | #import "fishHookCheck.h" 10 | #import "inlineHookCheck.h" 11 | #import "uncacheModules.h" 12 | 13 | 14 | int main(int argc, char * argv[]) { 15 | 16 | test_fish_hook(); 17 | 18 | test_inline_hook_check(); 19 | 20 | getAllUncachedModules(); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /AppEnvCheck/uncacheModules.h: -------------------------------------------------------------------------------- 1 | // 2 | // uncacheModules.h 3 | // AppEnvCheck 4 | // 5 | // Created by liaogang on 2018/10/9. 6 | // Copyright © 2018年 liaogang. All rights reserved. 7 | // 8 | 9 | #ifndef uncacheModules_h 10 | #define uncacheModules_h 11 | 12 | #include 13 | 14 | void getAllUncachedModules(); 15 | 16 | #endif /* uncacheModules_h */ 17 | -------------------------------------------------------------------------------- /AppEnvCheck/uncacheModules.m: -------------------------------------------------------------------------------- 1 | // 2 | // uncacheModules.c 3 | // AppEnvCheck 4 | // 5 | // Created by liaogang on 2018/10/9. 6 | // Copyright © 2018年 liaogang. All rights reserved. 7 | // 8 | 9 | #include "uncacheModules.h" 10 | #include "defs.h" 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #import 17 | 18 | /* 19 | 可以用MachoView打开一个dylib了解详细 20 | 定位到 dylib , Load Commands下的LC_ID_DYLIB 一节下,找到此动态库的路径全名 21 | 如: /Library/MobileSubstrate/DynamicLibraries/awemeHOOK.dylib 22 | */ 23 | void print_mach_header_dylib_name(const struct mach_header_64* mheader) 24 | { 25 | if(mheader->magic == MH_MAGIC_64 && mheader->ncmds > 0) 26 | { 27 | void *loadCmd = (void*)(mheader + 1) ; 28 | struct segment_command_64 *sc = (struct segment_command_64 *)loadCmd; 29 | 30 | for ( int index = 0; index < mheader->ncmds; ++index , sc = (struct segment_command_64*)((BYTE*)sc + sc->cmdsize)) 31 | { 32 | 33 | if (sc->cmd == LC_ID_DYLIB) { 34 | 35 | struct dylib_command *dc = (struct dylib_command *)sc; 36 | struct dylib dy = dc->dylib; 37 | char *str = (char*)dc + dy.name.offset; 38 | 39 | 40 | NSLog(@"%s",str); 41 | 42 | //第二种方法 43 | //也可以用vm_read_overwrite来读取信息 44 | break; 45 | } 46 | 47 | } 48 | 49 | } 50 | } 51 | 52 | 53 | 54 | 55 | 56 | 57 | void getAllUncachedModules() 58 | { 59 | NSLog(@"--- getAllUncachedModules ---"); 60 | 61 | integer_t task_info_out[TASK_DYLD_INFO_COUNT]; 62 | mach_msg_type_number_t task_info_outCnt = TASK_DYLD_INFO_COUNT; 63 | if( task_info( mach_task_self_ , TASK_DYLD_INFO , task_info_out, &task_info_outCnt) == KERN_SUCCESS ) 64 | { 65 | struct task_dyld_info dyld_info = *(struct task_dyld_info*)(void*)(task_info_out); 66 | struct dyld_all_image_infos* infos = (struct dyld_all_image_infos *) dyld_info.all_image_info_addr; 67 | 68 | /* only images not in dyld shared cache 相比于infoarray ,这里过滤掉了在dyld_shared_cache里面的那些库 */ 69 | struct dyld_uuid_info* pUuid_info = (struct dyld_uuid_info*) infos->uuidArray; //v4 70 | 71 | for( int i = 0 ; i < infos->uuidArrayCount; i++, pUuid_info += 1) 72 | { 73 | const struct mach_header_64* mheader = (const struct mach_header_64*)pUuid_info->imageLoadAddress; 74 | if (mheader->filetype == MH_DYLIB) { 75 | print_mach_header_dylib_name(mheader); 76 | } 77 | 78 | } 79 | } 80 | 81 | 82 | NSLog(@"--- end ---"); 83 | } 84 | 85 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## [Fish Hook](https://github.com/facebook/fishhook) 2 | 3 | 自已的代码编译生成的函数,都存放于macho文件的`__TEXT`区 4 | 如果是系统的原函数,则位于`__DATA`区 5 | 6 | 如果检测到系统的函数(如open,getenv等),它的函数地址位于`__TEXT`区,则可断定它被fish hook重绑定了 7 | 8 | ### 环境: arm64 9 | ### tested in: iOS11, iOS9 10 | ### 程序运行结果 11 | 12 | ``` 13 | open hooked: 0 14 | dladdr hooked: 0 15 | read hooked: 0 16 | getenv hooked: 0 17 | 18 | 2018-10-08 19:20:41.697 AppEnvCheck[12374:1659019] my getenv 19 | 2018-10-08 19:20:41.697 AppEnvCheck[12374:1659019] my getenv 20 | 2018-10-08 19:20:41.697 AppEnvCheck[12374:1659019] my getenv 21 | 2018-10-08 19:20:41.697 AppEnvCheck[12374:1659019] my open 22 | 2018-10-08 19:20:41.698 AppEnvCheck[12374:1659019] my getenv 23 | 2018-10-08 19:20:41.698 AppEnvCheck[12374:1659019] my getenv 24 | 2018-10-08 19:20:41.698 AppEnvCheck[12374:1659019] my getenv 25 | 2018-10-08 19:20:41.698 AppEnvCheck[12374:1659019] my getenv 26 | 27 | open hooked: 1 28 | dladdr hooked: 0 29 | read hooked: 0 30 | getenv hooked: 1 31 | ``` 32 | 33 | ## InLine Hook 34 | 35 | [substrate](https://github.com/coolstar/substitute.git) 36 | [HookZz](https://github.com/jmpews/HookZz) 37 | 38 | 检测函数前几个汇编指令是否为跳转指令即可。 39 | 40 | ### 环境: arm64 ,tested in: iOS9 41 | 42 | ``` 43 | open hooked: 0 44 | dladdr hooked: 0 45 | read hooked: 0 46 | getenv hooked: 0 47 | getchar hooked: 1 48 | ``` 49 | 50 | 51 | ## uncacheMubels.m 打印出所有不在dyld shared cache动态库的名字 52 | 53 | 用task_info找出进程的信息,得到dyld_all_image_infos,遍历dyld_uuid_info数组来打印信息. 54 | 这个方法,比用_dyld_image_count _dyld_get_image_name的方法准确,省去了名字匹配. 55 | 现在是个人都知道hook _dyld_get_image_name来修改返回. 56 | 57 | 58 | AppEnvCheck[13683:1851670] SubstrateBootstrap.dylib 59 | AppEnvCheck[13683:1851670] /Developer/usr/lib/libBacktraceRecording.dylib 60 | AppEnvCheck[13683:1851670] /Developer/Library/PrivateFrameworks/DTDDISupport.framework/libViewDebuggerSupport.dylib 61 | AppEnvCheck[13683:1851670] /usr/lib/system/introspection/libdispatch.dylib 62 | AppEnvCheck[13683:1851670] SubstrateLoader.dylib 63 | AppEnvCheck[13683:1851670] /Library/MobileSubstrate/DynamicLibraries/AppAnalyze.dylib 64 | AppEnvCheck[13683:1851670] /Library/Frameworks/CydiaSubstrate.framework/CydiaSubstrate 65 | AppEnvCheck[13683:1851670] /Library/MobileSubstrate/DynamicLibraries/AppEnvCheckHOOK.dylib 66 | AppEnvCheck[13683:1851670] /Library/MobileSubstrate/DynamicLibraries/SSLKillSwitch2.dylib 67 | AppEnvCheck[13683:1851670] /Library/MobileSubstrate/DynamicLibraries/TEMain.dylib 68 | AppEnvCheck[13683:1851670] /Library/MobileSubstrate/DynamicLibraries/TSTweakEx.dylib 69 | AppEnvCheck[13683:1851670] /Library/MobileSubstrate/DynamicLibraries/reveal2Loader.dylib 70 | 71 | --------------------------------------------------------------------------------