diff --git a/androguard.py b/androguard.py
index c95d2331..4c27fe11 100644
--- a/androguard.py
+++ b/androguard.py
@@ -86,21 +86,43 @@ class WM :
def __init__(self, andro, class_name, wm_type, output_file) :
if wm_type == [] :
- wm_type = [ WM_L3 ]
+ raise("....")
fd = open(output_file, "w")
- for method in andro.get_methods() :
- # FIXME
- _method, _vm = andro.get_method_descriptor(method.get_class_name(), method.get_name(), method.get_descriptor())
- wm.WM( _vm, _method, wm_type )
+ fd.write("\n")
+ fd.write("\n" % class_name)
+ a = analysis.VMBCA( andro.get_vm() )
+
+ for method in andro.get_methods() :
+ _method, _vm = andro.get_method_descriptor(method.get_class_name(), method.get_name(), method.get_descriptor())
+ w = wm.WM( _vm, _method, wm_type, a )
+
+ fd.write( w.save( ) )
+
+ fd.write("\n")
fd.close()
class WMCheck :
- def __init__(self, andro, intput_file) :
- pass
+ def __init__(self, andro, class_name, input_file) :
+ a = analysis.VMBCA( andro.get_vm() )
+
+ fd = open(input_file, "r")
+ buffxml = fd.read()
+ fd.close()
+
+ document = xml.dom.minidom.parseString(buffxml)
+
+ w_orig = wm.WMLoad( document )
+
+ for method in andro.get_methods() :
+ _method, _vm = andro.get_method_descriptor(method.get_class_name(), method.get_name(), method.get_descriptor())
+
+ w_cmp = wm.WMCheck( w_orig, _vm, _method, a )
+ #w_cmp.show()
+
def OBFU_NAMES_GEN(prefix="") :
return prefix + random.choice( string.letters ) + ''.join([ random.choice(string.letters + string.digits) for i in range(10 - 1) ] )
diff --git a/core/analysis/analysis.py b/core/analysis/analysis.py
index 82aa7dae..a69bd0c8 100644
--- a/core/analysis/analysis.py
+++ b/core/analysis/analysis.py
@@ -50,6 +50,22 @@ class ExternalFM :
def get_descriptor(self) :
return self.descriptor
+class ToString :
+ def __init__(self, tab) :
+ self.__tab = tab
+ self.__string = ""
+
+ def push(self, name) :
+ for i in self.__tab :
+ if name in self.__tab[i] :
+ if len(self.__string) > 0 :
+ if i == 'O' and self.__string[-1] == 'O' :
+ continue
+ self.__string += i
+
+ def get_string(self) :
+ return self.__string
+
##### JVM ######
FIELDS = {
"getfield" : "R",
@@ -60,6 +76,12 @@ FIELDS = {
METHODS = [ "invokestatic", "invokevirtual", "invokespecial" ]
+JVM_TOSTRING = { "O" : jvm.MATH_JVM_OPCODES.keys(),
+ "I" : jvm.INVOKE_JVM_OPCODES,
+ "G" : jvm.FIELD_READ_JVM_OPCODES,
+ "P" : jvm.FIELD_WRITE_JVM_OPCODES
+ }
+
class JVMBreakBlock :
def __init__(self, _vm) :
self.__ins = []
@@ -111,8 +133,8 @@ class JVMBreakBlock :
desc = getattr(self.__vm, self.__info[t][0])( o[0], o[1], o[2] )
# It's an external
- if desc[0] == None :
- desc = ( ExternalFM( o[0], o[1], o[2] ), self.__vm )
+ if desc == None :
+ desc = ExternalFM( o[0], o[1], o[2] )
if desc not in self.__info[t][1] :
self.__info[t][1][desc] = []
@@ -175,30 +197,43 @@ class GVM_BCA :
self.__vm = _vm
self.__method = _method
- BO = [ jvm.BREAK_JVM_OPCODES, JVMBreakBlock ]
+
+ BO = { "B_O" : jvm.BREAK_JVM_OPCODES, "B_O_C" : JVMBreakBlock, "TS" : JVM_TOSTRING }
if self.__vm.get_type() == "DVM" :
- BO = [ jvm.BREAK_DVM_OPCODES, DVMBreakBlock ]
+ BO = { "B_O" : dvm.BREAK_DVM_OPCODES, "B_O_C" : DVMBreakBlock, "TS" : DVM_TOSTRING }
+
+ self.__TS = ToString( BO[ "TS" ] )
code = self.__method.get_code()
- current_bb = BO[1]( self.__vm )
+ current_bb = BO["B_O_C"]( self.__vm )
self.__bb = [ current_bb ]
bc = code.get_bc()
for i in bc.get() :
name = i.get_name()
+
+ # String construction
+ self.__TS.push( name )
+
m_name = name.split("_")[0]
current_bb.push( i )
- if name in BO[0] or m_name in BO[0] :
+ if name in BO["B_O"] or m_name in BO["B_O"] :
current_bb.analyze()
- current_bb = BO[1]( self.__vm )
+ current_bb = BO["B_O_C"]( self.__vm )
self.__bb.append( current_bb )
if len( self.__bb ) > 1 :
self.__bb.pop(-1)
+ def get_bb(self) :
+ return self.__bb
+
+ def get_ts(self) :
+ return self.__TS.get_string()
+
def get_method(self) :
return self.__method
@@ -214,6 +249,7 @@ class GVM_BCA :
def show(self) :
print "METHOD", self.__method.get_class_name(), self.__method.get_name(), self.__method.get_descriptor()
+ print "\t TOSTRING = ", self.__TS.get_string()
# self.__method.show()
for i in self.__bb :
@@ -237,7 +273,7 @@ class GVM_BCA :
for i in self.__bb :
fields = i.get_fields()
for field in fields :
- print "\t\t-->", field[0].get_class_name(), field[0].get_name(), field[0].get_descriptor()
+ print "\t\t-->", field.get_class_name(), field.get_name(), field.get_descriptor()
for context in fields[field] :
print "\t\t\t |---|", context.mode, context.details
@@ -247,7 +283,7 @@ class GVM_BCA :
for i in self.__bb :
methods = i.get_methods()
for method in methods :
- print "\t\t-->", method[0].get_class_name(), method[0].get_name(), method[0].get_descriptor()
+ print "\t\t-->", method.get_class_name(), method.get_name(), method.get_descriptor()
for context in methods[method] :
print "\t\t\t |---|", context.details
diff --git a/core/bytecodes/jvm.py b/core/bytecodes/jvm.py
index 8508b782..31c71a7f 100644
--- a/core/bytecodes/jvm.py
+++ b/core/bytecodes/jvm.py
@@ -275,6 +275,10 @@ MATH_JVM_OPCODES = { "iand" : '&',
"ixor" : '^',
}
+INVOKE_JVM_OPCODES = [ "invokestatic", "invokevirtual", "invokespecial" ]
+FIELD_READ_JVM_OPCODES = [ "getfield", "getstatic" ]
+FIELD_WRITE_JVM_OPCODES = [ "putfield", "putstatic" ]
+
BREAK_JVM_OPCODES = [ "invokevirtual", "invokespecial", "invokestatic" ] + [ "areturn", "astore", "aastore", "bastore", "iinc", "istore", "iastore", "ireturn", "pop", "putfield", "putstatic" ] + [ "if_acmpeq", "if_icmpeq", "if_icmpne", "if_icmplt", "if_icmpge", "if_icmpgt", "if_icmple", "ifeq", "ifne", "iflt", "ifge", "ifgt", "ifle", "ifnonnull", "ifnull" ] #BRANCH_JVM_OPCODES
diff --git a/core/wm/wm.py b/core/wm/wm.py
index 0e297e68..dc719c50 100644
--- a/core/wm/wm.py
+++ b/core/wm/wm.py
@@ -1,6 +1,8 @@
-import os, sys, hashlib, random, types, itertools, hashlib
+import os, sys, hashlib, random, types, itertools, hashlib, cPickle, base64
-import analysis, misc
+from xml.sax.saxutils import escape, unescape
+
+import misc
import wm_l1, wm_l3, wm_l4
@@ -15,15 +17,26 @@ WM_BIND = {
}
class WM :
- def __init__(self, vm, method, wm_type) :
+ def __init__(self, vm, method, wm_type, analysis) :
+ self.__method = method
+ self.__wms = []
+
+ self.__a = analysis
+
list_x = []
- self.__a = analysis.VMBCA( vm )
-
+
for i in wm_type :
- l_x = WM_BIND[ i ]( vm, method, self.__a ).get()
+ wb = WM_BIND[ i ]( vm, method, self.__a )
+ wb.run()
+
+ l_x = wb.get()
+
for z in l_x :
list_x.append( z )
+ self.__wms.append( (i, wb) )
+
+ print list_x
if list_x == [] :
raise("list is empty")
@@ -44,15 +57,80 @@ class WM :
# print ob.verify_with_X( [ 12345668, 90877676, 878978, 87987673, 788789 ] )
# print ob.verify_with_X( [ 12345668, 90877676, 878978, 4, 87987673 ] )
# print ob.verify_with_X( [ 1, 2, 3, 4, 5, 6 ] )
-
- def get_hash(self) :
- return self.__ob.get_hash()
- def get_values(self) :
- l = []
- for k, v in self.__ob.get_points() :
- l.append( v )
- return l
+ def save(self) :
+ buffer = "\n" % ( self.__method.get_class_name(), escape( self.__method.get_name() ), self.__method.get_descriptor() )
+ buffer += "%s\n" % ( base64.b64encode( cPickle.dumps( self.__ob.get_y() ) ) )
+
+
+ for i in self.__wms :
+ buffer += "%s\n" % ( i[0], base64.b64encode( cPickle.dumps( i[1].get_export_context() ) ) )
+
+ buffer += "\n"
+
+ return buffer
+
+class WMMLoad :
+ def __init__(self, item) :
+ self.__class_name = item.getAttribute('class')
+ self.__name = unescape( item.getAttribute('name') )
+ self.__descriptor = item.getAttribute('descriptor')
+
+ self.__wms = []
+
+ x = base64.b64decode( item.getElementsByTagName( 'sss' )[0].firstChild.data )
+# print cPickle.loads( x )
+
+
+ for s_item in item.getElementsByTagName( 'wm' ) :
+ _type = int( s_item.getAttribute('type') )
+
+ wb = WM_BIND[ _type ]( None, None, None )
+
+ x = cPickle.loads( base64.b64decode( s_item.firstChild.data ) )
+ wb.set_context( x )
+
+
+ self.__wms.append( (_type, wb) )
+
+ def get_wms(self) :
+ return self.__wms
+
+ def get_name(self) :
+ return self.__name
+
+class WMLoad :
+ def __init__(self, document) :
+ self.__methods = []
+
+ for item in document.getElementsByTagName('method') :
+ self.__methods.append( WMMLoad( item ) )
+
+ def get_methods(self) :
+ return self.__methods
+
+class WMCheck :
+ def __init__(self, wm_orig, vm, method, analysis) :
+
+ print method.get_name()
+
+ for _method in wm_orig.get_methods() :
+ list_x = []
+ print "\t --->", _method.get_name()
+ for _type, _wm in _method.get_wms() :
+ wb = WM_BIND[ _type ]( vm, method, analysis )
+
+ wb.set_context( _wm.get_import_context() )
+ wb.run()
+
+ l_x = _wm.challenge( wb )
+
+ for i in l_x :
+ list_x.append( i )
+
+ print "\t\t X :", list_x
+ #print wm_orig.get_dwbo().verify_with_X( list_x )
+ print ""
class Polynomial :
def __init__(self, degree, secret_long, length) :
@@ -221,6 +299,9 @@ class DWBO :
result, success = self.__sss.join( coord_x, self.__points.values() )
return result, success
+ def get_y(self) :
+ return [ self.__points[k] for k in self.__points ]
+
def get_points(self) :
return self.__points
diff --git a/core/wm/wm_l1.py b/core/wm/wm_l1.py
index f48a41da..4a6d5037 100644
--- a/core/wm/wm_l1.py
+++ b/core/wm/wm_l1.py
@@ -1,19 +1,72 @@
+import misc
+
+import hashlib
def INIT() :
return WM_L1
+def levenshtein(a,b):
+ "Calculates the Levenshtein distance between a and b."
+ n, m = len(a), len(b)
+ if n > m:
+ # Make sure n <= m, to use O(min(n,m)) space
+ a,b = b,a
+ n,m = m,n
+
+ current = range(n+1)
+ for i in range(1,m+1):
+ previous, current = current, [i]+[0]*n
+ for j in range(1,n+1):
+ add, delete = previous[j]+1, current[j-1]+1
+ change = previous[j-1]
+ if a[j-1] != b[i-1]:
+ change = change + 1
+ current[j] = min(add, delete, change)
+
+ return current[n]
+
class WM_L1 :
def __init__(self, vm, method, analysis) :
- x = analysis.get(method)
+ self.__vm = vm
+ self.__method = method
+ self.__analysis = analysis
+ self.__context = {
+ "L_X" : [],
+ "STRING" : "",
+ }
- self.set_context( )
+ def run(self) :
+ x = self.__analysis.get(self.__method)
- raise("ooops")
+ self.__context[ "STRING" ] = x.get_ts()
+
+ self.__context[ "L_X" ].append(
+ misc.str2long( hashlib.md5( self.__context[ "STRING" ] ).hexdigest() )
+ )
+
+ def challenge(self, external_wm) :
+ distance = levenshtein( self.__context["STRING"], external_wm.get_context()["STRING"] )
+
+# print distance
+
+ if distance <= 2 :
+ return self.__context[ "L_X" ]
+
+ return []
def get(self) :
- return [ ]
-
- def set_context(self, values) :
- pass
+ return self.__context[ "L_X" ]
+ def set_context(self, values) :
+ for x in values :
+ self.__context[ x ] = values[ x ]
+
+ def get_context(self) :
+ return self.__context
+
+ def get_export_context(self) :
+ return self.__context
+
+ def get_import_context(self) :
+ return {}
diff --git a/core/wm/wm_l3.py b/core/wm/wm_l3.py
index 760b3456..370aeaf6 100644
--- a/core/wm/wm_l3.py
+++ b/core/wm/wm_l3.py
@@ -4,7 +4,6 @@ lua_code_init = '''
%s = {}
function %s:new()
o = {}
- print "coucou"
setmetatable(o, self)
self.__index = self
return o
diff --git a/core/wm/wm_l4.py b/core/wm/wm_l4.py
index 421b3ea0..8bdf3506 100644
--- a/core/wm/wm_l4.py
+++ b/core/wm/wm_l4.py
@@ -1,19 +1,66 @@
+import random
+
def INIT() :
return WM_L4
class WM_L4 :
def __init__(self, vm, method, analysis) :
- x = analysis.get(method)
+ self.__vm = vm
+ self.__method = method
+ self.__analysis = analysis
+
+ self.__context = {
+ "L_X" : [],
+ "OP_BIND" : {},
+ }
- self.set_context( { "op_bind" : { '&' : 500, '-' : 600, '+' : 700, '^' : 800 } } )
+ def __init_context(self) :
+ self.__context[ "OP_BIND" ][ '&' ] = self.new_randint()
+ self.__context[ "OP_BIND" ][ '|' ] = self.new_randint()
+ self.__context[ "OP_BIND" ][ '-' ] = self.new_randint()
+ self.__context[ "OP_BIND" ][ '+' ] = self.new_randint()
+ self.__context[ "OP_BIND" ][ '^' ] = self.new_randint()
- print method.get_name(), x.get_ops()
+ def run(self) :
+ x = self.__analysis.get(self.__method)
+
+ if self.__context[ "OP_BIND" ] == {} :
+ self.__init_context()
+
+ for i in x.get_bb() :
+ v = 0
+ for j in i.get_ops() :
+ v = v + self.__context[ "OP_BIND" ][ j ]
+
+ if v != 0 :
+ self.__context[ "L_X" ].append( v )
+
+ def new_randint(self) :
+ x = random.randint(300, 1000)
+
+ for i in self.__context[ "OP_BIND" ] :
+ if self.__context[ "OP_BIND" ][i] == x :
+ self.new_randint()
+
+ return x
+
+ def challenge(self, external_wm) :
+ return external_wm.get_context()["L_X"]
def get(self) :
- return [ 900090903, 980978789, 656767, 7667 ]
+ return self.__context["L_X"]
def set_context(self, values) :
- pass
+ for x in values :
+ self.__context[ x ] = values[ x ]
+ def get_context(self) :
+ return self.__context
+
+ def get_export_context(self) :
+ return { "OP_BIND" : self.__context["OP_BIND"] }
+
+ def get_import_context(self) :
+ return { "OP_BIND" : self.__context["OP_BIND"] }
diff --git a/demos/androguard_test_WM.py b/demos/androguard_test_WM.py
index 62e11e4c..1511b9a8 100755
--- a/demos/androguard_test_WM.py
+++ b/demos/androguard_test_WM.py
@@ -6,13 +6,13 @@ sys.path.append(PATH_INSTALL + "./")
import androguard
-TEST = './examples/android/Test/bin/classes/org/t0t0/android/Test1.class'
-TEST_STEAL = ''
-TEST_ANDRO = './examples/android/Test/bin/classes.dex'
+TEST_ORIG = './examples/android/Test/bin/classes/org/t0t0/android/Test1.class'
+TEST_JAVA_STEAL = './examples/java/test/orig/Test1.class'
+TEST_ANDRO_STEAL = './examples/android/Test/bin/classes.dex'
-_a = androguard.AndroguardS( TEST )
+_a = androguard.AndroguardS( TEST_ORIG )
-wm = androguard.WM( _a, "org.t0t0.android.Test1", [ androguard.WM_L1 ], "./wm.xml" )
+wm = androguard.WM( _a, "org.t0t0.android.Test1", [ androguard.WM_L1, androguard.WM_L4 ], "./wm.xml" )
-_b = androguard.AndroguardS( TEST_ANDRO )
-androguard.WMCheck( _b, "./wm.xml" )
+_b = androguard.AndroguardS( TEST_JAVA_STEAL )
+androguard.WMCheck( _b, "org.t0t0.android.Test1", "./wm.xml" )