简体   繁体   中英

Is it possible to detect sideloaded, re-signed, or modified iOS apps at runtime?

I'm a developer on an iOS and Android game. After releasing several updates, we've found a few websites that offer hacked versions of the game to give players an unfair advantage. Since this game has player-vs-player elements, we'd ideally like to stop these hacked versions from being used because it ruins the experience for players who aren't cheating.

We have found some ways to combat this problem on Android, but we've thus far haven't found good ways to deal with iOS.

We recently found a hack that involves side-loading a hacked IPA using "Cydia Impactor" and installing a custom provisioning profile. We'd like to be able to detect this so that we can disallow such players from polluting the player-vs-player ecosystem.

It seems like there are potentially three things we could detect in this situation:

  1. The iOS app is modified in some way (IPA file contains extra code or modified files). We're not sure whether it is possible for an iOS app to "introspect" its own installed files and identify changes at runtime?

  2. The iOS app was not installed via the App Store. Again, maybe something we can detect at runtime? But there may be some valid scenarios where this could occur with a non-hacked app, I suppose.

  3. The iOS app is (seemingly) re-signed or using a different provisioning profile. At the very least, detecting that the app is using a different signature than it was originally submitted to the app store with seems like something we'd never want to allow.

Admittedly, I am not super familiar with iOS app programming (we use a cross-platform game engine mostly). So, I'm not sure if any of those are easily detectable, or whether iOS "officially" supports any of these methods to detect insecure or hacked apps.

Ideally, we'd want the client to be able to report some sort of generated identifier/checksum/fingerprint to our server. Something like this would avoid the obvious client-side hack of making the "IsHacked" function always return false!

Has anyone had experience or success detecting any of the above situations? If so, are there any resources or documentation about the right way to detect such things?

Another Instrumentation Framework

We recently found a hack that involves side-loading a hacked IPA using "Cydia Impactor"...

Another tool that is often used in iOS it's Frida:

Inject your own scripts into black box processes. Hook any function, spy on crypto APIs or trace private application code, no source code needed. Edit, hit save, and instantly see the results. All without compilation steps or program restarts.

In App Decisions

Ideally, we'd want the client to be able to report some sort of generated identifier/checksum/fingerprint to our server. Something like this would avoid the obvious client-side hack of making the "IsHacked" function always return false!

Unfortunately an attacker can always return the same identifier/checksum/fingerprint by using the same technique to make IsHacked return always false . This is normally achieved with the use of an instrumentation framework, that will hook into the code at runtime, and return always the identifier/checksum/fingerprint for the genuine mobile app.

Any solutions that rely on client side decisions to check integrity/authenticity of the device or mobile app, can be bypassed by instrumentation frameworks.

iOS DeviceCheck

So, I'm not sure if any of those are easily detectable, or whether iOS "officially" supports any of these methods to detect insecure or hacked apps.

I have seen many developers turning to the iOS DeviceCheck to solve this type of issue, but normally they miss the point and goals of DeviceCheck:

Apple's DeviceCheck solution is primarily designed to validate the identity and track record of a physical mobile device without the need to track any personal information about the device or its user:

Using the DeviceCheck APIs, in combination with server-to-server APIs, you can set and query two bits of data per device, while maintaining user privacy. You might use this data to identify devices that have already taken advantage of a promotional offer that you provide,...

However, it is important to note that the responsibility for identification of the status of the device, ie did it already redeem a reward, has it shown abusive behavior, has it been guilty of fraud, etc. is with the developer:

... or to flag a device that you've determined to be fraudulent. The DeviceCheck APIs also let you verify that the token you receive comes from an authentic Apple device on which your app has been downloaded.

That's great that we can verify that the DeviceCheck token comes from an authentic iOS device, but developers should not underestimate the additional effort required to identify devices, in particular those which engage in abuse and fraud, because of the already mentioned instrumentation Frameworks, that may not be detected or may bypass the DeviceCheck.

So DeviceCheck can say something about the device authenticity, but cannot say anything about the mobile app authenticity, it's your mobile app the exact same one you uploaded to the Apple store, his it being instrumented by a framework like Frida, it's being object of a Man in the middle(MitM) attack? This are all things that are out of the scope of the DeviceCheck, and the ones you are looking to protect against.

Possible Solution

Has anyone had experience or success detecting any of the above situations?

Detecting a mobile app authenticity/integrity is achievable with a very high degree of confidence with an external Mobile App Attestation solution, aka a service that will not make the decisions in the mobile app or the device its running on, instead it will use an external server to make the decisions, that will send random challenges to the mobile app in order to determine its authenticity/integrity. You can read more about in article I wrote, specifically in the section, The role of Mobile App Attestation :

Before we dive into the role of a Mobile App Attestation service, we first need to understand the difference between what and who is accessing the API server. This is discussed in more detail in this article, where we can read:

The what is the thing making the request to the API server. Is it really a genuine instance of your mobile app, or is it a bot, an automated script or an attacker manually poking around your API server with a tool like Postman?

The who is the user of the mobile app that we can authenticate, authorize and identify in several ways, like using OpenID Connect or OAUTH2 flows.

The role of a Mobile App Attestation service is to authenticate what is sending the requests, thus only responding to requests coming from genuine mobile app instances and rejecting all other requests from unauthorized sources.

In order to know what is sending the requests to the API server, a Mobile App Attestation service, at run-time, will identify with high confidence that your mobile app is present, has not been tampered/repackaged, is not running in a rooted device, has not been hooked into by an instrumentation framework(Frida, xPosed, Cydia, etc.), and is not the object of a Man in the Middle Attack (MitM). This is achieved by running an SDK in the background that will communicate with a service running in the cloud to attest the integrity of the mobile app and device it is running on.

On a successful attestation of the mobile app integrity, a short time lived JWT token is issued and signed with a secret that only the API server and the Mobile App Attestation service in the cloud know. In the case that attestation fails the JWT token is signed with an incorrect secret. Since the secret used by the Mobile App Attestation service is not known by the mobile app, it is not possible to reverse engineer it at run-time even when the app has been tampered with, is running in a rooted device or communicating over a connection that is the target of a MitM attack.

The mobile app must send the JWT token in the header of every API request. This allows the API server to only serve requests when it can verify that the JWT token was signed with the shared secret and that it has not expired. All other requests will be refused. In other words a valid JWT token tells the API server that what is making the request is the genuine mobile app uploaded to the Google or Apple store, while an invalid or missing JWT token means that what is making the request is not authorized to do so, because it may be a bot, a repackaged app or an attacker making a MitM attack.

When implementing a Mobile App Attestation by yourself always keep in mind that the SDK you ship with the mobile app must not make any decisions, and must use certificate pinning in the communication channel with the server that launches the challenges and makes the decisions.

GOING THE EXTRA MILE

I always like to recommend the excellent resource from OWASP, the OWASP Mobile Security Testing Guide :

The Mobile Security Testing Guide (MSTG) is a comprehensive manual for mobile app security development, testing and reverse engineering.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM