├── README.md ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── src └── main │ └── java │ └── codechicken │ ├── obfuscator │ ├── ILogStreams.java │ ├── fs │ │ ├── IRemappable.java │ │ ├── ModEntry.java │ │ ├── ModFileEntry.java │ │ ├── ObfClassEntry.java │ │ ├── Mod.java │ │ ├── ObfWriteThread.java │ │ ├── DataBuffer.java │ │ ├── ZipMod.java │ │ ├── FileMod.java │ │ ├── DirMod.java │ │ ├── ASMFileEntry.java │ │ ├── ObfReadThread.java │ │ └── Main.java │ ├── DummyOutputStream.java │ ├── SystemLogStreams.java │ ├── IHeirachyEvaluator.java │ ├── ObfDirection.java │ ├── ObfRemapper.java │ ├── ConstantObfuscator.java │ ├── ObfuscationRun.java │ └── ObfuscationMap.java │ └── lib │ ├── config │ └── SimpleProperties.java │ └── asm │ ├── ObfMapping.java │ └── InstructionComparator.java ├── .gitignore ├── gradlew.bat ├── gradlew └── LICENSE /README.md: -------------------------------------------------------------------------------- 1 | CCObfuscator 2 | ============ 3 | A faster replacement obfuscator for Minecraft modding with a few additional features. -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCBProject/CCObfuscator/master/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/java/codechicken/obfuscator/ILogStreams.java: -------------------------------------------------------------------------------- 1 | package codechicken.obfuscator; 2 | 3 | import java.io.PrintStream; 4 | 5 | public interface ILogStreams 6 | { 7 | public PrintStream err(); 8 | public PrintStream out(); 9 | } 10 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /src/main/java/codechicken/obfuscator/fs/IRemappable.java: -------------------------------------------------------------------------------- 1 | package codechicken.obfuscator.fs; 2 | 3 | public interface IRemappable 4 | { 5 | /** 6 | * Run this object through the obfuscator and add it to the write queue 7 | */ 8 | public void remap(); 9 | } 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # exclude all 2 | /* 3 | 4 | # Include Important Folders 5 | !src/ 6 | 7 | # Other Files. 8 | !LICENSE.txt 9 | !README.md 10 | 11 | # Gradle stuff 12 | !gradle/ 13 | !gradlew 14 | !gradlew.bat 15 | !build.gradle 16 | !settings.gradle 17 | 18 | # Include git important files 19 | !.gitmodules 20 | !.gitignore 21 | -------------------------------------------------------------------------------- /src/main/java/codechicken/obfuscator/DummyOutputStream.java: -------------------------------------------------------------------------------- 1 | package codechicken.obfuscator; 2 | 3 | import java.io.OutputStream; 4 | 5 | public class DummyOutputStream extends OutputStream 6 | { 7 | public static DummyOutputStream instance = new DummyOutputStream(); 8 | 9 | @Override 10 | public void write(int b) 11 | { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/codechicken/obfuscator/fs/ModEntry.java: -------------------------------------------------------------------------------- 1 | package codechicken.obfuscator.fs; 2 | 3 | import java.io.IOException; 4 | import java.io.OutputStream; 5 | 6 | public abstract class ModEntry 7 | { 8 | public ModEntry(Mod mod) 9 | { 10 | this.mod = mod; 11 | } 12 | 13 | public final Mod mod; 14 | 15 | public abstract String getName(); 16 | 17 | public abstract void write(OutputStream os) throws IOException; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/codechicken/obfuscator/SystemLogStreams.java: -------------------------------------------------------------------------------- 1 | package codechicken.obfuscator; 2 | 3 | import java.io.PrintStream; 4 | 5 | public class SystemLogStreams implements ILogStreams 6 | { 7 | public static SystemLogStreams inst = new SystemLogStreams(); 8 | 9 | @Override 10 | public PrintStream err() 11 | { 12 | return System.err; 13 | } 14 | 15 | @Override 16 | public PrintStream out() 17 | { 18 | return System.out; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/codechicken/obfuscator/IHeirachyEvaluator.java: -------------------------------------------------------------------------------- 1 | package codechicken.obfuscator; 2 | 3 | import java.util.List; 4 | 5 | import codechicken.obfuscator.ObfuscationMap.ObfuscationEntry; 6 | 7 | public interface IHeirachyEvaluator 8 | { 9 | /** 10 | * @param desc The mapping descriptor of the class to evaluate heirachy for 11 | * @return A list of parents (srg or obf names) 12 | */ 13 | public List getParents(ObfuscationEntry desc); 14 | 15 | /** 16 | * @param srg_class The srg name of the class in question 17 | * @return True if this class does not inherit from any obfuscated class. 18 | */ 19 | public boolean isLibClass(ObfuscationEntry desc); 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/codechicken/obfuscator/fs/ModFileEntry.java: -------------------------------------------------------------------------------- 1 | package codechicken.obfuscator.fs; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.OutputStream; 6 | 7 | 8 | public class ModFileEntry extends ModEntry 9 | { 10 | public final DataBuffer buf; 11 | private final String name; 12 | 13 | public ModFileEntry(Mod mod, InputStream in, String name, long size) throws IOException 14 | { 15 | super(mod); 16 | this.name = name; 17 | buf = new DataBuffer(size); 18 | buf.read(in); 19 | buf.lock(); 20 | } 21 | 22 | @Override 23 | public String getName() 24 | { 25 | return name; 26 | } 27 | 28 | @Override 29 | public void write(OutputStream out) throws IOException 30 | { 31 | buf.write(out); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/codechicken/obfuscator/ObfDirection.java: -------------------------------------------------------------------------------- 1 | package codechicken.obfuscator; 2 | 3 | import codechicken.lib.asm.ObfMapping; 4 | import codechicken.obfuscator.ObfuscationMap.ObfuscationEntry; 5 | 6 | public class ObfDirection 7 | { 8 | public boolean obfuscate; 9 | public boolean srg; 10 | public boolean srg_cst; 11 | 12 | public ObfDirection setObfuscate(boolean obfuscate) 13 | { 14 | this.obfuscate = obfuscate; 15 | return this; 16 | } 17 | 18 | public ObfDirection setSearge(boolean srg) 19 | { 20 | this.srg = srg; 21 | return this; 22 | } 23 | 24 | public ObfDirection setSeargeConstants(boolean srg_cst) 25 | { 26 | this.srg_cst = srg_cst; 27 | return this; 28 | } 29 | 30 | public ObfMapping obfuscate(ObfuscationEntry map) 31 | { 32 | return srg ? map.srg : obfuscate ? map.obf : map.mcp; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/codechicken/obfuscator/fs/ObfClassEntry.java: -------------------------------------------------------------------------------- 1 | package codechicken.obfuscator.fs; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.OutputStream; 6 | 7 | import org.objectweb.asm.ClassReader; 8 | import org.objectweb.asm.ClassWriter; 9 | import org.objectweb.asm.tree.ClassNode; 10 | 11 | import codechicken.obfuscator.ObfuscationRun; 12 | 13 | public class ObfClassEntry extends ModEntry implements IRemappable 14 | { 15 | public ClassNode cnode; 16 | public byte[] bytes; 17 | 18 | public ObfClassEntry(Mod mod, InputStream in) throws IOException 19 | { 20 | super(mod); 21 | 22 | cnode = new ClassNode(); 23 | new ClassReader(in).accept(cnode, ClassReader.EXPAND_FRAMES); 24 | } 25 | 26 | @Override 27 | public String getName() 28 | { 29 | return mod.run.obfMapper.map(cnode.name) + ".class"; 30 | } 31 | 32 | public void remap() 33 | { 34 | ObfuscationRun run = mod.run; 35 | run.fine().println("Remapping: "+cnode.name); 36 | 37 | ClassWriter cw = new ClassWriter(0); 38 | run.remap(cnode, cw); 39 | bytes = cw.toByteArray(); 40 | 41 | mod.read.addWriteEntry(this); 42 | } 43 | 44 | @Override 45 | public void write(OutputStream os) throws IOException 46 | { 47 | os.write(bytes); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/codechicken/obfuscator/fs/Mod.java: -------------------------------------------------------------------------------- 1 | package codechicken.obfuscator.fs; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | 6 | import codechicken.obfuscator.ObfuscationRun; 7 | 8 | public abstract class Mod 9 | { 10 | public static interface ModEntryReader 11 | { 12 | public void read(Mod mod, InputStream in, String e_name, long e_length) throws IOException; 13 | } 14 | 15 | public String name; 16 | private boolean modify; 17 | 18 | public final ObfuscationRun run; 19 | public final ObfReadThread read; 20 | 21 | public Mod(ObfReadThread read, String name, boolean modify) 22 | { 23 | this.read = read; 24 | run = read.run; 25 | this.name = name; 26 | setModify(modify); 27 | } 28 | 29 | public boolean modify() 30 | { 31 | return modify; 32 | } 33 | 34 | public void setModify(boolean b) 35 | { 36 | if(b == modify) 37 | return; 38 | 39 | modify = b; 40 | if(modify) 41 | read.modEntries.add(this); 42 | else 43 | read.modEntries.remove(this); 44 | } 45 | 46 | public abstract void read(ModEntryReader reader) throws IOException; 47 | 48 | public abstract void write(ModEntry entry) throws IOException; 49 | 50 | public abstract boolean writeAsync(); 51 | 52 | public void close() throws IOException 53 | { 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/codechicken/obfuscator/fs/ObfWriteThread.java: -------------------------------------------------------------------------------- 1 | package codechicken.obfuscator.fs; 2 | 3 | import codechicken.obfuscator.ObfuscationRun; 4 | 5 | public class ObfWriteThread extends Thread 6 | { 7 | public ObfReadThread read; 8 | public ObfuscationRun run; 9 | 10 | public ObfWriteThread(ObfReadThread read) 11 | { 12 | this.read = read; 13 | run = read.run; 14 | setName("Obfuscation Write"); 15 | } 16 | 17 | @Override 18 | public void run() 19 | { 20 | while(true) 21 | { 22 | ModEntry e = read.getWriteEntry(); 23 | if(e == null) 24 | { 25 | if(read.finishedReading()) 26 | break; 27 | continue; 28 | } 29 | 30 | try 31 | { 32 | e.mod.write(e); 33 | } 34 | catch(Exception ex) 35 | { 36 | run.err().println("Failed to write entry: "+e.getName()+" of mod "+e.mod.name); 37 | ex.printStackTrace(run.err()); 38 | run.finish(true); 39 | return; 40 | } 41 | } 42 | 43 | for(Mod mod : read.modEntries) 44 | { 45 | try 46 | { 47 | mod.close(); 48 | } 49 | catch(Exception e) 50 | { 51 | run.err().println("Failed to close mod: "+mod.name); 52 | e.printStackTrace(run.err()); 53 | run.finish(true); 54 | return; 55 | } 56 | } 57 | 58 | run.finish(false); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/codechicken/obfuscator/fs/DataBuffer.java: -------------------------------------------------------------------------------- 1 | package codechicken.obfuscator.fs; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.OutputStream; 6 | import java.util.LinkedList; 7 | 8 | public class DataBuffer 9 | { 10 | private class DataEntry 11 | { 12 | final int len; 13 | final byte[] buf; 14 | 15 | public DataEntry(InputStream in) throws IOException 16 | { 17 | buf = new byte[blocksize]; 18 | int read = 0; 19 | int total = 0; 20 | while((read = in.read(buf, total, buf.length-total)) > 0) 21 | total+=read; 22 | 23 | len = total; 24 | } 25 | } 26 | private LinkedList data = new LinkedList(); 27 | private int length; 28 | private int blocksize = 4096; 29 | 30 | private boolean locked; 31 | 32 | public DataBuffer(long size) throws IOException 33 | { 34 | if(size > 16777216) 35 | throw new IOException("Please don't send us files > 16MB. You're doing it wrong"); 36 | if(size > 0) 37 | blocksize = (int)size; 38 | } 39 | 40 | public void lock() 41 | { 42 | locked = true; 43 | } 44 | 45 | public void read(InputStream in) throws IOException 46 | { 47 | if(locked) 48 | throw new IOException("Cannot read to a locked DataBuffer"); 49 | 50 | while(true) 51 | { 52 | DataEntry e = new DataEntry(in); 53 | if(e.len <= 0) 54 | break; 55 | 56 | data.add(e); 57 | length+=e.len; 58 | } 59 | } 60 | 61 | public int getLength() 62 | { 63 | return length; 64 | } 65 | 66 | public void write(OutputStream out) throws IOException 67 | { 68 | lock(); 69 | 70 | for(DataEntry e : data) 71 | out.write(e.buf, 0, e.len); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/codechicken/obfuscator/fs/ZipMod.java: -------------------------------------------------------------------------------- 1 | package codechicken.obfuscator.fs; 2 | 3 | import java.io.File; 4 | import java.io.FileOutputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.util.zip.ZipEntry; 8 | import java.util.zip.ZipInputStream; 9 | import java.util.zip.ZipOutputStream; 10 | 11 | public class ZipMod extends Mod 12 | { 13 | private ZipInputStream input; 14 | private ZipOutputStream output; 15 | 16 | public ZipMod(ObfReadThread read, String name, InputStream in, boolean modify) throws IOException 17 | { 18 | super(read, name, modify); 19 | input = new ZipInputStream(in); 20 | if(modify) 21 | { 22 | File out = new File(read.outDir, name); 23 | if(out.exists()) 24 | throw new RuntimeException("Duplicate output mod: "+name); 25 | 26 | out.getParentFile().mkdirs(); 27 | out.createNewFile(); 28 | 29 | output = new ZipOutputStream(new FileOutputStream(out)); 30 | } 31 | } 32 | 33 | public void read(ModEntryReader reader) throws IOException 34 | { 35 | run.out().println("Reading mod: "+name); 36 | while(true) 37 | { 38 | ZipEntry e = input.getNextEntry(); 39 | if(e == null) 40 | break; 41 | 42 | if(e.isDirectory()) 43 | continue; 44 | 45 | reader.read(this, input, e.getName(), e.getSize()); 46 | } 47 | 48 | input.close(); 49 | } 50 | 51 | public void write(ModEntry entry) throws IOException 52 | { 53 | run.fine().println("Writing: "+entry.getName()+" to "+name); 54 | output.putNextEntry(new ZipEntry(entry.getName())); 55 | entry.write(output); 56 | output.closeEntry(); 57 | } 58 | 59 | @Override 60 | public boolean writeAsync() 61 | { 62 | return false; 63 | } 64 | 65 | @Override 66 | public void close() throws IOException 67 | { 68 | output.close(); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/codechicken/obfuscator/fs/FileMod.java: -------------------------------------------------------------------------------- 1 | package codechicken.obfuscator.fs; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileOutputStream; 6 | import java.io.IOException; 7 | 8 | public class FileMod extends Mod 9 | { 10 | public static final String[] bannedFileNames = new String[]{"con", "prn", "aux", "nul"}; 11 | public static final boolean isWindows = System.getProperty("os.name").startsWith("Windows"); 12 | 13 | public static boolean isBanned(String name) 14 | { 15 | for(String b : bannedFileNames) 16 | { 17 | if(name.startsWith(b)) 18 | { 19 | int i = name.indexOf('.'); 20 | if(i < 0) 21 | i = name.length(); 22 | if(name.substring(0, i).equals(b)) 23 | return true; 24 | } 25 | } 26 | return false; 27 | } 28 | 29 | public final File file; 30 | 31 | public FileMod(ObfReadThread read, File file, boolean modify) 32 | { 33 | super(read, file.getName(), modify); 34 | this.file = file; 35 | } 36 | 37 | @Override 38 | public void read(ModEntryReader reader) throws IOException 39 | { 40 | run.out().println("Reading mod: "+name); 41 | FileInputStream in = new FileInputStream(file); 42 | reader.read(this, in, file.getName(), file.length()); 43 | in.close(); 44 | } 45 | 46 | @Override 47 | public void write(ModEntry entry) throws IOException 48 | { 49 | String fname = entry.getName(); 50 | while(isBanned(fname)) 51 | fname = '_'+fname; 52 | 53 | run.fine().println("Writing: "+fname+" to "+name); 54 | 55 | File out = new File(read.outDir, fname); 56 | if(out.exists()) 57 | throw new RuntimeException("Duplicate output mod: "+out.getName()); 58 | 59 | out.getParentFile().mkdirs(); 60 | out.createNewFile(); 61 | 62 | FileOutputStream fout = new FileOutputStream(out); 63 | entry.write(fout); 64 | fout.close(); 65 | } 66 | 67 | @Override 68 | public boolean writeAsync() 69 | { 70 | return false; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/codechicken/obfuscator/fs/DirMod.java: -------------------------------------------------------------------------------- 1 | package codechicken.obfuscator.fs; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileOutputStream; 6 | import java.io.IOException; 7 | import java.util.zip.ZipEntry; 8 | import java.util.zip.ZipOutputStream; 9 | 10 | public class DirMod extends FileMod 11 | { 12 | private ZipOutputStream zipout; 13 | 14 | public DirMod(ObfReadThread read, File dir, boolean modify, boolean zip) throws IOException 15 | { 16 | super(read, dir, modify); 17 | if(modify() && zip) 18 | { 19 | File out = new File(read.outDir, name+".zip"); 20 | if(out.exists()) 21 | throw new RuntimeException("Duplicate output mod: "+name); 22 | 23 | out.getParentFile().mkdirs(); 24 | out.createNewFile(); 25 | 26 | zipout = new ZipOutputStream(new FileOutputStream(out)); 27 | } 28 | } 29 | 30 | @Override 31 | public void read(ModEntryReader reader) throws IOException 32 | { 33 | run.out().println("Reading mod: "+name); 34 | read(file, "", reader); 35 | } 36 | 37 | private void read(File dir, String prefix, ModEntryReader reader) throws IOException 38 | { 39 | for(File file : dir.listFiles()) 40 | { 41 | String name = prefix+(prefix.length() == 0 ? "" : "/")+file.getName(); 42 | if(file.isDirectory()) 43 | read(file, name, reader); 44 | else 45 | { 46 | FileInputStream in = new FileInputStream(file); 47 | reader.read(this, in, name, file.length()); 48 | in.close(); 49 | } 50 | } 51 | } 52 | 53 | @Override 54 | public boolean writeAsync() 55 | { 56 | return true; 57 | } 58 | 59 | @Override 60 | public void write(ModEntry entry) throws IOException 61 | { 62 | if(zipout != null) 63 | { 64 | run.fine().println("Writing: "+entry.getName()+" to "+name); 65 | zipout.putNextEntry(new ZipEntry(entry.getName())); 66 | entry.write(zipout); 67 | zipout.closeEntry(); 68 | } 69 | else 70 | { 71 | super.write(entry); 72 | } 73 | } 74 | 75 | @Override 76 | public void close() throws IOException 77 | { 78 | if(zipout != null) 79 | zipout.close(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/codechicken/obfuscator/ObfRemapper.java: -------------------------------------------------------------------------------- 1 | package codechicken.obfuscator; 2 | 3 | import org.objectweb.asm.commons.Remapper; 4 | 5 | import codechicken.obfuscator.ObfuscationMap.ObfuscationEntry; 6 | 7 | public class ObfRemapper extends Remapper 8 | { 9 | public final ObfuscationMap obf; 10 | public ObfDirection dir; 11 | 12 | public ObfRemapper(ObfuscationMap obf, ObfDirection dir) 13 | { 14 | this.obf = obf; 15 | this.dir = dir; 16 | } 17 | 18 | @Override 19 | public String map(String name) 20 | { 21 | if(name.indexOf('$') >= 0) 22 | return map(name.substring(0, name.indexOf('$')))+name.substring(name.indexOf('$')); 23 | 24 | ObfuscationEntry map; 25 | if(dir.obfuscate) 26 | map = obf.lookupMcpClass(name); 27 | else 28 | map = obf.lookupObfClass(name); 29 | 30 | if(map != null && !dir.obfuscate(map).s_owner.equals(name))//If the name would have been changed by the obf lookup, use that. 31 | return dir.obfuscate(map).s_owner; 32 | else if (dir.obfuscate && ".".equals(obf.getDotPkA()) && name.startsWith(obf.getDotPkB())) 33 | { 34 | name = name.replaceFirst(obf.getDotPkB(), ""); 35 | if (name.startsWith("/")) 36 | { 37 | name = name.substring(1); 38 | } 39 | return name; 40 | } 41 | 42 | return name; 43 | } 44 | 45 | @Override 46 | public String mapFieldName(String owner, String name, String desc) 47 | { 48 | ObfuscationEntry map; 49 | if(dir.obfuscate) 50 | map = obf.lookupMcpField(owner, name); 51 | else 52 | map = obf.lookupObfField(owner, name); 53 | 54 | if(map == null) 55 | map = obf.lookupSrgField(owner, name); 56 | 57 | if(map != null) 58 | return dir.obfuscate(map).s_name; 59 | 60 | return name; 61 | } 62 | 63 | @Override 64 | public String mapMethodName(String owner, String name, String desc) 65 | { 66 | if(owner.length() == 0 || owner.charAt(0) == '[') 67 | return name; 68 | 69 | ObfuscationEntry map; 70 | if(dir.obfuscate) 71 | map = obf.lookupMcpMethod(owner, name, desc); 72 | else 73 | map = obf.lookupObfMethod(owner, name, desc); 74 | 75 | if(map == null) 76 | map = obf.lookupSrg(name); 77 | 78 | if(map != null) 79 | return dir.obfuscate(map).s_name; 80 | 81 | return name; 82 | } 83 | 84 | @Override 85 | public Object mapValue(Object cst) 86 | { 87 | if(cst instanceof String) 88 | { 89 | if(dir.srg_cst) 90 | { 91 | ObfuscationEntry map = obf.lookupSrg((String) cst); 92 | if(map != null) 93 | return dir.obfuscate(map).s_name; 94 | } 95 | return cst; 96 | } 97 | 98 | return super.mapValue(cst); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/codechicken/obfuscator/ConstantObfuscator.java: -------------------------------------------------------------------------------- 1 | package codechicken.obfuscator; 2 | 3 | import java.util.LinkedList; 4 | import java.util.List; 5 | import org.objectweb.asm.Opcodes; 6 | import org.objectweb.asm.tree.AbstractInsnNode; 7 | import org.objectweb.asm.tree.ClassNode; 8 | import org.objectweb.asm.tree.LdcInsnNode; 9 | import org.objectweb.asm.tree.MethodInsnNode; 10 | import org.objectweb.asm.tree.MethodNode; 11 | 12 | import codechicken.lib.asm.ObfMapping; 13 | 14 | import static org.objectweb.asm.tree.AbstractInsnNode.*; 15 | 16 | public class ConstantObfuscator implements Opcodes 17 | { 18 | public ObfRemapper obf; 19 | public List descCalls = new LinkedList(); 20 | public List classCalls = new LinkedList(); 21 | 22 | public ConstantObfuscator(ObfRemapper obf, String[] a_classCalls, String[] a_descCalls) 23 | { 24 | this.obf = obf; 25 | for(String callDesc : a_classCalls) 26 | classCalls.add(ObfMapping.fromDesc(callDesc)); 27 | 28 | for(String callDesc : a_descCalls) 29 | descCalls.add(ObfMapping.fromDesc(callDesc)); 30 | } 31 | 32 | public void transform(ClassNode cnode) 33 | { 34 | for(MethodNode method : cnode.methods) 35 | for(AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext()) 36 | obfuscateInsnSeq(insn); 37 | } 38 | 39 | private void obfuscateInsnSeq(AbstractInsnNode insn) 40 | { 41 | if(matchesClass(insn)) 42 | { 43 | LdcInsnNode node1 = (LdcInsnNode) insn; 44 | node1.cst = obf.map((String) node1.cst); 45 | } 46 | if(matchesDesc(insn)) 47 | { 48 | LdcInsnNode node1 = (LdcInsnNode) insn; 49 | LdcInsnNode node2 = (LdcInsnNode) node1.getNext(); 50 | LdcInsnNode node3 = (LdcInsnNode) node2.getNext(); 51 | ObfMapping mapping = new ObfMapping((String) node1.cst, (String) node2.cst, (String) node3.cst).map(obf); 52 | node1.cst = mapping.s_owner; 53 | node2.cst = mapping.s_name; 54 | node3.cst = mapping.s_desc; 55 | } 56 | } 57 | 58 | private boolean matchesClass(AbstractInsnNode insn) 59 | { 60 | if(insn.getType() != LDC_INSN) return false; 61 | insn = insn.getNext(); 62 | if(insn == null || insn.getType() != METHOD_INSN) return false; 63 | for(ObfMapping m : classCalls) 64 | if(m.matches((MethodInsnNode) insn)) 65 | return true; 66 | return false; 67 | } 68 | 69 | private boolean matchesDesc(AbstractInsnNode insn) 70 | { 71 | if(insn.getType() != LDC_INSN) return false; 72 | insn = insn.getNext(); 73 | if(insn == null || insn.getType() != LDC_INSN) return false; 74 | insn = insn.getNext(); 75 | if(insn == null || insn.getType() != LDC_INSN) return false; 76 | insn = insn.getNext(); 77 | if(insn == null || insn.getType() != METHOD_INSN) return false; 78 | for(ObfMapping m : descCalls) 79 | if(m.matches((MethodInsnNode) insn)) 80 | return true; 81 | return false; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto init 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto init 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :init 68 | @rem Get command-line arguments, handling Windows variants 69 | 70 | if not "%OS%" == "Windows_NT" goto win9xME_args 71 | 72 | :win9xME_args 73 | @rem Slurp the command line arguments. 74 | set CMD_LINE_ARGS= 75 | set _SKIP=2 76 | 77 | :win9xME_args_slurp 78 | if "x%~1" == "x" goto execute 79 | 80 | set CMD_LINE_ARGS=%* 81 | 82 | :execute 83 | @rem Setup the command line 84 | 85 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 86 | 87 | 88 | @rem Execute Gradle 89 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 90 | 91 | :end 92 | @rem End local scope for the variables with windows NT shell 93 | if "%ERRORLEVEL%"=="0" goto mainEnd 94 | 95 | :fail 96 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 97 | rem the _cmd.exe /c_ return code! 98 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 99 | exit /b 1 100 | 101 | :mainEnd 102 | if "%OS%"=="Windows_NT" endlocal 103 | 104 | :omega 105 | -------------------------------------------------------------------------------- /src/main/java/codechicken/lib/config/SimpleProperties.java: -------------------------------------------------------------------------------- 1 | package codechicken.lib.config; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.io.InputStreamReader; 7 | import java.io.PrintStream; 8 | import java.nio.charset.Charset; 9 | import java.util.HashMap; 10 | import java.util.Map.Entry; 11 | 12 | public class SimpleProperties 13 | { 14 | public HashMap propertyMap = new HashMap(); 15 | public File propertyFile; 16 | public boolean saveOnChange = false; 17 | public String encoding; 18 | 19 | private boolean loading = false; 20 | 21 | public SimpleProperties(File file, boolean saveOnChange, String encoding) 22 | { 23 | propertyFile = file; 24 | this.saveOnChange = saveOnChange; 25 | this.encoding = encoding; 26 | } 27 | 28 | public SimpleProperties(File file, boolean saveOnChange) 29 | { 30 | this(file, saveOnChange, Charset.defaultCharset().name()); 31 | } 32 | 33 | public SimpleProperties(File file) 34 | { 35 | this(file, true); 36 | } 37 | 38 | public void load() 39 | { 40 | clear(); 41 | loading = true; 42 | 43 | try 44 | { 45 | BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(propertyFile), encoding)); 46 | while(true) 47 | { 48 | String read = reader.readLine(); 49 | if(read == null) 50 | break; 51 | 52 | int equalIndex = read.indexOf('='); 53 | if(equalIndex == -1) 54 | continue; 55 | 56 | setProperty(read.substring(0, equalIndex), read.substring(equalIndex+1)); 57 | } 58 | reader.close(); 59 | } 60 | catch(Exception e) 61 | { 62 | throw new RuntimeException(e); 63 | } 64 | loading = false; 65 | } 66 | 67 | public void save() 68 | { 69 | try 70 | { 71 | PrintStream writer = new PrintStream(propertyFile); 72 | 73 | for(Entry entry : propertyMap.entrySet()) 74 | { 75 | writer.println(entry.getKey()+"="+entry.getValue()); 76 | } 77 | 78 | writer.close(); 79 | } 80 | catch(Exception e) 81 | { 82 | throw new RuntimeException(e); 83 | } 84 | } 85 | 86 | public void clear() 87 | { 88 | propertyMap.clear(); 89 | } 90 | 91 | public boolean hasProperty(String key) 92 | { 93 | return propertyMap.containsKey(key); 94 | } 95 | 96 | public void removeProperty(String key) 97 | { 98 | if(propertyMap.remove(key) != null && saveOnChange && !loading) 99 | save(); 100 | } 101 | 102 | public void setProperty(String key, int value) 103 | { 104 | setProperty(key, Integer.toString(value)); 105 | } 106 | 107 | public void setProperty(String key, boolean value) 108 | { 109 | setProperty(key, Boolean.toString(value)); 110 | } 111 | 112 | public void setProperty(String key, String value) 113 | { 114 | propertyMap.put(key, value); 115 | if(saveOnChange && !loading) 116 | save(); 117 | } 118 | 119 | public int getProperty(String property, int defaultvalue) 120 | { 121 | try { 122 | return Integer.parseInt(getProperty(property, Integer.toString(defaultvalue))); 123 | } catch(NumberFormatException nfe) 124 | {return defaultvalue;} 125 | } 126 | 127 | public boolean getProperty(String property, boolean defaultvalue) 128 | { 129 | try { 130 | return Boolean.parseBoolean(getProperty(property, Boolean.toString(defaultvalue))); 131 | } catch(NumberFormatException nfe) 132 | {return defaultvalue;} 133 | } 134 | 135 | public String getProperty(String property, String defaultvalue) 136 | { 137 | String value = propertyMap.get(property); 138 | if(value == null) 139 | { 140 | setProperty(property, defaultvalue); 141 | return defaultvalue; 142 | } 143 | return value; 144 | } 145 | 146 | public String getProperty(String property) 147 | { 148 | return propertyMap.get(property); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/main/java/codechicken/obfuscator/fs/ASMFileEntry.java: -------------------------------------------------------------------------------- 1 | package codechicken.obfuscator.fs; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.InputStreamReader; 7 | import java.io.OutputStream; 8 | import java.io.PrintWriter; 9 | import java.util.HashMap; 10 | import java.util.LinkedList; 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | import org.objectweb.asm.commons.Remapper; 15 | 16 | import codechicken.lib.asm.ObfMapping; 17 | 18 | import static org.objectweb.asm.tree.AbstractInsnNode.*; 19 | 20 | public class ASMFileEntry extends ModEntry implements IRemappable 21 | { 22 | public static Map types = new HashMap(); 23 | 24 | static 25 | { 26 | types.put("GETSTATIC", FIELD_INSN); 27 | types.put("PUTSTATIC", FIELD_INSN); 28 | types.put("GETFIELD", FIELD_INSN); 29 | types.put("PUTFIELD", FIELD_INSN); 30 | types.put("INVOKEVIRTUAL", METHOD_INSN); 31 | types.put("INVOKESPECIAL", METHOD_INSN); 32 | types.put("INVOKESTATIC", METHOD_INSN); 33 | types.put("INVOKEINTERFACE", METHOD_INSN); 34 | types.put("NEW", TYPE_INSN); 35 | types.put("ANEWARRAY", TYPE_INSN); 36 | types.put("CHECKCAST", TYPE_INSN); 37 | types.put("INSTANCEOF", TYPE_INSN); 38 | types.put("MULTIANEWARRAY", MULTIANEWARRAY_INSN); 39 | } 40 | 41 | public List lines = new LinkedList(); 42 | public final String name; 43 | 44 | public ASMFileEntry(Mod mod, InputStream in, String name) throws IOException 45 | { 46 | super(mod); 47 | this.name = name; 48 | 49 | BufferedReader r = new BufferedReader(new InputStreamReader(in)); 50 | String line; 51 | while((line = r.readLine()) != null) 52 | lines.add(line); 53 | } 54 | 55 | @Override 56 | public void remap() 57 | { 58 | Remapper mapper = mod.run.obfMapper; 59 | for(int i = 0; i < lines.size(); i++) 60 | { 61 | String line = lines.get(i); 62 | String comment = null; 63 | { 64 | int hpos = line.indexOf('#'); 65 | if(hpos >= 0) 66 | { 67 | comment = line.substring(hpos); 68 | line = line.substring(0, hpos); 69 | } 70 | } 71 | 72 | line = line.trim(); 73 | if(line.length() == 0) continue; 74 | String[] split = line.split(" "); 75 | Integer i_type = types.get(split[0]); 76 | if(i_type == null) 77 | continue; 78 | 79 | StringBuilder desc = new StringBuilder(); 80 | for(int j = 1; j < split.length; j++) 81 | desc.append(split[j]); 82 | split = new String[]{split[0], desc.toString()}; 83 | 84 | int type = i_type; 85 | switch(type) 86 | { 87 | case TYPE_INSN: 88 | split[1] = ObfMapping.fromDesc(split[1]).map(mapper).s_owner; 89 | break; 90 | case FIELD_INSN: 91 | split[1] = ObfMapping.fromDesc(split[1]).map(mapper).fieldDesc(); 92 | break; 93 | case METHOD_INSN: 94 | split[1] = ObfMapping.fromDesc(split[1]).map(mapper).methodDesc(); 95 | break; 96 | case MULTIANEWARRAY_INSN: 97 | split[1] = mapper.mapDesc(split[1]); 98 | break; 99 | } 100 | 101 | StringBuffer sb = new StringBuffer(); 102 | for(String s : split) 103 | { 104 | if(sb.length() > 0) 105 | sb.append(' '); 106 | sb.append(s); 107 | } 108 | if(comment != null) 109 | { 110 | sb.append(' '); 111 | sb.append(comment); 112 | } 113 | lines.set(i, sb.toString()); 114 | } 115 | 116 | mod.read.addWriteEntry(this); 117 | } 118 | 119 | @Override 120 | public String getName() 121 | { 122 | return name; 123 | } 124 | 125 | @Override 126 | public void write(OutputStream os) throws IOException 127 | { 128 | PrintWriter w = new PrintWriter(os); 129 | for(String line : lines) 130 | w.println(line); 131 | w.flush(); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/main/java/codechicken/lib/asm/ObfMapping.java: -------------------------------------------------------------------------------- 1 | package codechicken.lib.asm; 2 | 3 | import org.objectweb.asm.MethodVisitor; 4 | import org.objectweb.asm.commons.Remapper; 5 | import org.objectweb.asm.tree.AbstractInsnNode; 6 | import org.objectweb.asm.tree.FieldInsnNode; 7 | import org.objectweb.asm.tree.FieldNode; 8 | import org.objectweb.asm.tree.MethodInsnNode; 9 | import org.objectweb.asm.tree.MethodNode; 10 | import org.objectweb.asm.tree.TypeInsnNode; 11 | 12 | import com.google.common.base.Objects; 13 | 14 | public class ObfMapping 15 | { 16 | public String s_owner; 17 | public String s_name; 18 | public String s_desc; 19 | 20 | public boolean runtime; 21 | 22 | public ObfMapping(String owner) 23 | { 24 | this(owner, "", ""); 25 | } 26 | 27 | public ObfMapping(String owner, String name, String desc) 28 | { 29 | this.s_owner = owner; 30 | this.s_name = name; 31 | this.s_desc = desc; 32 | 33 | if(s_owner.contains(".")) 34 | throw new IllegalArgumentException(s_owner); 35 | } 36 | 37 | public ObfMapping(ObfMapping descmap, String subclass) 38 | { 39 | this(subclass, descmap.s_name, descmap.s_desc); 40 | } 41 | 42 | public static ObfMapping fromDesc(String s) 43 | { 44 | int lastDot = s.lastIndexOf('.'); 45 | if(lastDot < 0) 46 | return new ObfMapping(s, "", ""); 47 | int sep = s.indexOf('(');//methods 48 | int sep_end = sep; 49 | if(sep < 0) { 50 | sep = s.indexOf(' ');//some stuffs 51 | sep_end = sep+1; 52 | } 53 | if(sep < 0) { 54 | sep = s.indexOf(':');//fields 55 | sep_end = sep+1; 56 | } 57 | if(sep < 0) 58 | return new ObfMapping(s.substring(0, lastDot), s.substring(lastDot + 1), ""); 59 | 60 | return new ObfMapping(s.substring(0, lastDot), s.substring(lastDot+1, sep), s.substring(sep_end)); 61 | } 62 | 63 | public ObfMapping subclass(String subclass) 64 | { 65 | return new ObfMapping(this, subclass); 66 | } 67 | 68 | public boolean matches(MethodNode node) 69 | { 70 | return s_name.equals(node.name) && s_desc.equals(node.desc); 71 | } 72 | 73 | public boolean matches(MethodInsnNode node) 74 | { 75 | return s_owner.equals(node.owner) && s_name.equals(node.name) && s_desc.equals(node.desc); 76 | } 77 | 78 | public AbstractInsnNode toInsn(int opcode) 79 | { 80 | if(isClass()) 81 | return new TypeInsnNode(opcode, s_owner); 82 | else if(isMethod()) 83 | return new MethodInsnNode(opcode, s_owner, s_name, s_desc); 84 | else 85 | return new FieldInsnNode(opcode, s_owner, s_name, s_desc); 86 | } 87 | 88 | public void visitTypeInsn(MethodVisitor mv, int opcode) 89 | { 90 | mv.visitTypeInsn(opcode, s_owner); 91 | } 92 | 93 | public void visitMethodInsn(MethodVisitor mv, int opcode) 94 | { 95 | mv.visitMethodInsn(opcode, s_owner, s_name, s_desc); 96 | } 97 | 98 | public void visitFieldInsn(MethodVisitor mv, int opcode) 99 | { 100 | mv.visitFieldInsn(opcode, s_owner, s_name, s_desc); 101 | } 102 | 103 | public boolean isClass(String name) 104 | { 105 | return name.replace('.', '/').equals(s_owner); 106 | } 107 | 108 | public boolean matches(String name, String desc) 109 | { 110 | return s_name.equals(name) && s_desc.equals(desc); 111 | } 112 | 113 | public boolean matches(FieldNode node) 114 | { 115 | return s_name.equals(node.name) && s_desc.equals(node.desc); 116 | } 117 | 118 | public boolean matches(FieldInsnNode node) 119 | { 120 | return s_owner.equals(node.owner) && s_name.equals(node.name) && s_desc.equals(node.desc); 121 | } 122 | 123 | public String javaClass() 124 | { 125 | return s_owner.replace('/', '.'); 126 | } 127 | 128 | @Override 129 | public boolean equals(Object obj) 130 | { 131 | if(!(obj instanceof ObfMapping)) 132 | return false; 133 | 134 | ObfMapping desc = (ObfMapping)obj; 135 | return s_owner.equals(desc.s_owner) && s_name.equals(desc.s_name) && s_desc.equals(desc.s_desc); 136 | } 137 | 138 | @Override 139 | public int hashCode() 140 | { 141 | return Objects.hashCode(s_desc, s_name, s_owner); 142 | } 143 | 144 | @Override 145 | public String toString() 146 | { 147 | if(s_name.length() == 0) 148 | return "["+s_owner+"]"; 149 | if(s_desc.length() == 0) 150 | return "["+s_owner+"."+s_name+"]"; 151 | return "["+(isMethod() ? methodDesc() : fieldDesc())+"]"; 152 | } 153 | 154 | public String methodDesc() 155 | { 156 | return s_owner+"."+s_name+s_desc; 157 | } 158 | 159 | public String fieldDesc() 160 | { 161 | return s_owner+"."+s_name+":"+s_desc; 162 | } 163 | 164 | public boolean isClass() 165 | { 166 | return s_name.length() == 0; 167 | } 168 | 169 | public boolean isMethod() 170 | { 171 | return s_desc.contains("("); 172 | } 173 | 174 | public boolean isField() 175 | { 176 | return !isClass() && !isMethod(); 177 | } 178 | 179 | public ObfMapping map(Remapper mapper) 180 | { 181 | if(isMethod()) 182 | s_name = mapper.mapMethodName(s_owner, s_name, s_desc); 183 | else if(isField()) 184 | s_name = mapper.mapFieldName(s_owner, s_name, s_desc); 185 | 186 | s_owner = mapper.mapType(s_owner); 187 | 188 | if(isMethod()) 189 | s_desc = mapper.mapMethodDesc(s_desc); 190 | else if(s_desc.length() > 0) 191 | s_desc = mapper.mapDesc(s_desc); 192 | 193 | return this; 194 | } 195 | 196 | public ObfMapping copy() 197 | { 198 | return new ObfMapping(s_owner, s_name, s_desc); 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /src/main/java/codechicken/obfuscator/fs/ObfReadThread.java: -------------------------------------------------------------------------------- 1 | package codechicken.obfuscator.fs; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.util.HashMap; 8 | import java.util.LinkedList; 9 | import java.util.List; 10 | import java.util.Queue; 11 | 12 | import codechicken.obfuscator.IHeirachyEvaluator; 13 | import codechicken.obfuscator.ObfuscationRun; 14 | import codechicken.obfuscator.ObfuscationMap.ObfuscationEntry; 15 | import codechicken.obfuscator.fs.Mod.ModEntryReader; 16 | 17 | public class ObfReadThread extends Thread implements ModEntryReader, IHeirachyEvaluator 18 | { 19 | public ObfuscationRun run; 20 | 21 | public File[] mods; 22 | public File[] libs; 23 | public File outDir; 24 | 25 | private HashMap classMap = new HashMap(); 26 | private LinkedList classes = new LinkedList(); 27 | 28 | private String[] excludedPackages; 29 | private String[] ignoredPackages; 30 | private boolean zipDirs; 31 | 32 | private Queue writeQueue = new LinkedList(); 33 | public List modEntries = new LinkedList(); 34 | private boolean finishedReading = false; 35 | 36 | public ObfReadThread(ObfuscationRun run, File[] mods, File[] libs, File outDir, boolean zipDirs) 37 | { 38 | this.run = run; 39 | this.mods = mods; 40 | this.libs = libs; 41 | this.outDir = outDir; 42 | this.zipDirs = zipDirs; 43 | 44 | run.obf.setHeirachyEvaluator(this); 45 | excludedPackages = run.config.get("excludedPackages").split(";"); 46 | ignoredPackages = run.config.get("ignore").split(";"); 47 | setName("Obfuscation Read"); 48 | } 49 | 50 | @Override 51 | public void run() 52 | { 53 | ObfWriteThread write = null; 54 | try 55 | { 56 | run.start(); 57 | if(run.clean) 58 | { 59 | run.out().println("Cleaning: "+outDir.getName()); 60 | ObfuscationRun.deleteDir(outDir, false); 61 | } 62 | 63 | run.parseMappings(); 64 | 65 | write = new ObfWriteThread(this); 66 | write.start(); 67 | 68 | readMods(libs, false); 69 | readMods(mods, true); 70 | 71 | obfuscate(); 72 | } 73 | catch(Exception e) 74 | { 75 | e.printStackTrace(run.err()); 76 | if(write == null) 77 | run.finish(true); 78 | } 79 | finishedReading = true; 80 | } 81 | 82 | private void readMods(File[] files, boolean modify) 83 | { 84 | for(File file : files) 85 | { 86 | try 87 | { 88 | if(file.isDirectory()) 89 | { 90 | new DirMod(this, file, modify, zipDirs).read(this); 91 | } 92 | else if(file.getName().endsWith(".jar") || file.getName().endsWith(".zip")) 93 | { 94 | FileInputStream in = new FileInputStream(file); 95 | new ZipMod(this, file.getName(), in, modify).read(this); 96 | in.close(); 97 | } 98 | else if(file.getName().endsWith(".class")) 99 | new FileMod(this, file, modify).read(this); 100 | else 101 | run.err().println("Unknown class source: "+file.getName()); 102 | } 103 | catch(IOException e) 104 | { 105 | throw new RuntimeException("Failed to read mod: "+file.getName(), e); 106 | } 107 | } 108 | } 109 | 110 | @Override 111 | public void read(Mod mod, InputStream in, String e_name, long e_length) throws IOException 112 | { 113 | if(ignore(e_name)) 114 | return; 115 | 116 | if((e_name.endsWith(".jar") || e_name.endsWith(".zip")) && mod.writeAsync()) 117 | { 118 | new ZipMod(this, e_name, in, mod.modify()).read(this); 119 | } 120 | else if(e_name.endsWith(".class")) 121 | { 122 | if(exclude(e_name.replace('\\', '/'))) 123 | return; 124 | 125 | ObfClassEntry oce = new ObfClassEntry(mod, in); 126 | ObfClassEntry existing = classMap.get(oce.cnode.name); 127 | if(existing != null && existing.mod.modify() == mod.modify()) 128 | { 129 | run.err().println("Duplicate source found for "+oce.getName()+", "+existing.mod.name+" and "+mod.name); 130 | } 131 | else 132 | { 133 | if(existing == null || mod.modify()) 134 | classMap.put(oce.cnode.name, oce); 135 | 136 | if(mod.modify()) 137 | classes.add(oce); 138 | } 139 | } 140 | else if(mod.modify()) 141 | { 142 | if(e_name.endsWith(".asm")) 143 | classes.add(new ASMFileEntry(mod, in, e_name)); 144 | else 145 | addWriteEntry(new ModFileEntry(mod, in, e_name, e_length)); 146 | } 147 | } 148 | 149 | public boolean exclude(String name) 150 | { 151 | for(String p : excludedPackages) 152 | if(name.startsWith(p)) 153 | return true; 154 | 155 | return false; 156 | } 157 | 158 | public boolean ignore(String name) 159 | { 160 | for(String p : ignoredPackages) 161 | if(name.startsWith(p)) 162 | return true; 163 | 164 | return false; 165 | } 166 | 167 | private void obfuscate() 168 | { 169 | run.out().println((run.obfDir.obfuscate ? "O" : "Deo")+"bfuscating classes"); 170 | for(IRemappable e : classes) 171 | e.remap(); 172 | 173 | run.out().println("Remapping finished."); 174 | } 175 | 176 | @Override 177 | public List getParents(ObfuscationEntry desc) 178 | { 179 | ObfClassEntry e = classMap.get(desc.srg.s_owner); 180 | if(e == null) 181 | e = classMap.get(desc.obf.s_owner); 182 | if(e == null) 183 | return null; 184 | 185 | return ObfuscationRun.getParents(e.cnode); 186 | } 187 | 188 | @Override 189 | public boolean isLibClass(ObfuscationEntry desc) 190 | { 191 | return exclude(desc.srg.s_owner); 192 | } 193 | 194 | public void addWriteEntry(ModEntry e) 195 | { 196 | synchronized(writeQueue) 197 | { 198 | writeQueue.add(e); 199 | } 200 | } 201 | 202 | public ModEntry getWriteEntry() 203 | { 204 | synchronized(writeQueue) 205 | { 206 | return writeQueue.poll(); 207 | } 208 | } 209 | 210 | public boolean finishedReading() 211 | { 212 | return finishedReading; 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /src/main/java/codechicken/obfuscator/fs/Main.java: -------------------------------------------------------------------------------- 1 | package codechicken.obfuscator.fs; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.text.ParseException; 6 | 7 | import codechicken.lib.config.SimpleProperties; 8 | import codechicken.obfuscator.ObfuscationRun; 9 | 10 | import joptsimple.OptionException; 11 | import joptsimple.OptionParser; 12 | import joptsimple.OptionSet; 13 | 14 | import static java.util.Arrays.asList; 15 | 16 | public class Main 17 | { 18 | public static void main(String[] args) 19 | { 20 | OptionParser parser = new OptionParser(); 21 | parser.acceptsAll(asList("?", "help"), "Show the help"); 22 | parser.acceptsAll(asList("d", "deobfuscate"), "Deobfuscate inputs"); 23 | parser.acceptsAll(asList("r", "reobfuscate"), "Reobfuscate inputs"); 24 | parser.acceptsAll(asList("i", "input"), "comma separated list of paths to class sources to be obfuscated (zips or directories)") 25 | .withRequiredArg().ofType(File.class).withValuesSeparatedBy(','); 26 | parser.acceptsAll(asList("l", "libs"), "comma separated list of dependant libraries for determining class heirachy") 27 | .withRequiredArg().ofType(File.class).withValuesSeparatedBy(','); 28 | parser.acceptsAll(asList("o", "out"), "Output Path") 29 | .withRequiredArg().ofType(File.class); 30 | parser.acceptsAll(asList("m", "mapping"), "MCP conf or Forge gradle unpacked directory") 31 | .withRequiredArg().ofType(File.class); 32 | parser.accepts("srg", "joined/packaged.srg file") 33 | .withRequiredArg().ofType(File.class); 34 | parser.accepts("fields", "fields.csv file") 35 | .withRequiredArg().ofType(File.class); 36 | parser.accepts("methods", "methods.csv file") 37 | .withRequiredArg().ofType(File.class); 38 | parser.acceptsAll(asList("c", "conf"), "Config file") 39 | .withRequiredArg().ofType(File.class); 40 | parser.acceptsAll(asList("noclean"), "Disable cleaning of the output dir"); 41 | parser.acceptsAll(asList("q", "quiet"), "Disable error logging"); 42 | parser.acceptsAll(asList("v", "verbose"), "Enable detailed logging"); 43 | parser.acceptsAll(asList("zip"), "Set this to zip the contents of obfuscated directories"); 44 | parser.acceptsAll(asList("to-srg"), "Obfuscate/Deobfuscate to srg names"); 45 | parser.acceptsAll(asList("mcp"), "MCP dir, equal to -r " + 46 | "-input \"/bin/minecraft\" " + 47 | "-libs \"/lib,/jars/libraries\" " + 48 | "-m \"/conf\" " + 49 | "-o \"reobf/minecraft\"") 50 | .withOptionalArg().ofType(File.class); 51 | 52 | OptionSet options; 53 | try 54 | { 55 | options = parser.parse(args); 56 | } 57 | catch(OptionException ex) 58 | { 59 | System.err.println(ex.getLocalizedMessage()); 60 | System.exit(-1); 61 | return; 62 | } 63 | 64 | try 65 | { 66 | main(parser, options); 67 | } 68 | catch(IOException e) 69 | { 70 | throw new RuntimeException(e); 71 | } 72 | catch (ParseException e) 73 | { 74 | } 75 | } 76 | 77 | private static void main(OptionParser parser, OptionSet options) throws IOException, ParseException 78 | { 79 | boolean obfuscate = true; 80 | File[] mods = null; 81 | File[] libs = null; 82 | File confDir = null; 83 | File outDir = null; 84 | File[] mappings = null; 85 | 86 | if(options.has("mcp")) 87 | { 88 | File mcp = options.hasArgument("mcp") ? (File) options.valueOf("mcp") : new File("."); 89 | obfuscate = true; 90 | mods = new File[]{new File(mcp, "bin/minecraft")}; 91 | libs = new File[]{new File(mcp, "lib"), new File(mcp, "jars/libraries")}; 92 | confDir = new File(mcp, "conf"); 93 | outDir = new File(mcp, "reobf/minecraft"); 94 | } 95 | else 96 | { 97 | if(options.has("deobfuscate") == options.has("reobfuscate")) 98 | { 99 | System.err.println("Either -r or -d required."); 100 | parser.printHelpOn(System.err); 101 | return; 102 | } 103 | 104 | require("input", parser, options); 105 | require("libs", parser, options); 106 | require("out", parser, options); 107 | 108 | if(!options.has("mapping")) { 109 | require("srg", parser, options); 110 | require("fields", parser, options); 111 | require("methods", parser, options); 112 | } 113 | } 114 | 115 | if(options.has("reobfuscate")) 116 | obfuscate = true; 117 | if(options.has("deobfuscate")) 118 | obfuscate = false; 119 | if(options.has("input")) 120 | mods = options.valuesOf("input").toArray(new File[0]); 121 | if(options.has("libs")) 122 | libs = options.valuesOf("libs").toArray(new File[0]); 123 | if(options.has("out")) 124 | outDir = (File) options.valueOf("out"); 125 | if(options.has("mapping")) 126 | confDir = (File) options.valueOf("mapping"); 127 | 128 | if(confDir != null) 129 | mappings = ObfuscationRun.parseConfDir(confDir); 130 | else 131 | mappings = new File[]{ 132 | (File)options.valueOf("srg"), 133 | (File)options.valueOf("methods"), 134 | (File)options.valueOf("fields")}; 135 | 136 | File confFile; 137 | if(options.has("conf")) 138 | confFile = (File) options.valueOf("conf"); 139 | else 140 | confFile = new File("CCObfuscator.cfg"); 141 | if(!confFile.exists()) 142 | { 143 | confFile.getAbsoluteFile().getParentFile().mkdirs(); 144 | confFile.createNewFile(); 145 | } 146 | 147 | SimpleProperties p = new SimpleProperties(confFile); 148 | p.load(); 149 | ObfuscationRun.fillDefaults(p.propertyMap); 150 | p.save(); 151 | 152 | ObfuscationRun r = new ObfuscationRun(obfuscate, mappings, p.propertyMap); 153 | if(!options.has("noclean")) 154 | r.setClean(); 155 | if(options.has("verbose")) 156 | r.setVerbose(); 157 | if(options.has("quiet")) 158 | r.setQuiet(); 159 | if(options.has("to-srg")) 160 | r.setSearge(); 161 | 162 | new ObfReadThread(r, mods, libs, outDir, options.has("zip")).start(); 163 | } 164 | 165 | private static void require(String string, OptionParser parser, OptionSet options) throws ParseException, IOException 166 | { 167 | if(!options.has(string)) 168 | { 169 | System.err.println("--"+string+" required"); 170 | parser.printHelpOn(System.err); 171 | throw new ParseException(null, 0); 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /src/main/java/codechicken/obfuscator/ObfuscationRun.java: -------------------------------------------------------------------------------- 1 | package codechicken.obfuscator; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileReader; 6 | import java.io.PrintStream; 7 | import java.text.DecimalFormat; 8 | import java.util.LinkedList; 9 | import java.util.List; 10 | import java.util.Map; 11 | import org.objectweb.asm.ClassVisitor; 12 | import org.objectweb.asm.commons.RemappingClassAdapter; 13 | import org.objectweb.asm.tree.ClassNode; 14 | 15 | import com.google.common.base.Function; 16 | 17 | public class ObfuscationRun implements ILogStreams 18 | { 19 | public final ObfDirection obfDir; 20 | public final ObfuscationMap obf; 21 | public final ObfRemapper obfMapper; 22 | public final ConstantObfuscator cstMappper; 23 | 24 | public File[] mappings; 25 | public Map config; 26 | 27 | private PrintStream out = System.out; 28 | private PrintStream err = System.err; 29 | private PrintStream quietStream = new PrintStream(DummyOutputStream.instance); 30 | 31 | private boolean verbose; 32 | private boolean quiet; 33 | 34 | public boolean clean; 35 | private long startTime; 36 | private boolean finished; 37 | 38 | public ObfuscationRun(boolean obfuscate, File[] mappings, Map config) 39 | { 40 | obfDir = new ObfDirection().setObfuscate(obfuscate); 41 | this.mappings = mappings; 42 | this.config = config; 43 | 44 | obf = new ObfuscationMap().setLog(this); 45 | obfMapper = new ObfRemapper(obf, obfDir); 46 | cstMappper = new ConstantObfuscator(obfMapper, 47 | config.get("classConstantCalls").split(","), 48 | config.get("descConstantCalls").split(",")); 49 | } 50 | 51 | public ObfuscationRun setClean() 52 | { 53 | clean = true; 54 | return this; 55 | } 56 | 57 | public ObfuscationRun setVerbose() 58 | { 59 | verbose = true; 60 | return this; 61 | } 62 | 63 | public ObfuscationRun setQuiet() 64 | { 65 | quiet = true; 66 | return this; 67 | } 68 | 69 | public ObfuscationRun setOut(PrintStream p) 70 | { 71 | out = p; 72 | return this; 73 | } 74 | 75 | public PrintStream out() 76 | { 77 | return quiet ? quietStream : out; 78 | } 79 | 80 | public PrintStream fine() 81 | { 82 | return verbose ? out : quietStream; 83 | } 84 | 85 | public ObfuscationRun setErr(PrintStream p) 86 | { 87 | err = p; 88 | return this; 89 | } 90 | 91 | public PrintStream err() 92 | { 93 | return quiet ? quietStream : err; 94 | } 95 | 96 | public ObfuscationRun setSearge() 97 | { 98 | obfDir.setSearge(true); 99 | return this; 100 | } 101 | 102 | public ObfuscationRun setSeargeConstants() 103 | { 104 | obfDir.setSeargeConstants(true); 105 | return this; 106 | } 107 | 108 | public void start() 109 | { 110 | startTime = System.currentTimeMillis(); 111 | } 112 | 113 | public static Map fillDefaults(Map config) 114 | { 115 | if(!config.containsKey("excludedPackages")) 116 | config.put("excludedPackages", "java/;sun/;javax/;scala/;" + 117 | "argo/;org/lwjgl/;org/objectweb/;org/bouncycastle/;com/google/"); 118 | if(!config.containsKey("ignore")) 119 | config.put("ignore", "."); 120 | if(!config.containsKey("classConstantCalls")) 121 | config.put("classConstantCalls", 122 | "codechicken/lib/asm/ObfMapping.(Ljava/lang/String;)V," + 123 | "codechicken/lib/asm/ObfMapping.subclass(Ljava/lang/String;)Lcodechicken/lib/asm/ObfMapping;," + 124 | "codechicken/lib/asm/ObfMapping.(Lcodechicken/lib/asm/ObfMapping;Ljava/lang/String;)V"); 125 | if(!config.containsKey("descConstantCalls")) 126 | config.put("descConstantCalls", 127 | "codechicken/lib/asm/ObfMapping.(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V," + 128 | "org/objectweb/asm/MethodVisitor.visitFieldInsn(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V," + 129 | "org/objectweb/asm/tree/MethodNode.visitFieldInsn(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V," + 130 | "org/objectweb/asm/MethodVisitor.visitMethodInsn(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V," + 131 | "org/objectweb/asm/tree/MethodNode.visitMethodInsn(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V," + 132 | "org/objectweb/asm/tree/MethodInsnNode.(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V," + 133 | "org/objectweb/asm/tree/FieldInsnNode.(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); 134 | 135 | return config; 136 | } 137 | 138 | public static void processLines(File file, Function function) 139 | { 140 | try 141 | { 142 | BufferedReader reader = new BufferedReader(new FileReader(file)); 143 | String line; 144 | while((line = reader.readLine()) != null) 145 | function.apply(line); 146 | reader.close(); 147 | } 148 | catch(Exception e) 149 | { 150 | throw new RuntimeException(e); 151 | } 152 | } 153 | 154 | public static void processFiles(File dir, Function function, boolean recursive) 155 | { 156 | for(File file : dir.listFiles()) 157 | if(file.isDirectory() && recursive) 158 | processFiles(file, function, recursive); 159 | else 160 | function.apply(file); 161 | } 162 | 163 | public static void deleteDir(File directory, boolean remove) 164 | { 165 | if(!directory.exists()) 166 | { 167 | if(!remove)directory.mkdirs(); 168 | return; 169 | } 170 | for(File file : directory.listFiles()) 171 | { 172 | if(file.isDirectory()) 173 | { 174 | deleteDir(file, true); 175 | } 176 | else 177 | { 178 | if(!file.delete()) 179 | throw new RuntimeException("Delete Failed: "+file); 180 | } 181 | } 182 | if(remove) 183 | { 184 | if(!directory.delete()) 185 | throw new RuntimeException("Delete Failed: "+directory); 186 | } 187 | } 188 | 189 | public static File[] parseConfDir(File confDir) { 190 | File srgDir = new File(confDir, "conf"); 191 | if(!srgDir.exists()) 192 | srgDir = confDir; 193 | 194 | File srgs = new File(srgDir, "packaged.srg"); 195 | if(!srgs.exists()) 196 | srgs = new File(srgDir, "joined.srg"); 197 | if(!srgs.exists()) 198 | throw new RuntimeException("Could not find packaged.srg or joined.srg"); 199 | 200 | File mapDir = new File(confDir, "mappings"); 201 | if(!mapDir.exists()) 202 | mapDir = confDir; 203 | 204 | File methods = new File(mapDir, "methods.csv"); 205 | if(!methods.exists()) 206 | throw new RuntimeException("Could not find methods.csv"); 207 | File fields = new File(mapDir, "fields.csv"); 208 | if(!fields.exists()) 209 | throw new RuntimeException("Could not find fields.csv"); 210 | 211 | return new File[]{srgs, methods, fields}; 212 | } 213 | 214 | public long startTime() 215 | { 216 | return startTime; 217 | } 218 | 219 | public void remap(ClassNode cnode, ClassVisitor cv) 220 | { 221 | cstMappper.transform(cnode); 222 | cnode.accept(new RemappingClassAdapter(cv, obfMapper)); 223 | } 224 | 225 | public static List getParents(ClassNode cnode) 226 | { 227 | List parents = new LinkedList(); 228 | if(cnode.superName != null) 229 | parents.add(cnode.superName); 230 | 231 | for(String s_interface : cnode.interfaces) 232 | parents.add(s_interface); 233 | 234 | return parents; 235 | } 236 | 237 | public void finish(boolean errored) 238 | { 239 | long millis = System.currentTimeMillis()-startTime; 240 | out().println((errored ? "Errored after" : "Done in ")+new DecimalFormat("0.00").format(millis/1000D)+"s"); 241 | finished = true; 242 | } 243 | 244 | public boolean finished() 245 | { 246 | return finished; 247 | } 248 | 249 | public void parseMappings() 250 | { 251 | obf.parseMappings(mappings); 252 | } 253 | } 254 | -------------------------------------------------------------------------------- /src/main/java/codechicken/lib/asm/InstructionComparator.java: -------------------------------------------------------------------------------- 1 | package codechicken.lib.asm; 2 | 3 | import java.util.HashMap; 4 | import java.util.HashSet; 5 | import java.util.LinkedList; 6 | import java.util.List; 7 | 8 | import org.objectweb.asm.tree.AbstractInsnNode; 9 | import org.objectweb.asm.tree.FieldInsnNode; 10 | import org.objectweb.asm.tree.IincInsnNode; 11 | import org.objectweb.asm.tree.InsnList; 12 | import org.objectweb.asm.tree.IntInsnNode; 13 | import org.objectweb.asm.tree.JumpInsnNode; 14 | import org.objectweb.asm.tree.LabelNode; 15 | import org.objectweb.asm.tree.LdcInsnNode; 16 | import org.objectweb.asm.tree.LineNumberNode; 17 | import org.objectweb.asm.tree.LookupSwitchInsnNode; 18 | import org.objectweb.asm.tree.MethodInsnNode; 19 | import org.objectweb.asm.tree.TableSwitchInsnNode; 20 | import org.objectweb.asm.tree.TypeInsnNode; 21 | import org.objectweb.asm.tree.VarInsnNode; 22 | 23 | import static org.objectweb.asm.tree.AbstractInsnNode.*; 24 | 25 | import codechicken.lib.asm.ObfMapping; 26 | 27 | public class InstructionComparator 28 | { 29 | public static class InsnListSection 30 | { 31 | public InsnListSection(AbstractInsnNode first, AbstractInsnNode last) 32 | { 33 | this.first = first; 34 | this.last = last; 35 | } 36 | 37 | public InsnListSection(InsnList haystack, int start, int end) 38 | { 39 | this(haystack.get(start), haystack.get(end)); 40 | } 41 | 42 | public AbstractInsnNode first; 43 | public AbstractInsnNode last; 44 | } 45 | 46 | public static boolean varInsnEqual(VarInsnNode insn1, VarInsnNode insn2) 47 | { 48 | if(insn1.var == -1 || insn2.var == -1) 49 | return true; 50 | 51 | return insn1.var == insn2.var; 52 | } 53 | 54 | public static boolean methodInsnEqual(AbstractInsnNode absnode, int Opcode, ObfMapping method) 55 | { 56 | if(!(absnode instanceof MethodInsnNode) || absnode.getOpcode() != Opcode) 57 | return false; 58 | 59 | return method.matches((MethodInsnNode)absnode); 60 | } 61 | 62 | public static boolean methodInsnEqual(MethodInsnNode insn1, MethodInsnNode insn2) 63 | { 64 | return insn1.owner.equals(insn2.owner) && insn1.name.equals(insn2.name) && insn1.desc.equals(insn2.desc); 65 | } 66 | 67 | public static boolean fieldInsnEqual(FieldInsnNode insn1, FieldInsnNode insn2) 68 | { 69 | return insn1.owner.equals(insn2.owner) && insn1.name.equals(insn2.name) && insn1.desc.equals(insn2.desc); 70 | } 71 | 72 | public static boolean ldcInsnEqual(LdcInsnNode insn1, LdcInsnNode insn2) 73 | { 74 | if(insn1.cst.equals("~") || insn2.cst.equals("~")) 75 | return true; 76 | 77 | return insn1.cst.equals(insn2.cst); 78 | } 79 | 80 | public static boolean typeInsnEqual(TypeInsnNode insn1, TypeInsnNode insn2) 81 | { 82 | if(insn1.desc.equals("~") || insn2.desc.equals("~")) 83 | return true; 84 | 85 | return insn1.desc.equals(insn2.desc); 86 | } 87 | 88 | public static boolean iincInsnEqual(IincInsnNode node1, IincInsnNode node2) 89 | { 90 | return node1.var == node2.var && node1.incr == node2.incr; 91 | } 92 | 93 | public static boolean intInsnEqual(IntInsnNode node1, IntInsnNode node2) 94 | { 95 | if(node1.operand == -1 || node2.operand == -1) 96 | return true; 97 | 98 | return node1.operand == node2.operand; 99 | } 100 | 101 | public static boolean insnEqual(AbstractInsnNode node1, AbstractInsnNode node2) 102 | { 103 | if(node1.getOpcode() != node2.getOpcode()) 104 | return false; 105 | 106 | switch(node2.getType()) 107 | { 108 | case VAR_INSN: 109 | return varInsnEqual((VarInsnNode) node1, (VarInsnNode) node2); 110 | case TYPE_INSN: 111 | return typeInsnEqual((TypeInsnNode) node1, (TypeInsnNode) node2); 112 | case FIELD_INSN: 113 | return fieldInsnEqual((FieldInsnNode) node1, (FieldInsnNode) node2); 114 | case METHOD_INSN: 115 | return methodInsnEqual((MethodInsnNode) node1, (MethodInsnNode) node2); 116 | case LDC_INSN: 117 | return ldcInsnEqual((LdcInsnNode) node1, (LdcInsnNode) node2); 118 | case IINC_INSN: 119 | return iincInsnEqual((IincInsnNode) node1, (IincInsnNode) node2); 120 | case INT_INSN: 121 | return intInsnEqual((IntInsnNode)node1, (IntInsnNode)node2); 122 | default: 123 | return true; 124 | } 125 | } 126 | 127 | public static InsnList getImportantList(InsnList list) 128 | { 129 | if(list.size() == 0) 130 | return list; 131 | 132 | HashMap labels = new HashMap(); 133 | for(AbstractInsnNode insn = list.getFirst(); insn != null; insn = insn.getNext()) 134 | { 135 | if(insn instanceof LabelNode) 136 | labels.put((LabelNode)insn, (LabelNode)insn); 137 | } 138 | 139 | InsnList importantNodeList = new InsnList(); 140 | for(AbstractInsnNode insn = list.getFirst(); insn != null; insn = insn.getNext()) 141 | { 142 | if(insn instanceof LabelNode || insn instanceof LineNumberNode) 143 | continue; 144 | 145 | importantNodeList.add(insn.clone(labels)); 146 | } 147 | return importantNodeList; 148 | } 149 | 150 | public static boolean insnListMatches(InsnList haystack, InsnList needle, int start) 151 | { 152 | if(haystack.size()-start < needle.size()) 153 | return false; 154 | 155 | for(int i = 0; i < needle.size(); i++) 156 | { 157 | if(!insnEqual(haystack.get(i+start), needle.get(i))) 158 | return false; 159 | } 160 | return true; 161 | } 162 | 163 | public static List insnListFind(InsnList haystack, InsnList needle) 164 | { 165 | LinkedList list = new LinkedList(); 166 | for(int start = 0; start <= haystack.size()-needle.size(); start++) 167 | if(insnListMatches(haystack, needle, start)) 168 | list.add(start); 169 | 170 | return list; 171 | } 172 | 173 | public static List insnListFindStart(InsnList haystack, InsnList needle) 174 | { 175 | LinkedList callNodes = new LinkedList(); 176 | for(int callPoint : insnListFind(haystack, needle)) 177 | callNodes.add(haystack.get(callPoint)); 178 | return callNodes; 179 | } 180 | 181 | public static List insnListFindEnd(InsnList haystack, InsnList needle) 182 | { 183 | LinkedList callNodes = new LinkedList(); 184 | for(int callPoint : insnListFind(haystack, needle)) 185 | callNodes.add(haystack.get(callPoint+needle.size()-1)); 186 | return callNodes; 187 | } 188 | 189 | public static List insnListFindL(InsnList haystack, InsnList needle) 190 | { 191 | HashSet controlFlowLabels = new HashSet(); 192 | 193 | for(AbstractInsnNode insn = haystack.getFirst(); insn != null; insn = insn.getNext()) 194 | { 195 | switch(insn.getType()) 196 | { 197 | case 8: 198 | case 15: 199 | break; 200 | case 7: 201 | JumpInsnNode jinsn = (JumpInsnNode)insn; 202 | controlFlowLabels.add(jinsn.label); 203 | break; 204 | case 11: 205 | TableSwitchInsnNode tsinsn = (TableSwitchInsnNode)insn; 206 | for(LabelNode label : tsinsn.labels) 207 | controlFlowLabels.add(label); 208 | break; 209 | case 12: 210 | LookupSwitchInsnNode lsinsn = (LookupSwitchInsnNode)insn; 211 | for(LabelNode label : lsinsn.labels) 212 | controlFlowLabels.add(label); 213 | break; 214 | } 215 | } 216 | 217 | LinkedList list = new LinkedList(); 218 | nextsection: for(int start = 0; start <= haystack.size()-needle.size(); start++) 219 | { 220 | InsnListSection section = insnListMatchesL(haystack, needle, start, controlFlowLabels); 221 | if(section != null) 222 | { 223 | for(InsnListSection asection : list) 224 | if(asection.last == section.last) 225 | continue nextsection; 226 | 227 | list.add(section); 228 | } 229 | } 230 | 231 | return list; 232 | } 233 | 234 | private static InsnListSection insnListMatchesL(InsnList haystack, InsnList needle, int start, HashSet controlFlowLabels) 235 | { 236 | int h = start, n = 0; 237 | for(;h < haystack.size() && n < needle.size(); h++) 238 | { 239 | AbstractInsnNode insn = haystack.get(h); 240 | if(insn.getType() == 15) 241 | continue; 242 | if(insn.getType() == 8 && !controlFlowLabels.contains(insn)) 243 | continue; 244 | 245 | if(!insnEqual(haystack.get(h), needle.get(n))) 246 | return null; 247 | n++; 248 | } 249 | if(n != needle.size()) 250 | return null; 251 | 252 | return new InsnListSection(haystack, start, h-1); 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /src/main/java/codechicken/obfuscator/ObfuscationMap.java: -------------------------------------------------------------------------------- 1 | package codechicken.obfuscator; 2 | 3 | import java.io.File; 4 | import java.util.HashMap; 5 | import java.util.HashSet; 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.Objects; 9 | import java.util.Map.Entry; 10 | 11 | import com.google.common.base.Function; 12 | import com.google.common.collect.ArrayListMultimap; 13 | 14 | import codechicken.lib.asm.ObfMapping; 15 | 16 | public class ObfuscationMap 17 | { 18 | public class ObfuscationEntry 19 | { 20 | public final ObfMapping obf; 21 | public final ObfMapping srg; 22 | public final ObfMapping mcp; 23 | 24 | public ObfuscationEntry(ObfMapping obf, ObfMapping srg, ObfMapping mcp) 25 | { 26 | this.obf = obf; 27 | this.srg = srg; 28 | this.mcp = mcp; 29 | } 30 | } 31 | 32 | private class ClassEntry extends ObfuscationEntry 33 | { 34 | public Map mcpMap = new HashMap(); 35 | public Map srgMap = new HashMap(); 36 | public Map obfMap = new HashMap(); 37 | 38 | public ClassEntry(String obf, String srg) 39 | { 40 | super(new ObfMapping(obf, "", ""), 41 | new ObfMapping(srg, "", ""), 42 | new ObfMapping(srg, "", "")); 43 | } 44 | 45 | public ObfuscationEntry addEntry(ObfMapping obf_desc, ObfMapping srg_desc) 46 | { 47 | ObfuscationEntry entry = new ObfuscationEntry(obf_desc, srg_desc, srg_desc.copy()); 48 | obfMap.put(obf_desc.s_name.concat(obf_desc.s_desc), entry); 49 | srgMap.put(srg_desc.s_name, entry); 50 | 51 | if(srg_desc.s_name.startsWith("field_") || srg_desc.s_name.startsWith("func_")) 52 | srgMemberMap.put(srg_desc.s_name, entry); 53 | 54 | return entry; 55 | } 56 | 57 | public void inheritFrom(ClassEntry p) 58 | { 59 | inherit(obfMap, p.obfMap); 60 | inherit(srgMap, p.srgMap); 61 | inherit(mcpMap, p.mcpMap); 62 | } 63 | 64 | private void inherit(Map child, Map parent) 65 | { 66 | for(Entry e : parent.entrySet()) 67 | if(!child.containsKey(e.getKey())) 68 | child.put(e.getKey(), e.getValue()); 69 | } 70 | } 71 | 72 | private Map srgMap = new HashMap(); 73 | private Map obfMap = new HashMap(); 74 | private String dotPkA; 75 | private String dotPkB; 76 | private ArrayListMultimap srgMemberMap = ArrayListMultimap.create(); 77 | 78 | private IHeirachyEvaluator heirachyEvaluator; 79 | private HashSet mappedClasses = new HashSet(); 80 | public ILogStreams log = SystemLogStreams.inst; 81 | 82 | public ObfuscationMap setHeirachyEvaluator(IHeirachyEvaluator eval) 83 | { 84 | heirachyEvaluator = eval; 85 | return this; 86 | } 87 | 88 | public ObfuscationMap setLog(ILogStreams log) 89 | { 90 | this.log = log; 91 | return this; 92 | } 93 | 94 | public ObfuscationEntry addClass(String obf, String srg) 95 | { 96 | return addEntry(new ObfMapping(obf, "", ""), new ObfMapping(srg, "", "")); 97 | } 98 | 99 | public ObfuscationEntry addField(String obf_owner, String obf_name, String srg_owner, String srg_name) 100 | { 101 | return addEntry(new ObfMapping(obf_owner, obf_name, ""), 102 | new ObfMapping(srg_owner, srg_name, "")); 103 | } 104 | 105 | public ObfuscationEntry addMethod(String obf_owner, String obf_name, String obf_desc, String srg_owner, String srg_name, String srg_desc) 106 | { 107 | return addEntry(new ObfMapping(obf_owner, obf_name, obf_desc), 108 | new ObfMapping(srg_owner, srg_name, srg_desc)); 109 | } 110 | 111 | public ObfuscationEntry addEntry(ObfMapping obf_desc, ObfMapping srg_desc) 112 | { 113 | ClassEntry e = srgMap.get(srg_desc.s_owner); 114 | if(e == null) 115 | { 116 | e = new ClassEntry(obf_desc.s_owner, srg_desc.s_owner); 117 | obfMap.put(obf_desc.s_owner, e); 118 | srgMap.put(srg_desc.s_owner, e); 119 | } 120 | if(obf_desc.s_name.length() > 0) 121 | return e.addEntry(obf_desc, srg_desc); 122 | 123 | return e; 124 | } 125 | 126 | public void addMcpName(String srg_name, String mcp_name) 127 | { 128 | List entries = srgMemberMap.get(srg_name); 129 | if(entries.isEmpty()) 130 | { 131 | log.err().println("Tried to add mcp name ("+mcp_name+") for unknown srg key ("+srg_name+")"); 132 | return; 133 | } 134 | for(ObfuscationEntry entry : entries) 135 | { 136 | entry.mcp.s_name = mcp_name; 137 | srgMap.get(entry.srg.s_owner).mcpMap.put(entry.mcp.s_name.concat(entry.mcp.s_desc), entry); 138 | } 139 | } 140 | 141 | public String getDotPkA() { 142 | return dotPkA; 143 | } 144 | 145 | public String getDotPkB() { 146 | return dotPkB; 147 | } 148 | 149 | public ObfuscationEntry lookupSrg(String srg_key) 150 | { 151 | List list = srgMemberMap.get(srg_key); 152 | return list.isEmpty() ? null : list.get(0); 153 | } 154 | 155 | public ObfuscationEntry lookupMcpClass(String name) 156 | { 157 | return srgMap.get(name); 158 | } 159 | 160 | public ObfuscationEntry lookupObfClass(String name) 161 | { 162 | return obfMap.get(name); 163 | } 164 | 165 | public ObfuscationEntry lookupMcpField(String owner, String name) 166 | { 167 | return lookupMcpMethod(owner, name, ""); 168 | } 169 | 170 | public ObfuscationEntry lookupSrgField(String owner, String name) 171 | { 172 | if(name.startsWith("field_")) 173 | { 174 | ObfuscationEntry e = lookupSrg(name); 175 | if(e != null) 176 | return e; 177 | } 178 | 179 | evaluateHeirachy(owner); 180 | ClassEntry e = srgMap.get(owner); 181 | return e == null ? null : e.srgMap.get(name); 182 | } 183 | 184 | public ObfuscationEntry lookupObfField(String owner, String name) 185 | { 186 | return lookupObfMethod(owner, name, ""); 187 | } 188 | 189 | public ObfuscationEntry lookupMcpMethod(String owner, String name, String desc) 190 | { 191 | evaluateHeirachy(owner); 192 | ClassEntry e = srgMap.get(owner); 193 | return e == null ? null : e.mcpMap.get(name.concat(desc)); 194 | } 195 | 196 | public ObfuscationEntry lookupObfMethod(String owner, String name, String desc) 197 | { 198 | evaluateHeirachy(owner); 199 | ClassEntry e = obfMap.get(owner); 200 | return e == null ? null : e.obfMap.get(name.concat(desc)); 201 | } 202 | 203 | private boolean isMapped(ObfuscationEntry desc) 204 | { 205 | return mappedClasses.contains(desc.srg.s_owner); 206 | } 207 | 208 | private ObfuscationEntry getOrCreateClassEntry(String name) 209 | { 210 | ObfuscationEntry e = lookupObfClass(name); 211 | if(e == null) 212 | e = lookupMcpClass(name); 213 | if(e == null) 214 | e = addClass(name, name);//if the class isn't in obf or srg maps, it must be a custom mod class with no name change. 215 | return e; 216 | } 217 | 218 | public ObfuscationEntry evaluateHeirachy(String name) 219 | { 220 | ObfuscationEntry desc = getOrCreateClassEntry(name); 221 | if(isMapped(desc)) 222 | return desc; 223 | 224 | mappedClasses.add(desc.srg.s_owner); 225 | if(heirachyEvaluator == null) 226 | throw new IllegalArgumentException("Cannot call method/field mappings if a heirachy evaluator is not set."); 227 | 228 | if(!heirachyEvaluator.isLibClass(desc)) 229 | { 230 | List parents = heirachyEvaluator.getParents(desc); 231 | if(parents == null) 232 | log.err().println("Could not find class: "+desc.srg.s_owner); 233 | else 234 | for(String parent : parents) 235 | inherit(desc, evaluateHeirachy(parent)); 236 | } 237 | 238 | return desc; 239 | } 240 | 241 | public void inherit(ObfuscationEntry desc, ObfuscationEntry p_desc) 242 | { 243 | inherit(desc.srg.s_owner, p_desc.srg.s_owner); 244 | } 245 | 246 | public void inherit(String name, String parent) 247 | { 248 | ClassEntry e = srgMap.get(name); 249 | if(e == null) 250 | throw new IllegalStateException("Tried to inerit to an undefined class: "+name+" extends "+parent); 251 | ClassEntry p = srgMap.get(parent); 252 | if(p == null) 253 | throw new IllegalStateException("Tried to inerit from undefired parent: "+name+" extends "+parent); 254 | e.inheritFrom(p); 255 | } 256 | 257 | public void parseMappings(File[] mappings) 258 | { 259 | parseSRGS(mappings[0]); 260 | parseCSV(mappings[1]); 261 | parseCSV(mappings[2]); 262 | } 263 | 264 | public static String[] splitLast(String s, char c) 265 | { 266 | int i = s.lastIndexOf(c); 267 | return new String[]{s.substring(0, i), s.substring(i+1)}; 268 | } 269 | 270 | public static String[] split4(String s, char c) 271 | { 272 | String[] split = new String[4]; 273 | int i2 = s.indexOf(c); 274 | split[0] = s.substring(0, i2); 275 | int i = i2+1; 276 | i2 = s.indexOf(c, i); 277 | split[1] = s.substring(i, i2); 278 | i = i2+1; 279 | i2 = s.indexOf(c, i); 280 | split[2] = s.substring(i, i2); 281 | i = i2+1; 282 | i2 = s.indexOf(c, i); 283 | split[3] = s.substring(i); 284 | return split; 285 | } 286 | 287 | private void parseSRGS(File srgs) 288 | { 289 | log.out().println("Parsing "+srgs.getName()); 290 | 291 | Function function = new Function() 292 | { 293 | @Override 294 | public Void apply(String line) 295 | { 296 | int hpos = line.indexOf('#'); 297 | if(hpos > 0) 298 | line = line.substring(0, hpos).trim(); 299 | if(line.startsWith("CL: ")) 300 | { 301 | String[] params = splitLast(line.substring(4), ' '); 302 | addClass(params[0], params[1]); 303 | } 304 | else if(line.startsWith("FD: ")) 305 | { 306 | String[] params = splitLast(line.substring(4), ' '); 307 | String[] p1 = splitLast(params[0], '/'); 308 | String[] p2 = splitLast(params[1], '/'); 309 | addField(p1[0], p1[1], 310 | p2[0], p2[1]); 311 | return null; 312 | } 313 | else if(line.startsWith("MD: ")) 314 | { 315 | String[] params = split4(line.substring(4), ' '); 316 | String[] p1 = splitLast(params[0], '/'); 317 | String[] p2 = splitLast(params[2], '/'); 318 | addMethod(p1[0], p1[1], params[1], 319 | p2[0], p2[1], params[3]); 320 | return null; 321 | } 322 | else if(line.startsWith("PK: ")) 323 | { 324 | String[] params = splitLast(line.substring(4), ' '); 325 | if (".".equals(params[0]) || ".".equals(params[1])) 326 | { 327 | if (dotPkA != null || dotPkB != null) 328 | { 329 | throw new RuntimeException("Multiple dot PK lines are not supported."); 330 | } 331 | dotPkA = params[0]; 332 | dotPkB = params[1]; 333 | } else if (!Objects.equals(params[0], params[1])) 334 | { 335 | throw new RuntimeException("Unable to handle PK line: " + line); 336 | } 337 | } 338 | return null; 339 | } 340 | }; 341 | 342 | ObfuscationRun.processLines(srgs, function); 343 | } 344 | 345 | private void parseCSV(File csv) 346 | { 347 | log.out().println("Parsing "+csv.getName()); 348 | 349 | Function function = new Function() 350 | { 351 | @Override 352 | public Void apply(String line) 353 | { 354 | if(line.startsWith("func_") || line.startsWith("field_")) 355 | { 356 | int i = line.indexOf(','); 357 | String srg = line.substring(0, i); 358 | int i2 = i+1; 359 | i = line.indexOf(',', i2); 360 | String mcp = line.substring(i2, i); 361 | 362 | addMcpName(srg, mcp); 363 | } 364 | return null; 365 | } 366 | }; 367 | 368 | ObfuscationRun.processLines(csv, function); 369 | } 370 | } 371 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | [This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.] 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | 474 | Copyright (C) 2013 Chicken-Bones 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 489 | 490 | Also add information on how to contact you by electronic and paper mail. 491 | 492 | You should also get your employer (if you work as a programmer) or your 493 | school, if any, to sign a "copyright disclaimer" for the library, if 494 | necessary. Here is a sample; alter the names: 495 | 496 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 497 | library `Frob' (a library for tweaking knobs) written by James Random Hacker. 498 | 499 | {signature of Ty Coon}, 1 April 1990 500 | Ty Coon, President of Vice 501 | 502 | That's all there is to it! 503 | --------------------------------------------------------------------------------