def obfuscate(self, obfuscation_info: Obfuscation): self.logger.info('Running "{0}" obfuscator'.format(self.__class__.__name__)) try: for smali_file in util.show_list_progress(obfuscation_info.get_smali_files(), interactive=obfuscation_info.interactive, description='Inserting arithmetic computations in smali files'): self.logger.debug('Inserting arithmetic computations in file "{0}"'.format(smali_file)) with util.inplace_edit_file(smali_file) as current_file: editing_method = False start_label = None end_label = None for line in current_file: if line.startswith('.method ') and ' abstract ' not in line and \ ' native ' not in line and not editing_method: # Entering method. print(line, end='') editing_method = True elif line.startswith('.end method') and editing_method: # Exiting method. if start_label and end_label: print('\t:{0}'.format(end_label)) print('\tgoto/32 :{0}'.format(start_label)) start_label = None end_label = None print(line, end='') editing_method = False elif editing_method: # Inside method. print(line, end='') match = util.locals_pattern.match(line) if match and int(match.group('local_count')) >= 2: # If there are at least 2 registers available, add a fake branch at the beginning of # the method: one branch will continue from here, the other branch will go to the end # of the method and then will return here through a "goto" instruction. v0, v1 = util.get_random_int(1, 32), util.get_random_int(1, 32) start_label = util.get_random_string(16) end_label = util.get_random_string(16) tmp_label = util.get_random_string(16) print('\n\tconst v0, {0}'.format(v0)) print('\tconst v1, {0}'.format(v1)) print('\tadd-int v0, v0, v1') print('\trem-int v0, v0, v1') print('\tif-gtz v0, :{0}'.format(tmp_label)) print('\tgoto/32 :{0}'.format(end_label)) print('\t:{0}'.format(tmp_label)) print('\t:{0}'.format(start_label)) else: print(line, end='') except Exception as e: self.logger.error('Error during execution of "{0}" obfuscator: {1}'.format(self.__class__.__name__, e)) raise finally: obfuscation_info.used_obfuscators.append(self.__class__.__name__)
def obfuscate(self, obfuscation_info: Obfuscation): self.logger.info('Running "{0}" obfuscator'.format(self.__class__.__name__)) try: op_codes = util.get_nop_valid_op_codes() pattern = re.compile(r'\s+(?P<op_code>\S+)') for smali_file in util.show_list_progress(obfuscation_info.get_smali_files(), interactive=obfuscation_info.interactive, description='Inserting "nop" instructions in smali files'): self.logger.debug('Inserting "nop" instructions in file "{0}"'.format(smali_file)) with util.inplace_edit_file(smali_file) as current_file: for line in current_file: # Print original instruction. print(line, end='') # Check if this line contains an op code at the beginning of the string. match = pattern.match(line) if match: op_code = match.group('op_code') # If this is a valid op code, insert some nop instructions after it. if op_code in op_codes: nop_count = util.get_random_int(1, 5) print('\tnop\n' * nop_count, end='') except Exception as e: self.logger.error('Error during execution of "{0}" obfuscator: {1}'.format(self.__class__.__name__, e)) raise finally: obfuscation_info.used_obfuscators.append(self.__class__.__name__)
def add_random_fields(self, original_field_declaration: str): if self.added_fields < self.max_fields_to_add: for _ in range(util.get_random_int(1, 4)): print('\n', end='') print(original_field_declaration.replace( ':', '{0}:'.format(util.get_random_string(8))), end='') self.added_fields += 1
def rename_field_declarations(self, smali_files: List[str], interactive: bool = False) -> Set[str]: renamed_fields: Set[str] = set() # Search for field definitions that can be renamed. for smali_file in util.show_list_progress( smali_files, interactive=interactive, description="Renaming field declarations", ): with util.inplace_edit_file(smali_file) as (in_file, out_file): for line in in_file: # Field declared in class. field_match = util.field_pattern.match(line) if field_match: field_name = field_match.group("field_name") # Avoid sub-fields. if "$" not in field_name: # Rename field declaration (usages of this field will be # renamed later) and add some random fields. line = line.replace( "{0}:".format(field_name), "{0}:".format(self.rename_field(field_name)), ) out_file.write(line) # Add random fields. if self.added_fields < self.max_fields_to_add: for _ in range(util.get_random_int(1, 4)): out_file.write("\n") out_file.write( line.replace( ":", "{0}:".format( util.get_random_string(8)), )) self.added_fields += 1 field = "{field_name}:{field_type}".format( field_name=field_match.group("field_name"), field_type=field_match.group("field_type"), ) renamed_fields.add(field) else: out_file.write(line) else: out_file.write(line) return renamed_fields