在iOS(越狱设备)中完全隐藏电话 [英] Hide a phone call completely in iOS (jailbreak device)

查看:246
本文介绍了在iOS(越狱设备)中完全隐藏电话的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在ios中完全隐藏一个电话。我的首要任务是在ios 7上进行此操作(此时最新的ios版本!)但我想知道如果可能的话,如何隐藏ios 6及以下的电话。我找到了一些函数来挂钩 initWithAlertController SBUIFullscreenAlertAdapter 的方法。感谢creker在此链接中,我找到了另一种挂钩的方法最好这样做。问题是,当手机未锁定或手机被锁定时,手机仍然有一个电话栏,手机显示它正处于通讯中间。以下是截图:
图片链接

I want to hide a phone call completely in ios. My priority is to do this on ios 7 (latest ios version at this time!) but i would like to know how to hide a phone call on ios 6 and below too if possible. I have found some functions to do so as hooking into initWithAlertController method of class SBUIFullscreenAlertAdapter. Thanks to creker in this link I found another method to hook that is better to do so. The problem is it still has a callbar when the phone is not locked or when the phone is locked the phone shows that it's it in the middle of communication. Here are screenshots: link to image

我想知道解决这个问题的方法是什么?还有什么我应该知道的是为了实现我想要的东西吗?

I want to know what are the methods dealing with this to hook? Is there anything else that i should know for achieving what i want?

为了删除在通话结束后我想到的任何其他痕迹我删除了通话记录从它的数据库。有没有更好的方法?

For deleting any other traces that are left i thought of after the call is finished i delete the call history from it's database. Is there a better way?

推荐答案

我会尝试尽可能多地发布代码,但它不会从头开始工作。我使用自己的宏来生成钩子,所以你必须重写它们才能使用你的代码。我将使用伪函数 IsHiddenCall 来确定给定的呼叫是否是我们的隐藏呼叫(简单的电话号码检查)。它是为了简化代码。你显然必须自己实现它。将有其他伪函数,但它们的实现非常简单,并且从它们的名称中可以明显看出。这不是一个简单的调整,所以请耐心等待。

I will try to post as much code as I can but it will not work from scratch. I use my own macroses to generate hooks so you have to rewrite them to work with your code. I will use pseudo function IsHiddenCall to determine if a given call is our hidden call (simple phone number check). It's here to simplify the code. You obviously have to implement it yourself. There will be other pseudo functions but their implementation is very simple and will be obvious from their names. It's not a simple tweak so bear with me.

此外,代码是非ARC。

Also, the code is non-ARC.

基本上,我们挂钩可能告诉iOS的所有内容是一个电话。

Basically, we hook everything that might tell iOS that there is a phone call.

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

Let's start with iOS 7 as it's the last version of iOS right now and hidden call implementation is simpler than on iOS 6 and below.

我们需要的几乎所有内容都位于私有 TelephonyUtilities.framework 。在iOS 7中,Apple几乎在该框架中移动了与电话呼叫相关的所有内容。这就是为什么它变得更简单 - 所有其他iOS组件都使用该框架,所以我们只需要挂钩一次,而不需要在每个iOS守护程序中寻找可能与电话有关的框架。

Almost everything we need is located in private TelephonyUtilities.framework. In iOS 7 Apple moved almost everything related to phone calls in that framework. That's why it got simpler - all other iOS components use that framework so we only need to hook it once without the need to poke around in every iOS daemon, framework that might do something with phone calls.

所有方法都挂钩在两个进程中 - SpringBoard和MobilePhone(电话应用程序)。捆绑ID分别为 com.apple.springboard com.apple.mobilephone

All methods are hooked in two processes - SpringBoard and MobilePhone (phone application). Bundle IDs are com.apple.springboard and com.apple.mobilephone, respectively.

以下是我在两个流程中挂钩的 TelephonyUtilities.framework 方法的列表。

Here is the list of TelephonyUtilities.framework methods I hook in both processes.

//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 方法我在两个进程中挂钩。

Here is Foundation.framework method I hook in both processes.

//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对此一无所知所以当我们回答它时,音频路由没有完成,我们不会在另一端听到任何声音。 SetupAVController 这样做 - 它可以设置像iOS一样的有线电话时的音频路由。我使用来自私人的私人API Celestial.framework

Here is SetupAVController function I used earlier. Hidden call is trully hidden - iOS doesn't know anything about it so when we answer it audio routing is not done and we will not hear anything on the other end. SetupAVController does this - it setups audio routing like iOS does when there is active phone call. I use private APIs from private Celestial.framework

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流程中挂钩的方法

Here is method I hook only in MobilePhone process

/*
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流程。

Methods I hook in SpringBoard process.

//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中。我可能会稍后发布代码,因为我现在没有时间。答案已经很长了。

iOS 5-6

iOS 5-6 is more complex. Telephony code is scattered arount many iOS components and APIs. I might post the code later as I don't have time right now. The answer is already really long.

这篇关于在iOS(越狱设备)中完全隐藏电话的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