开发环境: iphone4 (ios4.3.2)
使用hook截获系统处理通知事件,然后进行相应的处理来达到截获的效果。目前的截获不是很完美,黑名单中的人打电话时会先出现“嘟.."声之后才会提示所拨打的用户正在通话中……
前提:需要class-dump CoreTelephony framework,并配置hook开发环境
1. 在说截获之前,先说说dlsym的使用
我们通常会在网上看到一些函数具有我们需要的功能,然后我们在class-dump出的头文件中查找去找不到,但是使用grep在framework中确实可以搜索到相应的符号,导致使用上出现一些麻烦。此时我们就可以使用dlsym来从动态库中获取相应的函数。
2. 挂断电话的函数
1 // CoreTelephony framework在系统中的路径 2 #define CTPATH "/XCode4.0andIphoneSDK4.3/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks/CoreTelephony.framework/CoreTelephony" 3 4 // 挂断电话函数 5 - (BOOL)disconnectCall:(id)call 6 { 7 void *framework = dlopen(CTPATH, RTLD_LAZY); 8 id (*CTCallDisconnect)(id) = dlsym(framework, "CTCallDisconnect"); 9 CTCallDisconnect(call); 10 dlclose(framework); 11 return YES; 12 }
CTCallDisconnect为挂断电话的函数,但是却没有在头文件中找到相应的声明,故使用dlsym来获取函数指针,进而来使用该函数。
disconnectCall被我定义在Util.m中,做为一个object clss去使用的,不过最好还是定义成C类型的,比较方便使用。
disconnectCall作为挂断电话的函数在下面的截获实现中会使用到。
dlopen等函数在#include <dlfcn.h>头文件中, dlopen之后一定要dlclose去关闭,否则会出现一些问题。
3. 截获电话通知处理事件
CTCallCenter中有些函数是对电话的状态进行通知的,故对CTCallCenter中的handleNotificationFromConnection进行了处理,代码如下:
1 extern "C" void replaced_CTCallCenter_handleNotificationFromConnection(CTCallCenter *self, SEL cmd, void *arg1, id arg2, id arg3) 2 { 3 // NSLog(@"------------------------------------------replaced_CTCallCenter_handleNotificationFromConnection, arg1 = %@, arg2 = %@, arg3 = %@", arg1, arg2, arg3); 4 5 // NSLog(@"------------arg2Type = %@, arg3Type = %@", NSStringFromClass([arg2 class]), NSStringFromClass([arg3 class])); 6 7 NSDictionary *dic = (NSDictionary *)arg3; 8 9 // 此处获得电话状态,CTCallStateDialing, CTCallStateIncoming, CTCallStateConnected, CTCallStateDisconnected等,定义在CTCallCenter.h(非class-dump的头文件)中 10 NSLog(@"-------kCTCallStatus = %@", [dic objectForKey:@"kCTCallStatus"]); 11 12 NSLog(@"--------currentCalls = %@, callEventHandler = %@", self.currentCalls, self.callEventHandler); 13 14 // 获得CTCall对象 15 CTCall *call = [dic objectForKey:@"kCTCall"]; 16 17 // NSLog(@"------callId = %@, callState = %@", call.callID, call.callState); 18 19 // 这里可以根据kCTCallStatus来判断需要进行的操作 20 if (call.callState == CTCallStateDialing) 21 { 22 NSLog(@"Call has been CTCallStateDialing"); 23 } 24 else if (call.callState == CTCallStateIncoming) 25 { 26 NSLog(@"Call has just been CTCallStateIncoming"); 27 //这儿可接可挂 28 // 挂断电话 29 BOOL flag = [Util disconnectCall:call]; 30 NSLog(@"----------------是否挂断. flag = %d", flag); 31 } 32 else if(call.callState == CTCallStateConnected) 33 { 34 NSLog(@"Call is CTCallStateConnected"); 35 } 36 else if (call.callState == CTCallStateDisconnected) 37 { 38 NSLog(@"Call is CTCallStateDisconnected"); 39 } 40 else 41 { 42 43 NSLog(@"None of the conditions"); 44 45 } 46 47 original_CTCallCenter_handleNotificationFromConnection(self, cmd, arg1, arg2, arg3); 48 }
上面的代码会对所有的电话都进行过滤处理,电话也都打不进来的,但是会留下一个未接电话。
此处只是提供一个思路,具体的截获需要对传进来的参数等等进行一些解析,并提供一些细致的处理。
在CoreTelephony framework中还含有其他的一些函数,例如对于电话状态改变等等的都可以去细致的研究下,相信会有很大的收获
http://www.cnblogs.com/ydhliphonedev/archive/2011/10/24/2223242.html
http://blog.csdn.net/laigb/article/details/6623068
extern NSString* const kCTSMSMessageReceivedNotification; extern NSString* const kCTSMSMessageReplaceReceivedNotification; extern NSString* const kCTSIMSupportSIMStatusNotInserted; extern NSString* const kCTSIMSupportSIMStatusReady; typedef struct __CTCall CTCall; extern NSString *CTCallCopyAddress(void*, CTCall *); void* CTSMSMessageSend(id server,id msg); typedef struct __CTSMSMessage CTSMSMessage; NSString *CTSMSMessageCopyAddress(void *, CTSMSMessage *); NSString *CTSMSMessageCopyText(void *, CTSMSMessage *); int CTSMSMessageGetRecordIdentifier(void * msg); NSString * CTSIMSupportGetSIMStatus(); NSString * CTSIMSupportCopyMobileSubscriberIdentity(); id CTSMSMessageCreate(void* unknow/*always 0*/,NSString* number,NSString* text); void * CTSMSMessageCreateReply(void* unknow/*always 0*/,void * forwardTo,NSString* text); id CTTelephonyCenterGetDefault(void); void CTTelephonyCenterAddObserver(id,id,CFNotificationCallback,NSString*,void*,int); void CTTelephonyCenterRemoveObserver(id,id,NSString*,void*); int CTSMSMessageGetUnreadCount(void); static void callback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { NSString *notifyname=(NSString *)name; if ([notifyname isEqualToString:@"kCTCallStatusChangeNotification"])//电话 { NSDictionary *info = (NSDictionary*)userInfo; NSString *state=[[info objectForKey:@"kCTCallStatus"] stringValue]; if ([state isEqualToString:@"5"])//disconnect NSLog(@"未接:%@",state); } else if ([notifyname isEqualToString:@"kCTCallIdentificationChangeNotification"]) { // CTCallCenter *center = [[CTCallCenter alloc] init]; // center.callEventHandler = ^(CTCall *call) { // NSLog(@"call:%@", [call description]); // }; NSDictionary *info = (NSDictionary *)userInfo; CTCall *call = (CTCall *)[info objectForKey:@"kCTCall"]; NSString *caller = CTCallCopyAddress(NULL, call); NSLog(@"电话号码:%@",caller); //CTCallDisconnect(call); /* or one of the following functions: CTCallAnswer CTCallAnswerEndingActive CTCallAnswerEndingAllOthers CTCallAnswerEndingHeld */ } else if ([notifyname isEqualToString:@"kCTRegistrationDataStatusChangedNotification"]) { } else if ([notifyname isEqualToString:@"kCTSMSMessageReceivedNotification"]) {//api 已过期 if ([[(NSDictionary *)userInfo allKeys] containsObject:@"kCTSMSMessage"]) // SMS Message { CTSMSMessage *message = (CTSMSMessage *) [(NSDictionary *)userInfo objectForKey:@"kCTSMSMessage"]; NSString *address = CTSMSMessageCopyAddress(NULL, message); NSString *text = CTSMSMessageCopyText(NULL, message); //NSArray *lines = [text componentsSeparatedByString:@"\n"]; //printf(" %s %d\n", [address cString], [lines count]); //printf(" %s\n", [text cString]); fflush(stdout); } } else if ([notifyname isEqualToString:@"kCTMessageReceivedNotification"])//收到短信 { /* kCTMessageIdKey = "-2147483636"; kCTMessageTypeKey = 1; */ NSDictionary *info = (NSDictionary *)userInfo; CFNumberRef msgID = (CFNumberRef)[info objectForKey:@"kCTMessageIdKey"]; int result; CFNumberGetValue((CFNumberRef)msgID, kCFNumberSInt32Type, &result); /* Class CTMessageCenter = NSClassFromString(@"CTMessageCenter"); id mc = [CTMessageCenter sharedMessageCenter]; id incMsg = [mc incomingMessageWithId: result]; int msgType = (int)[incMsg messageType]; if (msgType == 1) //experimentally detected number { id phonenumber = [incMsg sender]; NSString *senderNumber = (NSString *)[phonenumber canonicalFormat]; id incMsgPart = [[incMsg items] objectAtIndex:0]; NSData *smsData = [incMsgPart data]; NSString *smsText = [[NSString alloc] initWithData:smsData encoding:NSUTF8StringEncoding]; } */ } else if ([notifyname isEqualToString:@"kCTIndicatorsSignalStrengthNotification"])//信号 { /* kCTIndicatorsGradedSignalStrength = 2; kCTIndicatorsRawSignalStrength = "-101"; kCTIndicatorsSignalStrength = 19; */ } else if ([notifyname isEqualToString:@"kCTRegistrationStatusChangedNotification"])//网络注册状态 { /* kCTRegistrationInHomeCountry = 1; kCTRegistrationStatus = kCTRegistrationStatusRegisteredHome; */ } else if ([notifyname isEqualToString:@"kCTRegistrationDataStatusChangedNotification"]) { /* kCTRegistrationDataActive = 1; kCTRegistrationDataAttached = 1; kCTRegistrationDataConnectionServices = ( kCTDataConnectionServiceTypeInternet, kCTDataConnectionServiceTypeWirelessModemTraffic, kCTDataConnectionServiceTypeWirelessModemAuthentication ); kCTRegistrationDataContextID = 0; kCTRegistrationDataIndicator = kCTRegistrationDataIndicator3G; kCTRegistrationDataStatus = kCTRegistrationDataStatusAttachedAndActive; kCTRegistrationDataStatusInternationalRoaming = 1; kCTRegistrationRadioAccessTechnology = kCTRegistrationRadioAccessTechnologyUTRAN; */ } else if ([notifyname isEqualToString:@"kCTRegistrationCellChangedNotification"]) { /* kCTRegistrationGsmCellId = 93204174; kCTRegistrationGsmLac = 55583; kCTRegistrationInHomeCountry = 1; kCTRegistrationRadioAccessTechnology = kCTRegistrationRadioAccessTechnologyUTRAN; */ } else if ([notifyname isEqualToString:@"kCTIndicatorRadioTransmitNotification"]) { /* kCTRadioTransmitDCHStatus = 1; */ } //int unread=CTSMSMessageGetUnreadCount(); //if (unread>0) //NSLog(@"未读短信:%d",unread); NSLog(@"名字:%@-详细:%@",notifyname,userInfo); } static void signalHandler(int sigraised) { printf("\nInterrupted.\n"); exit(0); }
执行
id ct = CTTelephonyCenterGetDefault(); CTTelephonyCenterAddObserver(ct, NULL, callback, NULL, NULL, CFNotificationSuspensionBehaviorHold); // Handle Interrupts sig_t oldHandler = signal(SIGINT, signalHandler); if (oldHandler == SIG_ERR) { printf("Could not establish new signal handler"); exit(1); } // Run loop lets me catch notifications printf("Starting run loop and watching for notification.\n"); //CFRunLoopRun();