Disconnect or connect an iPhone call programmatically

前端 未结 2 1771
礼貌的吻别
礼貌的吻别 2021-01-03 09:50

I\'m working on a personal tweak for iOS. I want to disconnect/connect a phone call before the phone would show anything. I\'m hooking into the initWithAlertController

2条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2021-01-03 10:40

    There is much better place to do that - MPTelephonyManager -(void)displayAlertForCall:(id)call. This method is located in IncomingCall.servicebundle binary, not in SpringBoard itself. This binary is being loaded at runtime into SpringBoard when there is an incoming call. Before that IncomingCall.servicebundle is not loaded thus you can't hook it's methods.


    Hooking IncomingCall.servicebundle

    In order to hook the method, first, read this How to hook methods of MPIncomingPhoneCallController? SBPluginManager is loading *.servicebundle binaries at runtime. You need to hook it's -(Class)loadPluginBundle:(id)bundle method. It's gonna look something like this:

    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
    

    As you can see, hooking is deferred until IncomingCall.servicebundle is loaded. I don't know logos/theos that well but I think it can't do that. That's why I used CydiaSubstrate (MobileSubstrate) API.


    Hooking 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;
    }
    

提交回复
热议问题