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 的压缩。
如果有想到什么改进方法,欢迎在后台留言。