001 package cpw.mods.fml.common.asm;
002
003 import java.io.ByteArrayInputStream;
004 import java.io.InputStreamReader;
005 import java.io.ObjectInputStream.GetField;
006 import java.io.StringReader;
007 import java.net.JarURLConnection;
008 import java.nio.charset.Charset;
009 import java.security.CodeSource;
010 import java.security.cert.CertPath;
011 import java.security.cert.CertPathValidator;
012 import java.security.cert.Certificate;
013 import java.security.cert.CertificateFactory;
014 import java.security.cert.PKIXCertPathValidatorResult;
015 import java.security.cert.PKIXParameters;
016 import java.security.cert.TrustAnchor;
017 import java.security.cert.X509Certificate;
018 import java.util.Arrays;
019 import java.util.Collections;
020 import java.util.Map;
021
022 import javax.swing.JOptionPane;
023
024 import org.objectweb.asm.ClassReader;
025 import org.objectweb.asm.ClassVisitor;
026 import org.objectweb.asm.FieldVisitor;
027 import org.objectweb.asm.Opcodes;
028
029 import cpw.mods.fml.common.CertificateHelper;
030 import cpw.mods.fml.common.FMLLog;
031 import cpw.mods.fml.relauncher.IFMLCallHook;
032 import cpw.mods.fml.relauncher.RelaunchClassLoader;
033
034 public class FMLSanityChecker implements IFMLCallHook
035 {
036 private static final String FMLFINGERPRINT = "AE:F6:54:79:96:E9:1B:D1:59:70:6C:B4:6B:F5:4A:89:C5:CE:08:1D".toLowerCase().replace(":","");
037 private static final String FORGEFINGERPRINT = "DE:4C:F8:A3:F3:BC:15:63:58:10:04:4C:39:24:0B:F9:68:04:EA:7D".toLowerCase().replace(":", "");
038 static class MLDetectorClassVisitor extends ClassVisitor
039 {
040 private boolean foundMarker = false;
041 private MLDetectorClassVisitor()
042 {
043 super(Opcodes.ASM4);
044 }
045
046 @Override
047 public FieldVisitor visitField(int arg0, String arg1, String arg2, String arg3, Object arg4)
048 {
049 if ("fmlMarker".equals(arg1))
050 {
051 foundMarker = true;
052 }
053 return null;
054 }
055 }
056
057 private RelaunchClassLoader cl;
058
059 @Override
060 public Void call() throws Exception
061 {
062 CodeSource codeSource = getClass().getProtectionDomain().getCodeSource();
063 boolean goodFML = false;
064 if (codeSource.getLocation().getProtocol().equals("jar"))
065 {
066 Certificate[] certificates = codeSource.getCertificates();
067 if (certificates!=null)
068 {
069
070 for (Certificate cert : certificates)
071 {
072 String fingerprint = CertificateHelper.getFingerprint(cert);
073 if (fingerprint.equals(FMLFINGERPRINT))
074 {
075 FMLLog.info("Found valid fingerprint for FML. Certificate fingerprint %s", fingerprint);
076 goodFML = true;
077 }
078 else if (fingerprint.equals(FORGEFINGERPRINT))
079 {
080 FMLLog.info("Found valid fingerprint for Minecraft Forge. Certificate fingerprint %s", fingerprint);
081 goodFML = true;
082 }
083 else
084 {
085 FMLLog.severe("Found invalid fingerprint for FML: %s", fingerprint);
086 }
087 }
088 }
089 }
090 else
091 {
092 goodFML = true;
093 }
094 if (!goodFML)
095 {
096 FMLLog.severe("FML appears to be missing any signature data. This is not a good thing");
097 }
098 byte[] mlClass = cl.getClassBytes("ModLoader");
099 // Only care in obfuscated env
100 if (mlClass == null)
101 {
102 return null;
103 }
104 MLDetectorClassVisitor mlTester = new MLDetectorClassVisitor();
105 ClassReader cr = new ClassReader(mlClass);
106 cr.accept(mlTester, ClassReader.SKIP_CODE);
107 if (!mlTester.foundMarker)
108 {
109 JOptionPane.showMessageDialog(null, "<html>CRITICAL ERROR<br/>" +
110 "ModLoader was detected in this environment<br/>" +
111 "ForgeModLoader cannot be installed alongside ModLoader<br/>" +
112 "All mods should work without ModLoader being installed<br/>" +
113 "Because ForgeModLoader is 100% compatible with ModLoader<br/>" +
114 "Re-install Minecraft Forge or Forge ModLoader into a clean<br/>" +
115 "jar and try again.",
116 "ForgeModLoader critical error",
117 JOptionPane.ERROR_MESSAGE);
118 throw new RuntimeException("Invalid ModLoader class detected");
119 }
120 return null;
121 }
122
123 @Override
124 public void injectData(Map<String, Object> data)
125 {
126 cl = (RelaunchClassLoader) data.get("classLoader");
127 }
128
129 }