1
\$\begingroup\$

I'm thinking about porting my game to Google Play, and it would be free to play with time gates which are skippable if you watch an ad.

What are the ways of implementing an unhackable time gating?

  • Is it possible without internet connection? If yes, how?

  • If no, is there a way to implement it without custom backend, using Google Play's services?

Or should I care about this at all? Because...

  • It doesn't affect other players...

  • Most of the audience couldn't do it anyway, and if the game stays small, hacks couldn't really spread.

  • Then maybe I should just let them hack those time gates, it's a marginal revenue loss.

What do you think?

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Without an Internet connection, your code is in the hands of the enemy, and everything is hackable. The only way to provide a security guarantee is to put the code/assets on a device you or a trusted party controls and the hacker can't touch except through an API that obeys your game's rules. As to "should you care about this at all" - that's a judgement call you'll need to make for yourself. Different games use different business models that rely more or less on ad/purchase revenue to pass gates, and different developers have different risk tolerance here. \$\endgroup\$
    – DMGregory
    Commented Apr 29, 2020 at 17:21
  • \$\begingroup\$ A lot of mobile games that are ad-supported just automatically skip the ad if you turn off your internet connection, presumably because it's not worth the bother to fight people who are willing to put in effort to avoid the ads. \$\endgroup\$
    – Foxwarrior
    Commented Apr 29, 2020 at 17:42

1 Answer 1

2
\$\begingroup\$

We don’t worry about unhackability in our games. It’s not worth it. We just worry about making sure it works in the simpler, more frequent cases of the user changing their device clock, restarting their device, etc. As long as you don’t worry about people decompiling your code, it gets really simple.

You can put in checks to make sure your app isn’t a hacked version, and if it is, behave differently. We had experimented with that in the past, but ended up removing it since it didn’t really help or hurt much. Those checks only work if the hacker doesn’t find them as well, so they would need to be subtle if you want to avoid the hacker finding a workaround.

All that said, we have never seen hackers with a lot of intelligence hack our games. Generally it’s just people who don’t even play the game see that there is a new game that has virtual currency in it, swoop in and change the code to report an infinite balance, and release it with minimal/no testing. Half the time it doesn’t even work. Presumably we are not a big enough target. You probably won’t be either.

How to handle timing locally:

On launch, fetch and store (in a file) the current value of a non-modifiable clock (NMC), eg. CLOCK_MONOTONIC in native C, or SystemClock.elapsedRealtime() in Java. You will also need to track a known elapsed time (KET), starting at zero. Or, if you happen to have a known accurate time (eg. from a server) then you can use that value.

At any point, you can be certain that the KET is no less than the stored KET plus the current value of the NMC minus the stored NMC (assuming the device itself is not running its clock quickly, which I have never seen).

The source for the NMC value is generally a time since the device booted, meaning that if the user resets their device, that value also resets. You can therefore not be certain at any point that you have the actual KET, unless you are also tracking the time from a server, but you can be sure it isn’t past that, which is sufficient for time-gating.

On app close, store the current value of the NMC and the current KET (equal to the KET on launch plus the current NMC minus the stored NMC). Then check on launch if the current NMC is less than the stored NMC. If it is, then you know the KET is at least the stored KET plus the current value of the NMC (the user loses the amount of time between last app close and device reboot). Otherwise (the current value of the NMC is greater than the last stored NMC), the only thing you know is that the KET is the current value of the NMC, minus the stored NMC, plus the stored KET. This is the normal case when the user does not reboot their device, and will guarantee an accurate elapsed time tracker.

Normally, the KET is only advanced by the difference in values of stored NMC and current NMC. If you bring a server into the mix, the KET can also be advanced by differences in server time so that the user can restart their device and have their KET stay up to date (not losing time between last app close and device reboot). To do this, you can store KETs based on the NMC and the server. On launch, if you don’t have server access, use the NMC-based KET. If you do have server access, use the server-based KET and update the NMC-based KET at the same time.

\$\endgroup\$
0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .