Python3代码工程化加密

发布时间:2019-09-26 07:27:17编辑:auto阅读(1684)

    这几天公司的Python3需要加密,网上的文章要么提供思路不提供代码,要么加密之后自己都没法用了。。没办法只能自己写了

    文章整体思路

       1、修改python源码opcode为随机值

       修改下载后的Python源码包中opcode值(opcode可以理解为python读取代码的坐标,比如一个变量的opcode是5,则cpython读取这个变量时是从第5个字符串开始读的),修改后会导致关键变量的opcode混乱,除了自己的环境外,其他人都执行和解密不了了

       2、在修改好opcode的python环境,把所有py文件编译成pyc,然后删除原始py文件


    修改opcode的脚本:
    #!/usr/bin/env python2.7
    # encoding:utf-8
    #FileName scramble-opcodes.py
    __author__ = 'mafei'
    import argparse
    import re
    import random
    import os
    python_version = 'Python-3.5.3'
    regex_for_opcode_h = r'^#define\s+(?P<name>[A-Z_]+)\s+(?P<code>\d+)(?P<extra>.*)'
    regex_for_opcode_py = r'^(?P<key>[a-z_]+)+\(\'+(?P<name>[A-Z_]+)+\'+\,\s+(?P<code>\d+)(?P<extra>.*)'
    
    
    try:
        from importlib.machinery import SourceFileLoader
    except ImportError:
        import imp
        
        
    class replace_opcode(object):
        
        def __init__(self):
            self.replace_dict = {}
            self.not_have_argument_code_list = []
            self.have_argument_code_list = []
        
        def set_list(self, reg, file):
            f1 = open(file, 'r+')
            infos = f1.readlines()
            f1.seek(0, 0)
            for line in infos:
                rex = re.compile(reg).match(line)
                if rex:
                    if rex.group('name') in ['CALL_FUNCTION', 'CALL_FUNCTION_KW', 'CALL_FUNCTION_EX', 'CALL_FUNCTION_VAR',
                                             'CALL_FUNCTION_VAR_KW']:
                        continue
                    elif int(rex.group('code')) < 90:
                        self.not_have_argument_code_list.append(int(rex.group('code')))
                    else:
                        self.have_argument_code_list.append(int(rex.group('code')))
        
        def replace_file(self, reg, file, is_update=False):
            if not is_update:
                self.set_list(reg, file)
            f1 = open(file, 'r+')
            infos = f1.readlines()
            f1.seek(0, 0)
            for line in infos:
                rex = re.compile(reg).match(line)
                if rex:
                    n = self.replace_code(rex, is_update)
                    line = line.replace(rex.group('code'), str(n))
                f1.write(line)
            f1.close()
            
        def replace_code(self, rex, is_update):
            if is_update:
                try:
                    n = self.replace_dict[rex.group('name')]
                except:
                    n = rex.group('code')
                return n
            if rex.group('name') == "CALL_FUNCTION":
                n = int(rex.group('code'))
            elif rex.group('name') in ['CALL_FUNCTION_KW', 'CALL_FUNCTION_EX', 'CALL_FUNCTION_VAR',
                                       'CALL_FUNCTION_VAR_KW']:
                n = int(rex.group('code'))
            else:
                if int(rex.group('code')) < 90:
                    n = random.choice(self.not_have_argument_code_list)
                    self.not_have_argument_code_list.remove(n)
                else:
                    n = random.choice(self.have_argument_code_list)
                    self.have_argument_code_list.remove(n)
            self.replace_dict[rex.group('name')] = n
            return n
            
        def run(self, source_directory):
            OPCODE_PY = 'Lib/opcode.py'
            OPTARGETS_H = "Include/opcode.h"
            print source_directory
            print('start run......', os.path.join(source_directory, OPCODE_PY))
            self.replace_file(reg=regex_for_opcode_py, file=os.path.join(source_directory, OPCODE_PY))
            print('run {} end'.format(os.path.join(source_directory, OPCODE_PY)))
            print('start run......', os.path.join(source_directory, OPCODE_PY))
            self.replace_file(reg=regex_for_opcode_h, file=os.path.join(source_directory, OPTARGETS_H), is_update=True)
            print('run {} end'.format(os.path.join(source_directory, OPTARGETS_H)))
            self.write_opcode_targets_contents()
            print('run {} end'.format(os.path.join(source_directory, OPTARGETS_H)))
        
        def write_opcode_targets_contents(self, file='Python/opcode_targets.h'):
            """Write C code contents to the target file object.
            """
            targets = ['_unknown_opcode'] * 256
            for opname, op in sorted(self.replace_dict.items(), key=lambda nc: nc[1]):
                targets[op] = "TARGET_%s" % opname
            with open(os.path.join(source_directory, file), 'w') as f:
                f.write("static void *opcode_targets[256] = {\n")
                sep = ',%s' % os.linesep
                f.write(sep.join(["    &&%s" % s for s in targets]))
                f.write("\n};\n")
                
                
    if __name__ == '__main__':
        parser = argparse.ArgumentParser(description='Scramble python opcodes table')
        parser.add_argument('--python-source', dest='src', type=str,
                            help='Python source code', required=True)
        args = parser.parse_args()
        source_directory = os.path.abspath(args.src)
        # main(source_directory)
        replace_opcode_class = replace_opcode()
        replace_opcode_class.run(source_directory)
    cd /opt/
    下载源码包 wget 
    解压   tar xJf Python-3.5.3.tar.xz

    执行修改opcode操作

    python scramble-opcodes.py --python-source=/opt/Python-3.5.3


    #后面几步就是标准的python安装步骤啦

    cd /opt/Python-3.5.3 

    ./configure --prefix=/opt/python-3.5.3 && make && make install

    加入系统路径

    export PATH=/opt/python-3.5.3/bin/:$PATH
    
    这时候执行python3就可以进入python3.5.3的修改opcode后的环境了


    加密Python代码(一定要在修改过opcode的Python环境执行,否则不生效的)


    #!/usr/bin/env python2.7
    # encoding:utf-8
    __author__ = 'mafei'
    import os
    import subprocess
    import argparse
    import sys
    def compile_py3(source_dir):
        g = os.walk(source_dir)
        # compileall.compile_dir(source_dir, maxlevels=100)
        subprocess.check_output('{} -m compileall -b {}'.format(sys.executable,source_dir),shell=True)
        for path,d,filelist in g:
            for filename in filelist:
                #对所有py文件进行加密并删除原始文件
                if os.path.splitext(filename)[-1] =='.py':
                    os.remove(os.path.join(path, filename))
                    print('compile {}'.format(os.path.join(path, filename)))
    if __name__ == '__main__':
        parser = argparse.ArgumentParser(description='Scramble python opcodes table')
        parser.add_argument('--python-source', dest='src', type=str,
                            help='Python source code', required=True)
        args = parser.parse_args()
        source_directory = os.path.abspath(args.src)
        compile_py3(source_directory)

    转载自https://blog.51cto.com/mapengfei/1976189

关键字