(SCE) Sakki's Client Essentials, (Anti-Cheat)

Yeah, you’re right. I was modding the original… but I just recreated a new custom one and i’m getting the same error as you.

Hmmm… I think I wrote this for the old 1.6.4 launcher, so its path to the .jar is written as absolute, not relative. So I think that’s the problem. Gonna try the old launcher…

=======

Edit:

Old launcher no longer works, but i’m certain the problem is that its looking in the old path for the .class files. Just going to focus on the Forge version.

I may get some hate for this, but I want to throw it out there:

I will NOT take anything seriously, that requires WinRAR.

I have nothing against the .rar archive filetype…
…as long as I can open it without buying or pirating [substandard, closed source] third party software.
If I can’t open it with 7zip or a bash shell, I’m not opening it. Period.

1 Like

Ha… same! The only reason I mention WinRAR, is that it is absolutely the only way you’ll be able to copy over those secured .class files.

I mainly use 7z / izArc unless im working with this mod. Once i’m done with the Forge / Sp version, you wont have to do any unarchiving.

OK, I was able to get the 1.6.4 version to launch successfully. I simply renamed all of the _#.class files to the same name but without the _#. Of course this is problematic on Windows so I had to use my linux server to rename & create the jar file.

The first issue I encountered was caused by this piece of code:

if (new Date().after(new Date(1398920400054L))) { // Thu, 01 May 2014 05:00:00 GMT
    throw new Throwable(iiiIIiiiiI.IIiiIiIiIi((String)"tVf@yQ%")); // "EXPIRED!"
}

The client was crashing with “EXPIRED!” because it’s way after May 1st.

After getting by that, I was still able to bypass SCE without making any changes to the client or the server other than installing unmodified versions of SCE & OptiFine. My method is exactly the same as was with 1.7.2:

  • Server: Vanilla 1.6.4 jar with SCE installed. Nothing else.
  • Client: Same thing. “Hack” client: Same thing, but with OptiFine installed (like before).

If you mean by modifying network packets or something like that: No. It’s much more elegant and simple :smiley:

Want me to post the steps on how to do it?

1 Like

<fsdfdfdwdwdwdwdwd

I’m out and about so yes, if u can post those steps so that I can duplicate, that’d be great. Thx!

Oh forgot to tell you, you have to set the permissions server side if u wish to secure those clients. When u open the server console for the first time, it should tell u what usable perms there are. Otherwise, any client can get in. And it’s case sensitive.

Only use PEX so that we’re on the same page.

Curious, does the /sce inspect from the server work?

Yes, I’m using PEX with permissions:

groups:
  default:
    default: true
    permissions:
    - modifyworld.*
    - SCELite.Approved:minecraft01.jar

If I don’t enable my ‘workaround’, I can’t get in with OptiFine.

/sce inspect does work fine:

sce inspect hidendra
14:33:43 [INFO] ... inspecting the client... 
14:33:43 [INFO] -----------------------------------------------------------
14:33:43 [INFO] |      --== Sakki's Client Essentials (SCE) ==--          |
14:33:43 [INFO] |                     Status : Active                     |
14:33:43 [INFO] -----------------------------------------------------------
14:33:43 [INFO]  Inspected player : Hidendra
14:33:43 [INFO]  CUID : C937F439-B4832A29-187625EB4362A51465EED279
14:33:43 [INFO]  JVM Max Memory : 1,011.2 MB
14:33:43 [INFO]  JVM Total Memory : 499.2 MB
14:33:43 [INFO]  JVM Free Memory : 376 MB
14:33:43 [INFO]  JVM Available Processors : 8
14:33:43 [INFO]  Operating System : Windows 8.1
14:33:43 [INFO]  Operation System Version : 6.3
14:33:43 [INFO]  Operating System Architecture : amd64
14:33:43 [INFO]  Java Version : 1.8.0_20
14:33:43 [INFO]  Java Vendor : Oracle Corporation
14:33:43 [INFO]  Java Architecture : 64
14:33:43 [INFO] ----------------------------| Protected by : (SCE)

