Skip to content

Instantly share code, notes, and snippets.

@RecursiveG
Created December 31, 2015 03:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save RecursiveG/db028f46821ccc832005 to your computer and use it in GitHub Desktop.
Save RecursiveG/db028f46821ccc832005 to your computer and use it in GitHub Desktop.
Cracked Version of AntiCheat3 (http://www.mcbbs.net/thread-525761-1-1.html). To show how vulnerable and unreliable a client-mod based Minecraft anticheat system could be.
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.IResource;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommand;
import net.minecraft.command.ICommandSender;
import net.minecraft.crash.CrashReport;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.network.PacketBuffer;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.util.BlockPos;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.StringUtils;
import net.minecraft.world.WorldServer;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.common.config.Property;
import net.minecraftforge.fml.common.*;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.PlayerEvent;
import net.minecraftforge.fml.common.network.FMLEventChannel;
import net.minecraftforge.fml.common.network.FMLNetworkEvent;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.network.internal.FMLProxyPacket;
import net.minecraftforge.fml.relauncher.FMLInjectionData;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.apache.logging.log4j.Level;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.net.URLDecoder;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
@Mod(modid = AntiCheat3Cracked.MODID, name = AntiCheat3Cracked.NAME, version = AntiCheat3Cracked.VERSION, acceptedMinecraftVersions = "[1.8]")
public class AntiCheat3Cracked {
public static final String MODID = "AntiCheat3";
public static final String NAME = "AntiCheat3";
public static final String VERSION = "3.3.2";
private static LinkedHashMap<String, String> modMd5Map = new LinkedHashMap<String, String>();
private static LinkedHashMap<String, bu> h = new LinkedHashMap<String, bu>();
private static Map<EntityPlayerMP, PlayerMonitorRecord> playerLoginTimeMap = Collections.synchronizedMap(new HashMap<EntityPlayerMP, PlayerMonitorRecord>());
private static List<String> md5List = new ArrayList<String>();
private static Configuration config;
private static ChatComponentText kickMessage = new ChatComponentText("Invalid client data");
private static int maxWaitTime;
private static FMLEventChannel fmlEventChannel;
private static String md5Hash(String src) {
String ass = "";
try {
MessageDigest cipher = MessageDigest.getInstance("MD5");
cipher.update(src.getBytes());
byte[] b = cipher.digest();
StringBuffer strBuf = new StringBuffer("");
for (int o = 0; o < b.length; ++o) {
int i = b[o];
if (i < 0) {
i += 256;
}
if (i < 16) {
strBuf.append("0");
}
strBuf.append(Integer.toHexString(i));
}
ass = strBuf.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return ass;
}
private static String getRandomString(int length) {
String template = "abcdef0123456789";
Random random = new Random();
StringBuffer string = new StringBuffer();
for (int i = 0; i < length; ++i) {
int pos = random.nextInt(template.length());
string.append(template.charAt(pos));
}
return string.toString();
}
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
// Simply not check anything
// MinecraftForge.EVENT_BUS.register(new crack());
// FMLCommonHandler.instance().bus().register(new crack());
fmlEventChannel = NetworkRegistry.INSTANCE.newEventDrivenChannel("AntiCheat3");
fmlEventChannel.register((Object) this);
config = new Configuration(new File(String.format("%s/%s.cfg", event.getModConfigurationDirectory(), "AntiCheat")));
new Timer().schedule((TimerTask) new RecordClearTimer(), 0, 3000);
}
@Mod.EventHandler
public void Init(FMLInitializationEvent event) {
}
@Mod.EventHandler
@SideOnly(value = Side.CLIENT)
public void clientPostInit(FMLPostInitializationEvent event) {
// Simply not check anything
// this.w();
this.saveConfig();
}
@Mod.EventHandler
@SideOnly(value = Side.SERVER)
public void serverPostInit(FMLPostInitializationEvent event) {
this.loadName();
}
@Mod.EventHandler
@SideOnly(value = Side.SERVER)
public void serverLoad(FMLServerStartingEvent t) {
t.registerServerCommand((ICommand) new CommandHandler());
}
private String getFileMd5(File ls) throws IOException, NoSuchAlgorithmException {
FileInputStream im = new FileInputStream(ls.getAbsoluteFile());
MappedByteBuffer baka = im.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, ls.length());
MessageDigest nine = MessageDigest.getInstance("MD5");
nine.update(baka);
BigInteger bi = new BigInteger(1, nine.digest());
String ichi = bi.toString(16);
im.close();
return ichi;
}
private void saveConfig() {
config.load();
Property p = config.get("general", "MaxWaitTime", 5000);
p.comment = "Time wait for client reply at most (ms)";
HashSet<String> sh = new HashSet<String>(modMd5Map.values());
config.get("MD5List", "ServerConfig", sh.toArray(new String[sh.size()]));
config.save();
}
private void loadName() {
config.load();
Property p = config.get("general", "MaxWaitTime", 5000);
p.comment = "Time wait for client reply at most (ms)";
maxWaitTime = p.getInt();
if (maxWaitTime < 0) {
maxWaitTime = 0;
}
List<ModContainer> modList = Loader.instance().getModList();
for (ModContainer modContainer : modList) {
try {
if (!modContainer.getModId().equalsIgnoreCase("AntiCheat3")) continue;
File modFile = modContainer.getSource();
String md5 = this.getFileMd5(modFile);
FMLLog.log((Level) Level.INFO, (String) "%s modMd5:%s", (Object[]) new Object[]{modContainer.getName(), md5});
md5List.add(md5);
break;
} catch (NoSuchAlgorithmException e) {
FMLLog.log((Level) Level.ERROR, (String) "%s:%s", (Object[]) new Object[]{modContainer.getName(), e});
continue;
} catch (IOException e) {
md5List.add(modContainer.getName());
continue;
}
}
String[] roku = config.get("MD5List", "ServerConfig", md5List.toArray(new String[md5List.size()])).getStringList();
config.save();
md5List.clear();
for (int i = 0; i < roku.length; ++i) {
md5List.add(roku[i]);
}
FMLLog.info((String) "Server MD5List:", (Object[]) new Object[0]);
for (String nana : md5List) {
FMLLog.info((String) "%s", (Object[]) new Object[]{nana});
}
}
@SubscribeEvent
@SideOnly(value = Side.CLIENT)
public void serverChallengeReceived(FMLNetworkEvent.ClientCustomPacketEvent hachi) throws UnsupportedEncodingException {
String serverRandomString = new String(hachi.packet.payload().array()).replace(" ", "").trim();
HashSet<String> md5s = new HashSet<String>(modMd5Map.values());
String md5String = "";
for (String ue : md5s) {
md5String = md5String + ue + ",";
}
if (!StringUtils.isNullOrEmpty(md5String)) {
md5String = md5String.substring(0, md5String.length() - 1);
}
// md5String = md5String + serverRandomString;
// Simply not send anything
md5String = serverRandomString.substring(1);
try {
byte[] nisan = md5String.getBytes("UTF-8");
ByteBuf shida = Unpooled.wrappedBuffer(nisan);
FMLProxyPacket proxyPacket = new FMLProxyPacket(new PacketBuffer(shida), "AntiCheat3");
fmlEventChannel.sendToServer(proxyPacket);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
@SubscribeEvent
@SideOnly(value = Side.SERVER)
public void clientReplyRecived(FMLNetworkEvent.ServerCustomPacketEvent event) throws UnsupportedEncodingException {
String tmp = new String(event.packet.payload().array()).replace(" ", "").trim();
String[] clientMd5 = tmp.split(",");
tmp = "";
for (int i = 0; i < clientMd5.length - 2; ++i) {
tmp = tmp + clientMd5[i] + ",";
}
if (!StringUtils.isNullOrEmpty(tmp)) {
tmp = tmp.substring(0, tmp.length() - 1).replace(" ", "").trim();
}
FMLLog.info((String) "Client MD5:---%s", (Object[]) new Object[]{tmp});
boolean currentMd5Match = false;
if (!AntiCheat3Cracked.h.get(clientMd5[clientMd5.length - 1]).randStr.equals(clientMd5[clientMd5.length - 2])) {
event.manager.closeChannel(kickMessage);
return;
}
// Buggy
for (int i = 0; i < clientMd5.length - 2; ++i) {
for (int j = 0; j < md5List.size(); ++j) {
if (md5List.get(j).equalsIgnoreCase(clientMd5[i])) {
currentMd5Match = true;
break;
}
currentMd5Match = false;
}
if (currentMd5Match) continue;
event.manager.closeChannel(kickMessage);
return;
}
AntiCheat3Cracked.h.get((Object) clientMd5[clientMd5.length - 1]).clear = true;
}
private void computeModFileMd5(File nani) {
Object[] o = FMLInjectionData.data();
String natsu = (String) o[4];
if (nani.isDirectory()) {
File[] taguya;
for (File chou : taguya = nani.listFiles()) {
if (chou.isDirectory() && chou.getName() != natsu) continue;
if (chou.getName().endsWith(".jar") || chou.getName().endsWith(".zip") || chou.getName().endsWith(".litemod")) {
try {
String tsukue = this.getFileMd5(chou);
if (!modMd5Map.containsValue(tsukue)) {
FMLLog.info((String) "modjar----%s:%s", (Object[]) new Object[]{chou.getName(), tsukue});
modMd5Map.put(chou.getName(), tsukue);
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
this.computeModFileMd5(chou);
}
}
}
private void w() {
try {
Class kuruma = Class.forName("net.minecraft.client.main.Main");
String hanasu = kuruma.getProtectionDomain().getCodeSource().getLocation().getPath().split("!")[0];
hanasu = URLDecoder.decode(hanasu, "UTF-8").substring(6);
File iiari = new File(hanasu);
String md5 = this.getFileMd5(iiari);
FMLLog.info((String) "jar---%s:%s", (Object[]) new Object[]{iiari.getName(), md5});
modMd5Map.put(iiari.getName(), md5);
} catch (ClassNotFoundException e) {
FMLLog.log((Level) Level.ERROR, (String) "%s:%s", (Object[]) new Object[]{"GameJarERROR", e});
} catch (NoSuchAlgorithmException e) {
FMLLog.log((Level) Level.ERROR, (String) "%s:%s", (Object[]) new Object[]{"GameJarERROR", e});
} catch (IOException e) {
FMLLog.log((Level) Level.ERROR, (String) "%s:%s", (Object[]) new Object[]{"GameJarERROR", e});
}
List<ModContainer> ko = Loader.instance().getModList();
for (ModContainer a : ko) {
File so = a.getSource();
try {
if (a.getName().equals("Forge Mod Loader") || a.getName().equals("Minecraft Forge") || a.getName().equals("Minecraft Coder Pack"))
continue;
String modMD5 = this.getFileMd5(so);
FMLLog.info((String) "modjar----%s:%s", (Object[]) new Object[]{a.getName(), modMD5});
modMd5Map.put(a.getName(), modMD5);
Object[] o = FMLInjectionData.data();
File aso = (File) o[6];
File go = new File(aso, "mods");
this.computeModFileMd5(go);
} catch (NoSuchAlgorithmException e) {
FMLLog.log((Level) Level.ERROR, (String) "%s:%s", (Object[]) new Object[]{a.getName(), e});
} catch (IOException e) {
FMLLog.log((Level) Level.ERROR, (String) "%s:%s", (Object[]) new Object[]{a.getName(), e});
if (!this.isUnpackedMod(so)) continue;
Minecraft.getMinecraft().crashed(new CrashReport("error", new Throwable("Not allow unpacked mod")));
}
}
}
private boolean isUnpackedMod(File sf) {
if (sf.isDirectory()) {
File[] fy;
for (File s : fy = sf.listFiles()) {
if (s.getName().endsWith(".class")) {
FMLLog.log((Level) Level.ERROR, (String) "[%s] ,Not allow unpacked mod", (Object[]) new Object[]{s.getName()});
return true;
}
if (!this.isUnpackedMod(s)) continue;
return true;
}
}
return false;
}
private void kickPlayerIfTimeoutOrMarkAsClear(EntityPlayerMP player) {
PlayerMonitorRecord chichi = playerLoginTimeMap.get(player);
if (h.get(AntiCheat3Cracked.md5Hash(player.getDisplayNameString())) != null && !chichi.clear && chichi.timeOut + (long) maxWaitTime < System.currentTimeMillis()) {
if (!AntiCheat3Cracked.h.get((Object) AntiCheat3Cracked.md5Hash((String) player.getDisplayNameString())).clear) {
player.playerNetServerHandler.kickPlayerFromServer("Timed out");
}
chichi.clear = true;
}
}
public class CommandHandler
implements ICommand {
private static final String help = "Type \"/ac3 help\" for more infomation";
@Override
public String getCommandUsage(ICommandSender p_71518_1_) {
return null;
}
@Override
public boolean isUsernameIndex(String[] p_82358_1_, int p_82358_2_) {
return false;
}
@Override
public String getCommandName() {
return "ac3";
}
@Override
public List getCommandAliases() {
return null;
}
@Override
public void processCommand(ICommandSender cs, String[] args) throws CommandException {
if (args.length == 1) {
if ("reload".equalsIgnoreCase(args[0])) {
AntiCheat3Cracked.this.loadName();
cs.addChatMessage(new ChatComponentText("Configuration reloaded"));
return;
}
if ("help".equalsIgnoreCase(args[0])) {
cs.addChatMessage(new ChatComponentText("/ac3 reload - Reload configuration"));
return;
}
}
cs.addChatMessage(new ChatComponentText("Type \"/ac3 help\" for more infomation"));
}
@Override
public boolean canCommandSenderUseCommand(ICommandSender cs) {
boolean hasPermission = false;
if (cs instanceof EntityPlayer) {
EntityPlayer player = (EntityPlayer) cs;
hasPermission = MinecraftServer.getServer().getConfigurationManager().canSendCommands(player.getGameProfile());
} else if (cs instanceof DedicatedServer) {
hasPermission = true;
}
return hasPermission;
}
@Override
public List addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) {
return null;
}
public int compareTo(Object arg0) {
return 0;
}
}
public class crack {
@SubscribeEvent
@SideOnly(value = Side.CLIENT)
public void onTextureChanged(TextureStitchEvent.Post event) {
block4:
{
ResourceLocation se = new ResourceLocation("textures/blocks/stone.png");
try {
IResource ii = Minecraft.getMinecraft().getResourceManager().getResource(se);
BufferedImage ig = ImageIO.read(ii.getInputStream());
for (int i = 0; i < ig.getWidth(); ++i) {
for (int j = 0; j < ig.getHeight(); ++j) {
if (ig.getRGB(i, j) >> 24 != 0) continue;
Minecraft.getMinecraft().crashed(new CrashReport("error", new Throwable("Not allow transparent texture")));
break block4;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
@SubscribeEvent
@SideOnly(value = Side.SERVER)
public void onPlayerLoginEvent(PlayerEvent.PlayerLoggedInEvent event) throws UnsupportedEncodingException {
if (event.player instanceof EntityPlayerMP) {
EntityPlayerMP player = (EntityPlayerMP) event.player;
playerLoginTimeMap.put(player, new PlayerMonitorRecord(System.currentTimeMillis()));
String randString = AntiCheat3Cracked.getRandomString(32);
byte[] na = ("," + randString + "," + AntiCheat3Cracked.md5Hash(player.getDisplayNameString())).getBytes("UTF-8");
h.put(AntiCheat3Cracked.md5Hash(player.getDisplayNameString()), new bu(randString, System.currentTimeMillis()));
ByteBuf gag = Unpooled.wrappedBuffer(na);
FMLProxyPacket packet = new FMLProxyPacket(new PacketBuffer(gag), "AntiCheat3");
fmlEventChannel.sendTo(packet, player);
new Timer().schedule((TimerTask) new VerificationTimeoutListener(player), maxWaitTime + 50);
}
}
}
private class bu {
long loginTime;
String randStr;
boolean clear;
bu(String randStr, long ty) {
this.loginTime = ty;
this.randStr = randStr;
this.clear = false;
}
}
private class PlayerMonitorRecord {
long timeOut;
boolean clear;
PlayerMonitorRecord(long lf) {
this.timeOut = lf;
this.clear = false;
}
}
public class RecordClearTimer
extends TimerTask {
@Override
public void run() {
if (!playerLoginTimeMap.isEmpty()) {
Iterator<Map.Entry<EntityPlayerMP, PlayerMonitorRecord>> s = playerLoginTimeMap.entrySet().iterator();
while (s.hasNext()) {
Map.Entry payload = s.next();
EntityPlayerMP sabi = (EntityPlayerMP) payload.getKey();
PlayerMonitorRecord tsunami = (PlayerMonitorRecord) payload.getValue();
if (tsunami.clear) {
s.remove();
continue;
}
AntiCheat3Cracked.this.kickPlayerIfTimeoutOrMarkAsClear(sabi);
}
}
if (!h.isEmpty()) {
Iterator<Map.Entry<String, bu>> kokoro = h.entrySet().iterator();
while (kokoro.hasNext()) {
Map.Entry hentai = kokoro.next();
bu sf = (bu) hentai.getValue();
if (System.currentTimeMillis() - sf.loginTime <= 30000) continue;
kokoro.remove();
}
}
}
}
public class VerificationTimeoutListener
extends TimerTask {
private EntityPlayerMP player;
VerificationTimeoutListener(EntityPlayerMP e) {
this.player = e;
}
@Override
public void run() {
if (this.getPlayerInSomeWorld(this.player.getDisplayNameString()) != null) {
AntiCheat3Cracked.this.kickPlayerIfTimeoutOrMarkAsClear(this.player);
}
}
private EntityPlayer getPlayerInSomeWorld(String gay) {
for (WorldServer ws : MinecraftServer.getServer().worldServers) {
EntityPlayer isgay = ws.getPlayerEntityByName(gay);
if (isgay == null) continue;
return isgay;
}
return null;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment