Created
December 31, 2015 03:28
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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