在iOS中完全隐藏电话(越狱设备)

我想在ios中完全隐藏一个电话。 我的首要任务是在iOS 7(最新的ios版本,在这个时候!),但如果可能的话,我想知道如何隐藏在iOS 6及以下的电话。 我已经find了一些函数来挂钩到类SBUIFullscreenAlertAdapter initWithAlertController方法中。 感谢克里克在这个链接,我发现另一种方法挂钩,这样做更好。 问题是当手机没有locking或者手机被locking时,手机仍然有一个呼号栏,说明它正在通信中。 这里是截图: 链接到图像

我想知道处理这个钩子的方法是什么? 还有什么我应该知道实现我想要的?

为了删除通话结束后剩下的任何其他痕迹,我从通话logging中删除通话logging。 有没有更好的办法?

我会尽可能地发布尽可能多的代码,但它不会从头开始工作。 我使用自己的macros来生成钩子,所以你必须重写它们来处理你的代码。 我将使用伪functionIsHiddenCall来确定给定的电话是否是我们隐藏的电话(简单的电话号码检查)。 这是为了简化代码。 你显然必须自己实现它。 将会有其他的伪函数,但是它们的实现非常简单,并且将从它们的名字中显而易见。 这不是一个简单的调整,所以忍受着我。

此外,代码是非ARC。

基本上,我们把所有可能告诉iOS的东西都挂上电话。

IOS 7

让我们从iOS 7开始,因为它现在是iOS的最后一个版本,隐藏的调用实现比iOS 6和更低版本更简单。

几乎我们需要的所有东西都位于私人TelephonyUtilities.framework 。 在iOS 7中,苹果公司几乎将与该框架中的电话相关的所有事情都转移了出去 这就是为什么它变得更简单 – 所有其他的iOS组件都使用这个框架,所以我们只需要将其挂钩一次,而不需要在每个iOS守护进程中进行讨论。

所有的方法都被钩住了两个进程 – SpringBoard和MobilePhone(手机应用程序)。 捆绑ID分别是com.apple.springboardcom.apple.mobilephone

这是我在这两个进程中挂钩的TelephonyUtilities.framework方法的列表。

 //TUTelephonyCall -(id)initWithCall:(CTCallRef)call //Here we return nil in case of a hidden call. That way iOS will ignore it //as it checks for nil return value. InsertHookA(id, TUTelephonyCall, initWithCall, CTCallRef call) { if (IsHiddenCall(call) == YES) { return nil; } return CallOriginalA(TUTelephonyCall, initWithCall, call); } //TUCallCenter -(void)handleCallerIDChanged:(TUTelephonyCall*)call //This is CoreTelephony notification handler. We ignore it in case of a hidden call. //call==nil check is required because of our other hooks that might return //nil object. Passing nil to original implementation might break something. InsertHookA(void, TUCallCenter, handleCallerIDChanged, TUTelephonyCall* call) { if (call == nil || IsHiddenCall([call destinationID]) == YES) { return; } CallOriginalA(TUCallCenter, handleCallerIDChanged, call); } //TUCallCenter +(id)callForCTCall:(CTCallRef)call; //Just like TUTelephonyCall -(id)initWithCall:(CTCallRef)call InsertHookA(id, TUCallCenter, callForCTCall, CTCallRef call) { if (IsHiddenCall(call) == YES) { return nil; } return CallOriginalA(TUCallCenter, callForCTCall, call); } //TUCallCenter -(void)disconnectAllCalls //Here we disconnect every call there is except our hidden call. //This is required in case of a hidden conference call with hidden call. //Our call will stay hidden but active while other call is active. This method is called //when disconnect button is called - we don't wont it to cancel our hidden call InsertHook(void, TUCallCenter, disconnectAllCalls) { DisconnectAllExceptHiddenCall(); } //TUCallCenter -(void)disconnectCurrentCallAndActivateHeld //Just like TUCallCenter -(void)disconnectAllCalls InsertHook(void, TUCallCenter, disconnectCurrentCallAndActivateHeld) { DisconnectAllExceptHiddenCall(); } //TUCallCenter -(int)currentCallCount //Here we return current calls count minus our hidden call InsertHook(int, TUCallCenter, currentCallCount) { return CallOriginal(TUCallCenter, currentCallCount) - GetHiddenCallsCount(); } //TUCallCenter -(NSArray*)conferenceParticipantCalls //Hide our call from conference participants InsertHook(id, TUCallCenter, conferenceParticipantCalls) { NSArray* calls = CallOriginal(TUCallCenter, conferenceParticipantCalls); BOOL isThereHiddenCall = NO; NSMutableArray* callsWithoutHiddenCall = [NSMutableArray array]; for (id i in calls) { if (IsHiddenCall([i destinationID]) == NO) { [callsWithoutHiddenCall addObject:i]; } else { isThereHiddenCall = YES; } } if (callsWithoutHiddenCall.count != calls.count) { //If there is only two calls - hidden call and normal - there shouldn't be any sign of a conference call if (callsWithoutHiddenCall.count == 1 && isThereHiddenCall == YES) { [callsWithoutHiddenCall removeAllObjects]; } [self setConferenceParticipantCalls:callsWithoutHiddenCall]; [self _postConferenceParticipantsChanged]; } else { return calls; } } //TUTelephonyCall -(BOOL)isConferenced //Hide conference call in case of two calls - our hidden and normal InsertHook(BOOL, TUTelephonyCall, isConferenced) { if (CTGetCurrentCallCount() > 1) { if (CTGetCurrentCallCount() > 2) { //There is at least two normal calls - let iOS do it's work return CallOriginal(TUTelephonyCall, isConferenced); } if (IsHiddenCallExists() == YES) { //There is hidden call and one normal call - conference call should be hidden return NO; } } return CallOriginal(TUTelephonyCall, isConferenced); } //TUCallCenter -(void)handleCallStatusChanged:(TUTelephonyCall*)call userInfo:(id)userInfo //Call status changes handler. We ignore all events except those //that we marked with special key in userInfo object. Here we answer hidden call, setup //audio routing and doing other stuff. Our hidden call is indeed hidden, //iOS doesn't know about it and don't even setup audio routes. "AVController" is a global variable. InsertHookAA(void, TUCallCenter, handleCallStatusChanged, userInfo, TUTelephonyCall* call, id userInfo) { //'call' is nil when this is a hidden call event that we should ignore if (call == nil) { return; } //Detecting special key that tells us that we should process this hidden call event if ([[userInfo objectForKey:@"HiddenCall"] boolValue] == YES) { if (CTCallGetStatus(call) == kCTCallStatusIncoming) { CTCallAnswer(call); } else if (CTCallGetStatus(call) == kCTCallStatusActive) { //Setting up audio routing [AVController release]; AVController = [[objc_getClass("AVController") alloc] init]; SetupAVController(AVController); } else if (CTCallGetStatus(call) == kCTCallStatusHanged) { NSArray *calls = CTCopyCurrentCalls(nil); for (CTCallRef call in calls) { CTCallResume(call); } [calls release]; if (CTGetCurrentCallCount() == 0) { //No calls left - destroying audio controller [AVController release]; AVController = nil; } } return; } else if (IsHiddenCall([call destinationID]) == YES) { return; } CallOriginalAA(TUCallCenter, handleCallStatusChanged, userInfo, call, userInfo); } 

这里是Foundation.framework方法我钩在这两个过程中。

 //In iOS 7 telephony events are sent through local NSNotificationCenter. Here we suppress all hidden call notifications. InsertHookAAA(void, NSNotificationCenter, postNotificationName, object, userInfo, NSString* name, id object, NSDictionary* userInfo) { if ([name isEqualToString:@"TUCallCenterControlFailureNotification"] == YES || [name isEqualToString:@"TUCallCenterCauseCodeNotification"] == YES) { //'object' usually holds TUCall object. If 'object' is nil it indicates that these notifications are about hidden call and should be suppressed if (object == nil) { return; } } //Suppressing if something goes through if ([object isKindOfClass:objc_getClass("TUTelephonyCall")] == YES && IsHiddenCall([object destinationID]) == YES) { return; } CallOriginalAAA(NSNotificationCenter, postNotificationName, object, userInfo, name, object, userInfo); } 

这是我在CoreTelephony.framwork两个进程中挂钩的最后一个方法

 //CTCall +(id)callForCTCallRef:(CTCallRef)call //Return nil in case of hidden call InsertHookA(id, CTCall, callForCTCallRef, CTCallRef call) { if (IsHiddenCall(call) == YES) { return nil; } return CallOriginalA(CTCall, callForCTCallRef, call); } 

这是我之前使用的SetupAVController函数。 隐藏的呼叫是三重隐藏的 – iOS不知道任何事情,所以当我们回答audio路由没有完成,我们不会听到任何事情的另一端。 SetupAVController这样做 – 它设置像iOS一样的audio路由,当有活动的电话。 我使用来自私人Celestial.framework私有API

 extern id AVController_PickableRoutesAttribute; extern id AVController_AudioCategoryAttribute; extern id AVController_PickedRouteAttribute; extern id AVController_AllowGaplessTransitionsAttribute; extern id AVController_ClientPriorityAttribute; extern id AVController_ClientNameAttribute; extern id AVController_WantsVolumeChangesWhenPaused; void SetupAVController(id controller) { [controller setAttribute:[NSNumber numberWithInt:10] forKey:AVController_ClientPriorityAttribute error:NULL]; [controller setAttribute:@"Phone" forKey:AVController_ClientNameAttribute error:NULL]; [controller setAttribute:[NSNumber numberWithBool:YES] forKey:AVController_WantsVolumeChangesWhenPaused error:NULL]; [controller setAttribute:[NSNumber numberWithBool:YES] forKey:AVController_AllowGaplessTransitionsAttribute error:NULL]; [controller setAttribute:@"PhoneCall" forKey:AVController_AudioCategoryAttribute error:NULL]; } 

