今天写了一段有关在iPhone程序中开关WiFi型号的代码,经测试运行良好。
我想不用我多说大家都应该知道以上的功能只能在越狱的设备中实现!
好了,闲话稍少叙,进入正题:
1.首先要在SpringBoard启动之后,我们要执行hook动作:
NSString *identifier = [[NSBundle mainBundle] bundleIdentifier];
if ([identifier isEqualToString:@"com.apple.springboard"]) {
Class $SpringBoard = (objc_getClass("SpringBoard"));
_SpringBoard$applicationDidFinishLaunching$ = MSHookMessage($SpringBoard, @selector(applicationDidFinishLaunching:), &$SpringBoard$applicationDidFinishLaunching$);
}
2. 然后实现我们的HOOK函数,这里我们仅仅是注册了两个消息:
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL,
&NotificationReceivedCallback, CFSTR("turnOffWiFi"), NULL,
CFNotificationSuspensionBehaviorCoalesce);
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL,
&NotificationReceivedCallback, CFSTR("turnOnWiFi"), NULL,
CFNotificationSuspensionBehaviorCoalesce);
3. 最后我们要响应这两个信号,也就是实现我们在第二步中指明的那个回调方法(NotificationReceivedCallback)
static void NotificationReceivedCallback(CFNotificationCenterRef center,
void *observer, CFStringRef name,
const void *object, CFDictionaryRef
userInfo)
{
BOOL offOrOn = YES;
if ([(NSString *)name isEqualToString:@"turnOffWiFi"]) {
offOrOn = NO;
} else if ([(NSString *)name isEqualToString:@"turnOnWiFi"]) {
offOrOn = YES;
}
[[objc_getClass("SBWiFiManager") sharedInstance] setWiFiEnabled:offOrOn];
}
也就是这一步正真的对WiFi信号进行开关操作。好了我们的后台程序(dynamicLibrary)已经编写完成了。
然后在我们的前台程序中我们找个事件来发送我们在后台注册的那两个消息,例如一个Button和一个BOOL值来完成这功能:
BOOL turnOff = YES;
if (turnOn) {
CFNotificationCenterPostNotificationWithOptions(CFNotificationCenterGetDarwinNotifyCenter(), CFSTR("turnOffWiFi"), NULL, NULL, 0);
} else {
CFNotificationCenterPostNotificationWithOptions(CFNotificationCenterGetDarwinNotifyCenter(), CFSTR("turnOffWiFi"), NULL, NULL, 0);
}
测试设备:iPhone 3GS
系统:iOS 4.3.3
设备状态:已越狱
测试结果:Perfect!
注1:使用相同的方法我们可以启动和关闭蓝牙:
首先,我们要从BluetoothManager.framework这个私有库中dump出BluetoothManager这个类;
然后,我们就可以调用这个类的setPowered:方法启动和关闭蓝牙了(参数:YES为启动、NO为关闭)。
经过我的测试是可以正常使用的。
注2:我们同样可以对飞行模式作开启和关闭操作:
首先:我们从SpringBoard中可以dump出SBTelephonyManager和SBStatusBarDataManager这两个类,前者主要负责功能的开关,后者则是负责UI显示的。使用SBTelephonyManager的isInAirplaneMode方法可以得到当前的飞行模式状态,setIsInAirplaneMode:这个方法来设置飞行模式。使用SBStatusBarDataManager的airplaneModeChanged和_updateSignalStrengthItem来刷新UI显示状态。
以上的方法最终都是由后台(动态库)完成的,最近由于工作需要要在应用中直接开启关闭WiFi、Bluetooth和飞行模式,所以又做了一些研究工作。最终发现我们在App中也可以开启或关闭以上三种模式(当然这一切依旧需要在越狱环境),其中最简单的是蓝牙(Bluetooth)只要将一个名为BluetoothManager的私有库添加到工程中,然后使用其中的BluetoothManager这个单例就可以开关蓝牙了(Class-Dump);而WiFi和飞行模式相对复杂一些,但是他们缺只需要个共有库就可以,那就是SystemConfiguration.framework,下面我把开飞行模式的代码给出大家:
SCPreferencesRef preferences = SCPreferencesCreateWithAuthorization(kCFAllocatorDefault, CFSTR("MyAppIndtifier"), CFSTR("com.apple.radios.plist"), NULL);
if (preferences) {
Boolean result = SCPreferencesLock(preferences, YES);
if (result == TRUE) {
CFBooleanRef airplane = SCPreferencesGetValue(preferences, CFSTR("AirplaneMode"));
if (airplane == kCFBooleanTrue) {
airplane = kCFBooleanFalse;
} else {
airplane = kCFBooleanTrue;
}
result = SCPreferencesSetValue(preferences, CFSTR("AirplaneMode"), airplane);
if (result == TRUE) {
result = SCPreferencesCommitChanges(preferences);
if (result) {
result = SCPreferencesApplyChanges(preferences);
}
}
SCPreferencesUnlock(preferences);
}
CFRelease(preferences);
}
只要将com.apple.radios.plist换成com.apple.wifi.plist, 同时将AirplaneMode换成AllowEnable就可以开关蓝牙了。最后我们还需要Entitlements,它的内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)MyAppIndtifier</string>
</array>
<key>com.apple.SystemConfiguration.SCDynamicStore-write-access</key>
<true/>
<key>com.apple.SystemConfiguration.SCPreferences-write-access</key>
<array>
<string>com.apple.radios.plist</string>
<string>com.apple.wifi.plist</string>
</array>
</dict>
</plist>
我们需要用ldid给将这个Entitlements签到可执行程序就可以了!
最近的开发中又研究了一下VPN的开关方法,涉及到ManagedConfiguration、VPNUtilities以及SystemConfiguration三个framework,代码如下:
extern Boolean MCVPNPreferencesLock(SCPreferencesRef);
extern Boolean MCVPNPreferencesUnlock(SCPreferencesRef);
extern CFDictionaryRef MCVPNServiceGetConfigurationProperty(SCNetworkServiceRef, CFStringRef);
extern CFStringRef MCVPNServiceCopyPassword(SCNetworkServiceRef);
extern CFStringRef MCVPNServiceCopySharedSecret(SCNetworkServiceRef);
static void callout(SCNetworkConnectionRef connection, SCNetworkConnectionStatus status, void *info) {
}
- (BOOL)VPNEnabled {
BOOL retVal = NO;
CFBundleRef mainBundle = CFBundleGetMainBundle();
CFStringRef bundleIdentifier = CFBundleGetIdentifier(mainBundle);
SCPreferencesRef preferences = SCPreferencesCreateWithAuthorization(kCFAllocatorDefault, bundleIdentifier, nil, nil);
if (preferences) {
CFArrayRef services = SCNetworkServiceCopyAll(preferences);
if (services) {
CFIndex i, count = CFArrayGetCount(services);
for (i = 0; i < count; i++) {
SCNetworkServiceRef networkServerice = CFArrayGetValueAtIndex(services, i);
if (SCNetworkServiceGetEnabled(networkServerice)) {
SCNetworkInterfaceRef interface = SCNetworkServiceGetInterface(networkServerice);
CFStringRef interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
if (CFStringCompare(interfaceType, kSCNetworkInterfaceTypePPP, kCFCompareAnchored) == kCFCompareEqualTo || CFStringCompare(interfaceType, kSCNetworkInterfaceTypeIPSec, kCFCompareAnchored) == kCFCompareEqualTo) {
if (MCVPNPreferencesLock(preferences)) {
SCNetworkConnectionRef connection = SCNetworkConnectionCreateWithServiceID(kCFAllocatorDefault, SCNetworkServiceGetServiceID(networkServerice), NULL, NULL);
if (connection) {
SCNetworkConnectionStatus connectionStatus = SCNetworkConnectionGetStatus(connection);
if (connectionStatus == kSCNetworkConnectionConnecting || connectionStatus == kSCNetworkConnectionConnected) {
retVal = YES;
}
CFRelease(connection);
}
MCVPNPreferencesUnlock(preferences);
}
break;
}
}
}
CFRelease(services);
}
CFRelease(preferences);
}
return retVal;
}
- (void)setVPNEnabled:(BOOL)enabled {
CFBundleRef mainBundle = CFBundleGetMainBundle();
CFStringRef bundleIdentifier = CFBundleGetIdentifier(mainBundle);
SCPreferencesRef preferences = SCPreferencesCreateWithAuthorization(kCFAllocatorDefault, bundleIdentifier, nil, nil);
if (preferences) {
CFArrayRef services = SCNetworkServiceCopyAll(preferences);
if (services) {
CFIndex i, count = CFArrayGetCount(services);
for (i = 0; i < count; i++) {
SCNetworkServiceRef networkServerice = CFArrayGetValueAtIndex(services, i);
if (SCNetworkServiceGetEnabled(networkServerice)) {
SCNetworkInterfaceRef interface = SCNetworkServiceGetInterface(networkServerice);
CFStringRef interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
if (CFStringCompare(interfaceType, kSCNetworkInterfaceTypePPP, kCFCompareAnchored) == kCFCompareEqualTo) {
if (MCVPNPreferencesLock(preferences)) {
SCNetworkConnectionRef connection = SCNetworkConnectionCreateWithServiceID(kCFAllocatorDefault, SCNetworkServiceGetServiceID(networkServerice), callout, NULL);
if (connection) {
if (SCNetworkConnectionScheduleWithRunLoop(connection, CFRunLoopGetMain(), kCFRunLoopDefaultMode)) {
if (enabled) {
CFStringRef password = MCVPNServiceCopyPassword(networkServerice);
CFStringRef sharedSecret = MCVPNServiceCopySharedSecret(networkServerice);
CFDictionaryRef userOptions = nil;
if (password) {
NSArray *keys1 = [[NSArray alloc] initWithObjects:(NSString *)kSCPropNetIPSecAuthenticationMethod, (NSString *)kSCPropNetIPSecLocalCertificate, (NSString *)kSCPropNetIPSecLocalIdentifier, (NSString *)kSCPropNetIPSecLocalIdentifierType, (NSString *)kSCPropNetIPSecSharedSecret, (NSString *)kSCPropNetIPSecSharedSecretEncryption, (NSString *)kSCPropNetIPSecConnectTime, (NSString *)kSCPropNetIPSecRemoteAddress, (NSString *)kSCPropNetIPSecStatus, (NSString *)kSCPropNetIPSecXAuthEnabled, (NSString *)kSCPropNetIPSecXAuthName, (NSString *)kSCPropNetIPSecXAuthPassword, (NSString *)kSCPropNetIPSecXAuthPasswordEncryption, nil];
CFMutableDictionaryRef IPSecValue = CFDictionaryCreateMutable(kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
for (NSString *key in keys1) {
if (CFStringCompare(kSCPropNetIPSecSharedSecret, (CFStringRef)key, kCFCompareAnchored) == kCFCompareEqualTo) {
if (sharedSecret) {
CFDictionaryAddValue(IPSecValue, (const void *)key, (const void *)sharedSecret);
}
} else if (CFStringCompare(kSCPropNetIPSecXAuthPassword, (CFStringRef)key, kCFCompareAnchored) == kCFCompareEqualTo) {
if (password) {
CFDictionaryAddValue(IPSecValue, (const void *)key, (const void *)password);
}
} else {
CFStringRef value = (CFStringRef)MCVPNServiceGetConfigurationProperty(networkServerice, (CFStringRef)key);
if (value) {
CFDictionaryAddValue(IPSecValue, (const void *)key, (const void *)value);
}
}
}
[keys1 release];
NSArray *keys2 = [[NSArray alloc] initWithObjects:(NSString *)kSCPropNetPPPAuthName, (NSString *)kSCPropNetPPPAuthPassword, (NSString *)kSCPropNetPPPCommRemoteAddress, nil];
CFMutableDictionaryRef PPPSecValue = CFDictionaryCreateMutable(kCFAllocatorDefault, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
for (NSString *key in keys2) {
if (CFStringCompare(kSCPropNetPPPAuthPassword, (CFStringRef)key, kCFCompareAnchored) == kCFCompareEqualTo) {
if (password) {
CFDictionaryAddValue(PPPSecValue, (const void *)key, (const void *)password);
}
} else {
CFStringRef value = (CFStringRef)MCVPNServiceGetConfigurationProperty(networkServerice, (CFStringRef)key);
if (value) {
CFDictionaryAddValue(PPPSecValue, (const void *)key, (const void *)value);
}
}
}
[keys2 release];
CFStringRef keys[] = {kSCNetworkInterfaceTypeIPSec, kSCNetworkInterfaceTypePPP};
CFDictionaryRef values[] = {IPSecValue, PPPSecValue};
userOptions = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFRelease(IPSecValue);
CFRelease(PPPSecValue);
CFRelease(password);
}
SCNetworkConnectionStart(connection, userOptions, true);
if (userOptions) {
CFRelease(userOptions);
}
} else {
SCNetworkConnectionStop(connection, true);
}
SCNetworkConnectionUnscheduleFromRunLoop(connection, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
}
CFRelease(connection);
}
MCVPNPreferencesUnlock(preferences);
}
break;
} else if (CFStringCompare(interfaceType, kSCNetworkInterfaceTypeIPSec, kCFCompareAnchored) == kCFCompareEqualTo) {
if (MCVPNPreferencesLock(preferences)) {
SCNetworkConnectionRef connection = SCNetworkConnectionCreateWithServiceID(kCFAllocatorDefault, SCNetworkServiceGetServiceID(networkServerice), callout, NULL);
if (connection) {
if (SCNetworkConnectionScheduleWithRunLoop(connection, CFRunLoopGetMain(), kCFRunLoopDefaultMode)) {
if (enabled) {
CFStringRef password = MCVPNServiceCopyPassword(networkServerice);
CFStringRef sharedSecret = MCVPNServiceCopySharedSecret(networkServerice);
CFDictionaryRef userOptions = nil;
if (password) {
NSArray *keys1 = [[NSArray alloc] initWithObjects:(NSString *)kSCPropNetIPSecAuthenticationMethod, (NSString *)kSCPropNetIPSecLocalCertificate, (NSString *)kSCPropNetIPSecLocalIdentifier, (NSString *)kSCPropNetIPSecLocalIdentifierType, (NSString *)kSCPropNetIPSecSharedSecret, (NSString *)kSCPropNetIPSecSharedSecretEncryption, (NSString *)kSCPropNetIPSecConnectTime, (NSString *)kSCPropNetIPSecRemoteAddress, (NSString *)kSCPropNetIPSecStatus, (NSString *)kSCPropNetIPSecXAuthEnabled, (NSString *)kSCPropNetIPSecXAuthName, (NSString *)kSCPropNetIPSecXAuthPassword, (NSString *)kSCPropNetIPSecXAuthPasswordEncryption, nil];
CFMutableDictionaryRef IPSecValue = CFDictionaryCreateMutable(kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
for (NSString *key in keys1) {
if (CFStringCompare(kSCPropNetIPSecSharedSecret, (CFStringRef)key, kCFCompareAnchored) == kCFCompareEqualTo) {
if (sharedSecret) {
CFDictionaryAddValue(IPSecValue, (const void *)key, (const void *)sharedSecret);
}
} else if (CFStringCompare(kSCPropNetIPSecXAuthPassword, (CFStringRef)key, kCFCompareAnchored) == kCFCompareEqualTo) {
if (password) {
CFDictionaryAddValue(IPSecValue, (const void *)key, (const void *)password);
}
} else {
CFStringRef value = (CFStringRef)MCVPNServiceGetConfigurationProperty(networkServerice, (CFStringRef)key);
if (value) {
CFDictionaryAddValue(IPSecValue, (const void *)key, (const void *)value);
}
}
}
[keys1 release];
CFDictionaryRef PPPSecValue = CFDictionaryCreate(kCFAllocatorDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFStringRef keys[] = {kSCNetworkInterfaceTypeIPSec, kSCNetworkInterfaceTypePPP};
CFDictionaryRef values[] = {IPSecValue, PPPSecValue};
userOptions = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFRelease(IPSecValue);
CFRelease(PPPSecValue);
CFRelease(password);
}
SCNetworkConnectionStart(connection, userOptions, true);
if (userOptions) {
CFRelease(userOptions);
}
} else {
SCNetworkConnectionStop(connection, true);
}
SCNetworkConnectionUnscheduleFromRunLoop(connection, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
}
CFRelease(connection);
}
MCVPNPreferencesUnlock(preferences);
}
break;
}
}
}
CFRelease(services);
}
CFRelease(preferences);
}
}