I am building an app like RootMetrics - Cell Phone Coverage link https://itunes.apple.com/us/app/cell-phone-coverage-map/id399701910 here
or OpenSignal - https://itunes.apple.com/app/opensignal/id598298030
I need help to understand how they measure call/voice quality. As far as I understand such APIs are private and apps using them, would not be authorized on App Store. Can anyone tell me how to measure signal strength in such cases.
I do not believe this is possible without the use of private API:s. And as you said, Apple's bots will probably (definitely) find out when you try to upload the app to App Store.
If you still want to use a private API, this method for measuring carrier signal strength should to the trick:
-(int) getSignalStrength() {
void *libHandle = dlopen("/System/Library/Frameworks/CoreTelephony.framework/CoreTelephony", RTLD_LAZY);
int (*CTGetSignalStrength)();
CTGetSignalStrength = dlsym(libHandle, "CTGetSignalStrength");
if( CTGetSignalStrength == NULL)
NSLog(#"Could not find CTGetSignalStrength");
int result = CTGetSignalStrength();
dlclose(libHandle);
return result;
}
I would suggest taking the average value of about 10 measurements since I believe that these can differ a lot.
Related
Assume I have an iPhone connected to a wifi network with 3+ access points.
I'd like to collect all possible fields around wifi access strength/signal/etc from EACH access point and use that to triangulate, even while in background.
while true {
...
for access_point in access_points {
...
signal_strength = ...
}
}
I've been reading previous SO answers and other posts, and seems like it wasn't allowed on iOS without a jailbreak for a while, but is now availiable again.
Anyone can show a code snippet of how I'd go about doing this? All new to iOS development..
It's been quite a while since I worked with this, so I did a quick check again and now I am fairly certain you misunderstood something you've read. As far as I can tell, Apple did not suddenly revert their previous decision to restrict the public frameworks to scan for access points, i.e. specific MAC addresses and their signal strength.
You can query the specific rssi (signal strength) for a network (i.e. for an ssid), but not for individual MAC addresses. Before iOS 5 you could do that using private APIs, then you could do it with private APIs on a jailbroken device and that's pretty much it.
I don't have the code of my own, old stuff at hand (I used to do this for indoor location tracking before we switched to use iBeacons), so I can't provide you with a sample snippet myself. My code is dated and no longer functioning anyways, but you might find something here.
I would be really interested in the sources you mention that claim iOS 10 now allows this again. Apple closed this for privacy considerations (officially at least, and although this might be true in part it also means developers dealing with location-tracking now need to rely fully on Apple's framework for that only), so I highly doubt they went back on it.
Also, note that this is for sure not something trivial, especially if you're new to iOS development. I haven't even tackled the background idea, you can safely forget about that, because no matter what you do, you will not have a scanner that runs continuously in the background. That's against a very core principle of iOS programming.
I've answered how to ping ALL wifi networks in this question;
func getInterfaces() -> Bool {
guard let unwrappedCFArrayInterfaces = CNCopySupportedInterfaces() else {
print("this must be a simulator, no interfaces found")
return false
}
guard let swiftInterfaces = (unwrappedCFArrayInterfaces as NSArray) as? [String] else {
print("System error: did not come back as array of Strings")
return false
}
for interface in swiftInterfaces {
print("Looking up SSID info for \(interface)") // en0
guard let unwrappedCFDictionaryForInterface = CNCopyCurrentNetworkInfo(interface) else {
print("System error: \(interface) has no information")
return false
}
guard let SSIDDict = (unwrappedCFDictionaryForInterface as NSDictionary) as? [String: AnyObject] else {
print("System error: interface information is not a string-keyed dictionary")
return false
}
for d in SSIDDict.keys {
print("\(d): \(SSIDDict[d]!)")
}
}
return true
}
You may have seen this feature in jailbroken apps as it is possible to do this using private libraries, which means that apps that are sold on the iOS store can't be sold if they utilise them.
I am building an iOS app that transmits sensitive data to my server, and I'm signing my API requests as an additional measure. I want to make reverse engineering as hard as possible, and having used Cycript to find signing keys of some real-world apps, I know it's not hard to find these keys by attaching to a process. I am absolutely aware that if someone is really skilled and tries hard enough, they eventually will exploit, but I'm trying to make it as hard as possible, while still being convenient for myself and users.
I can check for jailbroken status and take additional measures, or I can do SSL pinning, but both are still easy to bypass by attaching to the process and modifying the memory.
Is there any way to detect if something (whether it be Cycript, gdb, or any similar tool that can be used for cracking the process) is attached to the process, while not being rejected from App Store?
EDIT: This is not a duplicate of Detecting if iOS app is run in debugger. That question is more related to outputting and it checks an output stream to identify if there's an output stream attached to a logger, while my question is not related to that (and that check doesn't cover my condition).
gdb detection is doable via the linked stackoverflow question - it uses the kstat to determine if the process is being debugged. This will detect if a debugger is currently attached to the process.
There is also a piece of code - Using the Macro SEC_IS_BEING_DEBUGGED_RETURN_NIL in iOS app - which allows you to throw in a macro that performs the debugger attached check in a variety of locations in your code (it's C/Objective-C).
As for detecting Cycript, when it is run against a process, it injects a dylib into the process to deal with communications between the cycript command line and the process - the library has part of the name looking like cynject. That name doesn't look similar to any libraries that are present on a typical iOS app. This should be detectable with a little loop like (C):
BOOL hasCynject() {
int max = _dyld_image_count();
for (int i = 0; i < max; i++) {
const char *name = _dyld_get_image_name(i);
if (name != NULL) {
if (strstr(name, "cynject") == 0) return YES;
}
}
}
Again, giving it a better name than this would be advisable, as well as obfuscating the string that you're testing.
These are only approaches that can be taken - unfortunately these would only protect you in some ways at run-time, if someone chooses to point IDA or some other disassembler at it then you would not be protected.
The reason that the check for debugger is implemented as a macro is that you would be placing the code in a variety of places in the code, and as a result someone trying to fix it would have to patch the app in a variety of places.
Based on #petesh's answer, I found the below code achieved what I wanted on a jailbroken phone with Cycript. The existence of printf strings is gold to a reverse engineer, so this code is only suitable for demo / crack-me apps.
#include <stdio.h>
#include <string.h>
#include <mach-o/dyld.h>
int main ()
{
int max = _dyld_image_count();
for (int i = 0; i < max; i++) {
const char *name = _dyld_get_image_name(i);
const char needle[11] = "libcycript";
char *ret;
if ((ret = strstr(name, needle)) != NULL){
printf("%s\nThe substring is: %s\n", name, ret);
}
}
return 0;
}
As far as I know, Cycript process injection is made possible by debug symbols. So, if you strip out debug symbols for the App Store release (the default build setting for the Release configuration), that would help.
Another action you could take, which would have no impact on the usability of the App, would be to use an obfuscator. However, this would render any crash reports useless, since you wouldn't be able to make sense of the symbols, even if the crash report was symbolicated.
I know it is possible to check the traffic usage of wifi and Data through built-in settings in iphone. But is there any solution like a library or function to fetch realtime network usage (upload/download) of the device? (like a real time netstat)
Reachability is one of the things that I found with regard to the mentioned.
http://developer.apple.com/library/ios/#samplecode/Reachability/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007324-Intro-DontLinkElementID_2
this app does something similar:
https://itunes.apple.com/us/app/data-control-manage-data-usage/id390646992?mt=8
Does anyone know what class to call or look for what certain method to access the real time traffic?
I hope that my question is understandable.
There is no high level API to support this, but since iOS is simply a rather pretty unix, you can of course go to the standard APIs.
In this case you would be looking for getifaddrs, which retrieves the in memory structures describing the various interfaces on the device.
You then have to parse these C structures, to get the interface details you want.
The getifaddr interface is documented ( man getifaddr), so you can use this.
I'll add a bit of code, but first a few caveats.
Apple don't really bother maintaining this stuff, so the network counts are 32 bit, so you have to handle 4Gb roll over.
The packet counts are mostly there, I think the tx packet count is always 0, but who is interested in packet counts anyway.
You can probably find better code here by searching for getifaddrs, but here is a short version to get you started.
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <net/if_var.h>
struct ifaddrs* addrs;
int getIFAddrsResult = getifaddrs(&addrs);
if (getIFAddrsResult == 0)
{
struct ifaddrs* addrsPtr = addrs; // need to keep original for freeifaddrs
while (addrsPtr != NULL)
{
NSString *name = [NSString stringWithFormat:#"%s",addrsPtr->ifa_name];
//NSLog(#"ifa_name %s == %#\n", cursor->ifa_name,name);
// names of interfaces: en0 is WiFi ,pdp_ip0 is WWAN
if (addrsPtr->ifa_addr->sa_family == AF_LINK)
{
const struct if_data* stats = (const struct if_data *) addrsPtr->ifa_data;
// We only consider the active data interface, and that will normally be the '0' interface.
if ([name isEqualToString:#"en0"])
{
// Wifi
// look at stats->ifi_obytes & ifi_ibytes
} else if ([name isEqualToString:#"pdp_ip0"])
{
// mobile broad band
} else {
// could be bluetooth, usb, ad hoc wifi, out of band signalling...
}
}
addrsPtr = addrsPtr->ifa_next;
}
freeifaddrs(addrs);
} else {
NSLog(#"getifaddrs failed with error : %s", strerror(getIFAddrsResult));
return nil;
}
P.S. I'm going for my diamond resurrect old questions badge :)
There is no such API in iOS, the App that you mentioned (and all similar apps), rely on an API provided by the carrier (or parsing the carriers website). If you want to implement this kind of App, I'm afraid you have to find something for every possible carrier you are interested in.
I've tried several techniques to capture a screenshot of an app from within that app. None of the techniques appear to capture the status bar -- it ends up being black.
There apparently was once a way to do this, but that interface is internal and Apple will not let you use it.
Any ideas?
Note: This is an attempt to solve this problem, where I need to determine if airplane mode is on or off (and no, simply knowing if the network is reachable is not sufficient).
However, it would seem that this question is of more general interest, and is distinct from that question.
Your actual issue, determining if a network interface is active, can be resolved with BSD networking functions. BEHOLD.
#include <sys/socket.h>
#include <ifaddrs.h>
#include <net/if.h>
BOOL IsNICTurnedOn(const char *nicName) {
BOOL result = NO;
struct ifaddrs *addrs = NULL;
if (0 == getifaddrs(&addrs)) {
for (struct ifaddrs *addr = addrs; addr != NULL; addr = addr->ifa_next) {
if (0 == strcmp(addr->ifa_name, nicName)) {
result = (0 != (addr->ifa_flags & (IFF_UP | IFF_RUNNING)));
break;
}
}
freeifaddrs(addrs);
}
return result;
}
To use this function:
BOOL isWWANEnabled = IsNICTurnedOn("pdp_ip0");
BOOL isWiFiEnabled = IsNICTurnedOn("en0");
At this point it seems clear that there is no simple way to detect if Airplane Mode is enabled. Although you could probably infer it by looking at low-level network stack info or scraping status bar pixels, either method would be relying on undocumented behavior. It's very possible that on a future release of iOS or a future iOS device, the behavior will change and your code will generate a false positive or false negative.
(Not to mention that, on future devices, the interference may not even be there.)
If I were in your shoes, I would:
File a bug to let Apple know you want this feature.
Work the notice into the app, regardless of whether Airplane Mode is enabled. Yes, it might be kind of annoying to the user if it is enabled, but the overall harm is minimal. I would probably make this an alert that pops up only once (storing a key in NSUserDefaults to indicate whether its already been displayed).
If you want to get super-fancy, analyze the recorded audio and, if the buzz is detected, remind the user again to enable Airplane Mode while recording. You could do this in real time or after the clip has been recorded, whatever makes more sense for your app.
As an alternative solution, perhaps you could detect the connection type, similar to: https://developer.apple.com/library/ios/#samplecode/Reachability/Introduction/Intro.html . With some additional checking for the device type, you could then warn the user only in the case where they need to act.
Kind of a different approach, but you can also link to pages within the Settings application. You could perhaps link to the primary page and tell the user the changes you require.
There appears to be no way to do this.
I'm looking for something corresponding to net.rim.device.api.system.ApplicationManager.getVisibleApplications(), but including applications that might not/do not have a UI. Any ideas?
Unreasonably complicated work-around solutions welcome, I'm growing slowly more sure that there's not a simple single call to do this...
If you know the application name you can detect if it is running or not by checking the size of the array containing all AppDescriptor actually running this app.
int codeModuleHandle = CodeModuleManager.getModuleHandle(applicationPackageName);
if (codeModuleHandle != 0) {
ApplicationDescriptor[] apDes = CodeModuleManager.getApplicationDescriptors(codeModuleHandle);
}
You could imagine a code to get all installed application and then check