Hack prevention (advice please)


#1

Hey,

I have a client sided app (no server involved) and during testing came across a couple issues regarding hacking.

There is a conceptual membership model and you’re a member if you have got days added to your account.

Doing some really trivial coding and using cheat engine you can modify the number of days you have on your account so in sense call it a membership hack.

To prevent this pragmatically is the following code acceptable?:

Current:
int days;
boolean isMember() {
return days > 0;
}

The new, updated method:

 int days;
 boolean member;

 boolean isMember() { return member; }

 void increment(int days) {
    if (days <= 0) return; 

    this.days += days;
    member = true;
 }

 void decrement(int days) {
    if (days <= 0) return;

    if ((this.days - days) > 0) {
       this.days -= days;
    } else {
       this.days = 0; 
       member = false;
    } 
 }

I don’t think people will be able to modify that boolean using any sort of memory hacking (near impossible, I think).

Is that type of coding style okay? Is there another way I should handle it?

Also in the case, you could change the member, what then? Create a thread that automatically rolls back changes that have been unintentionally performed? (seems bad, but a solution). If it was Java, what’s stopping reflection clients calling the increment method themselves (unless I do some clever redesign)?

All of these mentioned have failed me from going into production.

And any other general tips would be nice.

Thanks!


#2

As a rule, if it’s on a client computer then there’s nothing stopping them from circumventing any controls you put in place.

Of course, different controls have different skill levels required to overcome them. At the simple end of the spectrum you have the historically common case where users simply changed the computer clock.
Then you have more complex circumvention requirements, like delving into the registry.
At the advanced end, you have anything which requires reverse engineering and patching of a binary.

As far as your specific case goes, I don’t understand why you feel the example code you’ve provided is any more secure than any other code you could write.
Why do you feel this is the case when you’ve already pointed out that they have programming skill enough to modify whatever you currently have?


#3

I agree with what you’ve said. What I’m trying to do is make it as hard as possible.

In my example above, it seems (to me anyway) that locating booleans in memory is more of a task than finding integers or floats.
Finding which 1 turns into a 0 (vise versa) during a specific operation can be more tedious. That was my reasoning however I don’t really know many other developers that I can talk to hence why I’m here :stuck_out_tongue:

I also think the average hacker would attempt to modify the “days”. Sure they might be able to see their days change however it wouldn’t affect the usage of the application. Upon realizing that modifying the number did not work, a hacker might quit there. They may suspect it’s a different memory address handling the membership, modifying other integer related values.

In the case the source code for the actual application was some how obtained (e.g. decompiling a jar in Java) then yep, I’m screwed. But I’m using primarily C++ so I should be good?

Regarding other code that I could write. Point some out! The code posted on the thread was only an initial idea I had. If you could find a better code I’m all ears!

My goal is to be as secure as I can. Whether or not a hacker has the skills required isn’t something I’d allow to chance. It’s also a really great learning curve!

Regardless of my situation, I think it makes for a great discussion none the less :slight_smile:


#4

I don’t think it really matters whether it’s an integer or a boolean or something else.
In your particular case, using C++, your threat model is someone who’s already skilled at using a tool like IDA Pro. For someone with that skill set, it’s just a matter of spending the time to isolate the code responsible for the check, and then patching it to do what they want (e.g.: ‘return true’, or ‘return 999’).

If you have a gargantuan application then ‘spending the time’ is a potentially large effort in its own right, and this can dissuade people if they don’t perceive value in doing it (and aren’t simply pursuing kudos).
If you have a small application then the effort is relatively smaller.

When this sort of thing is the case, I guess the best thing you could do is make it tedious.
So instead of adhering to the DRY (Don’t Repeat Yourself) principle, you might repeat the code over and over throughout the code base.
At least then it’s not a case of patching a single location in the binary you produce, but many locations.

Finally, some people make use of strategies such as public/private key encryption to achieve licencing needs. The idea is that you hardcode a public key into your application, and then provide users with a ‘file’ (or just a stream of data from somewhere) that you have generated and then signed with the corresponding private key.
In your case, this stream of data would include whether they’re a member.
If they interfere with the stream of data (which can even be plain text, since you’re using the private key to sign the data rather than encrypt it) then verifying the signature will fail and the application knows that it has been tampered with.

However this is susceptible to reverse engineering as well. Your threat actor simply patches the public key in the application binary so that it uses their own public key, and then they sign their own licence files. Same problem at the end of the day.