Stringer is one of many commercial tools to apply obfuscation on java byte code level.
It supports various obfuscation techniques, but in this blog post I would like to analyse its ability to encrypt strings
and explore ways to automatically deobfuscate jars obfuscated by stringer.
Let’s take a look at how the actual string encryption applied by stringer looks like. The following snippets are
disassembled bytecode in jasmin notation:
As you can see, an encrypted string, is pushed onto the stack and a method with a revealing signature is called, returning
the decrypted string a runtime. My first attempt is to call the decrypt method myself with the same argument in the hope
that it returns the decrypted string.
Unfortunately, this does not lead to a properly decrypted string, so there must be some additional mechanisms in place
in order to prevent code lifting and to easily decrypt encrypted strings inside the jar file.
Looking at the decrypt method (xxx/yy/z), I can see the following instructions:
It looks like the decrypt method analyses the calling stack and uses information from this class/method
to setup its decryption key. Translating the same snippet to java code makes it quite clear:
So various information from the calling class/method is being used to generate a key that is needed for the actual
decryption. If the key does not match the expected values, only garbage is returned, making code lifting more challenging.
Let’s try to use proguard-core to modify the byte code in a way that we can
easily execute it and get the decrypted strings during static analysis. For readability I will not post the full source code,
but the relevant pieces of code to understand how this can be done.
We know that the decrypt method deduces its decryption key from the calling method. Now lets try to find all places in the jar
file that seems to decrypt a string:
With the code snippet above, we look for code patterns that load a constant string onto the stack and invoke a
static method which takes an Object as input and return a String. In the analysed samples of jars obfuscated
with stringer all encrypted strings were encrypted using the same pattern, and its also quite uncommon for generic code
to use similar patterns, thus we can easily find such encrypted strings in this case.
Now that we know which classes and methods contain encrypted strings, we can prepare the referenced decrypt method in such
a way that the protection mechanism is not effective. For this purpose, we replace the aforementioned code in the decrypt
method with the values of the actual calling method:
As you can see in this code snippet, we replace certain instruction patterns with known values so that the decryption
works regardless from which method it is being called. Now the only thing left to do is to copy the original code to
a new class, modify it as described, load the generated class and execute the method with the given encrypted string:
Now that we have the modified decrypt method, we can just call it via reflection using the encrypted string
as parameter. The returned result can be used to replace the original code in the obfuscated jar with a simple ldc instruction.
After we have implemented all this logic we see that the decrypted string still results in garbage, so there must be
another protection mechanism against code lifting. Some more debugging reveals that the CodeSource of the
ProtectionDomain of the class containing the
decrypt method is also verified. If this does not return the expected value, the decryption is unsuccessful. Luckily this
protection mechanism can easily be avoided by modifying the CodeSource of a given class using reflection:
So we change the CodeSource of the modified class to the one that the decrypt method expects, and finally, we can
decrypt any strings in the obfuscated jar simply by the means of static code analysis.
The full source code to decrypt jars obfuscated by stringer will be made available at a later time. More to come!
No comments found for this article.
Join the discussion for this article on this ticket. Comments appear on this page instantly.