以编程方式断开或连接iPhone电话

3
我正在开发一个针对iOS的个人调整。我想在手机显示任何内容之前断开/连接电话。我正在挂接到SBUIFullscreenAlertAdapter类的initWithAlertController:方法。当我只显示一个消息,显示来电号码及其名称时,一切都正常,但是当我尝试以编程方式回答电话或断开电话时,它会崩溃并进入安全模式。
以下是我的代码:
@interface SBUIFullscreenAlertAdapter
- (id)initWithAlertController:(id)arg1;
@end

@interface MPIncomingPhoneCallController
{
    struct __CTCall *_incomingCall;
}
- (id) incomingCallNumber;
- (void)stopRingingOrVibrating;
- (void)answerCall:(struct __CTCall *)arg1;
@end

%hook SBUIFullscreenAlertAdapter
- (id)initWithAlertController:(id)arg1
{
    MPIncomingPhoneCallController *phoneCall = (MPIncomingPhoneCallController*)arg1;
    [phoneCall stopRingingOrVibrating];
    if([phoneCall.incomingCallNumber isEqualToString:@"+98.........."]) {
        [phoneCall answerCall:_incomingCall];
    }
    %orig;
    return self;
}
%end

错误提示为:“使用未声明的标识符'_incomingCall'”。如何解决这个问题?在hook方法时有没有办法使用私有实例变量?有没有一个函数可以返回来电的CTCallRef*?还有其他方法可以实现这个功能吗?很明显,我正在为越狱的iOS设备编写代码,因此使用私有框架没有问题。
2个回答

4

有一个更好的方法可以实现这一点 - MPTelephonyManager -(void)displayAlertForCall:(id)call。这个方法位于IncomingCall.servicebundle二进制文件中,而不是SpringBoard本身。当有来电时,此二进制文件会在运行时加载到SpringBoard中。在此之前,IncomingCall.servicebundle没有被加载,因此您无法挂钩它的方法。


挂钩IncomingCall.servicebundle

为了挂钩该方法,首先请阅读如何挂钩MPIncomingPhoneCallController的方法?SBPluginManager会在运行时加载*.servicebundle二进制文件。您需要挂钩它的-(Class)loadPluginBundle:(id)bundle方法。代码大致如下:

void displayAlertForCall_hooked(id self, SEL _cmd, id arg1);
void(*displayAlertForCall_orig)(id, SEL, id) = NULL;

%hook SBPluginManager
-(Class)loadPluginBundle:(NSBundle*)bundle
{
    Class ret = %orig;

    if ([[bundle bundleIdentifier] isEqualToString:@"com.apple.mobilephone.incomingcall"] && [bundle isLoaded])
    {
        MSHookMessageEx(objc_getClass("MPTelephonyManager"),
                        @selector(displayAlertForCall:), 
                        (IMP)displayAlertForCall_hooked, 
                        (IMP*)&displayAlertForCall_orig);
    }

    return ret;
}
%end

正如您所看到的,挂钩是在加载IncomingCall.servicebundle后进行的。我不太了解logos/theos,但我认为它无法做到这一点。这就是为什么我使用CydiaSubstrate(MobileSubstrate)API。


钩取 MPTelephonyManager

#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
typedef void* CTCallRef;
void CTCallDisconnect(CTCallRef);
void CTCallAnswer(CTCallRef);    

void displayAlertForCall_hooked(id self, SEL _cmd, id arg1)
{
    CTCallRef call = NULL;
    if (SYSTEM_VERSION_LESS_THAN(@"7.0"))
    {
        //On iOS 6 and below arg1 has CTCallRef type
        call = arg1;
    }
    else
    {
       //On iOS 7 arg1 has TUTelephonyCall* type
       call = [arg1 call];
    }

    NSString *callNumber = (NSString*)CFBridgingRelease(CTCallCopyAddress(NULL, call));
    if ([callNumber isEqualToString:@"+98.........."]) 
    {
        CTCallAnswer(call);
        //CTCallDisconnect(call);
    }

    %orig;
}

非常感谢您的回答。我会尽快测试并回复! - Hamed
[在]creker,谢谢。它起作用了!MSHookMessageEx函数有一个错误。它只有4个参数,所以末尾的NULL是不需要的。顺便问一下,您知道如何在电话通信时禁用锁屏中显示的名称以及如何禁用呼叫栏吗? - Hamed
如果你想完全隐藏电话通话,而不让任何人知道它正在进行中,那么是的,我知道如何做到这一点,并且我在iOS 5-7上已经实现了。但是,这比我的回答要复杂得多。它需要钩住许多不同进程中的方法(数十个方法)。在iOS 6及以下版本中尤其复杂。在iOS 7上,苹果公司大幅改进了iOS电话组件的架构,因此使得实现你想要的功能变得更加简单。 - creker
我不想发布完整的示例,因为这将需要重写我的代码中的许多内容 - 而且由于各种原因,我不能只是复制粘贴我的代码。你可以问另一个问题,我可以指引你正确的方向,但最终你必须自己完成它,因为它真的取决于你想要实现什么。 - creker
@Hamed,请查看。 - creker

1

iOS 8.*:

Theos/Logos似乎很容易进行挂钩。

示例Tweak.xm文件(您需要8.1的TelephonyUtilities私有框架头文件):

#import "TelephonyUtilities/TUTelephonyCall.h"

%hook MPTelephonyManager

-(void)displayAlertForCall:(TUTelephonyCall*)phoneCall { // for iOS 9: displayAlertForCallIfNecessary
    NSLog(@"hooked displayAlertForCall method");
    if ([[NSBundle mainBundle].bundleIdentifier isEqualToString:@"com.apple.springboard"]) { // (don't know if required)
        [phoneCall answer]; // or [phoneCall disconnect];
    }
    %orig;
}

%end


%ctor {
    if ([[NSBundle bundleWithPath:@"/System/Library/SpringBoardPlugins/IncomingCall.servicebundle"] load]) {
        NSLog(@"IncomingCall.servicebundle loaded succesfully!");
    }
    else {
        NSLog(@"IncomingCall.servicebundle did not load succesfully.");
    }
}

感谢Phillip Tennen (https://github.com/codyd51/CallConnect)的贡献。


这似乎在iOS 9.x上不再起作用了。我想displayAlertForCall的签名已经改变或类似的事情发生了。目前,我无法在任何地方找到IncomingCall.servicebundle的iOS 9头文件,我自己也没有成功转储它们。我们从哪里获取IncomingCall.servicebundle的iOS 9头文件? - jakob.j
针对iOS 9,displayAlertForCall已更改为displayAlertForCallIfNecessary(如此处所示:https://github.com/CPDigitalDarkroom/iOS9-SpringBoard-Headers/blob/master/System/Library/SpringBoardPlugins/IncomingCall.servicebundle/MPTelephonyManager.h) - jakob.j

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接