Exemple #1
0
 def __init__(self, **args):
     # Logger
     self.logger = Log(
         log_name=f"pyobfx_log-{time.strftime('%X')}.txt",
         active=args['silent']) if not args['no_log'] else Log(
             active=args['silent'])
     self.logger.log('Starting obfuscator')
     # Strgen type
     self.strgen_type = {
         'jp': 3,
         'ch': 4,
         'in': 5
     }[args['str_gen']] if args['str_gen'] and args['str_gen'] in [
         'jp', 'ch', 'in'
     ] else 1
     # Header for obfuscated file
     self.obfx_header = "# Obfuscated with PyObfx #"
     # Escape placeholder
     self.escape_placeholder = "#escaped_char#"
     # Obfx arguments
     self.args = args
     # File name and content
     self.file_name = self.args['file']
     self.file_content = read_file(self.file_name)
     # Length constant for random string
     self.obf_len_constant = 2
     # Quote character distance from string (max)
     self.quote_dist_constant = 5
     # Imports obfuscation
     self.import_dict, self.import_content = self._prepare_imports(
     )  # warn: change self.file_content variable
     # Escape chars in file
     self.escaped_file = self._escape_file(self.file_content)
     # Tokenize the source and retrieve tokenizer object
     self.tokenizer = Tokenizer(self.escaped_file)
     self.has_handled = set()
     self.build_in_func = ['exit', '']  #过滤python内建函数
     # Random integers for obfuscation
     self.ints = [random.randint(1, 5) for _ in range(3)]
     # Deobfuscator declarations
     self.deobfuscators = {
         1: "lambda n: (n - ({} % {})) - {}".format(*self.ints[::-1]),
         2: "lambda n: (n ^ {}) / {}".format(*self.ints[:2]),
         3: "lambda n: n - sum({})".format(str(self.ints)),
         4: "lambda n: (n + ({} + {})) / {}".format(*self.ints[::-1]),
         5: "lambda n: (n + {}) / ({} + {})".format(*self.ints)
     }
     # New file extension for obfuscated file
     self.obfx_ext = "_obfx.py"
     # Randomized deobfuscator function names
     self.deobfuscator_name = generate_rand_str(self.strgen_type, 10)
     self.str_deobfuscator_name = generate_rand_str(self.strgen_type, 10)
     # Quote list
     self.quotes = ["'", '"', '"""']
     # Boolean value list
     self.boolean_val = ['True', 'False']
     # Escape Sequences
     self.escapes = [('\a', '\\a'), ('\b', '\\b'), \
     ('\f', '\\f'), ('\n', '\\n'), ('\r', '\\r'), \
      ('\t', '\\t'), ('\v', '\\v')]
Exemple #2
0
    def _obfuscate_names(self, token_type):
        self.logger.log("Obfuscating " + str(token_type).split('.')[-1] +
                        "s...")
        # Iterate through the tokens and check if
        # token type is Token.Name
        try:
            for t_index, token in enumerate(self.tokenizer.TOKENS):
                # Get the name value
                name_value = token[2]
                if token[1][0] == token_type and token[0] not in self.has_handled \
                    and name_value not in self.build_in_func:

                    if name_value.startswith('__') and name_value.endswith(
                            '__'):
                        continue
                    # Obfuscate the name string
                    obf_var_name = generate_rand_str(
                        self.strgen_type,
                        len(name_value) * self.obf_len_constant)
                    # Fix imports
                    if name_value in list(self.import_dict.keys()):
                        obf_var_name = self.import_dict[name_value]
                    else:
                        # Continue if current token is part of a function
                        # (eg.: random.randint)
                        if self.tokenizer.TOKENS[t_index+1][1][0] == Token.Operator or \
                            self.tokenizer.TOKENS[t_index-1][1][0] == Token.Operator:
                            continue
                    # Find usages for current name with find_index_by_id method
                    token_index = self.tokenizer.find_index_by_id(token[0])
                    # Iterate through the indexes and change current value with
                    # new obfuscated value
                    self.has_handled.add(token[0])
                    for index in token_index:
                        # Check if token is a function
                        # https://github.com/PyObfx/PyObfx/issues/61
                        if self.tokenizer.TOKENS[index -
                                                 1][1][0] == Token.Operator:
                            continue
                        current_token = self.tokenizer.TOKENS[index]
                        # Change list element
                        self.tokenizer.TOKENS[index] = (current_token[0],
                                                        (Token.Name,
                                                         obf_var_name),
                                                        obf_var_name)

        except Exception as ex:
            self.logger.log(
                f'{type(ex).__name__} has occured while obfuscating names \n[{ex}]',
                state='error')
        else:
            self.logger.log(
                str(token_type).split('.')[-1] + " obfuscation done.")
