后台大佬:python源码需要加密,所以不要显示。。。大灰狼:好的!实现加密网络传输有两种可行的方法,代码变量混淆,修改编译器opcode(本文使用的方法)两步:修改python编译器,让特定的编译器只能执行对应的pyc文件封装基本的环境变成docker镜像作为程序发布的基础镜像1.修改操作代码方法修改python源码文件相关的目标文件Lib/opcode.pyInclude/opcode.hPython/opcode_targets.h修改策略有3种:Disruptopcode策略总结:opcode.py中HAVE_ARGUMENT=90为分隔符,大于90的opcode有参数,小于90的opcode没有参数将所有opcode放入不同的list:not_have_argument_code_list和have_argument_code_list,除了4个callbackopcode随机打乱not_have_argument_code_list和have_argument_code_list的顺序遍历opcode.py中的所有opcode,取最后一个操作两个列表依次编码为当前操作的新操作码,并保存新操作码字典replace_dict将replace_dict按照操作码从小到大排序,并将overwrite写入Python/opcode_targets.h文件修改操作码执行方法modify_opcodes.py全部内容:#-*-coding:utf-8-*-#@File:modify_opcodes.py#@Date:2019/11/28#@Author:HiCooper#@Desc:modifyopcodes#targetPython-3.5.2importargparseimportosimportrandomimportre#修改相关文件:OPCODE_PY_PATH="Lib/opcode.py"OPCODE_H_PATH="Include/opcode.h"OPCODE_TARGETS_H_PATH="Python/opcode_targets.h"#回调操作名称集合:CALL_OP=['CALL_FUNCTION','CALL_FUNCTION_KW','CALL_FUNCTION_VAR','CALL_FUNCTION_VAR_KW']#opcode_py文件提取规律regex_for_opcode_py=r'^(?P[a-z_]+)+\(\'+(?P[A-Z_]+)+\'+\,\s+(?P\d+)(?P.*)'#opcode_h文件提取正则regex_for_opcode_h=r'^#define\s+(?P[A-Z_]+)\s+(?P\d+)(?P.*)'try:fromimportlib.machineryimportSourceFileLoaderexceptImportError:importimpclassReplaceOpCode(object):"""1.opcode.py中的`HAVE_ARGUMENT=90`是分隔符,大于90的opcode有参数,小于90的opcode没有参数2.将所有的opcode放入不同的列表:`not_have_argument_code_list`和`have_argument_code_list`,除了4个回调操作码3.随机打乱`not_have_argument_code_list`和`have_argument_code_list`的顺序4.遍历opcode.py中的所有操作码,将两个列表的最后一个操作码作为当前操作的新操作码,以及将其保存在新的操作码字典`replace_dict`5.根据opcode从小到大对`replace_dict`进行排序,写入`Python/opcode_targets.h`文件"""def__init__(self,source_directory):self.replace_dict={}self.not_have_argument_code_list=[]self.have_argument_code_list=[]self.set_list(source_directory)defset_list(self,source_directory):"""1.读取opcode_py的内容,保存操作码到`not_have_argument_code_list`和`have_argument_code_list`(跳过4个回调操作码)2.随机打乱顺序"""f1=open(os.path.join(source_directory,OPCODE_PY_PATH),'r+')infos=f1.readlines()f1.seek(0,0)forlineininfos:rex=re.compile(regex_for_opcode_py).match(line)ifrex:op_code=rex.group('code')ifrex.group('name')inCALL_OP:continueelifint(op_code)<90:self.not_have_argument_code_list.append(int(op_code))其他:self.have_argument_code_list.append(int(op_code))random.shuffle(self.not_have_argument_code_list)random.shuffle(self.have_argument_code_list)defreplace_file(self,reg,file,is_update_opcode_h=False):"""读取opcode.py或opcode.h内容并执行行替换"""f1=open(file,'r+')infos=f1.readlines()f1.seek(0,0)forlineininfos:rex=re.compile(reg).match(line)ifrex:code=self.get_new_op_code(rex,is_update_opcode_h)line=line.replace(rex.group('code'),str(code))f1.write(line)f1.close()defget_new_op_code(self,rex,is_update_opcode_h):"""获取新操作码"""op_name=rex.group('name')op_code=rex.group('code')ifis_update_opcode_h:#修改opcode.h文件时,从完成的字典中读取try:new_op_code=self.replace_dict[op_name]except:new_op_code=op_codereturnnew_op_code#修改opcode.py文件,如果CALL_OP中有op_name,则将名称和代码设置为字典replace_dict:#属于回复操作,默认操作码new_op_code=int(op_code)else:ifint(op_code)<90:new_op_code=self.not_have_argument_code_list.pop()else:new_op_code=self.have_argument_code_list.pop()self.replace_dict[op_name]=new_op_codereturnnew_op_codedefwrite_opcode_targets_contents(self,source_directory):"""将C代码内容写入目标文件对象。"""targets=['_unknown_opcode']*256foropname,opinsorted(self.replace_dict.items(),key=lambdanc:nc[1]):targets[op]="TARGET_%s"%opnamewithopen(os.path.join(source_directory,OPCODE_TARGETS_H_PATH),'w')作为f:f.write("staticvoid*opcode_targets[256]={\n")sep=',%s'%os.linesepf.write(sep.join(["&&%s"%sforsintargets]))f.write("\n};\n")defrun(self,source_directory):print('\n======开始修改操作码...======\n')self.replace_file(reg=regex_for_opcode_py,file=os.path.join(source_directory,OPCODE_PY_PATH))self.replace_file(reg=regex_for_opcode_h,file=os.path.join(source_directory,OPCODE_H_PATH),is_update_opcode_h=True)self.write_opcode_targets_contents(source_directory)print('\n======修改完成!======\n')if__name__=='__main__':parser=argparse.ArgumentParser(description='修改python操作码')parser.add_argument('--src',dest='src',type=str,help='Pythonsourcecodepath(supportrelativepath)',required=True)args=parser.parse_args()src=os.path.abspath(args.src)replaceOpCode=ReplaceOpCode(src)replaceOpCode.run(src)修改并执行pythonmodify_opcodes。py--src=./Python-3.5.2参考修改:https://blog.51cto.com/juispan/2065568注意:并不是所有的python版本都支持修改操作码。这里测试的python版本是Python-3.5.22。基于centos7搭建python执行环境镜像并修改python3.5.2Opcode及编译安装~~~~准备文件:修改_opcode.pyPython-3.5.2.tgz上一步源码压缩包,下载门户编译工程文件的工具类compile.py(后面会用到)稍后构建项目镜像)构建容器步骤总结:Step1.安装编译python源码所需的基础包Step2.修改opcode,编译安装,设置环境变量Step3.添加软链接到构建镜像的Dockfile完整内容:#自定义python3.5.2环境FROMcentos:centos7ENVLANG=en_US.UTF-8#工作目录WORKDIR/python#添加脚本,py源码包ADDPython-3.5.2.tgz编译。pymodify_opcode.py/python/#安装基础包RUNpython-V&&yum-yupdate&&\yuminstall-yyum-utilswgetmakedevice-mapper-persistent-data\lvm2net-toolsvim-enhancedgcczlib*openssl-develreadlinesqlite-devel\readline-devellibffi-devellibSM-devellibXrenderlibXext-devel&&\yumcleanall#修改opcode,编译安装,设置环境变量,设置pip源,升级pip,验证环境RUNpythonmodify_opcode.py--src=/python/Python-3.5.2/&&\cdPython-3.5.2&&./configure--prefix=/usr/local/python3&&\make&&makeinstall&&\echo"exportPATH=/usr/local/python3/bin:$PATH">>/etc/profile.d/python3.sh&&\echo"exportLANG=en_US.UTF-8">>/etc/profile.d/python3.sh&&\source/etc/bashrc&&\mkdir~/.pip&&\echo"[global]">>~/.pip/pip.conf&&\echo"index-url=https://pypi.tuna.tsinghua.edu.cn/simple">>~/.pip/pip.conf&&\pip3install--升级pip--no-cache-dir&&\python3-V&&pip3-V#添加软链接RUNln-s-b/usr/local/python3/bin/python3/usr/bin/python3&&\ln-s-b/usr/local/python3/bin/pip3/usr/bin/pip3#添加TiniENVTINI_VERSIONv0.18.0ADDhttps://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini/tiniRUNchmod+x/tiniENTRYPOINT["/tini","--"]CMD["/bin/bash"]mirrordockerbuild-thicooper/py3.5.2:v1.0根据Dockerfile构建。验证镜像环境假设上一步生成的ImageId为23fdd4e27c63dockerrun-it--namepy3.5.2v1.023fdd4e27c63/bin/bash成功进入容器后,验证python环境,完成文件compile.py完整内容#-*-coding:utf-8-*-importargparseimportos,sys,shutilimportcompilealldefsearch(curpath,s):L=os.listdir(curpath)#列出当前目录下的所有文件forsubpathinL:#遍历当前目录下的所有文件ifos.path.isdir(os.path.join(curpath,subpath)):#如果文件还是目录,递归搜索子目录newpath=os.path.join(curpath,subpath)search(newpath,s)elifos.path.isfile(os.path.join(curpath,subpath)):#如果是文件,判断是否包含搜索字符串ifsinsubpathand"__pycache__"incurpath:#将pyc文件移动到父目录parent_path=os.path.dirname(curpath)##获取parent_path所在目录为parent_path的父目录shutil.copy(os.path.join(curpath,subpath),parent_path)#renamename=subpath.split(".")re_name=(name[0]+"."+name[2])os.rename(os.path.join(parent_path,subpath),os.path.join(parent_path,re_name))如果子路径中有“.py”and".pyc"notinsubpath:#删除py文件print(os.path.join(curpath,子路径))os.remove(os.path.join(curpath,subpath))if__name__=='__main__':parser=argparse.ArgumentParser(description='modifypythonopcodes')parser.add_argument('--src',dest='src',type=str,help='项目源代码',required=True)args=parser.parse_args()workingpath=args.srccompileall.compile_dir(workingpath)search(workingpath,".pyc")print('\n======编译完成!======\n')3.构建项目镜像上一步构建的镜像作为基础环境测试项目只有一个app.py文件,文件内容#-*-coding:utf-8-*-importjiebatext='千真万确,安全第一,不规范驾驶,为亲人流泪项目构建Dockerfile内容FROMhicooper/py3.5.2:v1.0ENVLANG=en_US.UTF-8WORKDIR/appADDapp.py/app#installpageckageRUNpipinstalljieba&&\python/python/compile.py--src=./CMD["python","app.pyc"]构建项目镜像dockerbuild-tapp。运行项目dockerrunapp结果和原句类似:一千个理由一万个,安全第一,不规范驾驶,为亲人流泪两行Buildingprefixdictfromthedefaultdictionary...Loadingmodelfromcache/tmp/jieba.cacheLoadingmodelcost1.309seconds.Prefixdict已成功构建。分词:原因/千万条/,/安全/第一条/,/驾驶/否/规范/,/亲戚/两行/泪结束打包的项目图片比较大,这里有:1.39GB,OMG!!!