I’ll make a followup post in a couple mins with the method.

Alright. If you don’t mind I’ll post a tiny bit of the decompiled code to explain my reasoning. (apologies for the long post btw)

In the 1.7.2 SCELite client I happened upon this:

    private static /* synthetic */ String o(String a) { // hash(String filePath)
        int a2;
        MessageDigest a3 = null;
        try {
            a3 = MessageDigest.getInstance(biv.l("\u0019P\u0000*l+q")); // SHA-256
        } catch (NoSuchAlgorithmException a) {
            a.printStackTrace();
        }

        [...]

        StringBuffer a8 = new StringBuffer();
        int n = a2 = 0;
        while (n < a7.length) {
            String string = Integer.toString((a7[a2] & 255) + 256, 16);
            a8.append(string.substring(1));
            n = ++a2;
        }
        return a8.toString();
    }

The function just returns the SHA-256 hash for the given file. The fact that it returns just the SHA-256 hash of the file for this is actually completely meaningless. It could be MD5 or XOR with some key and it’d still work. The important thing was that it was the method that had to be trusted.

So what’s the secret? Modify the JRE. We all trust the JRE, right? In this case, it’s significantly easier than actually modifying your obfuscated mess. I only modified a couple classes inside rt.jar

For example, bypassing the date restriction by modifying java.util.Date:

    public boolean after(Date when) {
        if(getMillisOf(when) == 1398920400054L) {
            return false;
        }

        return getMillisOf(this) > getMillisOf(when);
    }

Yes, I could’ve changed my PC’s date most likely but that’s not as fun.

Now to actually bypass the check: note that StringBuffer is being used to create the final result hash. So instead of modifying the client (and thus changing the hash), the class actually creating the string can tell me it to me … :laughing:

    @Override
    public synchronized String toString() {
        if (toStringCache == null) {
            toStringCache = Arrays.copyOfRange(value, 0, count);
        }

        String value = new String(toStringCache, true);

        System.out.println(value);

        return value;
    }

Then I just re-ran the client to see what I get. Of course, you get a lot of strings but finding what I wanted was easy enough:

C:\Users\Hidendra\AppData\Roaming\.minecraft\versions\1.7.2-sce\1.7.2-sce.jar
2ccddca6223cfcc83b8f0229de15215f63c734cff7963e804cb2c7230a0888ee
bivh
bivh
8b287e2b9e9f1798ff3fbee2d8b9bacf575e3ab268beae03e84081853027ef87
bivh
bivl
bivl
bivl
[...]

(those strings prefixed with biv are the keys for the string decryption calls)

The first string – 2ccddca6223cfcc83b8f0229de15215f63c734cff7963e804cb2c7230a0888ee – is actually the SHA-256 hash exactly for the file 1.7.2-sce.jar. I didn’t really care about that (I didn’t even look at that until later) and blindly forged ahead: I then loaded up my illegal OptiFine client and saw what it spit out:

C:\Users\Hidendra\AppData\Roaming\.minecraft\versions\1.7.2-sce\1.7.2-sce.jar
7a39fdbc92c7d11de96fedb02c2941b47beda0bb93a077d16a5412466a9444af
bivh
bivh
8b287e2b9e9f1798ff3fbee2d8b9bacf575e3ab268beae03e84081853027ef87
bivh
bivl
[...]

Thus the first hash is the one that changes. All I had to do was make StringBuffer/toString() return 2ccddca6223cfcc83b8f0229de15215f63c734cff7963e804cb2c7230a0888ee when it sees 7a39fdbc92c7d11de96fedb02c2941b47beda0bb93a077d16a5412466a9444af. Then it’s done. After that, I could log into the server with my illegal OptiFine client because as far as SCE knew, the hash was identical :slight_smile:

