Using Python scripts in dirtyJOE

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.

Example

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.

4 Comments

  1. 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 ?

    Reply

Leave a Reply to pier-alexandre Cancel reply

Your email address will not be published. Required fields are marked *