From 5f075df842de0c378066743d52028f3405818614 Mon Sep 17 00:00:00 2001 From: artemis Date: Sat, 10 Aug 2024 10:23:12 +0800 Subject: [PATCH] =?UTF-8?q?OC=20=E5=B7=A5=E5=85=B7=E7=B1=BB=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dylib_dobby_hook/apps/AirBuddyHack.m | 8 -- dylib_dobby_hook/apps/MacUpdaterHack.m | 117 +++++++++++------- dylib_dobby_hook/apps/NavicatPremiumHack.m | 11 +- dylib_dobby_hook/apps/ProxyManHack.m | 12 +- dylib_dobby_hook/apps/TablePlusHack.m | 20 +-- dylib_dobby_hook/helpers/ForkLiftHelperHack.m | 13 -- dylib_dobby_hook/utils/CommonRetOC.m | 2 + dylib_dobby_hook/utils/MemoryUtils.h | 8 +- dylib_dobby_hook/utils/MemoryUtils.m | 29 +++-- dylib_dobby_hook/utils/MockCKContainer.h | 26 +++- dylib_dobby_hook/utils/MockCKContainer.m | 74 +++++++++-- dylib_dobby_hook/utils/MockCKDatabase.h | 13 +- dylib_dobby_hook/utils/MockCKDatabase.m | 89 +++++++++---- 13 files changed, 270 insertions(+), 152 deletions(-) diff --git a/dylib_dobby_hook/apps/AirBuddyHack.m b/dylib_dobby_hook/apps/AirBuddyHack.m index 9006939..a90ec55 100644 --- a/dylib_dobby_hook/apps/AirBuddyHack.m +++ b/dylib_dobby_hook/apps/AirBuddyHack.m @@ -147,14 +147,6 @@ - (BOOL)hack { [defaults setBool:true forKey:@"AMSkipOnboarding"]; [defaults synchronize]; -// boolForKeyImp = method_getImplementation(class_getInstanceMethod(NSClassFromString(@"NSUserDefaults"), NSSelectorFromString(@"boolForKey:"))); -// [MemoryUtils hookInstanceMethod: -// objc_getClass("NSUserDefaults") -// originalSelector:NSSelectorFromString(@"boolForKey:") -// swizzledClass:[self class] -// swizzledSelector:NSSelectorFromString(@"hk_boolForKey:") -// ]; -// return YES; } diff --git a/dylib_dobby_hook/apps/MacUpdaterHack.m b/dylib_dobby_hook/apps/MacUpdaterHack.m index 5ba49db..f39583c 100644 --- a/dylib_dobby_hook/apps/MacUpdaterHack.m +++ b/dylib_dobby_hook/apps/MacUpdaterHack.m @@ -26,7 +26,8 @@ @implementation MacUpdaterHack static IMP defaultStringIMP; static IMP defaultIntIMP; -static IMP dataTaskWithRequestIMP; +static IMP URLSessionIMP2; +static IMP dataTaskWithRequest; static IMP URLWithHostIMP; static IMP directoryContentsIMP; static IMP URLSessionIMP; @@ -175,17 +176,17 @@ +(id)hook_URLWithHost:(id)arg2 path:(id)arg3 query:(id)arg4 user:(id)arg5 passwo + (NSString *) hk_checksumSparkleFramework{ - NSLog(@">>>>>> hk_checksumSparkleFramework %@", self); + NSLog(@">>>>>> hk_checksumSparkleFramework"); // x86: 46e6b06e5626534a9c61b91cfb041ccf051a2db8 // arm: a5f76baec8ce44138ceadc97130d622642fe4d2e - // id ret = ((id (*)(id,SEL))checksumSparkleFrameworkIMP)(self,_cmd); - - NSString *Sparkle = [[Constant getCurrentAppPath] stringByAppendingString:@"/Contents/Frameworks/Sparkle.framework/Versions/B/Sparkle_Backup"]; - NSString *retFake = [EncryptionUtils calculateSHA1OfFile:Sparkle]; - return retFake; - - // return @"5cac513cff8b040faff3d4a6b40d13bbfa034334"; + static NSString *cachedChecksum = nil; + if (!cachedChecksum){ + NSString *Sparkle = [[Constant getCurrentAppPath] stringByAppendingString:@"/Contents/Frameworks/Sparkle.framework/Versions/B/Sparkle_Backup"]; + cachedChecksum = [[EncryptionUtils calculateSHA1OfFile:Sparkle] copy]; + NSLog(@">>>>>> hk_checksumSparkleFramework cachedChecksum = %@", cachedChecksum); + } + return cachedChecksum; } + (NSString *) hk_uniqueIdentifierForDB{ @@ -207,6 +208,48 @@ -(void)hk_URLSession:(NSURLSession *)arg2 didReceiveChallenge:(NSURLAuthenticati arg4(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:arg3.protectionSpace.serverTrust]); } } +// +//- (void)hook_URLSession:(id)session task:(id)task didCompleteWithError:(id)error{ +// +// // https://macupdater-backend.com/configfile.cgi?b=16971&c=d8cef3817314647190c70f16357d0204f80c7dd6&s=5cac513cff8b040faff3d4a6b40d13bbfa034334&p=bd4867852d87df9b6353c6cad95adb5cbdde0a81&u=4bxexx40docih65dv6azovmier5m2xc7fqsgjjzn&a=0&e=(null)&l=(null)&x=5 +// +// NSString *cacheDir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0]; +// NSString * cacheConfigFile = [cacheDir stringByAppendingPathComponent:@"MacUpdater/cache_configfile.cgi"]; +// +// +// NSFileManager *fileManager = [NSFileManager defaultManager]; +// NSDate *currentDate = [NSDate date]; +// BOOL fileExists = [fileManager fileExistsAtPath:cacheConfigFile]; +// +// +// id dataToDownload = [MemoryUtils getInstanceIvar:self ivarName:"dataToDownload"]; +// +// if (!fileExists) { +// [dataToDownload writeToFile:cacheConfigFile atomically:YES]; +// NSLog(@">>>>>> cache_configfile.cgi 文件不存在,已创建并写入数据"); +// } else { +// // 文件存在,检查文件的修改日期 +// NSDictionary *attributes = [fileManager attributesOfItemAtPath:cacheConfigFile error:nil]; +// NSDate *modificationDate = [attributes fileModificationDate]; +// +// if (modificationDate) { +// // 计算文件的修改日期与当前日期的时间差 +// NSTimeInterval timeInterval = [currentDate timeIntervalSinceDate:modificationDate]; +// NSTimeInterval oneMonthInterval = 30 * 24 * 60 * 60; // 一个大致的月份(30天) +// if (timeInterval > oneMonthInterval) { +// +// [dataToDownload writeToFile:cacheConfigFile atomically:YES]; +// NSLog(@">>>>>> cache_configfile.cgi 文件存在且超过一个月,已重新写入数据"); +// } +// } +// } +//// [MemoryUtils setInstanceIvar:self ivarName:"dataToDownload" value: +//// [NSData dataWithContentsOfFile:@"/Users/voidm/Downloads/[406] Response - macupdater-backend.com_configfile.cgi" options:0 error:nil] +//// ]; +// ((void(*)(id,SEL,id,id,id))URLSessionIMP2)(self,_cmd,session,task,error); +// return ; +//} + - (BOOL)hack { // [BEGIN] @@ -219,22 +262,15 @@ - (BOOL)hack { // [END] //// -[AppDelegate purchaseInit]: - Class __NSCFStringClz = NSClassFromString(@"__NSCFString"); - SEL defaultStringSel = NSSelectorFromString(@"defaultString"); - Method defaultStringMethod = class_getInstanceMethod(__NSCFStringClz, defaultStringSel); - defaultStringIMP = method_getImplementation(defaultStringMethod); - [MemoryUtils hookInstanceMethod:__NSCFStringClz - originalSelector:defaultStringSel + defaultStringIMP = [MemoryUtils hookInstanceMethod:NSClassFromString(@"__NSCFString") + originalSelector:NSSelectorFromString(@"defaultString") swizzledClass:[self class] swizzledSelector:@selector(hk_defaultString) ]; - - SEL defaultIntSel = NSSelectorFromString(@"defaultInt"); - Method defaultIntMethod = class_getInstanceMethod(__NSCFStringClz, defaultIntSel); - defaultIntIMP = method_getImplementation(defaultIntMethod); - [MemoryUtils hookInstanceMethod:__NSCFStringClz - originalSelector:defaultIntSel + + defaultIntIMP = [MemoryUtils hookInstanceMethod:NSClassFromString(@"__NSCFString") + originalSelector:NSSelectorFromString(@"defaultInt") swizzledClass:[self class] swizzledSelector:@selector(hk_defaultInt) ]; @@ -275,37 +311,24 @@ - (BOOL)hack { // 过滤 Framework 下的 dylib // -[NSString directoryContents]: - Class NSStringClz = NSClassFromString(@"NSString"); - SEL directoryContentsSel = NSSelectorFromString(@"directoryContents"); - Method directoryContentsMethod = class_getInstanceMethod(NSStringClz, directoryContentsSel); - directoryContentsIMP = method_getImplementation(directoryContentsMethod); - [MemoryUtils hookInstanceMethod:NSStringClz - originalSelector:directoryContentsSel + directoryContentsIMP = [MemoryUtils hookInstanceMethod:NSClassFromString(@"NSString") + originalSelector:NSSelectorFromString(@"directoryContents") swizzledClass:[self class] swizzledSelector:@selector(hk_directoryContents) ]; - - - Class AppDelegateClz = NSClassFromString(@"AppDelegate"); - SEL checksumSparkleFrameworkSel = NSSelectorFromString(@"checksumSparkleFramework"); - Method checksumSparkleFrameworkMethod = class_getClassMethod(AppDelegateClz, checksumSparkleFrameworkSel); - checksumSparkleFrameworkIMP = method_getImplementation(checksumSparkleFrameworkMethod); - [MemoryUtils hookClassMethod:AppDelegateClz - originalSelector:checksumSparkleFrameworkSel + + checksumSparkleFrameworkIMP = [MemoryUtils hookClassMethod:NSClassFromString(@"AppDelegate") + originalSelector:NSSelectorFromString(@"checksumSparkleFramework") swizzledClass:[self class] swizzledSelector:@selector(hk_checksumSparkleFramework) ]; -// 清除 API 中的 license 信息 - Class NSURLClz = NSClassFromString(@"NSURL"); - SEL URLWithHostSel = NSSelectorFromString(@"URLWithHost:path:query:user:password:fragment:scheme:port:"); - Method URLWithHostMethod = class_getClassMethod(NSURLClz, URLWithHostSel); - URLWithHostIMP = method_getImplementation(URLWithHostMethod); - [MemoryUtils hookClassMethod: - NSURLClz - originalSelector:URLWithHostSel +// 清除 API 中的 license 信息 + URLWithHostIMP = [MemoryUtils hookClassMethod: + NSClassFromString(@"NSURL") + originalSelector:NSSelectorFromString(@"URLWithHost:path:query:user:password:fragment:scheme:port:") swizzledClass:[self class] swizzledSelector:NSSelectorFromString(@"hook_URLWithHost:path:query:user:password:fragment:scheme:port:") ]; @@ -326,6 +349,14 @@ - (BOOL)hack { swizzledSelector:NSSelectorFromString(@"hk_URLSession:didReceiveChallenge:completionHandler:") ]; + +// TODO: 不知道 有没有好的办法来拦截修改 configfile.cgi 请求 +// URLSessionIMP2 = [MemoryUtils hookInstanceMethod:NSClassFromString(@"HTTPSecurePOST") +// originalSelector:NSSelectorFromString(@"URLSession:task:didCompleteWithError:") +// swizzledClass:[self class] +// swizzledSelector:NSSelectorFromString(@"hook_URLSession:task:didCompleteWithError:") +// ]; + return YES; } diff --git a/dylib_dobby_hook/apps/NavicatPremiumHack.m b/dylib_dobby_hook/apps/NavicatPremiumHack.m index ba82dbc..6126413 100644 --- a/dylib_dobby_hook/apps/NavicatPremiumHack.m +++ b/dylib_dobby_hook/apps/NavicatPremiumHack.m @@ -133,14 +133,9 @@ - (BOOL)hack { ]; - Class AboutNavicatWindowControllerClz = NSClassFromString(@"AboutNavicatWindowController"); - SEL displayRegisteredInfoSel = NSSelectorFromString(@"displayRegisteredInfo"); - Method dataTaskWithRequestMethod = class_getInstanceMethod(AboutNavicatWindowControllerClz, displayRegisteredInfoSel); - displayRegisteredInfoIMP = method_getImplementation(dataTaskWithRequestMethod); - - [MemoryUtils hookInstanceMethod: - AboutNavicatWindowControllerClz - originalSelector:displayRegisteredInfoSel + displayRegisteredInfoIMP = [MemoryUtils hookInstanceMethod: + NSClassFromString(@"AboutNavicatWindowController") + originalSelector:NSSelectorFromString(@"displayRegisteredInfo") swizzledClass:[self class] swizzledSelector: @selector(hk_displayRegisteredInfo) ]; diff --git a/dylib_dobby_hook/apps/ProxyManHack.m b/dylib_dobby_hook/apps/ProxyManHack.m index e3b3d14..c62f66f 100644 --- a/dylib_dobby_hook/apps/ProxyManHack.m +++ b/dylib_dobby_hook/apps/ProxyManHack.m @@ -88,14 +88,10 @@ - (BOOL)hack { NSString *proxymanCoreFilePath = [[Constant getCurrentAppPath] stringByAppendingString:@"/Contents/Frameworks/ProxymanCore.framework/Versions/A/ProxymanCore"]; uintptr_t proxymanCoreFileOffset =[MemoryUtils getCurrentArchFileOffset: proxymanCoreFilePath]; - - Class NSMutableArrayClass = NSClassFromString(@"_TtC8Proxyman25PremiumPlanViewController"); - SEL componentsJoinedByStringSeletor = NSSelectorFromString(@"viewDidLoad"); - Method componentsJoinedByStringMethod = class_getInstanceMethod(NSMutableArrayClass, componentsJoinedByStringSeletor); - viewDidLoadIMP = method_getImplementation(componentsJoinedByStringMethod); - [MemoryUtils hookInstanceMethod: - NSMutableArrayClass - originalSelector:componentsJoinedByStringSeletor + + viewDidLoadIMP = [MemoryUtils hookInstanceMethod: + NSClassFromString(@"_TtC8Proxyman25PremiumPlanViewController") + originalSelector:NSSelectorFromString(@"viewDidLoad") swizzledClass:[self class] swizzledSelector:NSSelectorFromString(@"hook_viewDidLoad") ]; diff --git a/dylib_dobby_hook/apps/TablePlusHack.m b/dylib_dobby_hook/apps/TablePlusHack.m index 10106e4..ed83a16 100644 --- a/dylib_dobby_hook/apps/TablePlusHack.m +++ b/dylib_dobby_hook/apps/TablePlusHack.m @@ -95,27 +95,17 @@ - (BOOL)hack { // r12 = [[RNDecryptor decryptData:"file bytes" withPassword:"x" error:&var_48] retain]; // +[RNDecryptor decryptData:withPassword:error:]: - Class RNDecryptorClz = NSClassFromString(@"RNDecryptor"); - SEL decryptDataSel = NSSelectorFromString(@"decryptData:withPassword:error:"); - Method decryptDataMethod = class_getClassMethod(RNDecryptorClz, decryptDataSel); - decryptDataIMP = method_getImplementation(decryptDataMethod); - - [MemoryUtils hookClassMethod: - RNDecryptorClz - originalSelector:decryptDataSel + decryptDataIMP = [MemoryUtils hookClassMethod: + NSClassFromString(@"RNDecryptor") + originalSelector:NSSelectorFromString(@"decryptData:withPassword:error:") swizzledClass:[self class] swizzledSelector:NSSelectorFromString(@"hk_decryptData:withPassword:error:") ]; - Class AFURLSessionManagerClz = NSClassFromString(@"AFHTTPSessionManager"); - SEL dataTaskWithRequestSel = NSSelectorFromString(@"dataTaskWithHTTPMethod:URLString:parameters:headers:uploadProgress:downloadProgress:success:failure:"); - Method dataTaskWithRequestMethod = class_getInstanceMethod(AFURLSessionManagerClz, dataTaskWithRequestSel); - dataTaskWithRequestIMP = method_getImplementation(dataTaskWithRequestMethod); - [MemoryUtils hookInstanceMethod: - AFURLSessionManagerClz - originalSelector:dataTaskWithRequestSel + dataTaskWithRequestIMP = [MemoryUtils hookInstanceMethod:NSClassFromString(@"AFHTTPSessionManager") + originalSelector:NSSelectorFromString(@"dataTaskWithHTTPMethod:URLString:parameters:headers:uploadProgress:downloadProgress:success:failure:") swizzledClass:[self class] swizzledSelector:NSSelectorFromString(@"hk_dataTaskWithHTTPMethod:URLString:parameters:headers:uploadProgress:downloadProgress:success:failure:") ]; diff --git a/dylib_dobby_hook/helpers/ForkLiftHelperHack.m b/dylib_dobby_hook/helpers/ForkLiftHelperHack.m index ff05476..d1f3d31 100644 --- a/dylib_dobby_hook/helpers/ForkLiftHelperHack.m +++ b/dylib_dobby_hook/helpers/ForkLiftHelperHack.m @@ -92,19 +92,6 @@ OSStatus hk_SecCodeCopySigningInformation_forklift(SecCodeRef codeRef, SecCSFlag } - (BOOL)hack { - - // Class ForkLiftHelper10HelperTool = NSClassFromString(@"_TtC31com_binarynights_ForkLiftHelper10HelperTool"); - // SEL listenerSel = NSSelectorFromString(@"listener:shouldAcceptNewConnection:"); - // Method listenerMethod = class_getInstanceMethod(ForkLiftHelper10HelperTool, listenerSel); - // listenerIMP = method_getImplementation(listenerMethod); - // [MemoryUtils hookInstanceMethod:ForkLiftHelper10HelperTool - // originalSelector:listenerSel - // swizzledClass:[self class] - // swizzledSelector:@selector(hk_listener:shouldAcceptNewConnection:) - // ]; - - // DobbyHook((void *)sub_10005ad20, (void *)hook_sub_10005ad20, (void *)&sub_10005ad20_ori); - DobbyHook(SecCodeCopySigningInformation, (void *)hk_SecCodeCopySigningInformation_forklift, (void *)&SecCodeCopySigningInformation_ori); DobbyHook(SecCodeCheckValidityWithErrors, (void *)hk_SecCodeCheckValidityWithErrors, (void *)&SecCodeCheckValidityWithErrors_ori); return YES; diff --git a/dylib_dobby_hook/utils/CommonRetOC.m b/dylib_dobby_hook/utils/CommonRetOC.m index a1f645a..7af5bc9 100644 --- a/dylib_dobby_hook/utils/CommonRetOC.m +++ b/dylib_dobby_hook/utils/CommonRetOC.m @@ -86,11 +86,13 @@ - (id)hook_NSFileManager:(nullable NSString *)containerIdentifier{ + (id)hook_containerWithIdentifier:identifier { NSLog(@">>>>>> hook_containerWithIdentifier identifier = %@",identifier); + // [CKContainer containerWithIdentifier:identifier]; return [MockCKContainer containerWithIdentifier:identifier]; } + (id)hook_defaultContainer { NSLog(@">>>>>> hook_defaultContainer"); + // [CKContainer defaultContainer]; return [MockCKContainer defaultContainer]; } diff --git a/dylib_dobby_hook/utils/MemoryUtils.h b/dylib_dobby_hook/utils/MemoryUtils.h index 48ecce8..568bc8a 100644 --- a/dylib_dobby_hook/utils/MemoryUtils.h +++ b/dylib_dobby_hook/utils/MemoryUtils.h @@ -38,10 +38,10 @@ + (void)inspectObjectWithAddress:(void *)address; + (void)exAlart:(NSString *)title message:(NSString *)message; -+ (void)hookInstanceMethod:(Class)originalClass originalSelector:(SEL)originalSelector swizzledClass:(Class)swizzledClass swizzledSelector:(SEL)swizzledSelector; -+ (void)hookClassMethod:(Class)originalClass originalSelector:(SEL)originalSelector swizzledClass:(Class)swizzledClass swizzledSelector:(SEL)swizzledSelector; -+ (void)replaceInstanceMethod:(Class)originalClass originalSelector:(SEL)originalSelector swizzledClass:(Class)swizzledClass swizzledSelector:(SEL)swizzledSelector; -+ (void)replaceClassMethod:(Class)originalClass originalSelector:(SEL)originalSelector swizzledClass:(Class)swizzledClass swizzledSelector:(SEL)swizzledSelector; ++ (IMP)hookInstanceMethod:(Class)originalClass originalSelector:(SEL)originalSelector swizzledClass:(Class)swizzledClass swizzledSelector:(SEL)swizzledSelector; ++ (IMP)hookClassMethod:(Class)originalClass originalSelector:(SEL)originalSelector swizzledClass:(Class)swizzledClass swizzledSelector:(SEL)swizzledSelector; ++ (IMP)replaceInstanceMethod:(Class)originalClass originalSelector:(SEL)originalSelector swizzledClass:(Class)swizzledClass swizzledSelector:(SEL)swizzledSelector; ++ (IMP)replaceClassMethod:(Class)originalClass originalSelector:(SEL)originalSelector swizzledClass:(Class)swizzledClass swizzledSelector:(SEL)swizzledSelector; + (id)getInstanceIvar:(Class)cls ivarName:(const char *)ivarName; diff --git a/dylib_dobby_hook/utils/MemoryUtils.m b/dylib_dobby_hook/utils/MemoryUtils.m index 4a9d54a..df002cb 100644 --- a/dylib_dobby_hook/utils/MemoryUtils.m +++ b/dylib_dobby_hook/utils/MemoryUtils.m @@ -489,7 +489,7 @@ + (void)exAlart:(NSString *)title message:(NSString *)message { } /** - 交换对象方法 -[_TtC8DevUtils16WindowController showUnregistered] + 交换 OC 对象方法,返回原始函数地址 [MemoryUtils hookInstanceMethod: objc_getClass("_TtC8DevUtils16WindowController") originalSelector:NSSelectorFromString(@"showUnregistered") @@ -502,11 +502,12 @@ + (void)exAlart:(NSString *)title message:(NSString *)message { @param swizzledClass 替换类 @param swizzledSelector 替换类的方法 */ -+ (void)hookInstanceMethod:(Class)originalClass originalSelector:(SEL)originalSelector swizzledClass:(Class)swizzledClass swizzledSelector:(SEL)swizzledSelector { ++ (IMP)hookInstanceMethod:(Class)originalClass originalSelector:(SEL)originalSelector swizzledClass:(Class)swizzledClass swizzledSelector:(SEL)swizzledSelector { Method originalMethod = class_getInstanceMethod(originalClass, originalSelector); Method swizzledMethod = class_getInstanceMethod(swizzledClass, swizzledSelector); - + IMP imp = nil; if (originalMethod && swizzledMethod) { + imp = method_getImplementation(originalMethod); method_exchangeImplementations(originalMethod, swizzledMethod); } else { NSLog(@">>>>>> Failed to swizzle method."); @@ -520,10 +521,11 @@ + (void)hookInstanceMethod:(Class)originalClass originalSelector:(SEL)originalSe swizzledMethod]; [self exAlart:@"hookInstanceMethod 异常 ?!!!" message:message]; } + return imp; } /** - 交换类方法 + 交换 OC 类方法,返回原始函数地址 [MemoryUtils hookClassMethod: objc_getClass("GlobalFunction") originalSelector:NSSelectorFromString(@"isInChina") @@ -535,11 +537,13 @@ + (void)hookInstanceMethod:(Class)originalClass originalSelector:(SEL)originalSe @param swizzledClass 替换类 @param swizzledSelector 替换类的类方法 */ -+ (void)hookClassMethod:(Class)originalClass originalSelector:(SEL)originalSelector swizzledClass:(Class)swizzledClass swizzledSelector:(SEL)swizzledSelector { ++ (IMP)hookClassMethod:(Class)originalClass originalSelector:(SEL)originalSelector swizzledClass:(Class)swizzledClass swizzledSelector:(SEL)swizzledSelector { Method originalMethod = class_getClassMethod(originalClass, originalSelector); Method swizzledMethod = class_getClassMethod(swizzledClass, swizzledSelector); + IMP imp = nil; if (originalMethod && swizzledMethod) { + imp = method_getImplementation(originalMethod); method_exchangeImplementations(originalMethod, swizzledMethod); } else { NSLog(@">>>>>> Failed to swizzle class method."); @@ -553,10 +557,11 @@ + (void)hookClassMethod:(Class)originalClass originalSelector:(SEL)originalSelec swizzledMethod]; [self exAlart:@"hookClassMethod 异常 ?!!!" message:message]; } + return imp; } /** - 替换对象方法 -[_TtC8DevUtils16WindowController showUnregistered] + 替换 OC 对象方法,返回原始函数地址 [MemoryUtils hookInstanceMethod: objc_getClass("_TtC8DevUtils16WindowController") originalSelector:NSSelectorFromString(@"showUnregistered") @@ -569,12 +574,14 @@ + (void)hookClassMethod:(Class)originalClass originalSelector:(SEL)originalSelec @param swizzledClass 替换类 @param swizzledSelector 替换类的方法 */ -+ (void)replaceInstanceMethod:(Class)originalClass originalSelector:(SEL)originalSelector swizzledClass:(Class)swizzledClass swizzledSelector:(SEL)swizzledSelector { ++ (IMP)replaceInstanceMethod:(Class)originalClass originalSelector:(SEL)originalSelector swizzledClass:(Class)swizzledClass swizzledSelector:(SEL)swizzledSelector { Method originalMethod = class_getInstanceMethod(originalClass, originalSelector); IMP swizzledImplementation = class_getMethodImplementation(swizzledClass, swizzledSelector); const char *types = method_getTypeEncoding(originalMethod); + IMP imp = nil; if (originalMethod && swizzledImplementation) { + imp = method_getImplementation(originalMethod); // 替换对象方法 class_replaceMethod(originalClass, originalSelector, swizzledImplementation, types); } else { @@ -589,10 +596,11 @@ + (void)replaceInstanceMethod:(Class)originalClass originalSelector:(SEL)origina swizzledImplementation]; [self exAlart:@"replaceInstanceMethod 异常 ?!!!" message:message]; } + return imp; } /** - 替换类方法 + 替换 OC 类方法,返回原始函数地址 [MemoryUtils hookClassMethod: objc_getClass("GlobalFunction") originalSelector:NSSelectorFromString(@"isInChina") @@ -604,12 +612,14 @@ + (void)replaceInstanceMethod:(Class)originalClass originalSelector:(SEL)origina @param swizzledClass 替换类 @param swizzledSelector 替换类的类方法 */ -+ (void)replaceClassMethod:(Class)originalClass originalSelector:(SEL)originalSelector swizzledClass:(Class)swizzledClass swizzledSelector:(SEL)swizzledSelector { ++ (IMP)replaceClassMethod:(Class)originalClass originalSelector:(SEL)originalSelector swizzledClass:(Class)swizzledClass swizzledSelector:(SEL)swizzledSelector { Method originalMethod = class_getClassMethod(originalClass, originalSelector); IMP swizzledImplementation = class_getMethodImplementation(swizzledClass, swizzledSelector); const char *types = method_getTypeEncoding(originalMethod); + IMP imp = nil; if (originalMethod && swizzledImplementation) { + imp = method_getImplementation(originalMethod); // 替换类方法 class_replaceMethod(object_getClass(originalClass), originalSelector, swizzledImplementation, types); } else { @@ -624,6 +634,7 @@ + (void)replaceClassMethod:(Class)originalClass originalSelector:(SEL)originalSe swizzledImplementation]; [self exAlart:@"replaceClassMethod 异常 ?!!!" message:message]; } + return imp; } /** diff --git a/dylib_dobby_hook/utils/MockCKContainer.h b/dylib_dobby_hook/utils/MockCKContainer.h index 6788da8..e92e076 100644 --- a/dylib_dobby_hook/utils/MockCKContainer.h +++ b/dylib_dobby_hook/utils/MockCKContainer.h @@ -10,9 +10,29 @@ #ifndef MockCKContainer_h #define MockCKContainer_h -@interface MockCKContainer : NSObject - +@interface MockCKContainer : CKContainer + +// [TEST] +// CKContainer* container = [CKContainer containerWithIdentifier:@"iCloud.com.example.myapp"]; +// CKDatabase *publicDatabase = [container publicCloudDatabase]; +// CKRecordID *artworkRecordID = [[CKRecordID alloc] initWithRecordName:@"123456"]; +// CKRecord *artworkRecord = [[CKRecord alloc] initWithRecordType:@"Artwork" recordID:artworkRecordID]; +// artworkRecord[@"title" ] = @"this is title"; +// [publicDatabase saveRecord:artworkRecord completionHandler:^(CKRecord *record, NSError *error){ +// if (error) { +// NSLog(@">>>>>> saveRecord error = %@",error); +// } +// }]; +// [publicDatabase fetchRecordWithID:artworkRecordID completionHandler:^(CKRecord * _Nullable record, NSError * _Nullable error) { +// if (error) { +// NSLog(@">>>>>> fetchRecordWithID error = %@",error); +// }else { +// +// NSLog(@">>>>>> fetchRecordWithID record = %@",record); +// } +// }]; +@property (nonatomic, strong) NSDictionary *options; @property (nonatomic, readonly) MockCKDatabase *privateDatabase; @property (nonatomic, readonly) MockCKDatabase *publicDatabase; @property (nonatomic, strong) NSString *identifier; @@ -25,6 +45,8 @@ - (CKDatabase *)publicCloudDatabase; +- (void)accountStatusWithCompletionHandler:(void (NS_SWIFT_SENDABLE ^)(CKAccountStatus accountStatus, NSError * error))completionHandler; + @end #endif /* MockCKContainer_h */ diff --git a/dylib_dobby_hook/utils/MockCKContainer.m b/dylib_dobby_hook/utils/MockCKContainer.m index f101fbb..5f2b750 100644 --- a/dylib_dobby_hook/utils/MockCKContainer.m +++ b/dylib_dobby_hook/utils/MockCKContainer.m @@ -10,21 +10,53 @@ #import #import "MockCKDatabase.h" #import - +#import +// +//@interface MockCKDeviceContext : NSObject +// +//@property (nonatomic, strong) NSString *deviceIdentifier; +//@property (nonatomic, strong) NSString *deviceModel; +//@property (nonatomic, strong) NSString *systemVersion; +//@property (nonatomic, strong) NSString *deviceName; +//@property (nonatomic, strong) NSString *localizedModel; +//@property (nonatomic, strong) NSString *systemName; +// +//@end +// +//@implementation MockCKDeviceContext +// +//- (instancetype)init { +// // [CKDeviceContext alloc]; +// // class_createInstance([CKDeviceContext class], 0); +// self = [super init]; +// if (self) { +// NSProcessInfo* processInfo = [NSProcessInfo processInfo]; +// _deviceIdentifier = [[NSUUID UUID] UUIDString]; // Simulated device identifier +// _deviceModel = [[processInfo hostName] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; +// _systemVersion = [[NSProcessInfo processInfo] operatingSystemVersionString]; +// _deviceName = [processInfo hostName]; +// _localizedModel = [[processInfo operatingSystemVersionString] stringByAppendingString:@" (macOS)"]; +// _systemName = @"macOS"; +// } +// return self; +//} +// +//@end @implementation MockCKContainer -- (instancetype)init { - self = [super init]; - if (self) { - _privateDatabase = [[MockCKDatabase alloc] init]; - _publicDatabase = [[MockCKDatabase alloc] init]; - } - return self; -} +//- (instancetype)init { +// self = [super init]; +// self = class_createInstance([MockCKContainer class], 0); +// if (self) { +// _privateDatabase = [[MockCKDatabase alloc] init]; +// _publicDatabase = [[MockCKDatabase alloc] init]; +// } +// return self; +//} + (instancetype)defaultContainer { - static MockCKContainer *defaultContainer = nil; + static MockCKContainer *defaultContainer = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ defaultContainer = [[self alloc] initWithIdentifier:@"default"]; @@ -38,11 +70,10 @@ + (instancetype)containerWithIdentifier:(NSString *)identifier { - (instancetype)initWithIdentifier:(NSString *)identifier { NSLog(@">>>>>> initWithIdentifier identifier = %@",identifier); - self = [super init]; if (self) { _identifier = [identifier copy]; - _privateDatabase = [[MockCKDatabase alloc] init]; - _publicDatabase = [[MockCKDatabase alloc] init]; + _privateDatabase = [[MockCKDatabase alloc] initDatabase]; + _publicDatabase = [[MockCKDatabase alloc] initDatabase]; } return self; } @@ -56,5 +87,22 @@ - (CKDatabase *)publicCloudDatabase { return (CKDatabase *)self.publicDatabase; } + +- (void)accountStatusWithCompletionHandler:(void (NS_SWIFT_SENDABLE ^)(CKAccountStatus accountStatus, NSError * error))completionHandler{ + NSLog(@">>>>>> accountStatusWithCompletionHandler"); + + // 模拟账户状态和错误 + CKAccountStatus mockAccountStatus = CKAccountStatusAvailable; + NSError *mockError = nil; + + if (completionHandler) { + completionHandler(mockAccountStatus, mockError); + } + +} + +//- (MockCKDeviceContext *)deviceContext { +// return [[MockCKDeviceContext alloc] init]; +//} @end diff --git a/dylib_dobby_hook/utils/MockCKDatabase.h b/dylib_dobby_hook/utils/MockCKDatabase.h index e86ce10..4cf6f12 100644 --- a/dylib_dobby_hook/utils/MockCKDatabase.h +++ b/dylib_dobby_hook/utils/MockCKDatabase.h @@ -10,18 +10,19 @@ #define MockCKDatabase_h -@interface MockCKDatabase : NSObject +@interface MockCKDatabase : CKDatabase @property (nonatomic, strong) NSMutableDictionary * records; @property (nonatomic, strong) NSMutableDictionary *recordZones; @property (nonatomic, strong) NSMutableDictionary *subscriptions; +- (instancetype)initDatabase ; -- (void)saveRecord:(CKRecord *)record completion:(void (^)(CKRecord *record, NSError *error))completion; -- (void)fetchRecordWithID:(CKRecordID *)recordID completion:(void (^)(CKRecord *record, NSError *error))completion; -- (void)deleteRecordWithID:(CKRecordID *)recordID completion:(void (^)(NSError *error))completion; -- (void)performQuery:(CKQuery *)query inZoneWithID:(CKRecordZoneID *)zoneID completion:(void (^)(NSArray *records, NSError *error))completion; -- (void)fetchAllRecordsWithCompletion:(void (^)(NSArray *records, NSError *error))completion; +- (void)saveRecord:(CKRecord *)record completionHandler:(void (^)(CKRecord *record, NSError *error))completionHandler; +- (void)fetchRecordWithID:(CKRecordID *)recordID completionHandler:(void (^)(CKRecord *record, NSError *error))completionHandler; +- (void)deleteRecordWithID:(CKRecordID *)recordID completionHandler:(void (^)(NSError *error))completionHandler; +- (void)performQuery:(CKQuery *)query inZoneWithID:(CKRecordZoneID *)zoneID completionHandler:(void (^)(NSArray *records, NSError *error))completionHandler; +- (void)fetchAllRecordsWithCompletion:(void (^)(NSArray *records, NSError *error))completionHandler; - (void)addOperation:(NSOperation *)operation; - (void)fetchAllRecordZonesWithCompletionHandler:(void (^)(NSArray * zones, NSError * error))completionHandler; diff --git a/dylib_dobby_hook/utils/MockCKDatabase.m b/dylib_dobby_hook/utils/MockCKDatabase.m index 28ee248..ea614c1 100644 --- a/dylib_dobby_hook/utils/MockCKDatabase.m +++ b/dylib_dobby_hook/utils/MockCKDatabase.m @@ -11,44 +11,42 @@ @implementation MockCKDatabase -- (instancetype)init { - self = [super init]; +- (instancetype)initDatabase { + // self = [super init]; if (self) { + // TODO: 是否需要考虑数据持久华 ? + // _records = [self loadPersistedDataForKey:@"records"]; + _records = [NSMutableDictionary dictionary]; } return self; } -- (void)saveRecord:(CKRecord *)record - completion:(void (^)(CKRecord *record, NSError *error))completion { +- (void)saveRecord:(CKRecord *)record completionHandler:(void (^)(CKRecord *record, NSError *error))completionHandler { NSLog(@">>>>>> saveRecord record = %@",record); self.records[record.recordID] = record; - if (completion) { - completion(record, nil); + if (completionHandler) { + completionHandler(record, nil); } } -- (void)fetchRecordWithID:(CKRecordID *)recordID - completion:(void (^)(CKRecord *record, NSError *error))completion { +- (void)fetchRecordWithID:(CKRecordID *)recordID completionHandler:(void (^)(CKRecord *record, NSError *error))completionHandler { NSLog(@">>>>>> fetchRecordWithID recordID = %@",recordID); CKRecord *record = self.records[recordID]; - if (completion) { - completion(record, nil); + if (completionHandler) { + completionHandler(record, nil); } } -- (void)deleteRecordWithID:(CKRecordID *)recordID - completion:(void (^)(NSError *error))completion { +- (void)deleteRecordWithID:(CKRecordID *)recordID completionHandler:(void (^)(NSError *error))completionHandler { NSLog(@">>>>>> deleteRecordWithID recordID = %@",recordID); [self.records removeObjectForKey:recordID]; - if (completion) { - completion(nil); + if (completionHandler) { + completionHandler(nil); } } -- (void)performQuery:(CKQuery *)query - inZoneWithID:(CKRecordZoneID *)zoneID - completion:(void (^)(NSArray *records, NSError *error))completion { +- (void)performQuery:(CKQuery *)query inZoneWithID:(CKRecordZoneID *)zoneID completionHandler:(void (^)(NSArray *records, NSError *error))completionHandler { NSLog(@">>>>>> performQuery query = %@,zoneID = %@",query,zoneID); NSPredicate *predicate = query.predicate; NSMutableArray *results = [NSMutableArray array]; @@ -59,24 +57,51 @@ - (void)performQuery:(CKQuery *)query } } - if (completion) { - completion(results, nil); + if (completionHandler) { + completionHandler(results, nil); } } -- (void)fetchAllRecordsWithCompletion:(void (^)(NSArray *records, NSError *error))completion { +- (void)fetchAllRecordsWithCompletion:(void (^)(NSArray *records, NSError *error))completionHandler { NSLog(@">>>>>> fetchAllRecordsWithCompletion"); - if (completion) { - completion(self.records.allValues, nil); + if (completionHandler) { + completionHandler(self.records.allValues, nil); } } - (void)addOperation:(NSOperation *)operation { - NSLog(@">>>>>> TODO addOperation operation = %@", operation); + NSString *operationClass = NSStringFromClass([operation class]); + BOOL isAsynchronous = [operation isAsynchronous]; + BOOL isReady = [operation isReady]; + BOOL isExecuting = [operation isExecuting]; + BOOL isFinished = [operation isFinished]; + BOOL isCancelled = [operation isCancelled]; + + NSLog(@">>>>>> addOperation operation: %@\nClass: %@\nIs Asynchronous: %@\nIs Ready: %@\nIs Executing: %@\nIs Finished: %@\nIs Cancelled: %@", + operation, + operationClass, + isAsynchronous ? @"YES" : @"NO", + isReady ? @"YES" : @"NO", + isExecuting ? @"YES" : @"NO", + isFinished ? @"YES" : @"NO", + isCancelled ? @"YES" : @"NO"); + + if (isAsynchronous && [operation isReady]) { + // 模拟操作执行 + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + if (operation.completionBlock) { + dispatch_async(dispatch_get_main_queue(), ^{ + operation.completionBlock(); + }); + } + }); + } } + + - (void)fetchAllRecordZonesWithCompletionHandler:(void (^)(NSArray * zones, NSError * error))completionHandler { NSLog(@">>>>>> fetchAllRecordZonesWithCompletionHandler"); NSArray *zones = [_recordZones allValues]; @@ -144,5 +169,23 @@ - (void)deleteSubscriptionWithID:(CKSubscriptionID)subscriptionID completionHand } } +#pragma mark - Persistence Methods +// +//- (void)persistData:(NSDictionary *)data forKey:(NSString *)key { +// NSString *path = [self pathForKey:key]; +// [NSKeyedArchiver archiveRootObject:data toFile:path]; +//} +// +//- (NSMutableDictionary *)loadPersistedDataForKey:(NSString *)key { +// NSString *path = [self pathForKey:key]; +// return [NSKeyedUnarchiver unarchiveObjectWithFile:path]; +//} +// +//- (NSString *)pathForKey:(NSString *)key { +// NSString *documentDirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; +// return [documentDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.dat", key]]; +//} + + @end