18

Possible Duplicate:
hiding strings in Obfuscated code

I'm trying to hide a little some static Strings of my app in order to make it harder to decompile, this way like the constants like cipher algorithms names are harder to find in the obfuscated code.

I've considered things like:

String CONCAT= "concat"+"string";
String RAW_STRING= "raw_string";
String FROM_BYTES=new String("from_bytes".getBytes());
String FROM_CHARS=new String(new char[]{'f','r','o','m','_','c','h','a','r','s'});
String FROM_CHAR2=new String(new char[]{102,114,111,109,95,99,104,97,114,115,95,50});

And the last two options seems to be "darker" than the raw option but I imagine there are better ways for doing this.

How can I improve this? Thanks

Community
  • 1
  • 1
Addev
  • 31,819
  • 51
  • 183
  • 302
  • 1
    I've never programmed for Android, however I can't see the point of the question. If the user does not know how to decompile, is only able to read the code through the Notepad, you just put some unused algorithm names, and s/he won't know which one is really involved. If s/he knows how to decompile, then there's no obfuscation that can prevent s/he from replacing the library call (I guess you use a well-known library with a well-known method name to instantiate the cipher) with a System.out.println. – ignis Oct 27 '12 at 16:36
  • I'm hiding such kind of strings using simple gradle function. It protects only from naked eye, but in any case, it's better than nothing: https://gist.github.com/shomeser/68f4fe360be0edac95e4 – Oleksii K. Mar 24 '15 at 15:02

2 Answers2

10

For one, you shouldn't just write

String FROM_CHAR2=new String(new char[]{102,114,111,109,95,99,104,97,114,115,95,50});

It's a dead give-away that the char array is actually a String.

You can do a combination of the followings:

  1. put your "String" in an int[] array
  2. or even better, break your String into several int arrays
  3. calculate/manipulate the array's values at various stage of the application, so its value will only become valid at a certain interval during a runtime, guaranteeing that it won't be deciphered at a curious glance by decompiling your code
  4. passes the array(s) back and forth, through local variables, back to instance variables, etc, before finally converting the arrays to a single array to be passed to the String constructor
  5. immediately set the String to null after use, just to reduce the amount of time the actual String exist at runtime
Kai
  • 15,284
  • 6
  • 51
  • 82
  • Any patterns or example code for #3? How does #5 help? – Nicholas Oct 27 '12 at 16:15
  • #5 helps because if someone can decompile your code, it means that they can also run it, put debugger flags into places, etc. So you should guard against runtime inspections as well. This means that the less time your actual String exists, the safer it is from prying eyes. – Kai Oct 27 '12 at 16:53
  • for #3, I haven't gone this far myself, but you can try [this](http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/658ab629-e603-4e6f-985c-2bb8c1669b27/) _or_ use something like [jzlib](http://www.jcraft.com/jzlib/) to "zip" your Strings into byte arrays, and unzip them when needed. Don't use Android's zip lib because its method names can't be obfuscated, making the whole enterprise quite obvious. – Kai Oct 27 '12 at 16:56
  • To clarify, I have used JZLib to zip individual Strings, and it definitely works, but it was for data size reduction reason and not for obfuscation. – Kai Oct 28 '12 at 09:19
  • Still, I don't understand how can this work when I just replace the cipher-instantiating std library call with a System.out.println. – ignis Oct 28 '12 at 23:20
2

I would prefer to set the value in the static (class) initializer using an decryption algo Something like

class ...
  String CONCAT;

  static {
     CONCAT = uncrypt ("ahgsdhagcf");
  } 

where uncrypt might be really a good unencryption algo or somewhat weaker a base64 decode.

In any case you need a simple program to encode your string first.

stefan bachert
  • 9,413
  • 4
  • 33
  • 40