I am trying to read RSSI of iPhone WIFI connection to AP.
Using Xcode 6.1.1 with iPhone6+ ios 8.1.3
Code below crashes at apple80211Open() and gets EXC_BAD_ACCESS (code=1, address= 0) on iOS 8. (code works on iOS 7.1)
This is for app that is NOT for Apple Store -- for adhoc distribution only.
=================================================================
void *libHandle;
void *airportHandle;
int (*apple80211Open)(void *);
int (*apple80211Bind)(void *, NSString *);
int (*apple80211Close)(void *);
int (*apple80211GetInfoCopy)(void *, CFDictionaryRef *);
NSMutableDictionary *infoDict = [NSMutableDictionary new];
NSDictionary * tempDictionary;
libHandle = dlopen("/System/Library/SystemConfiguration/IPConfiguration.bundle/IPConfiguration", RTLD_LAZY);
char *dlerror_error;
if (libHandle == NULL && (dlerror_error = dlerror()) != NULL) {
NSLog(#"%s", dlerror_error);
}
apple80211Open = dlsym(libHandle, "Apple80211Open");
apple80211Bind = dlsym(libHandle, "Apple80211BindToInterface");
apple80211Close = dlsym(libHandle, "Apple80211Close");
apple80211GetInfoCopy = dlsym(libHandle, "Apple80211GetInfoCopy");
apple80211Open(&airportHandle);
apple80211Bind(airportHandle, #"en0");
CFDictionaryRef info = NULL;
apple80211GetInfoCopy(airportHandle, &info);
tempDictionary = (__bridge NSDictionary *)info;
apple80211Close(airportHandle);
[infoDict setObject:(tempDictionary[#"RSSI"])[#"RSSI_CTL_AGR"] ? (tempDictionary[#"RSSI"])[#"RSSI_CTL_AGR"] : #"0" forKey:#"RSSI"];
[infoDict setObject:tempDictionary[#"BSSID"] ? tempDictionary[#"BSSID"] : #"null" forKey:#"BSSID"];
[infoDict setObject:tempDictionary[#"SSID_STR"] ? tempDictionary[#"SSID_STR"] : #"null" forKey:#"SSID"];
[infoDict setObject:tempDictionary[#"RATE"] ? tempDictionary[#"RATE"] : #"0" forKey:#"SPEED"];
That's because Apple removed the 80211 framework from within IPConfiguration. The symbols can't be found, dlsym returns NULL, and - a crash (you should always check return values, you know).
To begin with, this was a private framework. In new versions of iOS (8+), it's deprecated in favor of MobileWifi, and the use of entitlements (and XPC) so as to have /usr/libexec/wifid to all the work.
There's more detail on this in this article: http://newosxbook.com/articles/11208ellpA.html
The Apple80211 API was removed from IPConfiguration at some point e.g. iOS 11 & 12, but came back in iOS 13 and as of today the methods are all still there and working in iOS 13.4.1. What I expect is the reason you were unable to get it working is likely since iOS 8 you need the com.apple.wlan.authentication entitlement as mentioned here.
There is currently a sneaky way to use this entitlement in apps (for your own use), but it will stop working in iOS 13.5.
Related
Has anyone found a new way to uniquely identify a device in iOS 10? I haven't seen any documentation mentioning changes in that area and I wanted to ask before I surrendered to identifier for vendor.
If you're submitting to the store, the only real identifier you have left is the Advertising Identifier for the AdSupport framework.
If you want to go down the rabbit hole a little further and potentially go into some unsafe API territory, you could hook into IOKit and try to get the battery identifier on the device. This is taken from Anthony Agatiello gist of UIDevice extensions:
- (NSString *)batteryID {
void *IOKit = dlopen("/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit", RTLD_LAZY);
NSParameterAssert(IOKit);
mach_port_t *kIOMasterPortDefault = dlsym(IOKit, "kIOMasterPortDefault");
NSParameterAssert(kIOMasterPortDefault);
CFMutableDictionaryRef (*IOServiceNameMatching)(const char *name) = dlsym(IOKit, "IOServiceNameMatching");
NSParameterAssert(IOServiceNameMatching);
mach_port_t (*IOServiceGetMatchingService)(mach_port_t masterPort, CFDictionaryRef matching) = dlsym(IOKit, "IOServiceGetMatchingService");
NSParameterAssert(IOServiceGetMatchingService);
kern_return_t (*IORegistryEntryCreateCFProperties)(mach_port_t entry, CFMutableDictionaryRef *properties, CFAllocatorRef allocator, UInt32 options) = dlsym(IOKit, "IORegistryEntryCreateCFProperties");
NSParameterAssert(IORegistryEntryCreateCFProperties);
kern_return_t (*IOObjectRelease)(mach_port_t object) = dlsym(IOKit, "IOObjectRelease");
NSParameterAssert(IOObjectRelease);
CFMutableDictionaryRef properties = NULL;
mach_port_t service = IOServiceGetMatchingService(*kIOMasterPortDefault, IOServiceNameMatching("charger"));
IORegistryEntryCreateCFProperties(service, &properties, kCFAllocatorDefault, 0);
IOObjectRelease(service);
service = 0;
NSDictionary *dictionary = (__bridge NSDictionary *)properties;
NSData *batteryIDData = [dictionary objectForKey:#"battery-id"];
CFRelease(properties);
properties = NULL;
dlclose(IOKit);
return [NSString stringWithUTF8String:[batteryIDData bytes]];
}
This still works on iOS 10.
I have a problem.
I have working Code for iOS to add a private Key to the Keychain by SecItemAdd. It works without any error.
On OS X with the same attributes and values, it does not work.
Any ideas, whats the problem. Here is the part of the Code:
NSData * keyData = ...
NSString * name = #"TestKey"
NSString * keyID = #"TestKey"
const id keys[] = {
(__bridge id)(kSecClass),
(__bridge id)(kSecAttrKeyClass),
(__bridge id)(kSecAttrLabel),
(__bridge id)(kSecAttrApplicationLabel),
(__bridge id)(kSecAttrIsPermanent),
(__bridge id)(kSecAttrAccessible),
(__bridge id)(kSecValueData) };
const id values[] = {
(__bridge id)(kSecClassKey),
(__bridge id)(kSecAttrKeyClassPrivate),
name,
keyID,
(id)kCFBooleanTrue,
(__bridge id)(kSecAttrAccessibleAfterFirstUnlock),
keyData };
NSMutableDictionary * attributes = [[NSMutableDictionary alloc] initWithObjects:values forKeys:keys count:ATTR_COUNT(keys)];
CFTypeRef result;
NSError * error = nil;
OSStatus osStatus = SecItemAdd((__bridge CFDictionaryRef)attributes, &result);
The error is:
25303 (errKCNoSuchAttr / errSecNoSuchAttr: / The attribute does not
exist.).)
The Error code specifies The attribute does not exist, it is due to the attribute : kSecAttrKeyClass. Try removing this attribute, and use tag names to distinguish the different keys. I was also getting similar issue in my code.
Which OS X version are you trying to support? OS X Keychain Services are different than iOS Keychain Services. For example, kSecClass is only available as of OS X 10.7, and kSecAttrAccessible 10.9.
How to get application name running in foreground? it was working in iOS 7 using SpringBoard but in iOS 8 I don't get the result. Any help is appreciated. I don't need to submit my app on apple store so if any patch or script also available then please let me know.
Code is working fine on below iOS 8.0
- (NSMutableString*) getActiveApps
{
mach_port_t *port;
void *lib = dlopen(SBSERVPATH, RTLD_LAZY);
int (*SBSSpringBoardServerPort)() =
dlsym(lib, "SBSSpringBoardServerPort");
port = (mach_port_t *)SBSSpringBoardServerPort();
dlclose(lib);
//mach_port_t * port = [self getSpringBoardPort];
// open springboard lib
//void *lib = dlopen(SBSERVPATH, RTLD_LAZY);
// retrieve function SBFrontmostApplicationDisplayIdentifier
void *(*SBFrontmostApplicationDisplayIdentifier)(mach_port_t *port, char *result) =
dlsym(lib, "SBFrontmostApplicationDisplayIdentifier");
// reserve memory for name
char appId[256];
memset(appId, 0, sizeof(appId));
// retrieve front app name
SBFrontmostApplicationDisplayIdentifier(port, appId);
// close dynlib
dlclose(lib);
return [[NSString stringWithFormat:#"%s", appId] retain];
}
Also I show new framework FrontBoard anyone know should it will help to out of this problem?
There's no way to do that anymore in iOS 8 since a vulnerability was discovered. A background app could attack though the frontmost app. More details here: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-4361
Does MonoTouch have a simple mechanism for retrieving the device serial number (not UDID) of an iOS device? Is there a third-party library which I can use to obtain this?
In case it matters, I'm looking to use this functionality in an in-house application and am not concerned with the App Store approval process.
UPDATE: from iOS 8, we cannot retrieve the serial number of our iDevice.
To retrieve iphone serial number from Monotouch, you can use this technic:
Create a static library .a from XCode that have a function to get serial number
In MonoDevelop, create a binding project to bind you .a library into C# classes/functions (http://docs.xamarin.com/guides/ios/advanced_topics/binding_objective-c_libraries)
In your application, you call this binding library (in step 2).
For detail:
STEP 1. In my library.a, I have a class DeviceInfo, here is the implementation to get Serial number
#import "DeviceInfo.h"
#import <dlfcn.h>
#import <mach/port.h>
#import <mach/kern_return.h>
#implementation DeviceInfo
- (NSString *) serialNumber
{
NSString *serialNumber = nil;
void *IOKit = dlopen("/System/Library/Frameworks/IOKit.framework/IOKit", RTLD_NOW);
if (IOKit)
{
mach_port_t *kIOMasterPortDefault = dlsym(IOKit, "kIOMasterPortDefault");
CFMutableDictionaryRef (*IOServiceMatching)(const char *name) = dlsym(IOKit, "IOServiceMatching");
mach_port_t (*IOServiceGetMatchingService)(mach_port_t masterPort, CFDictionaryRef matching) = dlsym(IOKit, "IOServiceGetMatchingService");
CFTypeRef (*IORegistryEntryCreateCFProperty)(mach_port_t entry, CFStringRef key, CFAllocatorRef allocator, uint32_t options) = dlsym(IOKit, "IORegistryEntryCreateCFProperty");
kern_return_t (*IOObjectRelease)(mach_port_t object) = dlsym(IOKit, "IOObjectRelease");
if (kIOMasterPortDefault && IOServiceGetMatchingService && IORegistryEntryCreateCFProperty && IOObjectRelease)
{
mach_port_t platformExpertDevice = IOServiceGetMatchingService(*kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice"));
if (platformExpertDevice)
{
CFTypeRef platformSerialNumber = IORegistryEntryCreateCFProperty(platformExpertDevice, CFSTR("IOPlatformSerialNumber"), kCFAllocatorDefault, 0);
if (CFGetTypeID(platformSerialNumber) == CFStringGetTypeID())
{
serialNumber = [NSString stringWithString:(__bridge NSString*)platformSerialNumber];
CFRelease(platformSerialNumber);
}
IOObjectRelease(platformExpertDevice);
}
}
dlclose(IOKit);
}
return serialNumber;
}
#end
STEP 2. In ApiDefinition.cs of my Binding Library project in Monotouch, I add this binding:
[BaseType (typeof (NSObject))]
public interface DeviceInfo {
[Export ("serialNumber")]
NSString GetSerialNumber ();
}
STEP 3. In my application, I import Reference to Binding library project in step 2, then add
using MyBindingProject;
...
string serialNumber = "";
try {
DeviceInfo nativeDeviceInfo = new DeviceInfo ();
NSString temp = nativeDeviceInfo.GetSerialNumber();
serialNumber = temp.ToString();
} catch (Exception ex) {
Console.WriteLine("Cannot get serial number {0} - {1}",ex.Message, ex.StackTrace);
}
Hope that helps. Don't hesitate if you have any question.
Does anyone know if it's possible to directly send an iMessage using a private framework?
I tried using CTMessageCenter from CoreTelephony but it'll send an SMS even though my phone can send iMessages.
I haven't tested this, but look at the code posted here. If you look at httpResponseForMethod:URI:, you see where he/she sends a message (appears to be hardcode to support iOS 5 or iOS 4):
CKSMSService *smsService = [CKSMSService sharedSMSService];
//id ct = CTTelephonyCenterGetDefault();
CKConversationList *conversationList = nil;
NSString *value =[[UIDevice currentDevice] systemVersion];
if([value hasPrefix:#"5"])
{
//CKMadridService *madridService = [CKMadridService sharedMadridService];
//NSString *foo = [madridService _temporaryFileURLforGUID:#"A5F70DCD-F145-4D02-B308-B7EA6C248BB2"];
NSLog(#"Sending SMS");
conversationList = [CKConversationList sharedConversationList];
CKSMSEntity *ckEntity = [smsService copyEntityForAddressString:Phone];
CKConversation *conversation = [conversationList conversationForRecipients:[NSArray arrayWithObject:ckEntity] create:TRUE service:smsService];
NSString *groupID = [conversation groupID];
CKSMSMessage *ckMsg = [smsService _newSMSMessageWithText:msg forConversation:conversation];
[smsService sendMessage:ckMsg];
[ckMsg release];
} else {
//4.0
id ct = CTTelephonyCenterGetDefault();
void* address = CKSMSAddressCreateWithString(pid);
int group = [grp intValue];
if (group <= 0) {
group = CKSMSRecordCreateGroupWithMembers([NSArray arrayWithObject:address]);
}
void *msg_to_send = _CKSMSRecordCreateWithGroupAndAssociation(NULL, address, msg, group, 0);
CKSMSRecordSend(ct, msg_to_send);
}
The code uses normal SMS, but you can see the following commented out code:
//CKMadridService *madridService = [CKMadridService sharedMadridService];
The "Madrid" service is probably what can send iMessages. See the private header here.
Both SMS and iMessage private APIs are in the ChatKit.framework.
Through a non jailbreak iPhone there is absolutely no access to the iMessage CoreTelephony API