The method was essentially the same with the 1.6.4 version. It seemed like it spit out a couple more hashes, but I did not really care about that and just blindly remapped them to what the clean client gave.

For my exact StringBuffer changes, I did make it a bit easier on myself, so here: https://cryptbin.com/aiU4T4#7279c882098bd430a24733e92a3af9ae (key = input string, value = what to return instead)

This could’ve been done in multiple other ways as well; I just took the easier of the ways.

I do like the idea though and completely agree that something like this is great for stopping common tools like you say.

14 Likes

Ok, just got back. That’s awesome… i’m sure the guys above are having a field day with that. So in essense you determinated the SHA hash of the file, and fed it back to the server via a modified JRE.

Now I know what to counter… just don’t use Java’s built in methods for hash generation!

Now that was a constructive reply / replies, so 'preciate it! I’ll even “like” your reply.

Correct. All that really mattered was making sure the value the hash function returned was the same, not even needing to know it was SHA.

I’m not even sure how you’d counter it in the current implementation. If I wanted to be really nasty, I’m guessing I could have looked at FileInputStream too: when it’s constructed with C:\Users\Hidendra\AppData\Roaming\.minecraft\versions\1.7.2-sce\1.7.2-sce.jar, subtly change it to [...]\1.7.2-sce-clean.jar which if I’m not mistaken would completely avoid having to get the hashes ahead of time.

I wonder how well analysing the loaded classes would work, although not sure how reliable it would be on Forge when mods may be doing their own injections at different points in time.

I’m rolling in the likes today :laughing:

1 Like

I still think that even creating a custom hash function does it.

I haven’t really looked through your code (even if its obfuscated) to say much, but from a logical point of view, even if you would create a method that can determine a difference between two objects that seems 100% secure, modifying the source code at runtime would still allow to just simply return a “true” in the end.

