用Python实现代码混淆器

862 阅读5分钟
原文链接: mp.weixin.qq.com

    Python 是一门解释型语言,他的优点在于不需要编译,直接就可以运行,不过这也是他的缺点,对于没有进行编译的 Python 代码来说(Python 代码也可以编译),他是暴露的,虽说 Python 代码编译了之后的确可以减少这种代码泄露风险,代码编译之后是只可执行不可阅读的,不过网上也有很多反编译的工具和方法,所以我们可以再做一个手脚,那就是代码混淆,代码混淆的目的是让你的代码变得难以阅读,让阅读者无法理解代码的作用,从而起到保护代码的作用(当然这不能用在开发的过程中)。

下面来看一下实现的过程:

由于代码混淆器应该是面向多语言的,所以我们将一个语言的混淆器封装成一个类,这篇文章我只以 Python 代码混淆器为例进行讲解。

我们新建一个类 PyObfuscation

class PyObfuscation(object):    '''Obfuscation the code of Python'''    def __init__(self, filename):        self.filename = filename        # Check the file's type, if not '.py', raise error.        if os.path.splitext(filename)[-1] != '.py':            raise TypeError("The file's type is not Python file")        with open(filename) as f:            self.content = f.readlines()

这个类的初始化参数是你想进行代码混淆的文件路径,之后在 __init__ 方法中检测该文件是否是适合这个混淆器的文件,如果不是就抛出错误,如果没错误就加载文件内容。

然后就开始定义每个混淆的方法了,我在这篇文章就只介绍一种方法,就是改变变量的方法。

    def changeVariable(self):        '''Make the variables very ugly.'''        var_dict = {}  # The variable correspondence        reg = re.compile('(\s*)([a-zA-Z,]*?)\s*=\s*(.*)', re.S)        lines = self.content[:]        content = []                for line in lines:            match = re.match(reg, line)            if match:                block = match.group(1)                vars = re.findall('\w+', match.group(2))  # The matched variables' name                values = match.group(3)  # The matched values' name                                for index, var in enumerate(vars[:]):                    new_variable = var_dict.get(var)  # Get the global variable                    if not new_variable:                        # Randomly select 16 letters as variable names                        new_variable = ''.join([random.choice(string.letters) for i in range(16)])                        # If the name conflicts                        while new_variable in var_dict:                            new_variable = ''.join([random.choice(string.letters) for i in range(16)])                        var_dict[var] = new_variable  # Append the variable correspondence                                            vars[index] = new_variable  # Change the variable's name                # Change to new string                line = block + ','.join(vars) + '=' + values                content.append(line)            else:                content.append(line)

我们定义了一个方法,用来改变文件中的变量名,使其变得特别难看,首先我们创建一个字典,用来保存被修改的变量,我们用正则表达式来匹配声明变量的语法,然后新建一个列表,存储改变之后的内容,因为 Python 中强制使用缩进,所以我们还要匹配出句子前面的缩进部分,然后就是匹配变量名和变量的值了,这个在正则表达式里面已经分组了,所以可以根据分组直接选择,new_variable = ''.join([random.choice(string.letters) for i in range(16)]) 这一句是用来生成新的变量名,用16个英文字母代替,如果新生成的变量名已经存在于 var_dict 中,就继续生成,直到他的值是唯一的,然后将新生成的变量名对应关系存入 var_dict 中。

# Change all the variable name which in the dictionary        s = ';:;'.join(content)        for key, value in var_dict.items():            s = re.sub(r'\b'+key+r'\b', value, s)  # Match the whole word        content = s.split(';:;')        return content

最后一步就是将文件中的变量按照 var_dict 中的对应关系进行更改了,我们用 “;:;” 作为每行分隔的标志,然后用正则表达式全词匹配出文件中的变量名进行更改。最后返回的是一个列表,对应每一行的内容。

以上就是这个代码混淆器的基本原理实现,我只实现了一个功能,原本我还想将所有代码变成一行代码,但是发现 Python 不能这样写代码,所以就放弃了,这个 Python 语言混淆器变量混淆的那一块还有一个需求没实现,就是将导入的模块名也混淆。

这个混淆器其实不仅仅只适用于 Python ,只要知道了某个语言的语法,同样可以实现该语言的混淆器,比如在 C 语言里面可以将所有代码都放在一行,就像 HTML 和 CSS 的压缩。

如果有想到什么改进方法,欢迎在后台留言。