com.yworks.yguard.obf.KeywordNameMaker Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of retroguard Show documentation
Show all versions of retroguard Show documentation
The open-source Java obfuscation tool working with Ant and Gradle by yWorks - the diagramming experts
/**
* YGuard -- an obfuscation library for Java(TM) classfiles.
*
* Original Copyright (c) 1999 Mark Welsh ([email protected])
* Modifications Copyright (c) 2002 yWorks GmbH ([email protected])
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* The author may be contacted at [email protected]
*
* Java and all Java-based marks are trademarks or registered
* trademarks of Sun Microsystems, Inc. in the U.S. and other countries.
*/
package com.yworks.yguard.obf;
import java.io.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Name generator that uses (almost) the full Java identifier namespace,
* and chooses to put some of the keyword names (legal in JVM, illegal in
* Java language) out front in sequence.
*
* @author Mark Welsh
*/
public class KeywordNameMaker implements NameMaker
{
// Constants -------------------------------------------------------------
private static final String DUMMY_ARG_LIST = "dummy";
// Fields ----------------------------------------------------------------
private int skipped = 0; // Names skipped in the sequence
private Vector namesToDate = new Vector();
private Hashtable argCount = new Hashtable();
private String[] noObfNames = null; // List of names not to be obfuscated
private String[] keywordsToUse;
private String[] keywordsToExclude;
private String[] firstLetter;
private String[] nextLetter;
private String[] noKeywords = {};
private String[] someKeywords = {
"a", "if", "do", "for", "int", "new", "try", "byte", "case", "char",
"else", "goto", "long", "null", "void"
};
private String[] allKeywords = {
"if", "do", "for", "int", "new", "try", "byte", "case", "char",
"else", "goto", "long", "null", "this", "void", "true", "false",
"break", "catch", "class", "const", "float", "final", "short",
"super", "throw", "while", "double", "import", "native", "public",
"return", "static", "switch", "throws", "boolean", "default",
"extends", "finally", "package", "private", "abstract", "continue",
"volatile", "interface", "protected", "transient", "implements",
"instanceof", "synchronized"
};
private static final AtomicBoolean scrambled = new AtomicBoolean(false);
private static String[] firstLetterLower = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l",
"m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x",
"y", "z"};
private static String[] nextLetterLower = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l",
"m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x",
"y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
private static String[] firstLetterAll = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l",
"m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x",
"y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
"K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
"W", "X", "Y", "Z"};
private static String[] nextLetterAll = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l",
"m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x",
"y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
"K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
"W", "X", "Y", "Z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
/**
* Shuffle the mapping strings in random order, thus making the generator
* produce a different mapping. Can be called once (and only once) in each
* obfuscation run; calling this method repeatedly would produce overlapping names.
*/
public static void scramble() {
if (scrambled.compareAndSet(false, true)) {
firstLetterLower = scramble(firstLetterLower);
nextLetterLower = scramble(nextLetterLower);
firstLetterAll = scramble(firstLetterAll);
nextLetterAll = scramble(nextLetterAll);
}
}
private static String[] scramble( String... orderedInput) {
List list = Arrays.asList(orderedInput);
Collections.shuffle(list);
String[] randomOutput = list.toArray(new String[0]);
return randomOutput;
}
// Class Methods ---------------------------------------------------------
/** Main method for testing. */
/* public static void main(String[] args)
{
PrintWriter pw = new PrintWriter(
new BufferedOutputStream(
new FileOutputStream("keywordnamemaker.tst")));
try
{
NameMaker nmk = new KeywordNameMaker();
for (int i = 0; i < 1000000; i++)
{
pw.println(nmk.nextName(null));
}
}
finally
{
pw.close();
}
}
*/
// Instance Methods ------------------------------------------------------
/** Ctor. */
public KeywordNameMaker()
{
this(null);
}
/** Ctor - block names not to be obfuscated from the mapping target space. */
public KeywordNameMaker(String[] noObfNames)
{
this(noObfNames, true);
}
/** Ctor - block names not to be obfuscated from the mapping target space. */
public KeywordNameMaker(String[] noObfNames, boolean useKeywords)
{
this(noObfNames, true, false);
}
/** Ctor - block names not to be obfuscated from the mapping target space. */
public KeywordNameMaker(String[] noObfNames, boolean useKeywords, boolean lowerCaseOnly)
{
this.noObfNames = noObfNames == null ? new String[0] : noObfNames;
if (useKeywords)
{
keywordsToUse = someKeywords;
keywordsToExclude = someKeywords;
}
else
{
keywordsToUse = noKeywords;
keywordsToExclude = allKeywords;
}
if (lowerCaseOnly)
{
firstLetter = firstLetterLower;
nextLetter = nextLetterLower;
}
else
{
firstLetter = firstLetterAll;
nextLetter = nextLetterAll;
}
}
/** Return the next unique name for this namespace. */
public String nextName(String descriptor)
{
// Check for arg-list in hashtable
String argList = DUMMY_ARG_LIST;
if (descriptor != null)
{
argList = getArgList(descriptor);
}
Integer intCount = (Integer)argCount.get(argList);
int theCount = 0;
if (intCount == null)
{
argCount.put(argList, new Integer(theCount));
}
else
{
theCount = intCount.intValue() + 1;
argCount.remove(argList);
argCount.put(argList, new Integer(theCount));
}
return getName(theCount);
}
// Extract the arg-list from a descriptor
private String getArgList(String descriptor)
{
int pos = descriptor.indexOf(')');
return descriptor.substring(1, pos);
}
// Generate i'th allowed, unique name
private String getName(int index)
{
// If we have previously computed this name, just return it
String name = null;
if (index < namesToDate.size())
{
name = (String)namesToDate.elementAt(index);
}
else
{
// Generate a new valid name for the sequence
for (;;)
{
name = getNewName(index + skipped);
if (!Tools.isInArray(name, noObfNames) &&
(index + skipped < keywordsToUse.length ||
!Tools.isInArray(name, keywordsToExclude)))
{
break;
}
skipped++;
}
namesToDate.addElement(name);
}
return name;
}
// Generate j'th name in sequence (can repeat keywords)
private String getNewName(int index)
{
String name = null;
// Check if we are in the 'keyword' part of the namespace
if (index < keywordsToUse.length)
{
name = keywordsToUse[index];
}
else
{
// Check if we are in the single letter part of the namespace
index -= keywordsToUse.length;
if (index < firstLetter.length)
{
name = firstLetter[index];
}
else
{
// We are in the >=2 letter part of namespace
index -= firstLetter.length;
int nextLetters = 1;
int subspaceSize = nextLetter.length;
while (index >= firstLetter.length * subspaceSize)
{
index -= firstLetter.length * subspaceSize;
nextLetters++;
subspaceSize *= nextLetter.length;
}
// Pull out the name
StringBuffer sb = new StringBuffer(firstLetter[index / subspaceSize]);
while (subspaceSize != 1)
{
index %= subspaceSize;
subspaceSize /= nextLetter.length;
sb.append(nextLetter[index / subspaceSize]);
}
// Check for collision with keywords
name = sb.toString();
}
}
return name;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy