12

I've read from the apt tool page that one can create AnnotationProcessors to generate new derived files (source files, class files, deployment descriptors, etc.). I am looking for example to do so.

My need is to encode all annotated strings at compile time, so that reading the class file does not allow reading the static strings:

Base code:

String message = (@Obfuscated "a string that should not be readable in class file");

Should be reworked as:

String message = new ObfuscatedString(new long[] {0x86DD4DBB5166C13DL, 0x4C79B1CDC313AE09L, 0x1A353051DAF6463BL}).toString();

Based on the static ObfuscatedString.obfuscate(String) method of the TrueLicense framework, the processor can generate the code to replace the annotated string. Indeed, this method generates the string "new ObfuscatedString([numeric_code]).toString()". At runtime the toString() method of ObfuscatedString is able to return the string encoded in the numeric code.

Any idea on how to write the process() method of the AnnotationProcessor to edit the annotated code?

Thanks in advance,

Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
Martin Pernollet
  • 2,285
  • 1
  • 28
  • 39

4 Answers4

2

You could have

String message = Obfuscated.decode("a string that should not be readable in class file");

which compiles normally, however after compilation you have a tool which examines the bytecode e.g. using ObjectWeb's ASM, changes the String literal so it looks like

String message = Obfuscated.decode("\u86DD\u4DBB\u5166\uC13D\u4C79\uB1CD\uC313\uAE09\u1A35\u3051\uDAF6\u463B");

To make it easer to identify strings which need to be changed, you could add a prefix to them, and you could ensure this prefix does appear after the code has been obfuscated.

String s = "Obfuscate: a string that should not be readable in class file";
// later
String message = Obfuscated.decode(s);
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • ASM seems a very interesting tool I'm glad you talked about! I found a great doc introducing the tool (http://download.forge.objectweb.org/asm/asm-guide.pdf). However, since the code edit is rather simple, I'm wondering if I can do it with annotation to avoid ASM learning curve... and learn annotations! – Martin Pernollet Jul 01 '11 at 15:34
2

I bet spoon may be what you are looking for. But why do you want to obfuscate static strings?

carlosayam
  • 1,396
  • 1
  • 10
  • 15
  • I obfuscate strings in compiled code to make hard to find the classes that handle the licensing part of our software. Without this, it is pretty easy to reverse engineer the code and find the "if" to be removed to unlock the software. Spoon seems a really great tool for such a task, and its eclipse integration makes it as appealing as ObjectWeb's ASM. Do you have some ideas about the pros and cons for using the first or the other? – Martin Pernollet Jul 07 '11 at 08:22
  • It finally seems very difficult to find sample code or peoples experienced with raw java annotations for performing my task. I think I will go through one of those suggested tools. – Martin Pernollet Jul 07 '11 at 08:25
1

Zelix KlassMaster offers this ability. If memory serves, it used to be free for companies under 3 developers, but I just checked their purchase page, and it seems that they now charge a small-developers fee for small companies. I haven't used it in several years (at least 5 or 7), but it did a fantastic job obfuscating strings, and code in general.

Eric B.
  • 23,425
  • 50
  • 169
  • 316
1

When I am going to generate the version for distribution it, I have a class that override all the constants with the Ofuscated String call:

This is the process:

  1. I run my ANT, that copy all the code in other place.
  2. The ANT call to OfuscateJavaConstant.
  3. I Compile the code.

The ANT:

 <java classname="de.schlichtherle.util.ObfuscatedString">
     <arg value="${of.constant}" />
     <classpath>
         <pathelement location="${exit.path}/${buildDir}" />
         <path refid="myclasspath" />
     </classpath>
  </java>

The Java Ofuscate code (ObfuscatedString):

public static void main(String[] args) {
    if ( args!=null ){
        String[] ficheros = args[0].split(";");

        if ( args!=ficheros )
            for (String ruta:ficheros)
                ofuscateConstantClass( ruta );
    }
}

private static void ofuscateConstantClass( String fileName ){

    File archivo = null;
    FileReader fr = null;
    BufferedReader br = null;
    List<String> sb  = new ArrayList<String>();
    FileWriter fichero = null;
    PrintWriter pw = null;

    try{
        archivo = new File( fileName );
        fr = new FileReader (archivo);
        br = new BufferedReader(fr);
        String linea;
        while( (linea=br.readLine())!=null ){

            String noWhite = linea.trim().replaceAll(" +", " ");

            if ( noWhite.toLowerCase().startsWith("public static final string") && noWhite.endsWith("\";") ){

                String firstPart = noWhite.substring(0, noWhite.indexOf("\"") );
                String constant = noWhite.substring(noWhite.indexOf("\"")+1, noWhite.lastIndexOf("\"") );
                String ofuscatedConstant = obfuscate( constant );
                String secondPart = noWhite.substring(noWhite.lastIndexOf("\"")+1 );
                sb.add( firstPart + ofuscatedConstant + secondPart );
                System.out.println( constant + "-->" + ofuscatedConstant );
            } else
                sb.add( linea );
        }

        fichero = new FileWriter( fileName );
        pw = new PrintWriter(fichero);
        for (String s:sb)
            pw.println( s );

    } catch ( Exception e){

    } finally {
         try{
             if( null != fr )
                 fr.close();
             if( null != pw )
                 pw.close();
             if( null != fichero )
                 fichero.close();
         }catch (Exception e2){
            e2.printStackTrace();
         }
    }

}

Hope it helps :)

ganzux
  • 874
  • 3
  • 15
  • 35