如何保护python脚本?

如何保护python脚本?,python,Python,几年前,当我准备发布我的第一个python应用程序时,我不得不面对一个问题:如何混淆python脚本,以便没有清晰的代码显示给我的客户?现在我有了一个解决方案 构建模糊脚本 首先将Python脚本编译为代码对象 char *filename = "foo.py"; char *source = read_file( filename ); PyCodeObject *co = Py_CompileString( source, "<frozen foo>", Py_file_inpu

几年前,当我准备发布我的第一个python应用程序时,我不得不面对一个问题:如何混淆python脚本,以便没有清晰的代码显示给我的客户?

现在我有了一个解决方案

构建模糊脚本 首先将Python脚本编译为代码对象

char *filename = "foo.py";
char *source = read_file( filename );
PyCodeObject *co = Py_CompileString( source, "<frozen foo>", Py_file_input );
更改了原始字节码:

    Increase oparg of each absolute jump instruction by the size of wrap header

    Obfuscate original byte code

    ...
换行页脚:

    LOAD_GLOBALS    N + 1 (__armor_exit__)
    CALL_FUNCTION   0
    POP_TOP
    END_FINALLY
  • 将函数名
    \uuuuuu armor\u enter
    \uuuuuu armor\u exit\uuuuuuuuu
    附加到
    co\u consts

  • co_stacksize
    增加2

  • CO\u标志中设置CO\u模糊(0x8000000)标志

  • 递归地更改
    co_consts
    中的所有代码对象

  • 然后序列化这个经过改造的代码对象,混淆它以保护常量和文本字符串

    char*string\u code=marshal.dumps(co);
    char*obfuscated_code=模糊_算法(字符串_code);
    
    最后生成模糊脚本

    sprintf(buf,“\uuuu-pyarmor\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu;
    保存文件(“dist/foo.py”,buf);
    
    模糊化脚本是一个普通的Python脚本,看起来像这样

    __pyarmor__(__name__, __file__, b'\x01\x0a...')
    
    运行模糊脚本 为了通过公共Python解释器运行模糊的脚本
    dist/foo.py
    , 有3个功能需要添加到模块
    内置
    \uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
    uuuuuuuuuuuuuuuuuuuuuuuuu

    • 首先将调用
      \uuuuuuuuuuuuuuuuuuuuuu
      ,它将从混淆的代码中导入原始模块

      static PyObject*
      __pyarmor(字符*名称,字符*路径名,无符号字符*模糊代码)
      {
      char*string\u code=恢复\u模糊化\u代码(模糊化\u代码);
      PyCodeObject*co=marshal.loads(字符串\u代码);
      返回PyImport\u ExecCodeModuleEx(名称、co、路径名);
      }
      
    • 执行代码对象后,将立即调用
      \uuuuuuu\uuuu\uuuuu\uuuuu

      static PyObject*
      __装甲输入(PyObject*self,PyObject*args)
      {
      //获取代码对象
      PyFrameObject*frame=PyEval_GetFrame();
      PyCodeObject*f_code=frame->f_code;
      //增加此代码对象的引用调用
      //借用公司名称->作为呼叫计数器的ob\U refcnt
      //一般来说,Python解释器不会增加它
      PyObject*refcalls=f_code->co_name;
      refcalls->ob_refcnt++;
      //如果字节码被混淆,则还原它
      如果(模糊化了(f_代码->co_标志)){
      恢复字节码(f码->co码);
      清除模糊标志(f代码);
      }
      Py_返回_无;
      }
      
    • 只要代码对象完成执行,就会调用
      \uuuuuuuuu\uuuuuuuu\uuuuuuuuuu\uuuuuuuuuu

      static PyObject*
      __装甲\u退出\u(PyObject*self,PyObject*args)
      {
      //获取代码对象
      PyFrameObject*frame=PyEval_GetFrame();
      PyCodeObject*f_code=frame->f_code;
      //减少此代码对象的引用调用
      PyObject*refcalls=f_code->co_name;
      refcalls->ob_refcnt--;
      //仅当任何函数未使用此代码对象时,才模糊字节代码
      //在多线程或递归调用中,可以引用一个代码对象
      //由多个功能同时执行
      if(refcalls->ob_refcnt==1){
      混淆字节码(f码->co码);
      设置模糊标志(f代码);
      }
      //清除此帧中的f_局部变量
      清除\u帧\u局部变量(帧);
      Py_返回_无;
      }
      

    有兴趣吗?访问

    其他问题的答案都很旧:因此这里需要更新。
    __pyarmor__(__name__, __file__, b'\x01\x0a...')