这里是我只在MobilePhone进程中挂钩的方法

 /* PHRecentCall -(id)initWithCTCall:(CTCallRef)call Here we hide hidden call from call history. Doing it in MobilePhone will hide our call even if we were in MobilePhone application when hidden call was disconnected. We not only delete it from the database but also prevent UI from showing it. */ InsertHookA(id, PHRecentCall, initWithCTCall, CTCallRef call) { if (call == NULL) { return CallOriginalA(PHRecentCall, initWithCTCall, call); } if (IsHiddenCall(call) == YES) { //Delete call from call history CTCallDeleteFromCallHistory(call); //Update MobilePhone app UI id PHRecentsViewController = [[[[[UIApplication sharedApplication] delegate] rootViewController] tabBarViewController] recentsViewController]; if ([PHRecentsViewController isViewLoaded]) { [PHRecentsViewController resetCachedIndexes]; [PHRecentsViewController _reloadTableViewAndNavigationBar]; } } return CallOriginalA(PHRecentCall, initWithCTCall, call); } 

方法我在SpringBoard进程中挂钩。

 //SpringBoard -(void)_updateRejectedInputSettingsForInCallState:(char)state isOutgoing:(char)outgoing triggeredbyRouteWillChangeToReceiverNotification:(char)triggered //Here we disable proximity sensor InsertHookAAA(void, SpringBoard, _updateRejectedInputSettingsForInCallState, isOutgoing, triggeredbyRouteWillChangeToReceiverNotification, char state, char outgoing, char triggered) { CallOriginalAAA(SpringBoard, _updateRejectedInputSettingsForInCallState, isOutgoing, triggeredbyRouteWillChangeToReceiverNotification, state, outgoing, triggered); if (IsHiddenCallExists() == YES && CTGetCurrentCallCount() == 1) { BKSHIDServicesRequestProximityDetectionMode = (void (*)(int))dlsym(RTLD_SELF, "BKSHIDServicesRequestProximityDetectionMode"); BKSHIDServicesRequestProximityDetectionMode(0); } } //BBServer -(void)publishBulletin:(id)bulletin destinations:(unsigned int)destinations alwaysToLockScreen:(char)toLockScreen //Suppress hidden call bulletins InsertHookAAA(void, BBServer, publishBulletin, destinations, alwaysToLockScreen, id bulletin, unsigned int destinations, char toLockScreen) { if ([[bulletin section] isEqualToString:@"com.apple.mobilephone"] == YES) { NSArray *recordTypeComponents = [[bulletin recordID] componentsSeparatedByString:@" "]; NSString *recordType = recordTypeComponents[0]; NSString *recordCode = recordTypeComponents[1]; //Missed call bulletin if ([recordType isEqualToString:@"missedcall"] == YES) { NSArray *recordCodeComponents = [recordCode componentsSeparatedByString:@"-"]; NSString *phoneNumber = recordCodeComponents[0]; if (IsHiddenCall(phoneNumber) == YES) { return; } } } CallOriginalAAA(BBServer, publishBulletin, destinations, alwaysToLockScreen, bulletin, destinations, toLockScreen); } //TUCallCenter -(id)init //CoreTelephony notifications handler setup InsertHook(id, TUCallCenter, init) { CTTelephonyCenterAddObserver(CTTelephonyCenterGetDefault(), self, CallStatusNotificationCallback, kCTCallStatusChangeNotification, NULL, CFNotificationSuspensionBehaviorDeliverImmediately); return CallOriginal(TUCallCenter, init); } //Call status changes handler. Here we redirect status changes into hooked TUCallCenter method and doing some other stuff. void CallStatusNotificationCallback(CFNotificationCenterRef center, void* observer, CFStringRef name, const void* object, CFDictionaryRef userInfo) { if (object == NULL) { return; } if (IsHiddenCall((CTCallRef)object) == YES) { [observer handleCallStatusChanged:object userInfo:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:@"HiddenCall"]]; } else { if (CTCallGetStatus((CTCallRef)object) == kCTCallStatusHanged) { if (IsHiddenCallExists() == YES) { //Setting up all the audio routing again. When normal call is hanged iOS may break audio routing as it doesn't know there is another active call exists (hidden call) SetupAVController(AVController); } else if (CTGetCurrentCallCount() == 0) { [AVController release]; AVController = nil; } } } if (CTGetCurrentCallCount() > 1 && IsHiddenCallExists() == YES) { //Here we setup hidden conference call NSArray *calls = CTCopyCurrentCalls(nil); for (CTCallRef call in calls) { CTCallJoinConference(call); } [calls release]; } } 

iOS 5-6

iOS 5-6比较复杂。 电话代码分散了许多iOS组件和API。 以后我可能会发布代码,因为我现在没有时间。 答案已经很长了