In recent business development, we have encountered the situation that our project APP positioning has been tampered with, especially in android terminal. In order to prevent this kind of black production using virtual positioning wool pulling, iOS also had to carry out virtual positioning evasive. After doing technical research, I found that it is difficult to truly achieve virtual positioning by a single mobile phone on aN iPhone, but there is still a possibility. Bugly records of a project app of the company reported that users have used jailbroken iphones, which really makes this kind of behavior really suspicious. With the joint efforts of myself and my company partners, I have roughly investigated the following situations of using virtual positioning (the methods of using Xcode virtual positioning are ignored in this paper) :
One: use a jailbroken phone.
General app users use the jailbreak iphone case, general can infer that the user’s behavior while suspected of wool by competing goods company (or app can do reverse analysis), because buy a new cell phone prison break than buy a normal mobile phone is difficult, and in the use of system upgrade and appstore, all not as good as normal cell phone, I have touched the superficial knowledge of the iPhone5s through jailbreaking app reverse.
Identification mode:
It is suggested to adopt a one-size-fits-all approach. Identify whether the mobile phone is installed with Cydia.app. If so, it is directly judged as a jailbroken mobile phone, and report the information of “device exception” to the background. If you don’t use this way, please continue to read, there will be other ways to solve later. A professional reverse engineer can definitely avoid checking the Cydia installation by app developers. Of course, in this case, the app has a large market share and is used by competitors for reverse analysis. In this case, virtual identification is basically meaningless. Personally, I suggest that you directly lock and stop the interface service of this mobile app. Here’s an article on how developers can tell if an iPhone has been jailbroken.
Code implementation:
/// check whether it is jailbroken device
/// - Returns: true Indicates device jailbreak
func isBrokenDevice(a) -> Bool {
var isBroken = false
let cydiaPath = "/Applications/Cydia.app"
let aptPath = "/private/var/lib/apt"
if FileManager.default.fileExists(atPath: cydiaPath) {
isBroken = true
}
if FileManager.default.fileExists(atPath: aptPath) {
isBroken = true
}
return isBroken
}
Copy the code
Second: use ace assistant.
For scenarios where virtual location is used, most drivers or docking personnel should punch in. In this case, it is possible that a new crop of black sheep is being harvested using virtual location-based methods. For Apple phones, at present, can be very possible to achieve, when the ace assistant virtual location function.
Usage steps: Download ace Assistant MAC client, connect to iPhone, click virtual location in toolbox, select location on the map, and then click Modify virtual location to modify the location information of the map.
Principle: USB connection is made between computer and mobile phone on unjailbroken device. Computer sends simulated coordinate data to DTSimulateLocation service on mobile phone through special protocol to achieve false location. At present, built-in location simulation in Xcode is achieved with the help of this technology. (Source)
Identification mode:
I. Through recording the virtual positioning data of Ace’s assistant for many times, it is found that the height of longitude and latitude of its virtual positioning information is 0, and the data bits of longitude and latitude are also worth studying. The real and virtual positioning data are shown below:
The real location
The virtual orientation
A closer look at the data shows that the black hat of virtual positioning can be easily broken if we compare the height of the location information and also check the double digits of latitude and longitude. So if we compare the height of virtual positioning to 0, it is regarded as virtual positioning, then there will be a question, the real altitude is zero location, how to solve? Here under the popular science of China’s altitude zero position, China level zero is located in Qingdao East Sea road silver Sea world, “the People’s Republic of China level zero”, is the only level zero in China. Unique leveling zero. At the same time, because of the comparison of the double digits of latitude and longitude, it is found that the number of digits of virtual positioning is obviously wrong. By checking the precision of swift float and double digits, it is found that the longitude and latitude data of virtual positioning only meet the double precision digits perfunctorily. The effective number of swift float is 7. The significant digit of a double is 15. Of course, the weight of this comparison is relatively low. The author just updated the version of Ace Assistant and found that the latitude and longitude of the new version is more detailed, but it still fails to reach the effective digit level of double. Relative to the current ace assistant height comparison recognition for virtual positioning, has been completely possible to do
Code implementation:
If location.altitude == 0.0 {print(" virtual location ")} // If the number is less than 12, then it is considered to be virtual, But as small weight of abnormal data record or can let longitude = location. Coordinate. The longitude let longitudeStr = "\(longitude)".components(separatedBy: "."). Last?? "" longitude: \(longitude r.count)") if longitude < 12 {print(" longitude ")}Copy the code
Second, the longitude and latitude of the data after positioning is sent up to the background, and then the background obtains detailed longitude and latitude information according to the received longitude and latitude, and makes a depth comparison of the geographical information of the driver except the longitude and latitude. Priority is given to the comparison of Altitude, horizontalAccuracy and verticalAccuracy. Based on whether the values are equal, determine.
Three,
(1) By obtaining the public IP address, you can obtain the general location based on the IP address through the interface, but the error range is a little large.
Var ipAddress: String? { let ipUrl = URL(string: "https://ipof.in/txt")! let ip = try? String.init(contentsOf: ipUrl, encoding: .utf8) return ip }Copy the code
(2) Read the position of app through Wi-Fi hotspot
(3) using CLCircularRegion to set the specified latitude and longitude of the regional center and the range of configurable radius for monitoring.
Code brief implementation:
Manager = CLLocationManager() // Set location services manager agent manager? .delegate = self // Set the location mode manager?. DesiredAccuracy = kCLLocationAccuracyBest // Update distance manager?. DistanceFilter = 100 / / send the authorization application manager?. RequestWhenInUseAuthorization () let latitude = 115.47560123242931 let longitude = 29.9757535600194 let centerCoordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude) let locationIDStr = "" let clRegion = CLCircularRegion(center: centerCoordinate, radius: 100, identifier: StartMonitoring (for: clRegion) agent func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) { } func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) { }Copy the code
(4) through IBeacon technology, use the CBPeripheralManager under the CoreBluetooth framework to establish a bluetooth base station. This positioning is directly end-to-end, eliminating GPS satellite and cellular data communication from the base station.
Code brief implementation:
func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) { for beacon in beacons { var proximityStr: String = "" switch beacon.proximity { case .far: proximityStr = "Unknown" case .immediate: proximityStr = "Immediate" case .near: proximityStr = "Near" case .unknown: ProximityStr = "Unknown"} var beaconStr = "+ beacon. ProximityUUID. UuidString +" major: "+ beacon. Major. StringValue +" minor: "+ beacon. Minor. StringValue +" distance: \(Int64(beacon.rssi))" + "proximityStr print("beacon info: \(beaconStr)") } } func locationManager(_ manager: CLLocationManager, rangingBeaconsDidFailFor region: CLBeaconRegion, withError error: Error) { } ---------------------------------------------------------------------------------- / / can't create a class alone observe CBPeripheralManagerDelegate agreement, need to abide by the NSObjectProtocol agreement, Here directly inherited NSObject class CoreBluetoothManager: NSObject, CBPeripheralManagerDelegate {/ / build a bluetooth base station. lazy var peripheralManager: CBPeripheralManager = CBPeripheralManager(delegate: self, queue: DispatchQueue.main, options: nil) lazy var region: CLBeaconRegion = { guard let uuid = UUID(uuidString: "xxx") else { return CLBeaconRegion() } let major: CLBeaconMajorValue = 1 let minor: CLBeaconMajorValue = 1 let ID = "Name of the created Bluetooth base base" let region = CLBeaconRegion(proximityUUID: UUID, major: major, minor: minor, identifier: id) return region }() func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) { switch peripheral.state { case CBManagerState.poweredOn: if let data = self.region.peripheralData(withMeasuredPower: nil) as? [String : Any] { self.peripheralManager.startAdvertising(data) } case CBManagerState.poweredOff, CBManagerState.resetting, CBManagerState.unauthorized, CBManagerState.unsupported, CBManagerState.unknown: break } } func peripheralManagerDidStartAdvertising(_ peripheral: CBPeripheralManager, error: Error?) {}}Copy the code
4 (to be improved), the solution attached to the end of this article I have tried, layer by layer through KVC read CLLocation _internal fLocation, can only read up to this. The following error will be reported when reading from KVC:
Expression can't be run, because there is no JIT compiled function
Copy the code
Further research, I found this explanation in apple’s official development documentation, there is also said to set debug+ optimization policy, but the iOS default bug environment is -onOne level. The main reason seems to be that the JIT Settings are found in the Signature &Capabilities Hardened Runtime at the time of MAC client development. Allow Execution of JIT-compiled Code If there is another way to read the actual location of CLLocation (which is a perfect solution), please let me know.
The attached:
CLLocation object private variable _internal instance object official definition:
@interface CLLocationInternal : NSObject {
struct {
int suitability;
struct {
double latitude;
double longitude;
} coordinate;
double horizontalAccuracy;
double altitude;
double verticalAccuracy;
double speed;
double speedAccuracy;
double course;
double courseAccuracy;
double timestamp;
int confidence;
double lifespan;
int type;
struct {
double latitude;
double longitude;
} rawCoordinate;
double rawCourse;
int floor;
unsigned int integrity;
int referenceFrame;
int rawReferenceFrame;
} fLocation;
CLLocationMatchInfo * fMatchInfo;
double fTrustedTimestamp;
}
Copy the code
@class NSData;
@interface CLLocationMatchInfo : NSObject <NSCopying.NSSecureCoding> {
id _internal;
}
@property (nonatomic.readonly) long long matchQuality;
@property (nonatomic.readonly) CLLocationCoordinate2D matchCoordinate;
@property (nonatomic.readonly) double matchCourse;
@property (nonatomic.readonly) int matchFormOfWay;
@property (nonatomic.readonly) int matchRoadClass;
@property (getter=isMatchShifted,nonatomic.readonly) BOOL matchShifted;
@property (nonatomic.copy.readonly) NSData * matchDataArray;
Copy the code