Post

Cracking Francium Client

Discovery

I was originally sent the client by a close friend of mine who bought it and then suggested I crack it. The file I was sent was called appleskin-fabric-mc1.19-2.4.1.jar after opening the jar in Recaf I found that it was simply the mod from Modrinth with no changes, or so I thought.

After looking closer in the META-INF/jars folder I discovered 2 .jar files called cloth-config-fabric-7.0.65.jar and org_apache-5.2.1.jar I opened both of these in Recaf and found that one of them looked suspicious.

Recaf workspace

I had found it, the client was hidden in plain sight.

Analysis

Main.class

I started by looking at the Main class and inspecting the onInitialize method which is called when the client is loaded by the fabric loader.

Recaf workspace Main.class

I found an instruction invokedynamic protected_by_eskid, which indicated that the client was protected by Eskid, an obfuscator I hadn’t heard of in a while. However, this wasn’t a significant issue as the obfuscation was fairly weak, and I could easily read the bytecode. I was more interested in the getstatic org/apache/core/Client.INSTANCE Lorg/apache/core/Client; instruction, which led me to the Client class.

Client.class

The first method that caught my eye was load as it was nearest the top.

Recaf workspace Client.class load()

This method sent a request to a server to check if the user running the client was whitelisted. If they were not, then the client would close. However, the method had an unusual way of checking if the server’s response was valid. Upon reviewing the code, I noticed an if statement that, if true, would call another method called init() and then return, effectively ignoring the rest of the code.

Recaf workspace Client.class init()

Here, I discovered that this method was responsible for loading the entire client.

Cracking

Now that I had found the init() method and knew that it was responsible for loading the client, I could easily crack it by just stopping the call to load() from onInitialize and calling init() instead.

Instead of editing the bytecode of the original jar I decided to just make a simple mod that would call init() instead of load(). So I changed the main entrypoint of Francium to com.thnkscj.franciumcracked.FranciumCracked.

Before:

Recaf workspace fabric.mod.json

After:

Recaf workspace fabric.mod.json after

I then created a new class called FranciumCracked and added the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.thnkscj.franciumcracked;

import net.fabricmc.api.ModInitializer;
import org.apache.core.Client;

public class FranciumCracked implements ModInitializer {
    public void onInitialize() {
        System.out.println("____ ____ ____ _  _ ____ _ _  _ _  _ ");
        System.out.println("|___ |__/ |__| |\ | |    | |  | |\/| ");
        System.out.println("|    |  \ |  | | \| |___ | |__| |  | ");
        System.out.println("                                     ");
        System.out.println("Cracked by Thnks_CJ | github.com/ThnksCJ");
        Client.INSTANCE.init();
    }
}

In my IDE I created a dummy class called org.apache.core.Client and added the following code:

1
2
3
4
5
6
7
8
9
package org.apache.core;

public class Client {
    public static Client INSTANCE = new Client();

    public void init() {

    }
}

So that the code would compile. I spliced the 2 jars together and loaded Francium. It worked! I had cracked Francium by simply calling init() instead of load().

Overview

This was a very simple crack, and I could have easily edited the bytecode of the original jar, but it was obfuscated and I was feeling lazy, so this approach was much easier. This serves as an example of how NOT to protect your client. I would advise using a better obfuscator and inlining the init() method into load(). Instead of calling init() from load(), you could have the code from init() directly in load(). This would make it a bit harder to crack.

This post is licensed under CC BY 4.0 by the author.