Exemple #3
0
    def _prepare_imports(self):
        self.logger.log('Extracting imports...')
        # for the content to be obfuscated
        replaced = ""
        # for the  remaining content except import parts
        other_content = ""
        obf_dict = {}
        enter = False
        file_content_ln = self.file_content.split('\n')
        try:
            # Drafts
            draft1 = '^from\s+(.+)\s+import\s+(.*)'
            draft2 = '^import\s+(.+)'
            for num, line in enumerate(file_content_ln):
                #-------------------------------#
                que1 = re.search('as\s+([^:]+)$', line)  # import .. as ..
                if que1:
                    # same for the next 4 steps
                    # Get random variable name
                    obf_name = generate_rand_str(
                        self.strgen_type,
                        len(line.split(' as ')[1]) * self.obf_len_constant)
                    real_namespace = line.split(' as ')[1]
                    obf_dict[real_namespace] = obf_name
                    replaced += line.split(
                        ' as ')[0] + ' as ' + obf_name + '\n'
                    continue
                #-------------------------------#
                que2 = re.search(draft1, line)
                if que2:
                    if que2.group(2).strip() == '*':
                        obf_dict[que2.group(2).strip()] = que2.group(2).strip()
                        replaced += line + '\n'
                        continue
                    # from x import (y, z, t)
                    re_imp = re.search('\((.+)\)', line)
                    if re_imp:  #re_imp: x,y,z
                        for namespace in re_imp.group(1).split(','):
                            # routine
                            obf_name = generate_rand_str(
                                self.strgen_type,
                                len(namespace.strip()) * self.obf_len_constant)
                            real_namespace = namespace.strip()
                            obf_dict[real_namespace] = obf_name

                            replaced += f"from {que2.group(1)} import {namespace} as {obf_name}\n"
                        continue
                    #----------------------------#

                    if '(' in que2.group(2) and not ')' in que2.group(2):

                        # from x import (
                        #   y,z,a,
                        #   b,c,d
                        #   )

                        # this code block is for catching the
                        # namespaces between '(' and ')'
                        enter = True
                        index = 1
                        tmp = ""
                        while True:
                            new_ln = file_content_ln[num + index]
                            tmp += new_ln
                            index += 1
                            if ')' in new_ln:
                                break

                        tmp = tmp.replace(')', '')
                        namesp_list = [i.strip() for i in tmp.split(',')]

                        for namesp in namesp_list:
                            # routine
                            obf_name = generate_rand_str(
                                self.strgen_type,
                                len(namesp.strip()) * self.obf_len_constant)
                            real_namespace = namesp.strip()
                            obf_dict[real_namespace] = obf_name

                            replaced += f"from {que2.group(1)} import {namesp} as {obf_name}\n"
                            continue
                    # ------------------------------ #
                    if ',' in que2.group(2):
                        for namespace in que2.group(2).split(
                                ','):  # from x import y,z,t
                            obf_name = generate_rand_str(
                                self.strgen_type,
                                len(namespace.strip()) * self.obf_len_constant)
                            real_namespace = namespace.strip()
                            obf_dict[real_namespace] = obf_name

                            replaced += f"from {que2.group(1)} import {namespace} as {obf_name}\n"

                        continue
                    # ---------------------------- #

                    if not ',' in que2.group(2) and not '(' in que2.group(
                            2):  # from x import y (single)
                        obf_name = generate_rand_str(
                            self.strgen_type,
                            len(que2.group(2)) * self.obf_len_constant)
                        real_namespace = que2.group(2)
                        obf_dict[real_namespace] = obf_name

                        replaced += re.sub(draft1, line + f' as {obf_name}\n',
                                           line)

                        continue
                # ------------------------- #
                que3 = re.search(draft2, line)
                if que3:
                    if ',' in que3.group(1):
                        for namespace in que3.group(1).split(
                                ','):  # import x,y,z
                            obf_name = generate_rand_str(
                                self.strgen_type,
                                len(namespace.strip()) * self.obf_len_constant)
                            real_namespace = namespace.strip()
                            obf_dict[real_namespace] = obf_name

                            replaced += f'import {namespace} as {obf_name}\n'
                        continue
                    # -------------------- #
                    else:
                        obf_name = generate_rand_str(
                            self.strgen_type,
                            len(que3.group(1)) * self.obf_len_constant)
                        real_namespace = que3.group(1)
                        obf_dict[real_namespace] = obf_name

                        replaced += f"import {real_namespace} as {obf_name}\n"

                        continue
                # --------------------- #
                # Escape other import things
                if enter:
                    if '(' in line:
                        enter = True
                    continue

                # all contents except import
                other_content += line + '\n'

            # eleminate the class variable from import parts
            self.file_content = other_content
        except Exception as ex:
            self.logger.log(
                f'{type(ex).__name__} has occured while extracting the imports \n[{ex}]',
                state='critical')
        else:
            self.logger.log('Imports extracted from source.')
        return (obf_dict, replaced)