diff --git a/WeChatTweak.framework/Versions/A/Resources/Info.plist b/WeChatTweak.framework/Versions/A/Resources/Info.plist index c16dca1..ebfe4da 100644 --- a/WeChatTweak.framework/Versions/A/Resources/Info.plist +++ b/WeChatTweak.framework/Versions/A/Resources/Info.plist @@ -3,7 +3,7 @@ BuildMachineOSBuild - 16G29 + 17A365 CFBundleDevelopmentRegion en CFBundleExecutable @@ -27,17 +27,17 @@ DTCompiler com.apple.compilers.llvm.clang.1_0 DTPlatformBuild - 8E3004b + 9A235 DTPlatformVersion GM DTSDKBuild - 16E185 + 17A360 DTSDKName - macosx10.12 + macosx10.13 DTXcode - 0833 + 0900 DTXcodeBuild - 8E3004b + 9A235 NSHumanReadableCopyright Copyright © 2017年 Sunnyyoung. All rights reserved. diff --git a/WeChatTweak.framework/Versions/A/Resources/TweakPreferecesController.nib b/WeChatTweak.framework/Versions/A/Resources/TweakPreferecesController.nib index 399b569..f0d03dc 100644 Binary files a/WeChatTweak.framework/Versions/A/Resources/TweakPreferecesController.nib and b/WeChatTweak.framework/Versions/A/Resources/TweakPreferecesController.nib differ diff --git a/WeChatTweak.framework/Versions/A/WeChatTweak b/WeChatTweak.framework/Versions/A/WeChatTweak index 86c5b4e..e231808 100755 Binary files a/WeChatTweak.framework/Versions/A/WeChatTweak and b/WeChatTweak.framework/Versions/A/WeChatTweak differ diff --git a/WeChatTweak.xcodeproj/project.pbxproj b/WeChatTweak.xcodeproj/project.pbxproj index f120c7b..7c58903 100644 --- a/WeChatTweak.xcodeproj/project.pbxproj +++ b/WeChatTweak.xcodeproj/project.pbxproj @@ -9,6 +9,10 @@ /* Begin PBXBuildFile section */ 7D14E5A41F6447DB00D75132 /* AlfredManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 7D14E5A21F6447DB00D75132 /* AlfredManager.h */; }; 7D14E5A51F6447DB00D75132 /* AlfredManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D14E5A31F6447DB00D75132 /* AlfredManager.m */; }; + 7D9049F51F82A41A004E6370 /* fishhook.c in Sources */ = {isa = PBXBuildFile; fileRef = 7D9049F31F82A415004E6370 /* fishhook.c */; }; + 7D9049F61F82A41A004E6370 /* fishhook.h in Headers */ = {isa = PBXBuildFile; fileRef = 7D9049F41F82A415004E6370 /* fishhook.h */; }; + 7D9049F91F82B6FB004E6370 /* NSString+WeChatTweak.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D9049F81F82B6FB004E6370 /* NSString+WeChatTweak.m */; }; + 7D9049FA1F82B708004E6370 /* NSString+WeChatTweak.h in Headers */ = {isa = PBXBuildFile; fileRef = 7D9049F71F82B6FB004E6370 /* NSString+WeChatTweak.h */; }; 7DF8422C1F40583F00D42D79 /* WeChatTweak.h in Headers */ = {isa = PBXBuildFile; fileRef = 7DF8422A1F40583F00D42D79 /* WeChatTweak.h */; settings = {ATTRIBUTES = (Public, ); }; }; 7DF842341F4058AB00D42D79 /* WeChatTweak.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DF842331F4058AB00D42D79 /* WeChatTweak.m */; }; 7DF842521F4058C600D42D79 /* TweakPreferecesController.h in Headers */ = {isa = PBXBuildFile; fileRef = 7DF8424F1F4058C600D42D79 /* TweakPreferecesController.h */; }; @@ -16,8 +20,6 @@ 7DF842541F4058C600D42D79 /* TweakPreferecesController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7DF842511F4058C600D42D79 /* TweakPreferecesController.xib */; }; 7DF8425B1F4058DD00D42D79 /* NSBundle+WeChatTweak.h in Headers */ = {isa = PBXBuildFile; fileRef = 7DF842571F4058DD00D42D79 /* NSBundle+WeChatTweak.h */; }; 7DF8425C1F4058DD00D42D79 /* NSBundle+WeChatTweak.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DF842581F4058DD00D42D79 /* NSBundle+WeChatTweak.m */; }; - 7DF8425D1F4058DD00D42D79 /* NSString+WeChatTweak.h in Headers */ = {isa = PBXBuildFile; fileRef = 7DF842591F4058DD00D42D79 /* NSString+WeChatTweak.h */; }; - 7DF8425E1F4058DD00D42D79 /* NSString+WeChatTweak.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DF8425A1F4058DD00D42D79 /* NSString+WeChatTweak.m */; }; 7DF842601F40590500D42D79 /* WeChatTweakHeaders.h in Headers */ = {isa = PBXBuildFile; fileRef = 7DF8425F1F40590500D42D79 /* WeChatTweakHeaders.h */; }; 7DF842621F40592800D42D79 /* WeChatTweak.framework in Export Framework */ = {isa = PBXBuildFile; fileRef = 7DF842271F40583F00D42D79 /* WeChatTweak.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 7DF842651F40594400D42D79 /* Prefs-Tweak.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 7DF842641F40594400D42D79 /* Prefs-Tweak.tiff */; }; @@ -42,6 +44,10 @@ 153504EC5C9196C0D85213CF /* libPods-WeChatTweak.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-WeChatTweak.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 7D14E5A21F6447DB00D75132 /* AlfredManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AlfredManager.h; sourceTree = ""; }; 7D14E5A31F6447DB00D75132 /* AlfredManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AlfredManager.m; sourceTree = ""; }; + 7D9049F31F82A415004E6370 /* fishhook.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = fishhook.c; sourceTree = ""; }; + 7D9049F41F82A415004E6370 /* fishhook.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = fishhook.h; sourceTree = ""; }; + 7D9049F71F82B6FB004E6370 /* NSString+WeChatTweak.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSString+WeChatTweak.h"; sourceTree = ""; }; + 7D9049F81F82B6FB004E6370 /* NSString+WeChatTweak.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSString+WeChatTweak.m"; sourceTree = ""; }; 7DF842271F40583F00D42D79 /* WeChatTweak.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = WeChatTweak.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 7DF8422A1F40583F00D42D79 /* WeChatTweak.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WeChatTweak.h; sourceTree = ""; }; 7DF8422B1F40583F00D42D79 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -51,8 +57,6 @@ 7DF842511F4058C600D42D79 /* TweakPreferecesController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TweakPreferecesController.xib; sourceTree = ""; }; 7DF842571F4058DD00D42D79 /* NSBundle+WeChatTweak.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSBundle+WeChatTweak.h"; sourceTree = ""; }; 7DF842581F4058DD00D42D79 /* NSBundle+WeChatTweak.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSBundle+WeChatTweak.m"; sourceTree = ""; }; - 7DF842591F4058DD00D42D79 /* NSString+WeChatTweak.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+WeChatTweak.h"; sourceTree = ""; }; - 7DF8425A1F4058DD00D42D79 /* NSString+WeChatTweak.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+WeChatTweak.m"; sourceTree = ""; }; 7DF8425F1F40590500D42D79 /* WeChatTweakHeaders.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeChatTweakHeaders.h; sourceTree = ""; }; 7DF842641F40594400D42D79 /* Prefs-Tweak.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = "Prefs-Tweak.tiff"; sourceTree = ""; }; A82E6F61C63DBD47219BB308 /* Pods-WeChatTweak.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WeChatTweak.debug.xcconfig"; path = "Pods/Target Support Files/Pods-WeChatTweak/Pods-WeChatTweak.debug.xcconfig"; sourceTree = ""; }; @@ -88,6 +92,15 @@ name = Manager; sourceTree = ""; }; + 7D9049F21F82A3F5004E6370 /* Vendor */ = { + isa = PBXGroup; + children = ( + 7D9049F31F82A415004E6370 /* fishhook.c */, + 7D9049F41F82A415004E6370 /* fishhook.h */, + ); + name = Vendor; + sourceTree = ""; + }; 7DF8421D1F40583F00D42D79 = { isa = PBXGroup; children = ( @@ -114,6 +127,7 @@ 7D14E5A11F6447B900D75132 /* Manager */, 7DF842551F4058C900D42D79 /* Controller */, 7DF842561F4058D300D42D79 /* Category */, + 7D9049F21F82A3F5004E6370 /* Vendor */, 7DF842631F40594400D42D79 /* Resources */, 7DF842321F40584700D42D79 /* Supporting Files */, ); @@ -144,8 +158,8 @@ children = ( 7DF842571F4058DD00D42D79 /* NSBundle+WeChatTweak.h */, 7DF842581F4058DD00D42D79 /* NSBundle+WeChatTweak.m */, - 7DF842591F4058DD00D42D79 /* NSString+WeChatTweak.h */, - 7DF8425A1F4058DD00D42D79 /* NSString+WeChatTweak.m */, + 7D9049F71F82B6FB004E6370 /* NSString+WeChatTweak.h */, + 7D9049F81F82B6FB004E6370 /* NSString+WeChatTweak.m */, ); name = Category; sourceTree = ""; @@ -174,12 +188,13 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 7D9049FA1F82B708004E6370 /* NSString+WeChatTweak.h in Headers */, 7DF8422C1F40583F00D42D79 /* WeChatTweak.h in Headers */, 7DF8425B1F4058DD00D42D79 /* NSBundle+WeChatTweak.h in Headers */, + 7D9049F61F82A41A004E6370 /* fishhook.h in Headers */, 7D14E5A41F6447DB00D75132 /* AlfredManager.h in Headers */, 7DF842601F40590500D42D79 /* WeChatTweakHeaders.h in Headers */, 7DF842521F4058C600D42D79 /* TweakPreferecesController.h in Headers */, - 7DF8425D1F4058DD00D42D79 /* NSString+WeChatTweak.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -213,7 +228,7 @@ 7DF8421E1F40583F00D42D79 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0830; + LastUpgradeCheck = 0900; ORGANIZATIONNAME = Sunnyyoung; TargetAttributes = { 7DF842261F40583F00D42D79 = { @@ -293,9 +308,10 @@ buildActionMask = 2147483647; files = ( 7D14E5A51F6447DB00D75132 /* AlfredManager.m in Sources */, - 7DF8425E1F4058DD00D42D79 /* NSString+WeChatTweak.m in Sources */, 7DF842531F4058C600D42D79 /* TweakPreferecesController.m in Sources */, + 7D9049F91F82B6FB004E6370 /* NSString+WeChatTweak.m in Sources */, 7DF842341F4058AB00D42D79 /* WeChatTweak.m in Sources */, + 7D9049F51F82A41A004E6370 /* fishhook.c in Sources */, 7DF8425C1F4058DD00D42D79 /* NSBundle+WeChatTweak.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -313,7 +329,9 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; @@ -321,7 +339,11 @@ CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -345,7 +367,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.12; + MACOSX_DEPLOYMENT_TARGET = 10.13; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -364,7 +386,9 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; @@ -372,7 +396,11 @@ CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -390,7 +418,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.12; + MACOSX_DEPLOYMENT_TARGET = 10.13; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; VERSIONING_SYSTEM = "apple-generic"; @@ -412,6 +440,7 @@ INFOPLIST_FILE = WeChatTweak/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.10; PRODUCT_BUNDLE_IDENTIFIER = net.sunnyyoung.WeChatTweak; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -432,6 +461,7 @@ INFOPLIST_FILE = WeChatTweak/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.10; PRODUCT_BUNDLE_IDENTIFIER = net.sunnyyoung.WeChatTweak; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; diff --git a/WeChatTweak/AlfredManager.m b/WeChatTweak/AlfredManager.m index 9b7700f..fe84fa9 100644 --- a/WeChatTweak/AlfredManager.m +++ b/WeChatTweak/AlfredManager.m @@ -40,7 +40,7 @@ GroupStorage *groupStorage = [serviceCenter getService:objc_getClass("GroupStorage")]; NSMutableArray *array = [NSMutableArray array]; [array addObjectsFromArray:[contactStorage GetAllFriendContacts]]; - [array addObjectsFromArray:[groupStorage GetGroupContactList:0x2 ContactType:0x0]]; + [array addObjectsFromArray:[groupStorage GetGroupContactList:2 ContactType:0]]; array; }); NSArray *results = ({ diff --git a/WeChatTweak/WeChatTweak.m b/WeChatTweak/WeChatTweak.m index 429708a..068504d 100755 --- a/WeChatTweak/WeChatTweak.m +++ b/WeChatTweak/WeChatTweak.m @@ -8,16 +8,42 @@ #import "WeChatTweak.h" #import "WeChatTweakHeaders.h" +#import "fishhook.h" #import "NSBundle+WeChatTweak.h" #import "NSString+WeChatTweak.h" #import "TweakPreferecesController.h" #import "AlfredManager.h" +// Global Function +static NSArray *(*original_NSSearchPathForDirectoriesInDomains)(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, BOOL expandTilde); +NSArray *tweak_NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, BOOL expandTilde) { + if (domainMask == NSUserDomainMask) { + NSMutableArray *directories = [original_NSSearchPathForDirectoriesInDomains(directory, domainMask, expandTilde) mutableCopy]; + [directories enumerateObjectsUsingBlock:^(NSString * _Nonnull object, NSUInteger index, BOOL * _Nonnull stop) { + switch (directory) { + case NSDocumentDirectory: directories[index] = [NSHomeDirectory() stringByAppendingPathComponent:@"/Library/Containers/com.tencent.xinWeChat/Data/Documents"]; break; + case NSLibraryDirectory: directories[index] = [NSHomeDirectory() stringByAppendingPathComponent:@"/Library/Containers/com.tencent.xinWeChat/Data/Library"]; break; + case NSApplicationSupportDirectory: directories[index] = [NSHomeDirectory() stringByAppendingPathComponent:@"/Library/Containers/com.tencent.xinWeChat/Data/Library/Application Support"]; break; + case NSCachesDirectory: directories[index] = [NSHomeDirectory() stringByAppendingPathComponent:@"/Library/Containers/com.tencent.xinWeChat/Data/Library/Caches"]; break; + default: break; + } + }]; + return directories; + } else { + return original_NSSearchPathForDirectoriesInDomains(directory, domainMask, expandTilde); + } +} + @implementation NSObject (WeChatTweak) #pragma mark - Constructor static void __attribute__((constructor)) tweak(void) { + // Global Function Hook + rebind_symbols((struct rebinding[1]) { + { "NSSearchPathForDirectoriesInDomains", tweak_NSSearchPathForDirectoriesInDomains, (void *)&original_NSSearchPathForDirectoriesInDomains } + }, 1); + // Method Swizzling class_addMethod(objc_getClass("AppDelegate"), @selector(applicationDockMenu:), method_getImplementation(class_getInstanceMethod(objc_getClass("AppDelegate"), @selector(tweak_applicationDockMenu:))), "@:@"); [objc_getClass("AppDelegate") jr_swizzleMethod:NSSelectorFromString(@"applicationDidFinishLaunching:") withMethod:@selector(tweak_applicationDidFinishLaunching:) error:nil]; [objc_getClass("AppDelegate") jr_swizzleMethod:NSSelectorFromString(@"applicationShouldTerminate:") withMethod:@selector(tweak_applicationShouldTerminate:) error:nil]; diff --git a/WeChatTweak/WeChatTweakHeaders.h b/WeChatTweak/WeChatTweakHeaders.h index 8ee6acc..c5d4a14 100644 --- a/WeChatTweak/WeChatTweakHeaders.h +++ b/WeChatTweak/WeChatTweakHeaders.h @@ -65,7 +65,8 @@ - (WCContactData *)GetGroupContact:(NSString *)session; - (NSArray *)GetAllGroups; -- (NSArray *)GetGroupContactList:(NSInteger) arg1 ContactType:(NSInteger) arg2; +- (NSArray *)GetGroupContactList:(NSInteger)arg1 ContactType:(NSInteger)arg2; + @end @interface MMServiceCenter : NSObject diff --git a/WeChatTweak/fishhook.c b/WeChatTweak/fishhook.c new file mode 100644 index 0000000..205ee82 --- /dev/null +++ b/WeChatTweak/fishhook.c @@ -0,0 +1,210 @@ +// Copyright (c) 2013, Facebook, Inc. +// All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name Facebook nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific +// prior written permission. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#import "fishhook.h" + +#import +#import +#import +#import +#import +#import +#import + +#ifdef __LP64__ +typedef struct mach_header_64 mach_header_t; +typedef struct segment_command_64 segment_command_t; +typedef struct section_64 section_t; +typedef struct nlist_64 nlist_t; +#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT_64 +#else +typedef struct mach_header mach_header_t; +typedef struct segment_command segment_command_t; +typedef struct section section_t; +typedef struct nlist nlist_t; +#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT +#endif + +#ifndef SEG_DATA_CONST +#define SEG_DATA_CONST "__DATA_CONST" +#endif + +struct rebindings_entry { + struct rebinding *rebindings; + size_t rebindings_nel; + struct rebindings_entry *next; +}; + +static struct rebindings_entry *_rebindings_head; + +static int prepend_rebindings(struct rebindings_entry **rebindings_head, + struct rebinding rebindings[], + size_t nel) { + struct rebindings_entry *new_entry = (struct rebindings_entry *) malloc(sizeof(struct rebindings_entry)); + if (!new_entry) { + return -1; + } + new_entry->rebindings = (struct rebinding *) malloc(sizeof(struct rebinding) * nel); + if (!new_entry->rebindings) { + free(new_entry); + return -1; + } + memcpy(new_entry->rebindings, rebindings, sizeof(struct rebinding) * nel); + new_entry->rebindings_nel = nel; + new_entry->next = *rebindings_head; + *rebindings_head = new_entry; + return 0; +} + +static void perform_rebinding_with_section(struct rebindings_entry *rebindings, + section_t *section, + intptr_t slide, + nlist_t *symtab, + char *strtab, + uint32_t *indirect_symtab) { + uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1; + void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr); + for (uint i = 0; i < section->size / sizeof(void *); i++) { + uint32_t symtab_index = indirect_symbol_indices[i]; + if (symtab_index == INDIRECT_SYMBOL_ABS || symtab_index == INDIRECT_SYMBOL_LOCAL || + symtab_index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS)) { + continue; + } + uint32_t strtab_offset = symtab[symtab_index].n_un.n_strx; + char *symbol_name = strtab + strtab_offset; + if (strnlen(symbol_name, 2) < 2) { + continue; + } + struct rebindings_entry *cur = rebindings; + while (cur) { + for (uint j = 0; j < cur->rebindings_nel; j++) { + if (strcmp(&symbol_name[1], cur->rebindings[j].name) == 0) { + if (cur->rebindings[j].replaced != NULL && + indirect_symbol_bindings[i] != cur->rebindings[j].replacement) { + *(cur->rebindings[j].replaced) = indirect_symbol_bindings[i]; + } + indirect_symbol_bindings[i] = cur->rebindings[j].replacement; + goto symbol_loop; + } + } + cur = cur->next; + } + symbol_loop:; + } +} + +static void rebind_symbols_for_image(struct rebindings_entry *rebindings, + const struct mach_header *header, + intptr_t slide) { + Dl_info info; + if (dladdr(header, &info) == 0) { + return; + } + + segment_command_t *cur_seg_cmd; + segment_command_t *linkedit_segment = NULL; + struct symtab_command* symtab_cmd = NULL; + struct dysymtab_command* dysymtab_cmd = NULL; + + uintptr_t cur = (uintptr_t)header + sizeof(mach_header_t); + for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { + cur_seg_cmd = (segment_command_t *)cur; + if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { + if (strcmp(cur_seg_cmd->segname, SEG_LINKEDIT) == 0) { + linkedit_segment = cur_seg_cmd; + } + } else if (cur_seg_cmd->cmd == LC_SYMTAB) { + symtab_cmd = (struct symtab_command*)cur_seg_cmd; + } else if (cur_seg_cmd->cmd == LC_DYSYMTAB) { + dysymtab_cmd = (struct dysymtab_command*)cur_seg_cmd; + } + } + + if (!symtab_cmd || !dysymtab_cmd || !linkedit_segment || + !dysymtab_cmd->nindirectsyms) { + return; + } + + // Find base symbol/string table addresses + uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff; + nlist_t *symtab = (nlist_t *)(linkedit_base + symtab_cmd->symoff); + char *strtab = (char *)(linkedit_base + symtab_cmd->stroff); + + // Get indirect symbol table (array of uint32_t indices into symbol table) + uint32_t *indirect_symtab = (uint32_t *)(linkedit_base + dysymtab_cmd->indirectsymoff); + + cur = (uintptr_t)header + sizeof(mach_header_t); + for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { + cur_seg_cmd = (segment_command_t *)cur; + if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { + if (strcmp(cur_seg_cmd->segname, SEG_DATA) != 0 && + strcmp(cur_seg_cmd->segname, SEG_DATA_CONST) != 0) { + continue; + } + for (uint j = 0; j < cur_seg_cmd->nsects; j++) { + section_t *sect = + (section_t *)(cur + sizeof(segment_command_t)) + j; + if ((sect->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS) { + perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab); + } + if ((sect->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS) { + perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab); + } + } + } + } +} + +static void _rebind_symbols_for_image(const struct mach_header *header, + intptr_t slide) { + rebind_symbols_for_image(_rebindings_head, header, slide); +} + +int rebind_symbols_image(void *header, + intptr_t slide, + struct rebinding rebindings[], + size_t rebindings_nel) { + struct rebindings_entry *rebindings_head = NULL; + int retval = prepend_rebindings(&rebindings_head, rebindings, rebindings_nel); + rebind_symbols_for_image(rebindings_head, (const struct mach_header *) header, slide); + free(rebindings_head); + return retval; +} + +int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel) { + int retval = prepend_rebindings(&_rebindings_head, rebindings, rebindings_nel); + if (retval < 0) { + return retval; + } + // If this was the first call, register callback for image additions (which is also invoked for + // existing images, otherwise, just run on existing images + if (!_rebindings_head->next) { + _dyld_register_func_for_add_image(_rebind_symbols_for_image); + } else { + uint32_t c = _dyld_image_count(); + for (uint32_t i = 0; i < c; i++) { + _rebind_symbols_for_image(_dyld_get_image_header(i), _dyld_get_image_vmaddr_slide(i)); + } + } + return retval; +} diff --git a/WeChatTweak/fishhook.h b/WeChatTweak/fishhook.h new file mode 100644 index 0000000..0d8e36a --- /dev/null +++ b/WeChatTweak/fishhook.h @@ -0,0 +1,76 @@ +// Copyright (c) 2013, Facebook, Inc. +// All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name Facebook nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific +// prior written permission. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef fishhook_h +#define fishhook_h + +#include +#include + +#if !defined(FISHHOOK_EXPORT) +#define FISHHOOK_VISIBILITY __attribute__((visibility("hidden"))) +#else +#define FISHHOOK_VISIBILITY __attribute__((visibility("default"))) +#endif + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + +/* + * A structure representing a particular intended rebinding from a symbol + * name to its replacement + */ +struct rebinding { + const char *name; + void *replacement; + void **replaced; +}; + +/* + * For each rebinding in rebindings, rebinds references to external, indirect + * symbols with the specified name to instead point at replacement for each + * image in the calling process as well as for all future images that are loaded + * by the process. If rebind_functions is called more than once, the symbols to + * rebind are added to the existing list of rebindings, and if a given symbol + * is rebound more than once, the later rebinding will take precedence. + */ +FISHHOOK_VISIBILITY +int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel); + +/* + * Rebinds as above, but only in the specified image. The header should point + * to the mach-o header, the slide should be the slide offset. Others as above. + */ +FISHHOOK_VISIBILITY +int rebind_symbols_image(void *header, + intptr_t slide, + struct rebinding rebindings[], + size_t rebindings_nel); + +#ifdef __cplusplus +} +#endif //__cplusplus + +#endif //fishhook_h +