Skip to content

Commit 929031c

Browse files
author
Nikita
authored
Added CLI arguments, added Stream API usage (#3)
* Changed Usage section, Needed APIs section * Fix README * Changed Usage section * Added CLI arguments, added Stream API usage
1 parent 4c8ee44 commit 929031c

14 files changed

+213
-191
lines changed

README.md

+9-4
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@
22
NeonObf-uscator is start-up obfuscator
33

44
## Usage
5-
java -jar NeonObf.jar <jar_to_obfuscate> <jar_to_obfuscate_out> </path/to/libs/> <_transformers> <min/norm/max>
5+
**WARNING**: currently doesn't working with Java 9.
66

7-
Example: java -jar NeonObf.jar IN.jar OUT.jar libs SourceFileRemover;LineNumberObfuscation;FinalRemover;LocalVariableNameObfuscator;BasicTypesEncryption;GotoFloodObfuscation;CodeHider max
87

9-
P.S.: you can use "null" (w/o quotes) as </path/to/libs/>
8+
Get usage by running
109

11-
It's highly recommended to use ProGuard with short names obfuscation before NeonObf
10+
```
11+
java -jar NeonObf.jar
12+
```
13+
14+
15+
It's highly recommended to use ProGuard with short names obfuscation before NeonObf as it's reducing memory usage of NeonObf
1216

1317
## License
1418
MIT
@@ -27,3 +31,4 @@ ObjectWeb ASM v6.0 (BETA):
2731
- asm-analysis
2832
- asm-commons
2933
- asm-tree
34+
- commons-cli

com/neonObf/CustomClassWriter.java

+2-4
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,17 @@ public static List<ClassNode> loadHierachy(ClassNode specificNode) {
4545
ClassTree thisTree = getClassTree(specificNode.name);
4646
ClassNode superClass = null;
4747
superClass = assureLoaded(specificNode.superName);
48-
if (superClass == null) {
48+
if (superClass == null)
4949
throw new IllegalArgumentException("Could not load " + specificNode.name);
50-
}
5150
ClassTree superTree = getClassTree(superClass.name);
5251
superTree.subClasses.add(specificNode.name);
5352
thisTree.parentClasses.add(superClass.name);
5453
toProcess.add(superClass);
5554

5655
for(String interfaceReference : (List<String>) specificNode.interfaces) {
5756
ClassNode interfaceNode = assureLoaded(interfaceReference);
58-
if (interfaceNode == null) {
57+
if (interfaceNode == null)
5958
throw new IllegalArgumentException("Could not load " + interfaceReference);
60-
}
6159
ClassTree interfaceTree = getClassTree(interfaceReference);
6260
interfaceTree.subClasses.add(specificNode.name);
6361
thisTree.parentClasses.add(interfaceReference);

com/neonObf/DirWalker.java

+14-17
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,14 @@
22

33

44
import java.io.File;
5-
import java.io.FileInputStream;
65
import java.util.ArrayList;
7-
import java.util.Enumeration;
8-
import java.util.zip.ZipEntry;
6+
import java.util.Collections;
97
import java.util.zip.ZipFile;
108

119
import org.objectweb.asm.ClassReader;
1210

1311
public class DirWalker {
1412
public DirWalker(File file, boolean isLibrary) throws Throwable {
15-
Main inst = Main.getInstance();
1613
String name = file.getName();
1714
String path = file.getAbsolutePath();
1815
if (file.isDirectory()) {
@@ -25,7 +22,8 @@ public DirWalker(File file, boolean isLibrary) throws Throwable {
2522
if (name.endsWith("jar"))
2623
loadZIP(new File(path), isLibrary);
2724
if (name.endsWith("class"))
28-
loadClass(new File(path), isLibrary);
25+
if(!name.equals("module-info.class"))
26+
loadClass(new File(path), isLibrary);
2927
}
3028
}
3129

@@ -42,19 +40,18 @@ public void loadClass(File f, boolean isLibrary) throws Throwable {
4240
public void loadZIP(File f, boolean isLibrary) throws Throwable {
4341
Main inst = Main.getInstance();
4442
final ZipFile zipIn = new ZipFile(f);
45-
final Enumeration<? extends ZipEntry> e = zipIn.entries();
4643
ArrayList<String> classList = new ArrayList<>();
47-
while (e.hasMoreElements()) {
48-
final ZipEntry next = e.nextElement();
49-
if (next.getName().endsWith(".class")) {
50-
if(isLibrary)
51-
classList.add(next.getName().replaceAll("(.*)\\.class", "$1"));
52-
else
53-
inst.classes.add(CustomClassWriter.loadClass(zipIn.getInputStream(next), ClassReader.SKIP_FRAMES));
54-
} else
55-
if (next.isDirectory())
56-
continue;
57-
}
44+
Collections.list(zipIn.entries()).forEach((next) -> {
45+
try {
46+
if (next.getName().endsWith(".class") && !next.getName().equals("module-info.class"))
47+
if (isLibrary)
48+
classList.add(next.getName().replaceAll("(.*)\\.class", "$1"));
49+
else
50+
inst.classes.add(CustomClassWriter.loadClass(zipIn.getInputStream(next), ClassReader.SKIP_FRAMES));
51+
} catch(Throwable t) {
52+
t.printStackTrace();
53+
}
54+
});
5855
zipIn.close();
5956
inst.loadedAPI.add(new ZIPLibrary(f, classList, isLibrary));
6057
}

com/neonObf/Main.java

+95-81
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import java.util.zip.ZipFile;
1717
import java.util.zip.ZipOutputStream;
1818

19+
import org.apache.commons.cli.*;
1920
import org.objectweb.asm.ClassWriter;
2021
import org.objectweb.asm.tree.ClassNode;
2122
import org.objectweb.asm.tree.InnerClassNode;
@@ -32,102 +33,113 @@ public class Main extends Thread {
3233
public ArrayList<ClassFile> files = new ArrayList<ClassFile>();
3334
public HashMap<String, ClassNode> nameToNode = new HashMap<String, ClassNode>();
3435
public HashMap<ClassNode, String> nodeToName = new HashMap<ClassNode, String>();
36+
public String[] libraries;
3537
public ArrayList<Library> loadedAPI = new ArrayList<Library>();
36-
public ArrayList<File> paths = new ArrayList<File>();
3738
public String[] usedTransformers;
3839
public HashMap<String, Integer> pkgLens = new HashMap<String, Integer>();
3940
public SmartNameGen nameGen;
4041
public String[] args;
42+
public CommandLine cmd;
4143

4244
public static Main getInstance() {
4345
return instance;
4446
}
4547

46-
private void checkArgs() throws Throwable {
47-
if (args.length < 5) {
48-
System.out
49-
.println("Usage: java -jar NeonObf.jar <jar_to_obfuscate> <jar_to_obfuscate_out> </path/to/libs/> <transformers> <min/norm/max>");
50-
throw new Throwable();
51-
}
52-
53-
for(int i = 0; i < args.length; i++)
54-
if (parseArg(args[i], i, args)) {
55-
checkArgs();
56-
break;
57-
}
58-
}
59-
6048
/***
6149
* Parses argument
62-
*
63-
* @param arg
64-
* Argument from massive
65-
* @param index
66-
* Index of argument in massive
67-
* @param args
68-
* All arguments
69-
* @return Needed in restart argument checking?
50+
*
7051
* @throws Throwable
7152
*/
72-
public boolean parseArg(String arg, int index, String[] args) throws Throwable {
73-
File f;
74-
switch (index) {
75-
case 0:
76-
if (!(f = new File(arg)).exists())
77-
throw new Throwable("Jar to obfuscate not found :L");
78-
inF = f;
53+
public void parseArgs() throws Throwable {
54+
Options options = new Options();
7955

80-
break;
81-
case 1:
82-
if ((f = new File(arg)).exists()) {
83-
String postfix = "." + new Random().nextInt(100);
84-
args[1] += postfix;
85-
System.out.println("Out file already exists. Using " + postfix);
86-
return true;
87-
}
88-
outF = f;
56+
Option inputArg = new Option("i", "input", true, "Input .jar/.class file/folder path");
57+
inputArg.setRequired(true);
58+
inputArg.setArgName("path");
59+
options.addOption(inputArg);
60+
61+
Option outputArg = new Option("o", "output", true, "Output .jar path");
62+
outputArg.setRequired(true);
63+
outputArg.setArgName("path");
64+
options.addOption(outputArg);
65+
66+
Option librariesArg = new Option("l", "libraries", true, "Libraries path (separated by semicolons/multiple arguments)");
67+
librariesArg.setRequired(false);
68+
librariesArg.setArgName("path");
69+
options.addOption(librariesArg);
70+
71+
Option transformersArg = new Option("t", "transformers", true, "Transformers (separated by semicolons/multiple arguments)");
72+
transformersArg.setRequired(true);
73+
transformersArg.setArgName("transformers");
74+
options.addOption(transformersArg);
75+
76+
Option dictionaryArg = new Option("d", "dictionary", true, "Dictionary type");
77+
dictionaryArg.setRequired(true);
78+
dictionaryArg.setArgName("1/2/3");
79+
options.addOption(dictionaryArg);
80+
81+
CommandLineParser parser = new DefaultParser();
82+
HelpFormatter formatter = new HelpFormatter();
83+
84+
try {
85+
cmd = parser.parse(options, args);
86+
} catch (ParseException e) {
87+
System.out.println(e.getMessage());
88+
formatter.printHelp("java -jar NeonObf.jar", options, true);
89+
System.out.println("Example: java -jar NeonObf.jar --input IN.jar --output OUT.jar --transformers SourceFileRemover;LineNumberObfuscation;FinalRemover;LocalVariableNameObfuscator;BasicTypesEncryption;GotoFloodObfuscation;CodeHider --dictionary 3");
90+
91+
System.exit(1);
92+
return;
93+
}
94+
95+
if (!(inF = new File(cmd.getOptionValue("input"))).exists())
96+
throw new Throwable("Error: Input file does not exist.");
97+
98+
if ((outF = new File(cmd.getOptionValue("output"))).exists())
99+
throw new Throwable("Error: Output file already exists.");
100+
101+
ArrayList<String> librariesList = new ArrayList<>();
102+
if(cmd.hasOption("libraries"))
103+
for (String libraryName1 : cmd.getOptionValues("libraries"))
104+
for (String libraryName2 : libraryName1.split(";"))
105+
librariesList.add(libraryName2);
106+
libraries = librariesList.toArray(new String[librariesList.size()]);
89107

108+
ArrayList<String> usedTransformersList = new ArrayList<>();
109+
for(String transformerName1 : cmd.getOptionValues("transformers"))
110+
for(String transformerName2 : transformerName1.split(";"))
111+
usedTransformersList.add(transformerName2);
112+
usedTransformers = usedTransformersList.toArray(new String[usedTransformersList.size()]);
113+
114+
int dictiounary;
115+
try {
116+
dictiounary = Integer.parseInt(cmd.getOptionValue("dictionary"));
117+
} catch(NumberFormatException t) {
118+
throw new Throwable("Dictionary must be a number (1-3)");
119+
}
120+
switch(dictiounary) {
121+
case 1:
122+
nameGen = new SmartNameGen("abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + "_");
90123
break;
91124
case 2:
92-
if (!(f = new File(arg)).exists() && !arg.equalsIgnoreCase("null"))
93-
throw new Throwable(".JAR/.class/folder with libraries must exist! (it can be empty folder or \'null\')");
94-
125+
nameGen = new SmartNameGen("abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + "_.#{}");
95126
break;
96127
case 3:
97-
usedTransformers = arg.split(";");
98-
99-
break;
100-
case 4:
101-
if (arg.equalsIgnoreCase("min"))
102-
nameGen = new SmartNameGen("abcdefghijklmnopqrstuvwxyz"
103-
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + "_");
104-
else
105-
if (arg.equalsIgnoreCase("norm"))
106-
nameGen = new SmartNameGen("abcdefghijklmnopqrstuvwxyz"
107-
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + "_.#{}");
108-
else
109-
if (arg.equalsIgnoreCase("max"))
110-
nameGen = new SmartNameGen("\r" + "\t");
111-
else
112-
throw new Throwable("Arg " + index + " is not valid. Arg is " + arg);
113-
114-
//existTransformers.put("AntiMemoryDump", new AntiMemoryDump());
115-
transformers.put("BasicTypesEncryption", new BasicTypesEncryption());
116-
transformers.put("CodeHider", new CodeHider());
117-
transformers.put("FinalRemover", new FinalRemover());
118-
transformers.put("GotoFloodObfuscation", new GotoFloodObfuscation());
119-
transformers.put("LineNumberObfuscation", new LineNumberObfuscation());
120-
transformers.put("LocalVariableNameObfuscator", new LocalVariableNameObfuscator());
121-
transformers.put("SourceFileRemover", new SourceFileRemover());
122-
transformers.put("TryCatch", new TryCatch());
123-
128+
nameGen = new SmartNameGen("\r" + "\t");
124129
break;
125130
default:
126-
System.out.println("Arg " + index + " is excess.");
127-
break;
131+
throw new Throwable("Dictionary number must be in range of 1 to 3");
128132
}
129133

130-
return false;
134+
//existTransformers.put("AntiMemoryDump", new AntiMemoryDump());
135+
transformers.put("BasicTypesEncryption", new BasicTypesEncryption());
136+
transformers.put("CodeHider", new CodeHider());
137+
transformers.put("FinalRemover", new FinalRemover());
138+
transformers.put("GotoFloodObfuscation", new GotoFloodObfuscation());
139+
transformers.put("LineNumberObfuscation", new LineNumberObfuscation());
140+
transformers.put("LocalVariableNameObfuscator", new LocalVariableNameObfuscator());
141+
transformers.put("SourceFileRemover", new SourceFileRemover());
142+
transformers.put("TryCatch", new TryCatch());
131143
}
132144

133145
public static boolean isEmpty(MethodNode mn) {
@@ -150,7 +162,7 @@ public void run() {
150162
try {
151163
printLogo();
152164
try {
153-
checkArgs();
165+
parseArgs();
154166
} catch(Throwable t) {
155167
String msg = t.getMessage();
156168
if (msg != null)
@@ -161,10 +173,9 @@ public void run() {
161173

162174
System.out.println("Loading java APIs...");
163175
new DirWalker(new File(System.getProperty("java.home") + File.separatorChar + "lib"), true);
164-
if (!args[2].equalsIgnoreCase("null")) {
165-
System.out.println("Loading user APIs...");
166-
new DirWalker(new File(args[2]), true);
167-
}
176+
System.out.println("Loading user APIs...");
177+
for(String lib : libraries)
178+
new DirWalker(new File(lib), true);
168179
System.out.println("All APIs loaded!");
169180

170181
System.out.println("--------------------------------------------------");
@@ -186,8 +197,11 @@ public void run() {
186197
for(String transformerName : usedTransformers) {
187198
System.out.println("Started transformation with " + transformerName + " transformer");
188199

189-
modClasses = transformers.get(transformerName).obfuscate(modClasses);
190-
200+
try {
201+
modClasses = transformers.get(transformerName).obfuscate(modClasses);
202+
} catch(NullPointerException npe) {
203+
throw new Throwable("Transformer name \"" + transformerName + "\" aren't defined in Main#transformers.", npe);
204+
}
191205
System.out.println("Transformation completed with " + transformerName + " transformer");
192206
}
193207

@@ -202,7 +216,7 @@ public void run() {
202216
saveAll();
203217
System.out.println("All classes saved!");
204218
} catch(Throwable t) {
205-
t.printStackTrace();
219+
System.out.println(t.getMessage());
206220
}
207221
}
208222

@@ -251,7 +265,7 @@ public static String getDateTag() {
251265

252266
public byte[] dump(ClassNode node, boolean autoAdd) {
253267
if (node.innerClasses != null)
254-
((List<InnerClassNode>) node.innerClasses).stream().filter(in -> in.innerName != null).forEach(in -> {
268+
((List<InnerClassNode>) node.innerClasses).parallelStream().filter(in -> in.innerName != null).forEach(in -> {
255269
if (in.innerName.indexOf('/') != -1)
256270
in.innerName = in.innerName.substring(in.innerName.lastIndexOf('/') + 1); // Stringer
257271
});

com/neonObf/transformers/AntiMemoryDump.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,23 @@
1515

1616
/**
1717
* BETA
18-
+ At moment (22.02.2017) this is abadoned module. I don't have enough time
18+
+ At moment (22.02.2017) this is abandoned module. I don't have enough time
1919
*
2020
* @author moofMonkey
2121
*/
22+
@Deprecated
2223
public class AntiMemoryDump extends Transformer {
24+
@Deprecated
2325
public AntiMemoryDump(MethodNode _mn) {
2426
super(_mn, null);
2527
}
2628

29+
@Deprecated
2730
public AntiMemoryDump() {
2831
super(null, null);
2932
}
3033

34+
@Deprecated
3135
@Override
3236
public void run() {
3337
ListIterator<AbstractInsnNode> iterator;
@@ -52,6 +56,7 @@ public void run() {
5256
}
5357
}
5458

59+
@Deprecated
5560
@Override
5661
public ArrayList<ClassNode> obfuscate(ArrayList<ClassNode> classes) throws Throwable {
5762
for(int i = 0; i < classes.size(); i++) {

0 commit comments

Comments
 (0)