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.
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.
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.
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.
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:
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.