Python scripting in dirtyJOE can be used to modify CONSTANT_Utf8 objects from Constant Pool. One of the main use is decryption of CONSTANT_Utf8 objects in obfuscated .class files. Decrypted objects are useful in forensic analysis, they can be also used to translate obfuscated java application.
I’ll show how to use python scripting on sample obfuscated java malware called Boonana. Mentioned malware appeared in october 2010 and was obfuscated with Zelix KlassMaster 5.3.3E (according to entry in constant pool “ZKM5.3.3E”).
Script should contain only one simple function that will be called by dirtyJOE on each encrypted Utf8 object:
def dj_decryptUTF8(inBuf): return 
inBuf – input buffer, it is tuple, where each byte of Utf8 string is represented as integer value
return – output buffer should be a list, where each byte of Utf8 string is represented as integer value
Universal script for decrypting Utf8 objects encrypted by Zelix KlassMaster obfuscator can be found in \scripts\ directory. It is very simple, all what is needed is to find proper ‘key’ value:
def dj_decryptUTF8_ZKM(inBuffer, key): i = 0 ik = 0 ret =  last = len(inBuffer) while i < last: c = inBuffer[i] if c == 0: break defAdd = 1 if (c >> 5) == 6: c = ((c & 0x1f) << 6) + (inBuffer[i+1] & 0x3f) defAdd = 2 elif (c >> 4) == 0xE: c = ((c & 0xf) << 12) + ((inBuffer[i+1] & 0x3f) << 6) \ + (inBuffer[i+2] & 0x3f) defAdd = 3 ret += [c ^ key[ik % 5]] i += defAdd ik += 1 return ret # 'instr' argument is input buffer represented as tuple # function should return list object def dj_decryptUTF8(inBuf): key = [48, 16, 127, 16, 97] return dj_decryptUTF8_ZKM(inBuf, key)
‘key’ value is very easy to find, all references to the encrypted object have to be checked, following those references will reveal function that is responsible for decryption. For example:
- Lets get first encrypted CONSTANT_Utf8 object from Constant Pool, it is object number 147
- Check references to this object be selecting ‘Show References‘ option from the context menu
- References window shows that object 147 is referenced only once by ‘Constant Pool: 13’
- Check references to object 13 (it is CONSTANT_String object)
- References window shows that object 13 is referenced only once by ‘Method: <clinit>, attribute: Code, bytecode@00000089’
Checking this method at given position reveals this code:
00000086 : dup 00000087 : bipush 15 00000089 : ldc "Xd `[?gxdB~dOS" 0000008B : jsr pos.000000B0 0000008E : aastore
jsr opcode is acronym for ‘jump subroutine’, and subroutine at pos.000000B0 looks like this:
000000B0 : astore_0 000000B1 : invokevirtual char java.lang.String.toCharArray() 000000B4 : dup 000000B5 : arraylength 000000B6 : swap 000000B7 : iconst_0 000000B8 : istore_1 000000B9 : swap 000000BA : dup_x1 000000BB : iconst_1 000000BC : if_icmpgt pos.0000010A 000000BF : dup 000000C0 : iload_1 000000C1 : dup2 000000C2 : caload 000000C3 : iload_1 000000C4 : iconst_5 000000C5 : irem 000000C6 : tableswitch l: 0, h: 3, def: pos.000000F8, pos.(000000E4, 000000E9, 000000EE, 000000F3) 000000E4 : bipush 48 000000E6 : goto pos.000000FA 000000E9 : bipush 16 000000EB : goto pos.000000FA 000000EE : bipush 127 000000F0 : goto pos.000000FA 000000F3 : bipush 16 000000F5 : goto pos.000000FA 000000F8 : bipush 97 000000FA : ixor 000000FB : i2c 000000FC : castore 000000FD : iinc local.01, 1 00000100 : swap 00000101 : dup_x1 00000102 : ifne pos.0000010A 00000105 : dup2 00000106 : swap 00000107 : goto pos.000000C1 0000010A : swap 0000010B : dup_x1 0000010C : iload_1 0000010D : if_icmpgt pos.000000BF 00000110 : new java.lang.String 00000113 : dup_x1 00000114 : swap 00000115 : invokespecial void java.lang.String.(char) 00000118 : invokevirtual java.lang.String java.lang.String.intern() 0000011B : swap 0000011C : pop 0000011D : ret local.00
As it may be noticed, the green part of this subroutine contains key for decryption routine: 48, 16, 127, 16, 97. At this point, script can be tested in dirtyJOE by selecting ‘Run Python Script‘ option from the Constant Pool context menu:
‘Decrypt‘ button is used strictly for script testing purposes, it will show string after decryption in ‘Preview‘ field. After clicking ‘Save‘ button, object will be decrypted again, and user will be prompted by below message box:
When script is finished it can be run on all encrypted Utf8 objects (by choosing ‘Run Python Script on All Utf8 Objects‘ option from the Constant Pool context menu):
‘Decrypt‘ button has similar function as in previous window. After clicking ‘Save‘ button user will be prompted to accept all changes:
That’s pretty much all.
Very interesting sir, thank you brother ReWolf!
You talk about “‘Method: , attribute: Code, bytecode@00000089′”.
On the .class I am reading, reference is “Method: , attribute: Code, bytecode@000000B0”.
After, I go to Dirty-Joe “Methods” tab, I select “” (I presume its not clinit..), the attribute is “code” by default. I double click on the attribute, but there is no “B0” declaration. Its the same thing If I click on “init” method. Am I doing it in the right way ?
Okay, method really exists. Its the last one. Thank you
I’m glad that it works for you ;)