git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1090 379699f6-c40d-0410-875b-85095c16579ebranch_1_1
parent
f7be2d00d5
commit
2f04c0e0cb
@ -0,0 +1,26 @@ |
||||
# This is a sample script file to obfuscate the JODE project. |
||||
|
||||
# First we select what we want to strip. There are several possibilities: |
||||
# unreach - strip unreachable methods and classes. |
||||
# source - strip source file attribute. |
||||
# lnt - strip line number table. |
||||
# lvt - strip local variable table. |
||||
# inner - strip inner class info |
||||
strip = "unreach" |
||||
|
||||
load = new WildCard { value = "jode" } |
||||
|
||||
preserve = new WildCard { value = "jode.Decompiler.main.*" }, |
||||
new WildCard { value = "jode.JodeApplet.<init>.()V" }, |
||||
new WildCard { value = "jode.JodeWindow.main.*" }, |
||||
new WildCard { value = "jode.obfuscator.Main.main.*" }, |
||||
new WildCard { value = "jode.swingui.Main.main.*" } |
||||
|
||||
# value = "jode.Decompiler.main.*", |
||||
# "jode.JodeApplet.<init>.()V", |
||||
# "jode.JodeWindow.main.*", |
||||
# "jode.obfuscator.Main.main.*", |
||||
# "jode.swingui.Main.main.*" |
||||
|
||||
analyzer = new SimpleAnalyzer |
||||
post = new LocalOptimizer, new RemovePopAnalyzer |
@ -0,0 +1,109 @@ |
||||
/* AndIdentifierMatcher Copyright (C) 1999 Jochen Hoenicke. |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2, or (at your option) |
||||
* any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; see the file COPYING. If not, write to |
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
||||
* |
||||
* $Id$ |
||||
*/ |
||||
|
||||
package jode.obfuscator; |
||||
import @COLLECTIONS@.Collection; |
||||
|
||||
public class MultiIdentifierMatcher implements IdentifierMatcher, OptionHandler { |
||||
/** |
||||
* Useful constant for giving to the constructor. |
||||
*/ |
||||
public static boolean OR = true; |
||||
/** |
||||
* Useful constant for giving to the constructor. |
||||
*/ |
||||
public static boolean AND = false; |
||||
|
||||
IdentifierMatcher[] matchers; |
||||
boolean isOr; |
||||
|
||||
/** |
||||
* Create an empty MultiIdentifierMatcher. |
||||
*/ |
||||
public MultiIdentifierMatcher() { |
||||
this.matchers = new IdentifierMatcher[0]; |
||||
} |
||||
|
||||
/** |
||||
* Create an IdentifierMatcher out of other matchers. |
||||
* @param isOr if true, match should return the logical (shortcut) |
||||
* or of the underlying matchers, if false it returns the logical and. |
||||
* @param matchers the underlying matchers |
||||
*/ |
||||
public MultiIdentifierMatcher(boolean isOr, |
||||
IdentifierMatcher[] matchers) { |
||||
this.isOr = isOr; |
||||
this.matchers = matchers; |
||||
} |
||||
|
||||
public void setOption(String option, Collection values) { |
||||
if (option.equals("or")) { |
||||
isOr = true; |
||||
matchers = (IdentifierMatcher[]) |
||||
values.toArray(new IdentifierMatcher[values.size()]); |
||||
} else if (option.equals("and")) { |
||||
isOr = false; |
||||
matchers = (IdentifierMatcher[]) |
||||
values.toArray(new IdentifierMatcher[values.size()]); |
||||
} else |
||||
throw new IllegalArgumentException("Invalid option `"+option+"'."); |
||||
} |
||||
|
||||
|
||||
public boolean matches(Identifier ident) { |
||||
for (int i=0; i< matchers.length; i++) { |
||||
if (matchers[i].matches(ident) == isOr) |
||||
return isOr; |
||||
} |
||||
return !isOr; |
||||
} |
||||
|
||||
public boolean matchesSub(Identifier ident, String name) { |
||||
for (int i=0; i< matchers.length; i++) { |
||||
if (matchers[i].matchesSub(ident, name) == isOr) |
||||
return isOr; |
||||
} |
||||
return !isOr; |
||||
} |
||||
|
||||
public String getNextComponent(Identifier ident) { |
||||
if (isOr == AND) { |
||||
for (int i=0; i< matchers.length; i++) { |
||||
String next = matchers[i].getNextComponent(ident); |
||||
if (next != null && matchesSub(ident, next)) |
||||
return next; |
||||
} |
||||
return null; |
||||
} |
||||
// OR case
|
||||
String next = null; |
||||
for (int i = 0; i < matchers.length; i++) { |
||||
if (!matchesSub(ident, null)) |
||||
continue; |
||||
if (next != null |
||||
&& matchers[i].getNextComponent(ident) != next) |
||||
return null; |
||||
next = matchers[i].getNextComponent(ident); |
||||
if (next == null) |
||||
return null; |
||||
} |
||||
return next; |
||||
} |
||||
} |
||||
|
@ -0,0 +1,8 @@ |
||||
package jode.obfuscator; |
||||
|
||||
import @COLLECTIONS@.Collection; |
||||
|
||||
public interface OptionHandler { |
||||
public void setOption(String option, Collection values) |
||||
throws IllegalArgumentException; |
||||
} |
@ -0,0 +1,7 @@ |
||||
package jode.obfuscator; |
||||
|
||||
public class ParseException extends Exception { |
||||
public ParseException(int linenr, String message) { |
||||
super ("line "+linenr+": "+message); |
||||
} |
||||
} |
@ -0,0 +1,258 @@ |
||||
package jode.obfuscator; |
||||
|
||||
import java.io.BufferedReader; |
||||
import java.io.IOException; |
||||
import java.io.Reader; |
||||
|
||||
import @COLLECTIONS@.Collection; |
||||
import @COLLECTIONS@.LinkedList; |
||||
|
||||
public class ScriptParser { |
||||
static int NO_TOKEN = -2; |
||||
static int EOF_TOKEN = -1; |
||||
static int STRING_TOKEN = 0; |
||||
static int NEW_TOKEN = 1; |
||||
static int EQUALS_TOKEN = 2; |
||||
static int COMMA_TOKEN = 3; |
||||
static int OPENBRACE_TOKEN = 4; |
||||
static int CLOSEBRACE_TOKEN = 5; |
||||
static int IDENTIFIER_TOKEN = 6; |
||||
static int NUMBER_TOKEN = 7; |
||||
Scanner scanner; |
||||
|
||||
class Scanner { |
||||
BufferedReader input; |
||||
String value; |
||||
String line; |
||||
int column; |
||||
int linenr; |
||||
int pushback = NO_TOKEN; |
||||
|
||||
public Scanner(Reader i) { |
||||
input = new BufferedReader(i); |
||||
} |
||||
|
||||
public void readString() throws ParseException { |
||||
StringBuffer val = new StringBuffer(); |
||||
while (column < line.length()) { |
||||
char c = line.charAt(column++); |
||||
if (c == '"') { |
||||
value = val.toString(); |
||||
return; |
||||
} |
||||
if (c == '\\') { |
||||
c = line.charAt(column++); |
||||
switch (c) { |
||||
case 'n': |
||||
val.append('\n'); |
||||
break; |
||||
case 't': |
||||
val.append('\t'); |
||||
break; |
||||
case 'r': |
||||
val.append('\r'); |
||||
break; |
||||
case 'u': |
||||
if (column+4 <= line.length()) { |
||||
try { |
||||
char uni = (char) Integer.parseInt |
||||
(line.substring(column, column+4), 16); |
||||
column += 4; |
||||
val.append(uni); |
||||
} catch (NumberFormatException ex) { |
||||
throw new ParseException |
||||
(linenr, |
||||
"Invalid unicode escape character"); |
||||
} |
||||
} else |
||||
throw new ParseException |
||||
(linenr, |
||||
"Invalid unicode escape character"); |
||||
break; |
||||
default: |
||||
val.append(c); |
||||
} |
||||
} else |
||||
val.append(c); |
||||
} |
||||
throw new ParseException(linenr, |
||||
"String spans over multiple lines"); |
||||
} |
||||
public void readIdentifier() { |
||||
int start = column-1; |
||||
while (column < line.length() |
||||
&& Character.isUnicodeIdentifierPart(line.charAt(column))) |
||||
column++; |
||||
value = line.substring(start, column); |
||||
} |
||||
|
||||
public void readNumber() { |
||||
boolean hex = false; |
||||
int start = column-1; |
||||
/* special case for hex numbers */ |
||||
if (line.charAt(start) == '0' && line.charAt(column) == 'x') { |
||||
column++; |
||||
hex = true; |
||||
} |
||||
while (column < line.length()) { |
||||
char c = line.charAt(column); |
||||
if (!Character.isDigit(c)) { |
||||
if (!hex) |
||||
break; |
||||
if ((c < 'A' || c > 'F') && (c < 'a' || c > 'f')) |
||||
break; |
||||
} |
||||
column++; |
||||
} |
||||
value = line.substring(start, column); |
||||
} |
||||
|
||||
public void pushbackToken(int token) { |
||||
if (pushback != NO_TOKEN) |
||||
throw new IllegalStateException |
||||
("Can only handle one pushback"); |
||||
pushback = token; |
||||
} |
||||
|
||||
public int getToken() throws ParseException, IOException { |
||||
if (pushback != NO_TOKEN) { |
||||
int result = pushback; |
||||
pushback = NO_TOKEN; |
||||
return result; |
||||
} |
||||
value = null; |
||||
while (true) { |
||||
if (line == null) { |
||||
line = input.readLine(); |
||||
if (line == null) |
||||
return EOF_TOKEN; |
||||
linenr++; |
||||
column = 0; |
||||
} |
||||
while (column < line.length()) { |
||||
char c = line.charAt(column++); |
||||
if (Character.isWhitespace(c)) |
||||
continue; |
||||
if (c == '#') |
||||
// this is a comment, skip this line
|
||||
break; |
||||
if (c == '=') |
||||
return EQUALS_TOKEN; |
||||
if (c == ',') |
||||
return COMMA_TOKEN; |
||||
if (c == '{') |
||||
return OPENBRACE_TOKEN; |
||||
if (c == '}') |
||||
return CLOSEBRACE_TOKEN; |
||||
if (c == '"') { |
||||
readString(); |
||||
return STRING_TOKEN; |
||||
} |
||||
if (Character.isDigit(c) || c == '+' || c == '-') { |
||||
readNumber(); |
||||
return NUMBER_TOKEN; |
||||
} |
||||
if (Character.isUnicodeIdentifierStart(c)) { |
||||
readIdentifier(); |
||||
if (value.equals("new")) |
||||
return NEW_TOKEN; |
||||
return IDENTIFIER_TOKEN; |
||||
} |
||||
throw new ParseException |
||||
(linenr, "Illegal character `"+c+"'"); |
||||
} |
||||
line = null; |
||||
} |
||||
} |
||||
|
||||
public String getValue() { |
||||
return value; |
||||
} |
||||
|
||||
public int getLineNr() { |
||||
return linenr; |
||||
} |
||||
} |
||||
|
||||
public ScriptParser(Reader reader) { |
||||
this.scanner = new Scanner(reader); |
||||
} |
||||
|
||||
public Object parseClass() throws ParseException, IOException { |
||||
int linenr = scanner.getLineNr(); |
||||
int token = scanner.getToken(); |
||||
if (token != IDENTIFIER_TOKEN) |
||||
throw new ParseException(linenr, "Class name expected"); |
||||
Object instance; |
||||
try { |
||||
Class clazz = Class.forName("jode.obfuscator."+scanner.getValue()); |
||||
instance = clazz.newInstance(); |
||||
} catch (ClassNotFoundException ex) { |
||||
throw new ParseException(scanner.getLineNr(), |
||||
"Class `"+scanner.getValue() |
||||
+"' not found"); |
||||
} catch (Exception ex) { |
||||
throw new ParseException(scanner.getLineNr(), |
||||
"Class `"+scanner.getValue() |
||||
+"' not valid: "+ex.getMessage()); |
||||
} |
||||
|
||||
token = scanner.getToken(); |
||||
if (token == OPENBRACE_TOKEN) { |
||||
if (!(instance instanceof OptionHandler)) |
||||
throw new ParseException |
||||
(scanner.getLineNr(), |
||||
"Class `"+instance.getClass().getName() |
||||
+"' doesn't handle options."); |
||||
parseOptions((OptionHandler) instance); |
||||
if (scanner.getToken() != CLOSEBRACE_TOKEN) |
||||
throw new ParseException(scanner.getLineNr(), "`}' expected"); |
||||
} else |
||||
scanner.pushbackToken(token); |
||||
return instance; |
||||
} |
||||
|
||||
public void parseOptions(OptionHandler optionHandler) |
||||
throws ParseException, IOException |
||||
{ |
||||
int token = scanner.getToken(); |
||||
while (true) { |
||||
if (token == EOF_TOKEN || token == CLOSEBRACE_TOKEN) { |
||||
scanner.pushbackToken(token); |
||||
return; |
||||
} |
||||
if (token != IDENTIFIER_TOKEN) |
||||
throw new ParseException(scanner.getLineNr(), |
||||
"identifier expected"); |
||||
String ident = scanner.getValue(); |
||||
if (scanner.getToken() != EQUALS_TOKEN) |
||||
throw new ParseException(scanner.getLineNr(), |
||||
"equal sign expected"); |
||||
|
||||
int linenr = scanner.getLineNr(); |
||||
Collection values = new LinkedList(); |
||||
do { |
||||
token = scanner.getToken(); |
||||
if (token == NEW_TOKEN) { |
||||
values.add(parseClass()); |
||||
} else if (token == STRING_TOKEN) { |
||||
values.add(scanner.getValue()); |
||||
} else if (token == NUMBER_TOKEN) { |
||||
values.add(new Integer(scanner.getValue())); |
||||
} |
||||
token = scanner.getToken(); |
||||
} while (token == COMMA_TOKEN); |
||||
try { |
||||
optionHandler.setOption(ident, values); |
||||
} catch (IllegalArgumentException ex) { |
||||
throw new ParseException(linenr, |
||||
optionHandler.getClass().getName() |
||||
+": "+ex.getMessage()); |
||||
} catch (RuntimeException ex) { |
||||
throw new ParseException(linenr, |
||||
optionHandler.getClass().getName() |
||||
+": Illegal value: "+ex.getMessage()); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -1,63 +0,0 @@ |
||||
/* StrongRenamer Copyright (C) 1999 Jochen Hoenicke. |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2, or (at your option) |
||||
* any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; see the file COPYING. If not, write to |
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
||||
* |
||||
* $Id$ |
||||
*/ |
||||
|
||||
package jode.obfuscator; |
||||
|
||||
public class StrongRenamer implements Renamer { |
||||
String charSetStart; |
||||
String charSetCont; |
||||
|
||||
public StrongRenamer(String charSetStart, String charSetCont) { |
||||
this.charSetStart = charSetStart; |
||||
this.charSetCont = charSetCont; |
||||
} |
||||
|
||||
public String generateName(Identifier ident, String lastName) { |
||||
if (lastName == null) |
||||
return charSetStart.substring(0,1); |
||||
|
||||
char firstCont = charSetCont.charAt(0); |
||||
int pos = lastName.length() - 1; |
||||
StringBuffer sb = new StringBuffer(lastName.length() + 1); |
||||
while (pos > 0) { |
||||
int index = charSetCont.indexOf(lastName.charAt(pos)) + 1; |
||||
if (index < charSetCont.length()) { |
||||
sb.append(lastName.substring(0, pos)); |
||||
sb.append(charSetCont.charAt(index)); |
||||
for (int i = lastName.length() - pos - 1; i-- > 0; ) |
||||
sb.append(firstCont); |
||||
return sb.toString(); |
||||
} |
||||
pos --; |
||||
} |
||||
|
||||
int index = charSetStart.indexOf(lastName.charAt(pos)) + 1; |
||||
if (index < charSetStart.length()) { |
||||
sb.append(charSetStart.charAt(index)); |
||||
for (int i = lastName.length() - 1; i-- > 0; ) |
||||
sb.append(firstCont); |
||||
return sb.toString(); |
||||
} else { |
||||
sb.append(charSetStart.charAt(0)); |
||||
for (int i = lastName.length(); i-- > 0; ) |
||||
sb.append(firstCont); |
||||
} |
||||
return sb.toString(); |
||||
} |
||||
} |
@ -0,0 +1,141 @@ |
||||
/* StrongRenamer Copyright (C) 1999 Jochen Hoenicke. |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2, or (at your option) |
||||
* any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; see the file COPYING. If not, write to |
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
||||
* |
||||
* $Id$ |
||||
*/ |
||||
|
||||
package jode.obfuscator; |
||||
import @COLLECTIONS@.Collection; |
||||
import @COLLECTIONS@.Iterator; |
||||
import @COLLECTIONEXTRA@.UnsupportedOperationException; |
||||
|
||||
public class StrongRenamer implements Renamer, OptionHandler { |
||||
static String[] idents = { |
||||
"Package", "Class", "Field", "Method", "Local" |
||||
}; |
||||
static String[] parts = { |
||||
"Start", "Part" |
||||
}; |
||||
String charsets[][]; |
||||
|
||||
public StrongRenamer() { |
||||
charsets = new String[idents.length][parts.length]; |
||||
for (int i=0; i< idents.length; i++) |
||||
for (int j=0; j< parts.length; j++) |
||||
charsets[i][j] = "abcdefghijklmnopqrstuvwxyz"; |
||||
} |
||||
|
||||
public void setOption(String option, Collection values) { |
||||
if (option.startsWith("charset")) { |
||||
Object value = values.iterator().next(); |
||||
if (values.size() != 1 || !(value instanceof String)) |
||||
throw new IllegalArgumentException |
||||
("Only string parameter are supported."); |
||||
String set = (String) value; |
||||
String remOpt = option.substring("charset".length()); |
||||
int part = -1, ident = -1; |
||||
if (remOpt.length() > 0) { |
||||
for (int i=0; i < idents.length; i++) { |
||||
if (remOpt.startsWith(idents[i])) { |
||||
remOpt = option.substring(idents[i].length()); |
||||
ident = i; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
if (remOpt.length() > 0) { |
||||
for (int j=0; j < parts.length; j++) { |
||||
if (remOpt.startsWith(parts[j])) { |
||||
remOpt = option.substring(parts[j].length()); |
||||
part = j; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
if (remOpt.length() > 0) |
||||
throw new IllegalArgumentException("Invalid charset `" |
||||
+option+"'"); |
||||
for (int i = 0; i < idents.length; i++) { |
||||
if (ident >= 0 && ident != i) |
||||
continue; |
||||
for (int j = 0; j < parts.length; j++) { |
||||
if (part >= 0 && part != j) |
||||
continue; |
||||
charsets[i][j] = set; |
||||
} |
||||
} |
||||
} else |
||||
throw new IllegalArgumentException("Invalid option `" |
||||
+option+"'"); |
||||
} |
||||
|
||||
public Iterator generateNames(Identifier ident) { |
||||
final String[] currCharset; |
||||
if (ident instanceof PackageIdentifier) |
||||
currCharset = charsets[0]; |
||||
else if (ident instanceof PackageIdentifier) |
||||
currCharset = charsets[1]; |
||||
else if (ident instanceof ClassIdentifier) |
||||
currCharset = charsets[2]; |
||||
else if (ident instanceof FieldIdentifier) |
||||
currCharset = charsets[3]; |
||||
else if (ident instanceof MethodIdentifier) |
||||
currCharset = charsets[4]; |
||||
else if (ident instanceof LocalIdentifier) |
||||
currCharset = charsets[5]; |
||||
else |
||||
throw new IllegalArgumentException(ident.getClass().getName()); |
||||
|
||||
return new Iterator() { |
||||
char[] name = null; |
||||
|
||||
public boolean hasNext() { |
||||
return true; |
||||
} |
||||
public Object next() { |
||||
if (name == null) { |
||||
name = new char[] { currCharset[0].charAt(0) }; |
||||
return new String(name); |
||||
} |
||||
|
||||
int pos = name.length - 1; |
||||
String charset = currCharset[1]; |
||||
while (pos >= 0) { |
||||
if (pos == 0) |
||||
charset = currCharset[0]; |
||||
|
||||
int index = charset.indexOf(name[pos]) + 1; |
||||
if (index < charset.length()) { |
||||
name[pos] = charset.charAt(index); |
||||
return new String(name); |
||||
} |
||||
name[pos--] = charset.charAt(0); |
||||
} |
||||
|
||||
name = new char[name.length+1]; |
||||
name[0] = currCharset[0].charAt(0); |
||||
char firstCont = currCharset[1].charAt(0); |
||||
for (int i=1; i <name.length; i++) |
||||
name[i] = firstCont; |
||||
return new String(name); |
||||
} |
||||
|
||||
public void remove() { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,21 @@ |
||||
package jode.obfuscator; |
||||
|
||||
import @COLLECTIONS@.Iterator; |
||||
|
||||
public class UniqueRenamer implements Renamer { |
||||
static int serialnr = 0; |
||||
public Iterator generateNames(Identifier ident) { |
||||
return new Iterator() { |
||||
public boolean hasNext() { |
||||
return true; |
||||
} |
||||
|
||||
public Object next() { |
||||
return "xxx" + serialnr++; |
||||
} |
||||
public void remove() { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
}; |
||||
} |
||||
} |
Loading…
Reference in new issue