├── .gitignore ├── Makefile ├── Other └── insert_dylib ├── WeWorkMacPlugin.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ └── WeWorkMacPlugin.xcscheme ├── WeWorkMacPlugin ├── Category │ ├── NSObject+WorkWeChat.h │ └── NSObject+WorkWeChat.m ├── Supporting Files │ ├── Info.plist │ ├── WeWorkMacPlugin.h │ └── main.mm ├── Utils │ ├── WLLTools.h │ ├── WLLTools.m │ └── WllQueue.h └── Vendor │ ├── BigBang.h │ ├── BigBang.m │ ├── fishhook.c │ └── fishhook.h ├── install.sh └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | # ---> macOS 2 | .DS_Store 3 | .AppleDouble 4 | .LSOverride 5 | 6 | # Icon must end with two \r 7 | Icon 8 | 9 | 10 | # Thumbnails 11 | ._* 12 | 13 | # Files that might appear in the root of a volume 14 | .DocumentRevisions-V100 15 | .fseventsd 16 | .Spotlight-V100 17 | .TemporaryItems 18 | .Trashes 19 | .VolumeIcon.icns 20 | 21 | # Directories potentially created on remote AFP share 22 | .AppleDB 23 | .AppleDesktop 24 | Network Trash Folder 25 | Temporary Items 26 | .apdisk 27 | 28 | # ---> Objective-C 29 | # Xcode 30 | # 31 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 32 | 33 | ## Build generated 34 | build/ 35 | DerivedData 36 | 37 | ## Various settings 38 | *.pbxuser 39 | !default.pbxuser 40 | *.mode1v3 41 | !default.mode1v3 42 | *.mode2v3 43 | !default.mode2v3 44 | *.perspectivev3 45 | !default.perspectivev3 46 | xcuserdata 47 | 48 | ## Other 49 | *.xccheckout 50 | *.moved-aside 51 | *.xcuserstate 52 | *.xcscmblueprint 53 | 54 | ## Obj-C/Swift specific 55 | *.hmap 56 | *.ipa 57 | 58 | # CocoaPods 59 | # 60 | # We recommend against adding the Pods directory to your .gitignore. However 61 | # you should judge for yourself, the pros and cons are mentioned at: 62 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 63 | # 64 | Pods/ 65 | Podfile.lock 66 | # Carthage 67 | # 68 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 69 | # Carthage/Checkouts 70 | 71 | Carthage/Build 72 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | build-wework: 2 | xcodebuild -project WeWorkMacPlugin.xcodeproj -scheme WeWorkMacPlugin -configuration Release -destination 'platform=OS X,arch=x86_64' DSTROOT="${PWD}" archive 3 | bash install.sh '企业微信' WeWorkMacPlugin.framework 4 | 5 | -------------------------------------------------------------------------------- /Other/insert_dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangliangliang2/WeWorkMacPlugin/ffb30d64d7b4ab59a237ec0872dce031b9e17819/Other/insert_dylib -------------------------------------------------------------------------------- /WeWorkMacPlugin.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | B770080020AD7A4E003E3154 /* WeWorkMacPlugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B77007F620AD7A4E003E3154 /* WeWorkMacPlugin.framework */; }; 11 | B770080720AD7A4E003E3154 /* WeWorkMacPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = B77007F920AD7A4E003E3154 /* WeWorkMacPlugin.h */; settings = {ATTRIBUTES = (Public, ); }; }; 12 | B7A5A6B920AD7AB8000FF11A /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = B7A5A6B820AD7AB8000FF11A /* main.mm */; }; 13 | B7A5A6BE20AD7B59000FF11A /* NSObject+WorkWeChat.h in Headers */ = {isa = PBXBuildFile; fileRef = B7A5A6BC20AD7B59000FF11A /* NSObject+WorkWeChat.h */; }; 14 | B7A5A6BF20AD7B59000FF11A /* NSObject+WorkWeChat.m in Sources */ = {isa = PBXBuildFile; fileRef = B7A5A6BD20AD7B59000FF11A /* NSObject+WorkWeChat.m */; }; 15 | B7A5A6C320AD7C00000FF11A /* fishhook.h in Headers */ = {isa = PBXBuildFile; fileRef = B7A5A6C120AD7C00000FF11A /* fishhook.h */; }; 16 | B7A5A6C420AD7C00000FF11A /* fishhook.c in Sources */ = {isa = PBXBuildFile; fileRef = B7A5A6C220AD7C00000FF11A /* fishhook.c */; }; 17 | B7A5A6C520AD7C00000FF11A /* fishhook.c in Sources */ = {isa = PBXBuildFile; fileRef = B7A5A6C220AD7C00000FF11A /* fishhook.c */; }; 18 | B7AA8E5120AE64DB004B5799 /* WllQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = B7AA8E4E20AE64DB004B5799 /* WllQueue.h */; }; 19 | B7AA8E5220AE64DB004B5799 /* WLLTools.h in Headers */ = {isa = PBXBuildFile; fileRef = B7AA8E4F20AE64DB004B5799 /* WLLTools.h */; }; 20 | B7AA8E5320AE64DB004B5799 /* WLLTools.m in Sources */ = {isa = PBXBuildFile; fileRef = B7AA8E5020AE64DB004B5799 /* WLLTools.m */; }; 21 | B7B89A8C20AEA2390060FD5D /* BigBang.m in Sources */ = {isa = PBXBuildFile; fileRef = B7B89A8A20AEA2380060FD5D /* BigBang.m */; }; 22 | B7B89A8D20AEA2390060FD5D /* BigBang.h in Headers */ = {isa = PBXBuildFile; fileRef = B7B89A8B20AEA2380060FD5D /* BigBang.h */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXContainerItemProxy section */ 26 | B770080120AD7A4E003E3154 /* PBXContainerItemProxy */ = { 27 | isa = PBXContainerItemProxy; 28 | containerPortal = B77007ED20AD7A4E003E3154 /* Project object */; 29 | proxyType = 1; 30 | remoteGlobalIDString = B77007F520AD7A4E003E3154; 31 | remoteInfo = WeWorkMacPlugin; 32 | }; 33 | /* End PBXContainerItemProxy section */ 34 | 35 | /* Begin PBXFileReference section */ 36 | B77007F620AD7A4E003E3154 /* WeWorkMacPlugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = WeWorkMacPlugin.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 37 | B77007F920AD7A4E003E3154 /* WeWorkMacPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WeWorkMacPlugin.h; sourceTree = ""; }; 38 | B77007FA20AD7A4E003E3154 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 39 | B77007FF20AD7A4E003E3154 /* WeWorkMacPluginTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = WeWorkMacPluginTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 40 | B7A5A6B820AD7AB8000FF11A /* main.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = ""; }; 41 | B7A5A6BC20AD7B59000FF11A /* NSObject+WorkWeChat.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSObject+WorkWeChat.h"; sourceTree = ""; }; 42 | B7A5A6BD20AD7B59000FF11A /* NSObject+WorkWeChat.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSObject+WorkWeChat.m"; sourceTree = ""; }; 43 | B7A5A6C120AD7C00000FF11A /* fishhook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fishhook.h; sourceTree = ""; }; 44 | B7A5A6C220AD7C00000FF11A /* fishhook.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fishhook.c; sourceTree = ""; }; 45 | B7AA8E4E20AE64DB004B5799 /* WllQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WllQueue.h; sourceTree = ""; }; 46 | B7AA8E4F20AE64DB004B5799 /* WLLTools.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WLLTools.h; sourceTree = ""; }; 47 | B7AA8E5020AE64DB004B5799 /* WLLTools.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WLLTools.m; sourceTree = ""; }; 48 | B7B89A8A20AEA2380060FD5D /* BigBang.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BigBang.m; sourceTree = ""; }; 49 | B7B89A8B20AEA2380060FD5D /* BigBang.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BigBang.h; sourceTree = ""; }; 50 | /* End PBXFileReference section */ 51 | 52 | /* Begin PBXFrameworksBuildPhase section */ 53 | B77007F220AD7A4E003E3154 /* Frameworks */ = { 54 | isa = PBXFrameworksBuildPhase; 55 | buildActionMask = 2147483647; 56 | files = ( 57 | ); 58 | runOnlyForDeploymentPostprocessing = 0; 59 | }; 60 | B77007FC20AD7A4E003E3154 /* Frameworks */ = { 61 | isa = PBXFrameworksBuildPhase; 62 | buildActionMask = 2147483647; 63 | files = ( 64 | B770080020AD7A4E003E3154 /* WeWorkMacPlugin.framework in Frameworks */, 65 | ); 66 | runOnlyForDeploymentPostprocessing = 0; 67 | }; 68 | /* End PBXFrameworksBuildPhase section */ 69 | 70 | /* Begin PBXGroup section */ 71 | B77007EC20AD7A4E003E3154 = { 72 | isa = PBXGroup; 73 | children = ( 74 | B77007F820AD7A4E003E3154 /* WeWorkMacPlugin */, 75 | B77007F720AD7A4E003E3154 /* Products */, 76 | ); 77 | sourceTree = ""; 78 | }; 79 | B77007F720AD7A4E003E3154 /* Products */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | B77007F620AD7A4E003E3154 /* WeWorkMacPlugin.framework */, 83 | B77007FF20AD7A4E003E3154 /* WeWorkMacPluginTests.xctest */, 84 | ); 85 | name = Products; 86 | sourceTree = ""; 87 | }; 88 | B77007F820AD7A4E003E3154 /* WeWorkMacPlugin */ = { 89 | isa = PBXGroup; 90 | children = ( 91 | B7AA8E4D20AE64DB004B5799 /* Utils */, 92 | B7A5A6C020AD7BE0000FF11A /* Vendor */, 93 | B7A5A6BB20AD7B34000FF11A /* Category */, 94 | B7A5A6B720AD7A9A000FF11A /* Supporting Files */, 95 | ); 96 | path = WeWorkMacPlugin; 97 | sourceTree = ""; 98 | }; 99 | B7A5A6B720AD7A9A000FF11A /* Supporting Files */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | B7A5A6B820AD7AB8000FF11A /* main.mm */, 103 | B77007F920AD7A4E003E3154 /* WeWorkMacPlugin.h */, 104 | B77007FA20AD7A4E003E3154 /* Info.plist */, 105 | ); 106 | path = "Supporting Files"; 107 | sourceTree = ""; 108 | }; 109 | B7A5A6BB20AD7B34000FF11A /* Category */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | B7A5A6BC20AD7B59000FF11A /* NSObject+WorkWeChat.h */, 113 | B7A5A6BD20AD7B59000FF11A /* NSObject+WorkWeChat.m */, 114 | ); 115 | path = Category; 116 | sourceTree = ""; 117 | }; 118 | B7A5A6C020AD7BE0000FF11A /* Vendor */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | B7B89A8B20AEA2380060FD5D /* BigBang.h */, 122 | B7B89A8A20AEA2380060FD5D /* BigBang.m */, 123 | B7A5A6C220AD7C00000FF11A /* fishhook.c */, 124 | B7A5A6C120AD7C00000FF11A /* fishhook.h */, 125 | ); 126 | path = Vendor; 127 | sourceTree = ""; 128 | }; 129 | B7AA8E4D20AE64DB004B5799 /* Utils */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | B7AA8E4E20AE64DB004B5799 /* WllQueue.h */, 133 | B7AA8E4F20AE64DB004B5799 /* WLLTools.h */, 134 | B7AA8E5020AE64DB004B5799 /* WLLTools.m */, 135 | ); 136 | path = Utils; 137 | sourceTree = ""; 138 | }; 139 | /* End PBXGroup section */ 140 | 141 | /* Begin PBXHeadersBuildPhase section */ 142 | B77007F320AD7A4E003E3154 /* Headers */ = { 143 | isa = PBXHeadersBuildPhase; 144 | buildActionMask = 2147483647; 145 | files = ( 146 | B7AA8E5120AE64DB004B5799 /* WllQueue.h in Headers */, 147 | B7B89A8D20AEA2390060FD5D /* BigBang.h in Headers */, 148 | B770080720AD7A4E003E3154 /* WeWorkMacPlugin.h in Headers */, 149 | B7AA8E5220AE64DB004B5799 /* WLLTools.h in Headers */, 150 | B7A5A6BE20AD7B59000FF11A /* NSObject+WorkWeChat.h in Headers */, 151 | B7A5A6C320AD7C00000FF11A /* fishhook.h in Headers */, 152 | ); 153 | runOnlyForDeploymentPostprocessing = 0; 154 | }; 155 | /* End PBXHeadersBuildPhase section */ 156 | 157 | /* Begin PBXNativeTarget section */ 158 | B77007F520AD7A4E003E3154 /* WeWorkMacPlugin */ = { 159 | isa = PBXNativeTarget; 160 | buildConfigurationList = B770080A20AD7A4E003E3154 /* Build configuration list for PBXNativeTarget "WeWorkMacPlugin" */; 161 | buildPhases = ( 162 | B77007F120AD7A4E003E3154 /* Sources */, 163 | B77007F220AD7A4E003E3154 /* Frameworks */, 164 | B77007F320AD7A4E003E3154 /* Headers */, 165 | B77007F420AD7A4E003E3154 /* Resources */, 166 | B753148C2405294500376A93 /* ShellScript */, 167 | ); 168 | buildRules = ( 169 | ); 170 | dependencies = ( 171 | ); 172 | name = WeWorkMacPlugin; 173 | productName = WeWorkMacPlugin; 174 | productReference = B77007F620AD7A4E003E3154 /* WeWorkMacPlugin.framework */; 175 | productType = "com.apple.product-type.framework"; 176 | }; 177 | B77007FE20AD7A4E003E3154 /* WeWorkMacPluginTests */ = { 178 | isa = PBXNativeTarget; 179 | buildConfigurationList = B770080D20AD7A4E003E3154 /* Build configuration list for PBXNativeTarget "WeWorkMacPluginTests" */; 180 | buildPhases = ( 181 | B77007FB20AD7A4E003E3154 /* Sources */, 182 | B77007FC20AD7A4E003E3154 /* Frameworks */, 183 | B77007FD20AD7A4E003E3154 /* Resources */, 184 | ); 185 | buildRules = ( 186 | ); 187 | dependencies = ( 188 | B770080220AD7A4E003E3154 /* PBXTargetDependency */, 189 | ); 190 | name = WeWorkMacPluginTests; 191 | productName = WeWorkMacPluginTests; 192 | productReference = B77007FF20AD7A4E003E3154 /* WeWorkMacPluginTests.xctest */; 193 | productType = "com.apple.product-type.bundle.unit-test"; 194 | }; 195 | /* End PBXNativeTarget section */ 196 | 197 | /* Begin PBXProject section */ 198 | B77007ED20AD7A4E003E3154 /* Project object */ = { 199 | isa = PBXProject; 200 | attributes = { 201 | LastUpgradeCheck = 0910; 202 | ORGANIZATIONNAME = Anonymous; 203 | TargetAttributes = { 204 | B77007F520AD7A4E003E3154 = { 205 | CreatedOnToolsVersion = 9.1; 206 | ProvisioningStyle = Automatic; 207 | }; 208 | B77007FE20AD7A4E003E3154 = { 209 | CreatedOnToolsVersion = 9.1; 210 | ProvisioningStyle = Automatic; 211 | }; 212 | }; 213 | }; 214 | buildConfigurationList = B77007F020AD7A4E003E3154 /* Build configuration list for PBXProject "WeWorkMacPlugin" */; 215 | compatibilityVersion = "Xcode 8.0"; 216 | developmentRegion = en; 217 | hasScannedForEncodings = 0; 218 | knownRegions = ( 219 | en, 220 | ); 221 | mainGroup = B77007EC20AD7A4E003E3154; 222 | productRefGroup = B77007F720AD7A4E003E3154 /* Products */; 223 | projectDirPath = ""; 224 | projectRoot = ""; 225 | targets = ( 226 | B77007F520AD7A4E003E3154 /* WeWorkMacPlugin */, 227 | B77007FE20AD7A4E003E3154 /* WeWorkMacPluginTests */, 228 | ); 229 | }; 230 | /* End PBXProject section */ 231 | 232 | /* Begin PBXResourcesBuildPhase section */ 233 | B77007F420AD7A4E003E3154 /* Resources */ = { 234 | isa = PBXResourcesBuildPhase; 235 | buildActionMask = 2147483647; 236 | files = ( 237 | ); 238 | runOnlyForDeploymentPostprocessing = 0; 239 | }; 240 | B77007FD20AD7A4E003E3154 /* Resources */ = { 241 | isa = PBXResourcesBuildPhase; 242 | buildActionMask = 2147483647; 243 | files = ( 244 | ); 245 | runOnlyForDeploymentPostprocessing = 0; 246 | }; 247 | /* End PBXResourcesBuildPhase section */ 248 | 249 | /* Begin PBXShellScriptBuildPhase section */ 250 | B753148C2405294500376A93 /* ShellScript */ = { 251 | isa = PBXShellScriptBuildPhase; 252 | buildActionMask = 2147483647; 253 | files = ( 254 | ); 255 | inputFileListPaths = ( 256 | ); 257 | inputPaths = ( 258 | ); 259 | outputFileListPaths = ( 260 | ); 261 | outputPaths = ( 262 | ); 263 | runOnlyForDeploymentPostprocessing = 0; 264 | shellPath = /bin/sh; 265 | shellScript = "#!/bin/bash\napp_name=\"企业微信\"\nframework_name=\"WeWorkMacPlugin\"\napp_bundle_path=\"/Applications/${app_name}.app/Contents/MacOS\"\napp_executable_path=\"${app_bundle_path}/${app_name}\"\napp_executable_backup_path=\"${app_executable_path}_backup\"\nframework_path=\"${app_bundle_path}/${framework_name}.framework\"\n# 备份WeChat原始可执行文件\nif [ ! -f \"$app_executable_backup_path\" ]\nthen\ncp \"$app_executable_path\" \"$app_executable_backup_path\"\nfi\n\nrm -rf \"./Other/Products/Debug/${framework_name}.framework\"\ncp -r \"${BUILT_PRODUCTS_DIR}/${framework_name}.framework\" \"./Other/Products/Debug/${framework_name}.framework\"\ncp -r \"${BUILT_PRODUCTS_DIR}/${framework_name}.framework\" ${app_bundle_path}\n./Other/insert_dylib --all-yes \"${framework_path}/${framework_name}\" \"$app_executable_backup_path\" \"$app_executable_path\"\n\n"; 266 | }; 267 | /* End PBXShellScriptBuildPhase section */ 268 | 269 | /* Begin PBXSourcesBuildPhase section */ 270 | B77007F120AD7A4E003E3154 /* Sources */ = { 271 | isa = PBXSourcesBuildPhase; 272 | buildActionMask = 2147483647; 273 | files = ( 274 | B7A5A6BF20AD7B59000FF11A /* NSObject+WorkWeChat.m in Sources */, 275 | B7AA8E5320AE64DB004B5799 /* WLLTools.m in Sources */, 276 | B7A5A6C420AD7C00000FF11A /* fishhook.c in Sources */, 277 | B7A5A6B920AD7AB8000FF11A /* main.mm in Sources */, 278 | B7B89A8C20AEA2390060FD5D /* BigBang.m in Sources */, 279 | ); 280 | runOnlyForDeploymentPostprocessing = 0; 281 | }; 282 | B77007FB20AD7A4E003E3154 /* Sources */ = { 283 | isa = PBXSourcesBuildPhase; 284 | buildActionMask = 2147483647; 285 | files = ( 286 | B7A5A6C520AD7C00000FF11A /* fishhook.c in Sources */, 287 | ); 288 | runOnlyForDeploymentPostprocessing = 0; 289 | }; 290 | /* End PBXSourcesBuildPhase section */ 291 | 292 | /* Begin PBXTargetDependency section */ 293 | B770080220AD7A4E003E3154 /* PBXTargetDependency */ = { 294 | isa = PBXTargetDependency; 295 | target = B77007F520AD7A4E003E3154 /* WeWorkMacPlugin */; 296 | targetProxy = B770080120AD7A4E003E3154 /* PBXContainerItemProxy */; 297 | }; 298 | /* End PBXTargetDependency section */ 299 | 300 | /* Begin XCBuildConfiguration section */ 301 | B770080820AD7A4E003E3154 /* Debug */ = { 302 | isa = XCBuildConfiguration; 303 | buildSettings = { 304 | ALWAYS_SEARCH_USER_PATHS = NO; 305 | CLANG_ANALYZER_NONNULL = YES; 306 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 307 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 308 | CLANG_CXX_LIBRARY = "libc++"; 309 | CLANG_ENABLE_MODULES = YES; 310 | CLANG_ENABLE_OBJC_ARC = YES; 311 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 312 | CLANG_WARN_BOOL_CONVERSION = YES; 313 | CLANG_WARN_COMMA = YES; 314 | CLANG_WARN_CONSTANT_CONVERSION = YES; 315 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 316 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 317 | CLANG_WARN_EMPTY_BODY = YES; 318 | CLANG_WARN_ENUM_CONVERSION = YES; 319 | CLANG_WARN_INFINITE_RECURSION = YES; 320 | CLANG_WARN_INT_CONVERSION = YES; 321 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 322 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 323 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 324 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 325 | CLANG_WARN_STRICT_PROTOTYPES = YES; 326 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 327 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 328 | CLANG_WARN_UNREACHABLE_CODE = YES; 329 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 330 | CODE_SIGN_IDENTITY = "Mac Developer"; 331 | COPY_PHASE_STRIP = NO; 332 | CURRENT_PROJECT_VERSION = 1; 333 | DEBUG_INFORMATION_FORMAT = dwarf; 334 | ENABLE_STRICT_OBJC_MSGSEND = YES; 335 | ENABLE_TESTABILITY = YES; 336 | GCC_C_LANGUAGE_STANDARD = gnu11; 337 | GCC_DYNAMIC_NO_PIC = NO; 338 | GCC_NO_COMMON_BLOCKS = YES; 339 | GCC_OPTIMIZATION_LEVEL = 0; 340 | GCC_PREPROCESSOR_DEFINITIONS = ( 341 | "DEBUG=1", 342 | "$(inherited)", 343 | ); 344 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 345 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 346 | GCC_WARN_UNDECLARED_SELECTOR = YES; 347 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 348 | GCC_WARN_UNUSED_FUNCTION = YES; 349 | GCC_WARN_UNUSED_VARIABLE = YES; 350 | MACOSX_DEPLOYMENT_TARGET = 10.12; 351 | MTL_ENABLE_DEBUG_INFO = YES; 352 | ONLY_ACTIVE_ARCH = YES; 353 | SDKROOT = macosx; 354 | VERSIONING_SYSTEM = "apple-generic"; 355 | VERSION_INFO_PREFIX = ""; 356 | }; 357 | name = Debug; 358 | }; 359 | B770080920AD7A4E003E3154 /* Release */ = { 360 | isa = XCBuildConfiguration; 361 | buildSettings = { 362 | ALWAYS_SEARCH_USER_PATHS = NO; 363 | CLANG_ANALYZER_NONNULL = YES; 364 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 365 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 366 | CLANG_CXX_LIBRARY = "libc++"; 367 | CLANG_ENABLE_MODULES = YES; 368 | CLANG_ENABLE_OBJC_ARC = YES; 369 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 370 | CLANG_WARN_BOOL_CONVERSION = YES; 371 | CLANG_WARN_COMMA = YES; 372 | CLANG_WARN_CONSTANT_CONVERSION = YES; 373 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 374 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 375 | CLANG_WARN_EMPTY_BODY = YES; 376 | CLANG_WARN_ENUM_CONVERSION = YES; 377 | CLANG_WARN_INFINITE_RECURSION = YES; 378 | CLANG_WARN_INT_CONVERSION = YES; 379 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 380 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 381 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 382 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 383 | CLANG_WARN_STRICT_PROTOTYPES = YES; 384 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 385 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 386 | CLANG_WARN_UNREACHABLE_CODE = YES; 387 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 388 | CODE_SIGN_IDENTITY = "Mac Developer"; 389 | COPY_PHASE_STRIP = NO; 390 | CURRENT_PROJECT_VERSION = 1; 391 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 392 | ENABLE_NS_ASSERTIONS = NO; 393 | ENABLE_STRICT_OBJC_MSGSEND = YES; 394 | GCC_C_LANGUAGE_STANDARD = gnu11; 395 | GCC_NO_COMMON_BLOCKS = YES; 396 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 397 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 398 | GCC_WARN_UNDECLARED_SELECTOR = YES; 399 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 400 | GCC_WARN_UNUSED_FUNCTION = YES; 401 | GCC_WARN_UNUSED_VARIABLE = YES; 402 | MACOSX_DEPLOYMENT_TARGET = 10.12; 403 | MTL_ENABLE_DEBUG_INFO = NO; 404 | SDKROOT = macosx; 405 | VERSIONING_SYSTEM = "apple-generic"; 406 | VERSION_INFO_PREFIX = ""; 407 | }; 408 | name = Release; 409 | }; 410 | B770080B20AD7A4E003E3154 /* Debug */ = { 411 | isa = XCBuildConfiguration; 412 | buildSettings = { 413 | CODE_SIGN_IDENTITY = ""; 414 | CODE_SIGN_STYLE = Automatic; 415 | COMBINE_HIDPI_IMAGES = YES; 416 | DEFINES_MODULE = YES; 417 | DEVELOPMENT_TEAM = GDFHW66V92; 418 | DYLIB_COMPATIBILITY_VERSION = 1; 419 | DYLIB_CURRENT_VERSION = 1; 420 | DYLIB_INSTALL_NAME_BASE = ./; 421 | FRAMEWORK_VERSION = A; 422 | INFOPLIST_FILE = "WeWorkMacPlugin/Supporting Files/Info.plist"; 423 | INSTALL_PATH = ./Other/Products/Release; 424 | LD_DYLIB_INSTALL_NAME = ./WeWorkMacPlugin.framework; 425 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 426 | PRODUCT_BUNDLE_IDENTIFIER = com.qiniu.WeWorkMacPlugin; 427 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 428 | SKIP_INSTALL = NO; 429 | }; 430 | name = Debug; 431 | }; 432 | B770080C20AD7A4E003E3154 /* Release */ = { 433 | isa = XCBuildConfiguration; 434 | buildSettings = { 435 | CODE_SIGN_IDENTITY = ""; 436 | CODE_SIGN_STYLE = Automatic; 437 | COMBINE_HIDPI_IMAGES = YES; 438 | DEFINES_MODULE = YES; 439 | DEVELOPMENT_TEAM = GDFHW66V92; 440 | DYLIB_COMPATIBILITY_VERSION = 1; 441 | DYLIB_CURRENT_VERSION = 1; 442 | DYLIB_INSTALL_NAME_BASE = ./; 443 | FRAMEWORK_VERSION = A; 444 | INFOPLIST_FILE = "WeWorkMacPlugin/Supporting Files/Info.plist"; 445 | INSTALL_PATH = ./Other/Products/Release; 446 | LD_DYLIB_INSTALL_NAME = ./WeWorkMacPlugin.framework; 447 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 448 | PRODUCT_BUNDLE_IDENTIFIER = com.qiniu.WeWorkMacPlugin; 449 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 450 | SKIP_INSTALL = NO; 451 | }; 452 | name = Release; 453 | }; 454 | B770080E20AD7A4E003E3154 /* Debug */ = { 455 | isa = XCBuildConfiguration; 456 | buildSettings = { 457 | CODE_SIGN_STYLE = Automatic; 458 | COMBINE_HIDPI_IMAGES = YES; 459 | DEVELOPMENT_TEAM = GDFHW66V92; 460 | INFOPLIST_FILE = WeWorkMacPluginTests/Info.plist; 461 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 462 | PRODUCT_BUNDLE_IDENTIFIER = com.qiniu.WeWorkMacPluginTests; 463 | PRODUCT_NAME = "$(TARGET_NAME)"; 464 | }; 465 | name = Debug; 466 | }; 467 | B770080F20AD7A4E003E3154 /* Release */ = { 468 | isa = XCBuildConfiguration; 469 | buildSettings = { 470 | CODE_SIGN_STYLE = Automatic; 471 | COMBINE_HIDPI_IMAGES = YES; 472 | DEVELOPMENT_TEAM = GDFHW66V92; 473 | INFOPLIST_FILE = WeWorkMacPluginTests/Info.plist; 474 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 475 | PRODUCT_BUNDLE_IDENTIFIER = com.qiniu.WeWorkMacPluginTests; 476 | PRODUCT_NAME = "$(TARGET_NAME)"; 477 | }; 478 | name = Release; 479 | }; 480 | /* End XCBuildConfiguration section */ 481 | 482 | /* Begin XCConfigurationList section */ 483 | B77007F020AD7A4E003E3154 /* Build configuration list for PBXProject "WeWorkMacPlugin" */ = { 484 | isa = XCConfigurationList; 485 | buildConfigurations = ( 486 | B770080820AD7A4E003E3154 /* Debug */, 487 | B770080920AD7A4E003E3154 /* Release */, 488 | ); 489 | defaultConfigurationIsVisible = 0; 490 | defaultConfigurationName = Release; 491 | }; 492 | B770080A20AD7A4E003E3154 /* Build configuration list for PBXNativeTarget "WeWorkMacPlugin" */ = { 493 | isa = XCConfigurationList; 494 | buildConfigurations = ( 495 | B770080B20AD7A4E003E3154 /* Debug */, 496 | B770080C20AD7A4E003E3154 /* Release */, 497 | ); 498 | defaultConfigurationIsVisible = 0; 499 | defaultConfigurationName = Release; 500 | }; 501 | B770080D20AD7A4E003E3154 /* Build configuration list for PBXNativeTarget "WeWorkMacPluginTests" */ = { 502 | isa = XCConfigurationList; 503 | buildConfigurations = ( 504 | B770080E20AD7A4E003E3154 /* Debug */, 505 | B770080F20AD7A4E003E3154 /* Release */, 506 | ); 507 | defaultConfigurationIsVisible = 0; 508 | defaultConfigurationName = Release; 509 | }; 510 | /* End XCConfigurationList section */ 511 | }; 512 | rootObject = B77007ED20AD7A4E003E3154 /* Project object */; 513 | } 514 | -------------------------------------------------------------------------------- /WeWorkMacPlugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /WeWorkMacPlugin.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /WeWorkMacPlugin.xcodeproj/xcshareddata/xcschemes/WeWorkMacPlugin.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 53 | 54 | 60 | 61 | 67 | 68 | 69 | 70 | 72 | 73 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /WeWorkMacPlugin/Category/NSObject+WorkWeChat.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+WorkWeChat.h 3 | // WeWorkMacPlugin 4 | // 5 | // Created by Anonymous on 17/05/2018. 6 | // Copyright © 2018 Anonymous. All rights reserved. 7 | // 8 | 9 | #import 10 | @interface NSObject (WorkWeChat) 11 | +(void)hookWorkWeChat; 12 | @end 13 | -------------------------------------------------------------------------------- /WeWorkMacPlugin/Category/NSObject+WorkWeChat.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+WorkWeChat.m 3 | // WeWorkMacPlugin 4 | // 5 | // Created by Anonymous on 17/05/2018. 6 | // Copyright © 2018 Anonymous. All rights reserved. 7 | // 8 | 9 | #import "NSObject+WorkWeChat.h" 10 | #import "WeWorkMacPlugin.h" 11 | #import "WLLTools.h" 12 | @implementation NSObject (WorkWeChat) 13 | +(void)hookWorkWeChat{ 14 | // 替换沙盒路径 15 | [WLLTools switchSandboxPath]; 16 | //校验 17 | wll_hookMethod(objc_getClass("NSBundle"), @selector(executablePath), [self class], @selector(hook_executablePath)); 18 | 19 | //去除水印 20 | wll_hookMethod(objc_getClass("WEWCustomView"), @selector(showWaterMark), [self class], @selector(hook_showWaterMark)); 21 | 22 | //多开 23 | wll_hookMethod(objc_getClass("__NSArrayI"), @selector(count), [self class], @selector(hook_count)); 24 | // 禁止小窗口 25 | wll_hookMethod(objc_getClass("WEWConvListController"), @selector(p_onTableViewDoubleClick), [self class], @selector(hook_p_onTableViewDoubleClick)); 26 | 27 | //多开控制栏目注册 28 | wll_hookMethod(objc_getClass("WEWApplicationLifeCricleObserver"), @selector(applicationDidFinishLaunching), [self class], @selector(hook_applicationDidFinishLaunching)); 29 | 30 | } 31 | 32 | - (NSString *)hook_executablePath { 33 | NSString *executablePath = [self hook_executablePath]; 34 | if ([executablePath hasSuffix:@"企业微信"]) { 35 | executablePath = [executablePath stringByAppendingString:@"_backup"]; 36 | } 37 | return executablePath; 38 | } 39 | 40 | - (BOOL)hook_showWaterMark{ 41 | return NO; 42 | } 43 | 44 | - (BOOL)hook_isRevoke{ 45 | return NO; 46 | } 47 | 48 | - (void)hook_p_onTableViewDoubleClick{ 49 | } 50 | 51 | - (void)hook_applicationDidFinishLaunching{ 52 | [self hook_applicationDidFinishLaunching]; 53 | [self addPlugin]; 54 | } 55 | 56 | - (void)addPlugin{ 57 | NSMenu *mainMenu = [NSApp mainMenu]; 58 | NSMenuItem *oneItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; 59 | [mainMenu insertItem:oneItem atIndex:2]; 60 | NSMenu *subMenu = [[NSMenu alloc] initWithTitle:@"Plugin"]; 61 | [oneItem setSubmenu:subMenu]; 62 | [subMenu addItemWithTitle:@"New Wework" action:@selector(onNewWeworkInstance:) keyEquivalent:@"N"]; 63 | [NSApp setMainMenu:mainMenu]; 64 | } 65 | 66 | - (void)onNewWeworkInstance:(NSMenuItem *)item { 67 | NSLog(@"%@",[WLLTools executeShellCommand:@"open -n /Applications/企业微信.app"]); 68 | } 69 | 70 | -(NSUInteger)hook_count{ 71 | NSUInteger count = [self hook_count]; 72 | if (count>0 && [[self performSelector:@selector(objectAtIndex:) withObject:0] isKindOfClass:[NSRunningApplication class]]){ 73 | return 0; 74 | } 75 | return count; 76 | } 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /WeWorkMacPlugin/Supporting Files/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 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSHumanReadableCopyright 22 | Copyright © 2018 Anonymous. All rights reserved. 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /WeWorkMacPlugin/Supporting Files/WeWorkMacPlugin.h: -------------------------------------------------------------------------------- 1 | // 2 | // WeWorkMacPlugin.h 3 | // WeWorkMacPlugin 4 | // 5 | // Created by Anonymous on 17/05/2018. 6 | // Copyright © 2018 Anonymous. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for WeWorkMacPlugin. 12 | FOUNDATION_EXPORT double WeWorkMacPluginVersionNumber; 13 | 14 | //! Project version string for WeWorkMacPlugin. 15 | FOUNDATION_EXPORT const unsigned char WeWorkMacPluginVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | @interface WEWApplicationLifeCricleObserver : NSObject 20 | - (void)applicationDidFinishLaunching; 21 | @end 22 | 23 | @interface WEWMessage : NSObject 24 | @property(nonatomic) BOOL isRevoke; 25 | @property(nonatomic) BOOL isRevokeByAck; // @synthesize isRevokeByAck=_isRevokeByAck; 26 | @property(nonatomic) BOOL isRevokeInReceiptMode; 27 | @end 28 | 29 | @interface WEWCustomView : NSView 30 | @property(nonatomic) BOOL showWaterMark; 31 | @end 32 | 33 | @interface WEWConvListController : NSObject 34 | - (void)p_onTableViewDoubleClick; 35 | @end 36 | 37 | -------------------------------------------------------------------------------- /WeWorkMacPlugin/Supporting Files/main.mm: -------------------------------------------------------------------------------- 1 | // 2 | // main.c 3 | // WeWorkMacPlugin 4 | // 5 | // Created by Anonymous on 17/05/2018. 6 | // Copyright © 2018 Anonymous. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "NSObject+WorkWeChat.h" 11 | static void __attribute__((constructor)) initialize(void) { 12 | NSLog(@"++++++++ WorkWechat Plugin loaded ++++++++"); 13 | [NSObject hookWorkWeChat]; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /WeWorkMacPlugin/Utils/WLLTools.h: -------------------------------------------------------------------------------- 1 | // 2 | // WLLTools.h 3 | // QQPlugin 4 | // 5 | // Created by Anonymous on 05/02/2018. 6 | // Copyright © 2018 Anonymous. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface WLLTools : NSObject 13 | 14 | /** 15 | 替换对象方法 16 | 17 | @param originalClass 原始类 18 | @param originalSelector 原始类的方法 19 | @param swizzledClass 替换类 20 | @param swizzledSelector 替换类的方法 21 | */ 22 | void wll_hookMethod(Class originalClass, SEL originalSelector, Class swizzledClass, SEL swizzledSelector); 23 | 24 | /** 25 | 替换类方法 26 | 27 | @param originalClass 原始类 28 | @param originalSelector 原始类的类方法 29 | @param swizzledClass 替换类 30 | @param swizzledSelector 替换类的类方法 31 | */ 32 | void wll_hookClassMethod(Class originalClass, SEL originalSelector, Class swizzledClass, SEL swizzledSelector); 33 | 34 | 35 | + (NSString *)executeShellCommand:(NSString *)msg; 36 | 37 | + (void)switchSandboxPath; 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /WeWorkMacPlugin/Utils/WLLTools.m: -------------------------------------------------------------------------------- 1 | // 2 | // WLLTools.m 3 | // QQPlugin 4 | // 5 | // Created by Anonymous on 05/02/2018. 6 | // Copyright © 2018 Anonymous. All rights reserved. 7 | // 8 | 9 | #import "WLLTools.h" 10 | #import "fishhook.h" 11 | static NSString * const kFilePath = @"%@/Library/Containers/com.tencent.WeWorkMac/Data"; 12 | @implementation WLLTools 13 | 14 | /** 15 | 替换对象方法 16 | 17 | @param originalClass 原始类 18 | @param originalSelector 原始类的方法 19 | @param swizzledClass 替换类 20 | @param swizzledSelector 替换类的方法 21 | */ 22 | void wll_hookMethod(Class originalClass, SEL originalSelector, Class swizzledClass, SEL swizzledSelector) { 23 | Method originalMethod = class_getInstanceMethod(originalClass, originalSelector); 24 | Method swizzledMethod = class_getInstanceMethod(swizzledClass, swizzledSelector); 25 | if(originalMethod && swizzledMethod) { 26 | method_exchangeImplementations(originalMethod, swizzledMethod); 27 | } 28 | } 29 | 30 | /** 31 | 替换类方法 32 | 33 | @param originalClass 原始类 34 | @param originalSelector 原始类的类方法 35 | @param swizzledClass 替换类 36 | @param swizzledSelector 替换类的类方法 37 | */ 38 | void wll_hookClassMethod(Class originalClass, SEL originalSelector, Class swizzledClass, SEL swizzledSelector) { 39 | Method originalMethod = class_getClassMethod(originalClass, originalSelector); 40 | Method swizzledMethod = class_getClassMethod(swizzledClass, swizzledSelector); 41 | if(originalMethod && swizzledMethod) { 42 | method_exchangeImplementations(originalMethod, swizzledMethod); 43 | } 44 | } 45 | 46 | 47 | + (NSString *)executeShellCommand:(NSString *)cmd { 48 | NSTask *task = [[NSTask alloc] init]; 49 | [task setLaunchPath:@"/bin/bash"]; 50 | [task setArguments:@[@"-c", cmd]]; 51 | NSPipe *errorPipe = [NSPipe pipe]; 52 | [task setStandardError:errorPipe]; 53 | NSFileHandle *file = [errorPipe fileHandleForReading]; 54 | [task launch]; 55 | NSData *data = [file readDataToEndOfFile]; 56 | return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 57 | } 58 | 59 | + (void)switchSandboxPath{ 60 | rebind_symbols((struct rebinding[2]) { 61 | { "NSSearchPathForDirectoriesInDomains", swizzled_NSSearchPathForDirectoriesInDomains, (void *)&original_NSSearchPathForDirectoriesInDomains }, 62 | { "NSHomeDirectory", swizzled_NSHomeDirectory, (void *)&original_NSHomeDirectory } 63 | }, 2); 64 | } 65 | 66 | 67 | #pragma mark - 替换 NSSearchPathForDirectoriesInDomains & NSHomeDirectory 68 | static NSArray *(*original_NSSearchPathForDirectoriesInDomains)(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, BOOL expandTilde); 69 | 70 | NSArray *swizzled_NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, BOOL expandTilde) { 71 | NSMutableArray *paths = [original_NSSearchPathForDirectoriesInDomains(directory, domainMask, expandTilde) mutableCopy]; 72 | NSString *sandBoxPath = [NSString stringWithFormat:kFilePath,original_NSHomeDirectory()]; 73 | 74 | [paths enumerateObjectsUsingBlock:^(NSString *filePath, NSUInteger idx, BOOL * _Nonnull stop) { 75 | NSRange range = [filePath rangeOfString:original_NSHomeDirectory()]; 76 | if (range.length > 0) { 77 | NSMutableString *newFilePath = [filePath mutableCopy]; 78 | [newFilePath replaceCharactersInRange:range withString:sandBoxPath]; 79 | paths[idx] = newFilePath; 80 | } 81 | }]; 82 | 83 | return paths; 84 | } 85 | 86 | static NSString *(*original_NSHomeDirectory)(void); 87 | 88 | NSString *swizzled_NSHomeDirectory(void) { 89 | return [NSString stringWithFormat:kFilePath,original_NSHomeDirectory()]; 90 | } 91 | 92 | 93 | @end 94 | -------------------------------------------------------------------------------- /WeWorkMacPlugin/Utils/WllQueue.h: -------------------------------------------------------------------------------- 1 | // 2 | // WllQueue.h 3 | // QQPlugin 4 | // 5 | // Created by Anonymous on 06/02/2018. 6 | // Copyright © 2018 Anonymous. All rights reserved. 7 | // 8 | 9 | #ifndef WllQueue_h 10 | #define WllQueue_h 11 | 12 | /** 13 | 队列指定 14 | 15 | */ 16 | 17 | static void DispactchSetSpecific(dispatch_queue_t queue, const void *key) { 18 | CFStringRef context = CFSTR("context"); 19 | dispatch_queue_set_specific(queue, 20 | key, 21 | (void*)context, 22 | (dispatch_function_t)CFRelease); 23 | } 24 | 25 | static void DispatchSync(dispatch_queue_t queue, const void *key, dispatch_block_t block) { 26 | CFStringRef context = (CFStringRef)dispatch_get_specific(key); 27 | // 该函数执行时如果在指定 dispatch_queue_t 则直接执行 block,如果不在指定 dispatch_queue_t 则 dispatch_sync 到指定队列执行,用于避免 dispatch_sync 可能引起的死锁 28 | if (context) { 29 | block(); 30 | } else { 31 | dispatch_sync(queue, block); 32 | } 33 | } 34 | 35 | static void DispatchAsync(dispatch_queue_t queue, const void *key, dispatch_block_t block) { 36 | CFStringRef context = (CFStringRef)dispatch_get_specific(key); 37 | // 该函数执行时如果在指定 dispatch_queue_t 则直接执行 block,如果不在指定 dispatch_queue_t 则 dispatch_async 到指定队列执行 38 | if (context) { 39 | block(); 40 | } else { 41 | dispatch_async(queue, block); 42 | } 43 | } 44 | 45 | #endif /* WllQueue_h */ 46 | -------------------------------------------------------------------------------- /WeWorkMacPlugin/Vendor/BigBang.h: -------------------------------------------------------------------------------- 1 | // 2 | // BigBang.h 3 | // 4 | // Created by jsb-xiakj on 2017/5/18. 5 | // Copyright © 2017年 xaikejie. All rights reserved. 6 | // 7 | 8 | #import 9 | #import 10 | #import 11 | @interface BigBang : NSObject 12 | +(void)hookClass:(NSString*)hookString; 13 | @end 14 | -------------------------------------------------------------------------------- /WeWorkMacPlugin/Vendor/BigBang.m: -------------------------------------------------------------------------------- 1 | // 2 | // BigBang.m 3 | // Created by jsb-xiakj on 2017/5/18. 4 | // 5 | 6 | #import "BigBang.h" 7 | #define BIGBANG @"BigBang_" 8 | 9 | #define WRAP_AND_RETURN(type) \ 10 | do { \ 11 | type val = 0; \ 12 | [invocation getArgument:&val atIndex:(NSInteger)index]; \ 13 | return @(val); \ 14 | } while (0) 15 | 16 | #define WRAP_GET_VALUE(type) \ 17 | do { \ 18 | type val = 0; \ 19 | [invocation getReturnValue:&val]; \ 20 | return @(val); \ 21 | } while (0) 22 | 23 | @implementation BigBang 24 | 25 | +(void)hookClass:(NSString*)hookString 26 | { 27 | Class hookClass = NSClassFromString(hookString); 28 | unsigned int outCount = 0; 29 | Method *methods = class_copyMethodList(hookClass, &outCount); 30 | for (int i = 0; i < outCount; i++) { 31 | Method method = methods[i]; 32 | SEL methodSel = method_getName(method); 33 | const char *typeEncoding = method_getTypeEncoding(method); 34 | IMP imp = method_getImplementation(method); 35 | if ([BigBang isMsgForwardIMP:imp]) { 36 | continue; 37 | } 38 | //过滤系统的隐藏函数 39 | NSString *selString=NSStringFromSelector(methodSel); 40 | 41 | NSString *fuctionString = @".cxx_destruct|dealloc|_isDeallocating|release|autorelease|retain|Retain|_tryRetain|copy|nsis_descriptionOfVariable:|respondsToSelector:|class|methodSignatureForSelector:|allowsWeakReference|etainWeakReference|init"; 42 | 43 | if ([selString hasPrefix:@"."]||[fuctionString containsString:selString]) { 44 | continue; 45 | } 46 | NSString *hookedName = [BigBang methodLogMethodName:selString]; 47 | // printf("%s:%s\n",[hookString UTF8String],[hookedName UTF8String]); 48 | class_addMethod(hookClass, NSSelectorFromString(hookedName), imp, typeEncoding); 49 | //将旧地址指向forward invocaton 50 | class_replaceMethod(hookClass, methodSel, [BigBang getMsgForwardIMP:hookClass sel:methodSel], typeEncoding); 51 | } 52 | 53 | IMP forwardInvocationImpl = imp_implementationWithBlock(^(id object, NSInvocation *invocation) { 54 | //NSLog(@"hookString=%@",hookString); 55 | NSString *newSelectorName = [BigBang methodLogMethodName:NSStringFromSelector(invocation.selector)]; 56 | invocation.selector = NSSelectorFromString(newSelectorName); 57 | @try { 58 | NSString *objString=[NSString stringWithFormat:@"%@",object]; 59 | NSUInteger number = invocation.methodSignature.numberOfArguments; 60 | newSelectorName=[newSelectorName stringByReplacingOccurrencesOfString:BIGBANG withString:@""]; 61 | NSString *returnType=[NSString stringWithUTF8String:invocation.methodSignature.methodReturnType]; 62 | returnType=[returnType stringByReplacingOccurrencesOfString:@"v" withString:@"void"]; 63 | returnType=[returnType stringByReplacingOccurrencesOfString:@"B" withString:@"BOOL"]; 64 | returnType=[returnType stringByReplacingOccurrencesOfString:@"q" withString:@"NSNumber"]; 65 | returnType=[returnType stringByReplacingOccurrencesOfString:@"@" withString:@"id"]; 66 | 67 | id obj =[BigBang getReturnValueInvocatein:invocation]; 68 | NSString *retObj=[NSString stringWithFormat:@"%@",obj]; 69 | NSMutableString *muString=[[NSMutableString alloc] init]; 70 | for (long i=2; i%@",i-1,classString,ret]; 75 | } 76 | 77 | printf("-(%s)%s(have %ld value)\nreturn:%s%s\nobject:%s\n ##########################################\n",[returnType UTF8String],[newSelectorName UTF8String],number-2,[retObj UTF8String],[muString UTF8String],[objString UTF8String]); 78 | } @catch (NSException *exception) { 79 | NSLog(@"%@",[exception description]); 80 | } @finally { 81 | 82 | } 83 | 84 | [invocation invoke]; 85 | }); 86 | class_addMethod(hookClass, @selector(forwardInvocation:), forwardInvocationImpl, "v@:@"); 87 | free(methods); 88 | NSString *superClassString = NSStringFromClass(object_getClass(hookClass)); 89 | if (![superClassString isEqualToString:hookString]) { 90 | if (!class_isMetaClass(hookClass)) { 91 | [BigBang hookClass:superClassString]; 92 | } 93 | } 94 | } 95 | 96 | + (id)argumentAtIndex:(NSUInteger)index 97 | withInvocatein:(NSInvocation *)invocation 98 | { 99 | const char *argType = [invocation.methodSignature getArgumentTypeAtIndex:index]; 100 | if (argType[0] == 'r') { 101 | argType++; 102 | } 103 | if (strcmp(argType, @encode(id)) == 0 || strcmp(argType, @encode(Class)) == 0) { 104 | __autoreleasing id returnObj; 105 | [invocation getArgument:&returnObj atIndex:(NSInteger)index]; 106 | return returnObj; 107 | } else if (strcmp(argType, @encode(char)) == 0) { 108 | WRAP_AND_RETURN(char); 109 | } else if (strcmp(argType, @encode(int)) == 0) { 110 | WRAP_AND_RETURN(int); 111 | } else if (strcmp(argType, @encode(short)) == 0) { 112 | WRAP_AND_RETURN(short); 113 | } else if (strcmp(argType, @encode(long)) == 0) { 114 | WRAP_AND_RETURN(long); 115 | } else if (strcmp(argType, @encode(long long)) == 0) { 116 | WRAP_AND_RETURN(long long); 117 | } else if (strcmp(argType, @encode(unsigned char)) == 0) { 118 | WRAP_AND_RETURN(unsigned char); 119 | } else if (strcmp(argType, @encode(unsigned int)) == 0) { 120 | WRAP_AND_RETURN(unsigned int); 121 | } else if (strcmp(argType, @encode(unsigned short)) == 0) { 122 | WRAP_AND_RETURN(unsigned short); 123 | } else if (strcmp(argType, @encode(unsigned long)) == 0) { 124 | WRAP_AND_RETURN(unsigned long); 125 | } else if (strcmp(argType, @encode(unsigned long long)) == 0) { 126 | WRAP_AND_RETURN(unsigned long long); 127 | } else if (strcmp(argType, @encode(float)) == 0) { 128 | WRAP_AND_RETURN(float); 129 | } else if (strcmp(argType, @encode(double)) == 0) { 130 | WRAP_AND_RETURN(double); 131 | } else if (strcmp(argType, @encode(BOOL)) == 0) { 132 | WRAP_AND_RETURN(BOOL); 133 | } else if (strcmp(argType, @encode(char *)) == 0) { 134 | WRAP_AND_RETURN(const char *); 135 | } else if (strcmp(argType, @encode(void (^)(void))) == 0) { 136 | __unsafe_unretained id block = nil; 137 | [invocation getArgument:&block atIndex:(NSInteger)index]; 138 | return [block copy]; 139 | } else { 140 | NSUInteger valueSize = 0; 141 | NSGetSizeAndAlignment(argType, &valueSize, NULL); 142 | 143 | unsigned char valueBytes[valueSize]; 144 | [invocation getArgument:valueBytes atIndex:(NSInteger)index]; 145 | 146 | return [NSValue valueWithBytes:valueBytes objCType:argType]; 147 | } 148 | 149 | return nil; 150 | 151 | #undef WRAP_AND_RETURN 152 | } 153 | 154 | + (id)getReturnValueInvocatein:(NSInvocation *)invocation 155 | { 156 | 157 | const char *returnType = invocation.methodSignature.methodReturnType; 158 | // Skip const type qualifier. 159 | if (returnType[0] == 'r') { 160 | returnType++; 161 | } 162 | 163 | if (strcmp(returnType, @encode(id)) == 0 || strcmp(returnType, @encode(Class)) == 0 || strcmp(returnType, @encode(void (^)(void))) == 0) { 164 | __autoreleasing id returnObj; 165 | [invocation getReturnValue:&returnObj]; 166 | return returnObj; 167 | } else if (strcmp(returnType, @encode(char)) == 0) { 168 | WRAP_GET_VALUE(char); 169 | } else if (strcmp(returnType, @encode(int)) == 0) { 170 | WRAP_GET_VALUE(int); 171 | } else if (strcmp(returnType, @encode(short)) == 0) { 172 | WRAP_GET_VALUE(short); 173 | } else if (strcmp(returnType, @encode(long)) == 0) { 174 | WRAP_GET_VALUE(long); 175 | } else if (strcmp(returnType, @encode(long long)) == 0) { 176 | WRAP_GET_VALUE(long long); 177 | } else if (strcmp(returnType, @encode(unsigned char)) == 0) { 178 | WRAP_GET_VALUE(unsigned char); 179 | } else if (strcmp(returnType, @encode(unsigned int)) == 0) { 180 | WRAP_GET_VALUE(unsigned int); 181 | } else if (strcmp(returnType, @encode(unsigned short)) == 0) { 182 | WRAP_GET_VALUE(unsigned short); 183 | } else if (strcmp(returnType, @encode(unsigned long)) == 0) { 184 | WRAP_GET_VALUE(unsigned long); 185 | } else if (strcmp(returnType, @encode(unsigned long long)) == 0) { 186 | WRAP_GET_VALUE(unsigned long long); 187 | } else if (strcmp(returnType, @encode(float)) == 0) { 188 | WRAP_GET_VALUE(float); 189 | } else if (strcmp(returnType, @encode(double)) == 0) { 190 | WRAP_GET_VALUE(double); 191 | } else if (strcmp(returnType, @encode(BOOL)) == 0) { 192 | WRAP_GET_VALUE(BOOL); 193 | } else if (strcmp(returnType, @encode(char *)) == 0) { 194 | WRAP_GET_VALUE(const char *); 195 | } else if (strcmp(returnType, @encode(void)) == 0) { 196 | return nil; 197 | } else { 198 | NSUInteger valueSize = 0; 199 | NSGetSizeAndAlignment(returnType, &valueSize, NULL); 200 | 201 | unsigned char valueBytes[valueSize]; 202 | [invocation getReturnValue:valueBytes]; 203 | 204 | return [NSValue valueWithBytes:valueBytes objCType:returnType]; 205 | } 206 | 207 | return nil; 208 | 209 | #undef WRAP_AND_RETURN 210 | } 211 | 212 | 213 | + (NSString *)methodLogMethodName:(NSString *)selName { 214 | return [BIGBANG stringByAppendingFormat:@"%@",selName]; 215 | } 216 | 217 | + (IMP)getMsgForwardIMP:(Class)logedClass sel:(SEL)selector { 218 | IMP msgForwardIMP = _objc_msgForward; 219 | #if !defined(__arm64__) 220 | Method method = class_getInstanceMethod(logedClass, selector); 221 | const char *encoding = method_getTypeEncoding(method); 222 | BOOL methodReturnsStructValue = encoding[0] == _C_STRUCT_B; 223 | if (methodReturnsStructValue) { 224 | @try { 225 | NSUInteger valueSize = 0; 226 | NSGetSizeAndAlignment(encoding, &valueSize, NULL); 227 | 228 | if (valueSize == 1 || valueSize == 2 || valueSize == 4 || valueSize == 8) { 229 | methodReturnsStructValue = NO; 230 | } 231 | } @catch (NSException *e) {} 232 | } 233 | if (methodReturnsStructValue) { 234 | msgForwardIMP = (IMP)_objc_msgForward_stret; 235 | } 236 | #endif 237 | return msgForwardIMP; 238 | } 239 | 240 | + (BOOL)isMsgForwardIMP:(IMP)impl { 241 | return impl == _objc_msgForward 242 | #if !defined(__arm64__) 243 | || impl == (IMP)_objc_msgForward_stret 244 | #endif 245 | ; 246 | } 247 | 248 | 249 | 250 | @end 251 | -------------------------------------------------------------------------------- /WeWorkMacPlugin/Vendor/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 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #ifdef __LP64__ 40 | typedef struct mach_header_64 mach_header_t; 41 | typedef struct segment_command_64 segment_command_t; 42 | typedef struct section_64 section_t; 43 | typedef struct nlist_64 nlist_t; 44 | #define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT_64 45 | #else 46 | typedef struct mach_header mach_header_t; 47 | typedef struct segment_command segment_command_t; 48 | typedef struct section section_t; 49 | typedef struct nlist nlist_t; 50 | #define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT 51 | #endif 52 | 53 | #ifndef SEG_DATA_CONST 54 | #define SEG_DATA_CONST "__DATA_CONST" 55 | #endif 56 | 57 | struct rebindings_entry { 58 | struct rebinding *rebindings; 59 | size_t rebindings_nel; 60 | struct rebindings_entry *next; 61 | }; 62 | 63 | static struct rebindings_entry *_rebindings_head; 64 | 65 | static int prepend_rebindings(struct rebindings_entry **rebindings_head, 66 | struct rebinding rebindings[], 67 | size_t nel) { 68 | struct rebindings_entry *new_entry = (struct rebindings_entry *) malloc(sizeof(struct rebindings_entry)); 69 | if (!new_entry) { 70 | return -1; 71 | } 72 | new_entry->rebindings = (struct rebinding *) malloc(sizeof(struct rebinding) * nel); 73 | if (!new_entry->rebindings) { 74 | free(new_entry); 75 | return -1; 76 | } 77 | memcpy(new_entry->rebindings, rebindings, sizeof(struct rebinding) * nel); 78 | new_entry->rebindings_nel = nel; 79 | new_entry->next = *rebindings_head; 80 | *rebindings_head = new_entry; 81 | return 0; 82 | } 83 | 84 | #if 0 85 | static int get_protection(void *addr, vm_prot_t *prot, vm_prot_t *max_prot) { 86 | mach_port_t task = mach_task_self(); 87 | vm_size_t size = 0; 88 | vm_address_t address = (vm_address_t)addr; 89 | memory_object_name_t object; 90 | #ifdef __LP64__ 91 | mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64; 92 | vm_region_basic_info_data_64_t info; 93 | kern_return_t info_ret = vm_region_64( 94 | task, &address, &size, VM_REGION_BASIC_INFO_64, (vm_region_info_64_t)&info, &count, &object); 95 | #else 96 | mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT; 97 | vm_region_basic_info_data_t info; 98 | kern_return_t info_ret = vm_region(task, &address, &size, VM_REGION_BASIC_INFO, (vm_region_info_t)&info, &count, &object); 99 | #endif 100 | if (info_ret == KERN_SUCCESS) { 101 | if (prot != NULL) 102 | *prot = info.protection; 103 | 104 | if (max_prot != NULL) 105 | *max_prot = info.max_protection; 106 | 107 | return 0; 108 | } 109 | 110 | return -1; 111 | } 112 | #endif 113 | 114 | static void perform_rebinding_with_section(struct rebindings_entry *rebindings, 115 | section_t *section, 116 | intptr_t slide, 117 | nlist_t *symtab, 118 | char *strtab, 119 | uint32_t *indirect_symtab) { 120 | uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1; 121 | void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr); 122 | 123 | for (uint i = 0; i < section->size / sizeof(void *); i++) { 124 | uint32_t symtab_index = indirect_symbol_indices[i]; 125 | if (symtab_index == INDIRECT_SYMBOL_ABS || symtab_index == INDIRECT_SYMBOL_LOCAL || 126 | symtab_index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS)) { 127 | continue; 128 | } 129 | uint32_t strtab_offset = symtab[symtab_index].n_un.n_strx; 130 | char *symbol_name = strtab + strtab_offset; 131 | bool symbol_name_longer_than_1 = symbol_name[0] && symbol_name[1]; 132 | struct rebindings_entry *cur = rebindings; 133 | while (cur) { 134 | for (uint j = 0; j < cur->rebindings_nel; j++) { 135 | if (symbol_name_longer_than_1 && strcmp(&symbol_name[1], cur->rebindings[j].name) == 0) { 136 | kern_return_t err; 137 | 138 | if (cur->rebindings[j].replaced != NULL && indirect_symbol_bindings[i] != cur->rebindings[j].replacement) 139 | *(cur->rebindings[j].replaced) = indirect_symbol_bindings[i]; 140 | 141 | /** 142 | * 1. Moved the vm protection modifying codes to here to reduce the 143 | * changing scope. 144 | * 2. Adding VM_PROT_WRITE mode unconditionally because vm_region 145 | * API on some iOS/Mac reports mismatch vm protection attributes. 146 | * -- Lianfu Hao Jun 16th, 2021 147 | **/ 148 | err = vm_protect (mach_task_self (), (uintptr_t)indirect_symbol_bindings, section->size, 0, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_COPY); 149 | if (err == KERN_SUCCESS) { 150 | /** 151 | * Once we failed to change the vm protection, we 152 | * MUST NOT continue the following write actions! 153 | * iOS 15 has corrected the const segments prot. 154 | * -- Lionfore Hao Jun 11th, 2021 155 | **/ 156 | indirect_symbol_bindings[i] = cur->rebindings[j].replacement; 157 | } 158 | goto symbol_loop; 159 | } 160 | } 161 | cur = cur->next; 162 | } 163 | symbol_loop:; 164 | } 165 | } 166 | 167 | static void rebind_symbols_for_image(struct rebindings_entry *rebindings, 168 | const struct mach_header *header, 169 | intptr_t slide) { 170 | Dl_info info; 171 | if (dladdr(header, &info) == 0) { 172 | return; 173 | } 174 | 175 | segment_command_t *cur_seg_cmd; 176 | segment_command_t *linkedit_segment = NULL; 177 | struct symtab_command* symtab_cmd = NULL; 178 | struct dysymtab_command* dysymtab_cmd = NULL; 179 | 180 | uintptr_t cur = (uintptr_t)header + sizeof(mach_header_t); 181 | for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { 182 | cur_seg_cmd = (segment_command_t *)cur; 183 | if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { 184 | if (strcmp(cur_seg_cmd->segname, SEG_LINKEDIT) == 0) { 185 | linkedit_segment = cur_seg_cmd; 186 | } 187 | } else if (cur_seg_cmd->cmd == LC_SYMTAB) { 188 | symtab_cmd = (struct symtab_command*)cur_seg_cmd; 189 | } else if (cur_seg_cmd->cmd == LC_DYSYMTAB) { 190 | dysymtab_cmd = (struct dysymtab_command*)cur_seg_cmd; 191 | } 192 | } 193 | 194 | if (!symtab_cmd || !dysymtab_cmd || !linkedit_segment || 195 | !dysymtab_cmd->nindirectsyms) { 196 | return; 197 | } 198 | 199 | // Find base symbol/string table addresses 200 | uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff; 201 | nlist_t *symtab = (nlist_t *)(linkedit_base + symtab_cmd->symoff); 202 | char *strtab = (char *)(linkedit_base + symtab_cmd->stroff); 203 | 204 | // Get indirect symbol table (array of uint32_t indices into symbol table) 205 | uint32_t *indirect_symtab = (uint32_t *)(linkedit_base + dysymtab_cmd->indirectsymoff); 206 | 207 | cur = (uintptr_t)header + sizeof(mach_header_t); 208 | for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { 209 | cur_seg_cmd = (segment_command_t *)cur; 210 | if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { 211 | if (strcmp(cur_seg_cmd->segname, SEG_DATA) != 0 && 212 | strcmp(cur_seg_cmd->segname, SEG_DATA_CONST) != 0) { 213 | continue; 214 | } 215 | for (uint j = 0; j < cur_seg_cmd->nsects; j++) { 216 | section_t *sect = 217 | (section_t *)(cur + sizeof(segment_command_t)) + j; 218 | if ((sect->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS) { 219 | perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab); 220 | } 221 | if ((sect->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS) { 222 | perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab); 223 | } 224 | } 225 | } 226 | } 227 | } 228 | 229 | static void _rebind_symbols_for_image(const struct mach_header *header, 230 | intptr_t slide) { 231 | rebind_symbols_for_image(_rebindings_head, header, slide); 232 | } 233 | 234 | int rebind_symbols_image(void *header, 235 | intptr_t slide, 236 | struct rebinding rebindings[], 237 | size_t rebindings_nel) { 238 | struct rebindings_entry *rebindings_head = NULL; 239 | int retval = prepend_rebindings(&rebindings_head, rebindings, rebindings_nel); 240 | rebind_symbols_for_image(rebindings_head, (const struct mach_header *) header, slide); 241 | if (rebindings_head) { 242 | free(rebindings_head->rebindings); 243 | } 244 | free(rebindings_head); 245 | return retval; 246 | } 247 | 248 | int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel) { 249 | int retval = prepend_rebindings(&_rebindings_head, rebindings, rebindings_nel); 250 | if (retval < 0) { 251 | return retval; 252 | } 253 | // If this was the first call, register callback for image additions (which is also invoked for 254 | // existing images, otherwise, just run on existing images 255 | if (!_rebindings_head->next) { 256 | _dyld_register_func_for_add_image(_rebind_symbols_for_image); 257 | } else { 258 | uint32_t c = _dyld_image_count(); 259 | for (uint32_t i = 0; i < c; i++) { 260 | _rebind_symbols_for_image(_dyld_get_image_header(i), _dyld_get_image_vmaddr_slide(i)); 261 | } 262 | } 263 | return retval; 264 | } 265 | -------------------------------------------------------------------------------- /WeWorkMacPlugin/Vendor/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 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | app_name="企业微信" 4 | shell_path="$(dirname "$0")" 5 | other_dir_path="${shell_path}/Other" 6 | framework_path="${other_dir_path}/Products/Release" 7 | app_path="/Applications/${app_name}.app" 8 | framework_name="WeWorkMacPlugin.framework" 9 | dylib_name="WeWorkMacPlugin" 10 | app_bundle_path="${app_path}/Contents/MacOS" 11 | app_executable_path="${app_bundle_path}/${app_name}" 12 | app_executable_backup_path="${app_executable_path}_backup" 13 | dylib_path="${app_bundle_path}/${framework_name}/${dylib_name}" 14 | 15 | if [ ! -w "${app_path}" ] 16 | then 17 | echo -e "\n\n 请输入密码 : " 18 | sudo chown -R $(whoami) "${app_path}" 19 | fi 20 | 21 | if [ ! -f "${app_executable_backup_path}" ] 22 | then 23 | cp "${app_executable_path}" "${app_executable_backup_path}" 24 | fi 25 | 26 | cp -rf "${framework_path}/${framework_name}" ${app_bundle_path} 27 | rm -rf ${framework_path}/* 28 | 29 | ${other_dir_path}/insert_dylib --all-yes "${dylib_path}" "${app_executable_backup_path}" "${app_executable_path}" 30 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## 功能: 2 | 3 | 1. 防撤回 4 | 2. 去水印 5 | 3. 多开 (工作需要,大家不要滥用。) 6 | 7 | ## 安装方式: 8 | 9 | 1. 先安装Xcode 10 | 11 | 2. cd 到项目目录,然后make 即可(推荐。) 12 | 13 | ```shell 14 | 如果make失败,尝试输入 15 | sudo chown -R $(whoami) /Applications/企业微信.app 16 | 然后再次make 17 | ``` 18 | 19 | 3. 20 | 21 | 4. 用Xcode打开WeWorkMacPlugin.xcodeproj,然后command+b编译后即可。 22 | 23 | ## 使用方式: 24 | 25 | 1. 防撤回、去水印 不需要任何操作,patch完程序就正常使用。 26 | 2. 多开 快捷键: ⇧⌘N 或者 Tabbar上的Plugin点击即可。 27 | 28 | --------------------------------------------------------------------------------