1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import sys, xml.dom.minidom, re, random, string, os
20
21 PATH_INSTALL = "./"
22
23 sys.path.append(PATH_INSTALL + "/core")
24 sys.path.append(PATH_INSTALL + "/core/bytecodes")
25 sys.path.append(PATH_INSTALL + "/core/predicates")
26 sys.path.append(PATH_INSTALL + "/core/analysis")
27 sys.path.append(PATH_INSTALL + "/core/vm")
28 sys.path.append(PATH_INSTALL + "/core/wm")
29 sys.path.append(PATH_INSTALL + "/core/protection")
30 sys.path.append(PATH_INSTALL + "/classification")
31
32 import bytecode, jvm, dvm, apk, misc, analysis, opaque
33 from error import error
34
35 VM_INT_AUTO = 0
36 VM_INT_BASIC_MATH_FORMULA = 1
37 VM_INT_BASIC_PRNG = 2
38 INVERT_VM_INT_TYPE = { "VM_INT_AUTO" : VM_INT_AUTO,
39 "VM_INT_BASIC_MATH_FORMULA" : VM_INT_BASIC_MATH_FORMULA,
40 "VM_INT_BASIC_PRNG" : VM_INT_BASIC_PRNG
41 }
43 """VM_int is the main high level Virtual Machine object to protect a method by remplacing all integer contants
44
45 @param andro : an L{Androguard} / L{AndroguardS} object to have full access to the desired information
46 @param class_name : the class of the method
47 @param method_name : the name of the method to protect
48 @param descriptor : the descriptor of the method
49 @param vm_int_type : the type of the Virtual Machine
50 """
51 - def __init__(self, andro, class_name, method_name, descriptor, vm_int_type) :
85
87 - def __init__(self, andro, class_name, wm_type) :
88 if wm_type == [] :
89 raise("....")
90
91 import wm
92 self._w = wm.WM( andro.get_vm(), class_name, wm_type, andro.get_analysis() )
93
96
98 - def __init__(self, andro, class_name, input_file) :
99 fd = open(input_file, "rb")
100 buffxml = fd.read()
101 fd.close()
102
103 document = xml.dom.minidom.parseString(buffxml)
104
105 w_orig = wm.WMLoad( document )
106 w_cmp = wm.WMCheck( w_orig, andro, andro.get_analysis() )
107
109 return prefix + random.choice( string.letters ) + ''.join([ random.choice(string.letters + string.digits) for i in range(10 - 1) ] )
110
111 OBFU_NAMES_FIELDS = 0
112 OBFU_NAMES_METHODS = 1
114 """
115 OBFU_Names is the object that change the name of a field or a method by a random string, and resolving
116 dependencies into other files
117
118 @param andro : an L{Androguard} object to have full access to the desired information, and represented a pool of files with the same format
119 @param class_name : the class of the method/field (a python regexp)
120 @param name : the name of the method/field (a python regexp)
121 @param descriptor : the descriptor of the method/field (a python regexp)
122 @param obfu_type : the type of the obfuscated (field/method) (OBFU_NAMES_FIELDS, OBFU_NAMES_METHODS)
123 @param gen_method : a method which generate random string
124 """
126 if obfu_type != OBFU_NAMES_FIELDS and obfu_type != OBFU_NAMES_METHODS :
127 raise("ooops")
128
129 re_class_name = re.compile(class_name)
130 re_name = re.compile(name)
131 re_descriptor = re.compile(descriptor)
132
133 if obfu_type == OBFU_NAMES_FIELDS :
134 search_in = andro.gets("fields")
135 elif obfu_type == OBFU_NAMES_METHODS :
136 search_in = andro.gets("methods")
137
138 depends = []
139
140
141 for fm in search_in :
142 if re_class_name.match( fm.get_class_name() ) :
143 if re_name.match( fm.get_name() ):
144 if re_descriptor.match( fm.get_descriptor() ) :
145 _, _vm = andro.get_method_descriptor( fm.get_class_name(), fm.get_name(), fm.get_descriptor() )
146 old_name = fm.get_name()
147 new_name = gen_method()
148
149
150 if obfu_type == OBFU_NAMES_METHODS :
151 _, _vm = andro.get_method_descriptor( fm.get_class_name(), fm.get_name(), fm.get_descriptor() )
152 if _vm.get_type() == "JVM" and old_name != "<init>" :
153 fm.set_name( new_name )
154 depends.append( (fm, old_name) )
155 elif obfu_type == OBFU_NAMES_FIELDS :
156 fm.set_name( new_name )
157 depends.append( (fm, old_name) )
158
159
160 for i in depends :
161 for _vm in andro.get_vms() :
162 if obfu_type == OBFU_NAMES_FIELDS :
163 _vm.set_used_field( [ i[0].get_class_name(), i[1], i[0].get_descriptor() ], [ i[0].get_class_name(), i[0].get_name(), i[0].get_descriptor() ] )
164 elif obfu_type == OBFU_NAMES_METHODS :
165 _vm.set_used_method( [ i[0].get_class_name(), i[1], i[0].get_descriptor() ], [ i[0].get_class_name(), i[0].get_name(), i[0].get_descriptor() ] )
166
170
173
176
179
180 - def _get(self, val, name) :
181 l = []
182 r = getattr(self.__bc, val)(name)
183 for i in r :
184 l.append( i )
185 return l
186
188 l = []
189 r = getattr(self.__bc, val)()
190 for i in r :
191 l.append( i )
192 return l
193
194 - def gets(self, name) :
195 return self._gets("get_" + name)
196
197 - def get(self, val, name) :
198 return self._get("get_" + val, name)
199
202
205
208
211
213 return self.__bc.save()
214
216 return getattr(self.__bc, value)
217
218 PROTECT_VM_AUTO = "protect_vm_auto"
219 PROTECT_VM_INTEGER = "protect_vm_integer"
220 PROTECT_VM_INTEGER_TYPE = "protect_vm_integer_type"
221
223 """Androguard is the main object to abstract and manage differents formats
224
225 @param files : a list of filenames (filename must be terminated by .class or .dex)
226 @param raw : specify if the filename is in fact a raw buffer (default : False) #FIXME
227 """
229 self.__files = files
230
231 self.__orig_raw = {}
232 for i in self.__files :
233 self.__orig_raw[ i ] = open(i, "rb").read()
234
235 self.__bc = []
236 self._analyze()
237
239 if isinstance(root, (list, tuple)):
240 for element in root :
241 for e in self._iterFlatten(element) :
242 yield e
243 else:
244 yield root
245
247 for i in self.__files :
248
249 if ".class" in i :
250 bc = jvm.JVMFormat( self.__orig_raw[ i ] )
251 elif ".jar" in i :
252 x = jvm.JAR( i )
253 bc = x.get_classes()
254 elif ".dex" in i :
255 bc = dvm.DalvikVMFormat( self.__orig_raw[ i ] )
256 elif ".apk" in i :
257 x = apk.APK( i )
258 bc = dvm.DalvikVMFormat( x.get_dex() )
259 else :
260 raise( "Unknown bytecode" )
261
262 if isinstance(bc, list) :
263 for j in bc :
264 self.__bc.append( (j[0], BC( jvm.JVMFormat(j[1]) ) ) )
265 else :
266 self.__bc.append( (i, BC( bc )) )
267
271
273 for _, bc in self.__bc :
274 if bc.get_class(class_name) == True :
275 return bc
276 return None
277
279 """Return raw format of all file"""
280 l = []
281 for _, bc in self.__bc :
282 l.append( bc._get_raw() )
283 return l
284
286 return self.__orig_raw
287
289 """
290 Return the specific method
291
292 @param class_name : the class name of the method
293 @param method_name : the name of the method
294 @param descriptor : the descriptor of the method
295 """
296 for file_name, bc in self.__bc :
297 x = bc.get_method_descriptor( class_name, method_name, descriptor )
298 if x != None :
299 return x, bc
300 return None, None
301
303 """
304 Return the specific field
305
306 @param class_name : the class name of the field
307 @param field_name : the name of the field
308 @param descriptor : the descriptor of the field
309 """
310 for file_name, bc in self.__bc :
311 x = bc.get_field_descriptor( class_name, field_name, descriptor )
312 if x != None :
313 return x, bc
314 return None, None
315
316 - def get(self, name, val) :
317 """
318 Return the specific value for all files
319
320 @param name :
321 @param val :
322 """
323 if name == "file" :
324 for file_name, bc in self.__bc :
325 if file_name == val :
326 return bc
327
328 return None
329 else :
330 l = []
331 for file_name, bc in self.__bc :
332 l.append( bc.get( name, val ) )
333
334 return list( self._iterFlatten(l) )
335
336 - def gets(self, name) :
337 """
338 Return the specific value for all files
339
340 @param name :
341 """
342 l = []
343 for file_name, bc in self.__bc :
344 l.append( bc.gets( name ) )
345
346 return list( self._iterFlatten(l) )
347
349 return [ i[1].get_vm() for i in self.__bc ]
350
353
355 """
356 Display all files
357 """
358 for _, bc in self.__bc :
359 bc.show()
360
362 """
363 Display all files
364 """
365 for _, bc in self.__bc :
366 bc.pretty_show()
367
368 - def do(self, fileconf) :
369 self.ianalyze()
370
371 fd = open(fileconf, "rb")
372 buffxml = fd.read()
373 fd.close()
374
375 document = xml.dom.minidom.parseString(buffxml)
376
377 main_path = document.getElementsByTagName( "main_path" )[0].firstChild.data
378 libs_path = document.getElementsByTagName( "libs_path" )[0].firstChild.data
379
380 if document.getElementsByTagName( "watermark" ) != [] :
381 watermark_item = document.getElementsByTagName( "watermark" )[0]
382 watermark_types = []
383 for item in watermark_item.getElementsByTagName( "type" ) :
384 watermark_types.append( str( item.firstChild.data ) )
385 watermark_output = watermark_item.getElementsByTagName( "output" )[0].firstChild.data
386 print watermark_types, "--->", watermark_output
387
388 fd = open(watermark_output, "w")
389
390 fd.write("<?xml version=\"1.0\"?>\n")
391 fd.write("<andro id=\"androguard wm\">\n")
392 wms = []
393 for i in self.get_bc() :
394 for class_name in i[1].get_classes_names() :
395 wm = WM( i[1], class_name, watermark_types )
396 fd.write( wm.get().save() )
397 fd.write("</andro>\n")
398 fd.close()
399
400 if document.getElementsByTagName( "protect_code" ) != [] :
401 import protection
402
403 protect_code_item = document.getElementsByTagName( "protect_code" )[0]
404 protection.ProtectCode( [ i[1] for i in self.get_bc() ], main_path + libs_path )
405
406
407
408
409
410
411
412 if document.getElementsByTagName( "save_path" ) != [] :
413 self.save( main_path + document.getElementsByTagName( "save_path" )[0].firstChild.data )
414 else :
415 self.save()
416
417 - def save(self, output_dir=None) :
418 for file_name, bc in self.get_bc() :
419 if output_dir == None :
420 output_file_name = file_name
421 else :
422 output_file_name = output_dir + os.path.basename( file_name )
423
424 print "[+] [AG] SAVING ... ", output_file_name
425 fd = open(output_file_name, "w")
426 fd.write( bc.save() )
427 fd.close()
428
430 """AndroguardS is the main object to abstract and manage differents formats but only per filename. In fact this class is just a wrapper to the main class Androguard
431
432 @param filename : the filename to use (filename must be terminated by .class or .dex)
433 @param raw : specify if the filename is a raw buffer (default : False)
434 """
435 - def __init__(self, filename, raw=False) :
436 self.__filename = filename
437 self.__orig_a = Androguard( [ filename ], raw )
438 self.__a = self.__orig_a.get( "file", filename )
439
442
444 """
445 This method returns the VMFormat which correspond to the file
446
447 @rtype: L{jvm.JVMFormat} or L{dvm.DalvikVMFormat}
448 """
449 return self.__a.get_vm()
450
452 """
453 Return the original format (with the modifications) into raw format
454
455 @rtype: string
456 """
457 return self.__a.save()
458
460 try :
461 return getattr(self.__orig_a, value)
462 except AttributeError :
463 return getattr(self.__a, value)
464