Even if it would be written in C(++/#) instead of java there’s no guarantee that it’s uncrackable. USB-Dongles are the best protection that is currently out there (at least from what I know) but even they will be cracked in the future (I’m sure somebody will come up with a solution). Like @mcmonkey already said; if you keep your code separated - client and server - you still have no way of telling if the client’s a trustable or an un-trustable one using some tricky code to hide it.

Good luck finding something worth using though, this will be an interesting thing to look out for :wink:

2 Likes

yeah, thanks to me and my awesome fans! (I have no fans :slight_smile: )

Well, didn’t you know what method to hit in the JRE (the SHA method) by seeing the SHA code in my code? Because you saw that in my code, you then were able to mod the JRE to intercept the SHA hash.

So would not a custom hash generator not alleviate that issue? I’m thinking it will. If so, then the next problem…

Regarding files on an IO level, same thing applies. Because I’m using built in JRE methods to read/write files, you (the hacker) know what you need to mod in the JRE, however, if I imbed custom code that does that instead of relying on native stuff, and make its functionality as random as possible, and unseemingly pointless, could that not alleviate the IO part of what you mentioned… or at the very least harder to interpret? Take that custom code, Obfuscate it… and it’ll be part of that hard to interpret mess that you mentioned above.

And hey, its appreciated that you even gave this 2 seconds of your time to look at my code. When I started this a year ago, I have not had one single reply with the detail you gave in 1 hours time… not one. I’ll just know that when there is a bug in MCStats that wasn’t fixed, it was prolly due to me.

====

Edit:
disregard some of that stuff above. You didn’t need to know it was SHA, you knew it was using the MessageDigest class, so that’s how you intercepted it.

Well, if its obfuscated, then that custom function will be unreadable and unable to interpret properly. I’m gonna do it just to see what he outcome is.

The code im using is heavily obfuscated. Forge and MC’s code is lightly obfuscated, and there is a big difference in trying to interpret the two.

It’s very easy to convert heavy obfuscation to light obfuscation as discussed above.

I looked above, but not seeing where that is discussed.

@saki2fifty

Right, you can take any Decompiler and make semi-intelligible source from it. Semi. It is still in a highly obfuscated (and broken) state (the source code from the decompiler)

Just in case people don’t feel like reading all of the above, the state SCE is in is this:

SCE was not hacked, instead Hidendra was able to use his “workaround” in order to bypass it… which entailed modding the JRE itself. But, I’m already addressing that.

What you are trying to do is to implement secure remote attestation of software on a malicous host. While the subject of software based remote attestation of software has been met with a lot of scepticism in the scientific comunity, some research papers have been made on the subject[1]. None of them have been as bold as to claim it could work to verify software on a malicous host. And this is the fundemantal problem that you have, an attacker can emulate any function and communication used in the process of the attestation because the attacker has complete controll over the system that is being attestated.

There exists products that does more or less the same thing that you want such as Valve Anti-Cheat and PunkBuster. Proving that it’s not all impossible, it can be done to some degree. They implement a good deal of countermesures to detect modifications of game clients. Probably using challenge and repsonse checks performed at regular intevals. But they still resort to a cat and mouse game to detect cheats that try outsmarts those checks. These products have a team of full time employees that analyses and add countermesures as new cheat techniques appear in the wild in order for the detection to still stay effective.

And this is where you will be at a severe disadvantage. Your attackers have a lot more time at hands to circumvent your anti cheat technology than you have making it. Added with the fact that software is usually a lot easier to break than it is to make, makes the prospects of your anti cheat software rather dim.

In addition to that here is a a few attacks on the top of my head that will be very hard to defend against:

  • Scripted inputs to the game client.
  • Modifying the graphics card driver to to make it render blocks transparently.
  • Modifications to the JVM targeting your checks.
  • Abusing bugs and glitches already present in the game.
  • Attacks using a malicous transparent proxy.

Don’t get me wrong on this. I too would like to have an effective anti-cheat measure to stop cheaters from turning everyone on the server into losers. But I just don’t see how remote attestation could solve it in an effective manner. It’s just too easy to modifiy software. Just take look at the fiasco that every major game publisher that uses DRM ends up with. Broken to bits and uploaded to pirate sites in days.

[1] This paper lists a lot of good referrences https://sparrow.ece.cmu.edu/group/pub/perrig-vandoorn-refutation.pdf

3 Likes

Yep, agreed. And exponentially at that.

Well, thanks for the response (!) and I have to say that I do agree with everything you just said. Well, the majority of it. One of the things though that Valve and others that have on their side when it comes to preventing the client from being hacked, is that the community is so large that they dare risk hacking only to be caught and permanently banned. I think right now there is a wave of bans happening on CSGO because I guess the players got too comfortable, started hacking, and now they are paying for it… losing their accounts and libraries along the way.

But anywho, I think my verbiage initially was too optimistic and unrealistic. I was under the impression that it would had been received a bit more favorably then how it was… but it’s all good, and I was humbled along the way.

When I first created it, it was for those small servers, and I had up to 10 servers using it with no problems. In that sense, it worked… and it worked very well. However, I do realize that all it would take is one hacker to hack it, distribute it… and the mod would be rendered useless.

I don’t underestimate hackers, I think I just worded it very badly in the original post as to my purpose.

Also, SCE wasn’t made to replace current anticheats. It was made to compliment it. NoCheat+ and similar being used for the logical aspect of prevention, and SCE for the heavy handed aspect.

  • Scripted inputs to the game client. (This would be reserved more for Nocheat+ and simliar, as its more logic based and not really SCE’s focus)
  • Modifying the graphics card driver to make it render blocks transparently. (Doable, but would this not be extremely hard to deliver across the board? … due to the number of cards and drivers out there?)
  • Modifications to the JVM targeting your checks (This can be addressed)
  • Abusing bugs and glitches already present in the game. (More reserved for NC+ and similar)
  • Attacks using a malicous transparent proxy (?? Not sure what you mean by this, can you explain?)

But, on the bright side, I’ve addressed those issues Hindendra presented earlier… :smiley:

what are you even doing with this?