如何有效地混淆Python代码?

如何有效地混淆Python代码?,python,Python,我正在寻找如何隐藏我的Python源代码 print "Hello World!" 如何对这个示例进行编码,使其不可读?我被告知使用base64,但我不确定如何使用。您可以使用对字符串进行编码来停止,但如果有人可以访问您的文件,它不会阻止他们查找您的代码 然后,在解码代码后,可以使用和执行代码 >>> import base64 >>> mycode = "print 'Hello World!'" >>> secret = base64

我正在寻找如何隐藏我的Python源代码

print "Hello World!" 
如何对这个示例进行编码,使其不可读?我被告知使用base64,但我不确定如何使用。

您可以使用对字符串进行编码来停止,但如果有人可以访问您的文件,它不会阻止他们查找您的代码

然后,在解码代码后,可以使用和执行代码

>>> import base64
>>> mycode = "print 'Hello World!'"
>>> secret = base64.b64encode(mycode)
>>> secret
'cHJpbnQgJ2hlbGxvIFdvcmxkICEn'
>>> mydecode = base64.b64decode(secret)
>>> eval(compile(mydecode,'<string>','exec'))
Hello World!
然后,您需要编写第二个脚本来执行
compile()
eval()
,这可能会将编码后的脚本作为字符串文字封装在脚本中。所以它看起来像这样:

>>> f = open('myscript.py')
>>> encoded = base64.b64encode(f.read())
import base64
myscript = """IyBUaGlzIGlzIGEgc2FtcGxlIFB5d
              GhvbiBzY3JpcHQKcHJpbnQgIkhlbG
              xvIiwKcHJpbnQgIldvcmxkISIK"""
eval(compile(base64.b64decode(myscript),'<string>','exec'))
import base64
import zlib
def run(code): exec(zlib.decompress(base64.b16decode(code)))
def enc(code): return base64.b16encode(zlib.compress(code))
def MakeSC():
    c = raw_input(" Encode: ")
    sc = "\\x" + "\\x".join("{0:x}".format(ord(c)) for c in c)
    print "\n shellcode =('" + sc + "'); exec(shellcode)"; MakeSC();
a6 = 90 # degreeIncrement = 90
a7 = 0.25 # durationIncrement = 0.25
def a8(a9, a10, a11): # def GetEditGlyphParams(self, waveform, editIndex):
    a12 = a10.leftSegments # segments = waveform.leftSegments
    a13 =  len(a9.a5) # waveformFunctionCount =  len(self.waveformFunctions)
    a14 = 0 # totalParameterCount = 0
    a15 = 0 # segmentIndex = 0
    while a15 < len(a12): # while segmentIndex < len(segments):
        a16 = a12[a15] # segment = segments[segmentIndex]
        a17 = len(a9.a3) # segmentParameterCount = len(self.sineFunctions)
        if a16.a332 == "line": # if segment.type == "line":
            a17 = len(a9.a4) # segmentParameterCount = len(self.lineFunctions)
导入base64
myscript=“”IyBUaGlzIGlzIGEgc2FtcGxlIFB5d
GhvbiBzY3JpcHQKcHJpbnQgIkhlbG
xviwkchjpbnqgildvcmxkisik“”
eval(compile(base64.b64解码(myscript),“”,'exec'))
所以它不是人类可读的

我的意思是所有的文件都被编码了!!当你打开它时,你什么都看不懂!这就是我想要的

最大限度地,您可以将源代码编译成字节码,然后只分发字节码。但即便如此,这也是可逆的。字节码可以反编译成半可读的源代码

Base64对于任何人来说都是微不足道的,因此它不能作为实际的保护,只能对完全不懂电脑的人“隐藏”来源。此外,如果您计划以任何方式实际运行该代码,则必须在脚本(或发行版中的另一个脚本,需要由合法用户运行)中包含解码器,这将立即泄露您的编码/加密

模糊处理技术通常涉及注释/文档剥离、名称篡改、垃圾代码插入等,因此即使您反编译字节码,也会得到不太可读的源代码。但它们仍然是Python的源代码,Python不擅长变成不可读的乱七八糟


如果您绝对需要保护一些功能,我建议使用编译语言,如C或C++,编译和分发。S/DLL,然后使用Python绑定到受保护代码。

< P>。Base64可以被解码。字节码可以反编译。Python最初只是进行解释,大多数解释语言都试图加快机器解释速度,而不是使人工解释变得困难

Python是为了可读和可共享而设计的,而不是为了混淆。关于如何格式化代码的语言决策是为了提高不同作者之间的可读性


模糊的python代码实际上与该语言不匹配。重新评估混淆代码的原因。

也许您应该考虑使用一些简单的方法,例如将源代码存储在内存中,因为这似乎是您关心的问题。您可以在usb密钥上创建加密文件,或者只加密整个卷(只要代码合适),这样您就可以在一天结束时随身携带密钥


为了编译,您可以使用类似或的东西来创建一个独立的可执行文件。如果你真的想多走一段路,那么看看a,以便添加更多的混淆。如果这些都不是选项,那么您至少可以将脚本编译成字节码,这样它就不会立即可读。请记住,这些方法只会减慢调试或反编译程序的速度。

我将以说教的方式写下我的答案

首先在Python解释器中键入:

import this
然后,查看Python发行版中Lib目录中的文件
this.py
,并尝试了解它的功能

然后,查看文档中的
eval
函数:

help(eval)

现在你应该找到一个有趣的方法来保护你的代码。但是要小心,因为这只适用于比你聪明的人!(我并不想冒犯你,任何足够聪明的人都可以理解你所做的事情。)

这只是一个有限的第一级混淆解决方案,但它是内置的:Python有一个针对字节码的编译器:

python -OO -m py_compile <your program.py>
python-OO-mpy\u编译
生成一个
.pyo
文件,该文件包含字节码、删除docstring的位置等。您可以使用
.py
扩展名重命名
.pyo
文件,
python
运行方式与您的程序类似,但不包含源代码

print "Hello World!" 
PS:您得到的“有限”模糊级别可以恢复代码(使用一些变量名,但没有注释和docstring)。请参见第一条注释,了解如何操作。然而,在某些情况下,这种程度的混淆可能被认为是足够的


PPS:如果您的程序导入了像这样模糊的模块,那么您需要使用
.pyc
后缀来重命名它们(我不确定这不会有一天中断),或者您可以使用
.pyo
并使用
python-O…pyo
运行它们(导入应该可以工作)。这将允许Python找到您的模块(否则,Python将查找
.py
模块)。

我最近偶然发现了这篇博客文章:作者在文章中谈到了使用内置AST模块对Python源文件进行模糊处理。编译后的二进制文件将用于HitB CTF,因此具有严格的混淆要求


由于您可以访问单个AST节点,因此使用此方法可以对源文件执行任意修改。根据所执行的转换,生成的二进制代码可能/可能与未模糊化的源代码的行为不完全相同。

如果要生成半模糊化的代码,请生成如下代码:

>>> f = open('myscript.py')
>>> encoded = base64.b64encode(f.read())
import base64
myscript = """IyBUaGlzIGlzIGEgc2FtcGxlIFB5d
              GhvbiBzY3JpcHQKcHJpbnQgIkhlbG
              xvIiwKcHJpbnQgIldvcmxkISIK"""
eval(compile(base64.b64decode(myscript),'<string>','exec'))
import base64
import zlib
def run(code): exec(zlib.decompress(base64.b16decode(code)))
def enc(code): return base64.b16encode(zlib.compress(code))
def MakeSC():
    c = raw_input(" Encode: ")
    sc = "\\x" + "\\x".join("{0:x}".format(ord(c)) for c in c)
    print "\n shellcode =('" + sc + "'); exec(shellcode)"; MakeSC();
a6 = 90 # degreeIncrement = 90
a7 = 0.25 # durationIncrement = 0.25
def a8(a9, a10, a11): # def GetEditGlyphParams(self, waveform, editIndex):
    a12 = a10.leftSegments # segments = waveform.leftSegments
    a13 =  len(a9.a5) # waveformFunctionCount =  len(self.waveformFunctions)
    a14 = 0 # totalParameterCount = 0
    a15 = 0 # segmentIndex = 0
    while a15 < len(a12): # while segmentIndex < len(segments):
        a16 = a12[a15] # segment = segments[segmentIndex]
        a17 = len(a9.a3) # segmentParameterCount = len(self.sineFunctions)
        if a16.a332 == "line": # if segment.type == "line":
            a17 = len(a9.a4) # segmentParameterCount = len(self.lineFunctions)
并制作如下文件(使用上述代码):

文件“something.py”:

只需导入“something.py”并运行
run(something.code)
即可运行文件中的代码

一个诀窍是使代码变得困难
$ gcc -o embedded -fPIC -I/usr/include/python2.7 -lpython2.7 embedded.c
$ chmod u+x ./embedded
$ time ./embedded
Hello world !

real  0m0.014s
user  0m0.008s
sys 0m0.004s
print('Hello World !')
$ time python hello_world.py
Hello World !

real  0m0.014s
user  0m0.008s
sys 0m0.004s
$ grep "Hello" ./embedded
Binary file ./embedded matches

$ grep "Hello World" ./embedded
$
...
PyRun_SimpleString("import base64\n"
                  "base64_code = 'your python code in base64'\n"
                  "code = base64.b64decode(base64_code)\n"
                  "exec(code)");
...
$ base64 hello_world.py
cHJpbnQoJ0hlbGxvIFdvcmxkICEnKQoK
#include <Python.h>

int
main(int argc, char *argv[])
{
  Py_SetProgramName(argv[0]);  /* optional but recommended */
  Py_Initialize();
  PyRun_SimpleString("import base64\n"
                    "base64_code = 'cHJpbnQoJ0hlbGxvIFdvcmxkICEnKQoK'\n"
                    "code = base64.b64decode(base64_code)\n"
                    "exec(code)\n");
  Py_Finalize();
  return 0;
}
$ gcc -o embedded_base64 -fPIC -I/usr/include/python2.7 -lpython2.7 ./embedded_base64.c
$ chmod u+x ./embedded_base64

$ time ./embedded_base64
Hello World !

real  0m0.014s
user  0m0.008s
sys 0m0.004s

$ grep "Hello" ./embedded_base64
$
$ pyconcrete-admin.py compile --source={your py script}  --pye
$ pyconcrete-admin.py compile --source={your py module dir} --pye
pyconcrete main.pye
src/*.pye  # your libs
$ python setup.py install \
  --install-lib={your project path} \
  --install-scripts={where you want to execute pyconcrete-admin.py and pyconcrete(exe)}
main.py       # import pyconcrete and your lib
pyconcrete/*  # put pyconcrete lib in project root, keep it as original files
src/*.pye     # your libs
(lambda _, __, ___, ____, _____, ______, _______, ________:
    getattr(
        __import__(True.__class__.__name__[_] + [].__class__.__name__[__]),
        ().__class__.__eq__.__class__.__name__[:__] +
        ().__iter__().__class__.__name__[_____:________]
    )(
        _, (lambda _, __, ___: _(_, __, ___))(
            lambda _, __, ___:
                chr(___ % __) + _(_, __, ___ // __) if ___ else
                (lambda: _).func_code.co_lnotab,
            _ << ________,
            (((_____ << ____) + _) << ((___ << _____) - ___)) + (((((___ << __)
            - _) << ___) + _) << ((_____ << ____) + (_ << _))) + (((_______ <<
            __) - _) << (((((_ << ___) + _)) << ___) + (_ << _))) + (((_______
            << ___) + _) << ((_ << ______) + _)) + (((_______ << ____) - _) <<
            ((_______ << ___))) + (((_ << ____) - _) << ((((___ << __) + _) <<
            __) - _)) - (_______ << ((((___ << __) - _) << __) + _)) + (_______
            << (((((_ << ___) + _)) << __))) - ((((((_ << ___) + _)) << __) +
            _) << ((((___ << __) + _) << _))) + (((_______ << __) - _) <<
            (((((_ << ___) + _)) << _))) + (((___ << ___) + _) << ((_____ <<
            _))) + (_____ << ______) + (_ << ___)
        )
    )
)(
    *(lambda _, __, ___: _(_, __, ___))(
        (lambda _, __, ___:
            [__(___[(lambda: _).func_code.co_nlocals])] +
            _(_, __, ___[(lambda _: _).func_code.co_nlocals:]) if ___ else []
        ),
        lambda _: _.func_code.co_argcount,
        (
            lambda _: _,
            lambda _, __: _,
            lambda _, __, ___: _,
            lambda _, __, ___, ____: _,
            lambda _, __, ___, ____, _____: _,
            lambda _, __, ___, ____, _____, ______: _,
            lambda _, __, ___, ____, _____, ______, _______: _,
            lambda _, __, ___, ____, _____, ______, _______, ________: _
        )
    )
)
char * filename = "xxx.py";
char * source = read_file( filename );
PyObject *co = Py_CompileString( source, filename, Py_file_input );
0   JUMP_ABSOLUTE            n = 3 + len(bytecode)    
3
...
... Here it's obfuscated bytecode
...

n   LOAD_GLOBAL              ? (__armor__)
n+3 CALL_FUNCTION            0
n+6 POP_TOP
n+7 JUMP_ABSOLUTE            0
char *original_code = marshal.dumps( co );
char *obfuscated_code = obfuscate_algorithm( original_code  );
__pyarmor__(__name__, b'${obfuscated_code}')
int __pyarmor__(char *name, unsigned char *obfuscated_code) 
{
  char *original_code = resotre_obfuscated_code( obfuscated_code );
  PyObject *co = marshal.loads( original_code );
  PyObject *mod = PyImport_ExecCodeModule( name, co );
}
__all__ = ['foo']

a = 'a'
_b = 'b'

def foo():
    print(a)

def bar():
    print(_b)

def _baz():
    print(a + _b)

foo()
bar()
_baz()
__all__ =['foo']#line:1
OO00OO0OO0O00O0OO ='a'#line:3
_O00OO0000OO0O0O0O ='b'#line:4
def foo ():#line:6
    print (OO00OO0OO0O00O0OO )#line:7
def O0000000OOOO00OO0 ():#line:9
    print (_O00OO0000OO0O0O0O )#line:10
def _OOO00000O000O0OOO ():#line:12
    print (OO00OO0OO0O00O0OO +_O00OO0000OO0O0O0O )#line:13
foo ()#line:15
O0000000OOOO00OO0 ()#line:16
_OOO00000O000O0OOO ()#line:17
You can recursively exclude all identifiers of certain modules from obfuscation.
You can exclude human readable configuration files containing Python code.
You can use getattr, setattr, exec and eval by excluding the identifiers they use.
You can even obfuscate module file names and string literals.
You can run your obfuscated code from any platform.
sudo pip install -U cython
pyobfuscate.py myfile.py >obfuscated.py
#!/usr/bin/env python3
import zlib, base64
exec(zlib.decompress(base64.b64decode('eJx1kcFOwzAMhu95ClMO66apu0/KAQEbE5eJC+IUpa27haVJ5Ljb+vakLYJx4JAoiT/7/+3c3626SKvSuBW6M4Sej96Jq9y1wRM/E3kSexnIOBZObrSNKI7Sl59YsWDq1wLMiEKNrenoYCqB1woDwzXF9nn2rskZd1jDh+9mhOD8DVvAQ8WdtrZfwg74aNwp7ZpnMXHUaltk878ybR/ZNKbSjP8JPWk6wdn72ntodQ8lQucIrdGlxaHgq3QgKqtjhCY/zlN6jQ0oZZxhpfKItlkuNB3icrE4XYbDwEBICRP6NjG1rri3YyzK356CtsGwZuNd/o0kYitvrBd18qgmj3kcwoTckYPtJPAyCVzSKPCMNErs85+rMINdp1tUSspMqVYbp1Q2DWKTJpcGURRDr9DIJs8wJFlKq+qzZRaQ4lAnVRuJgjFynj36Ol7SX/iQXr8ANfezCw==')))
# Created by pyminifier.py (https://github.com/liftoff/pyminifier)
#//'written in c++'

#include <iostream.h>
#define true false
import os
n = int(input())
_STACK_CALS=  [ ];
_i_CountCals__= (0x00)
while os.urandom(0x00 >> 0x01) or (1 & True):
  _i_CountCals__+= 0o0;break;# call shell command echo "hello world" > text.txt
""#print'hello'
__cal__= getattr( __builtins__  ,'c_DATATYPE_hFILE_radnom'[ 0x00 ]+'.h'[-1]+'getRndint'[3].lower() )
_o0wiXSysRdrct   =eval (  __cal__(0x63) + __cal__(104) + 'r_RUN_CALLER'[0] );
_i1CLS_NATIVE=  getattr (__builtins__ ,__cal__(101)+__cal__(118  )+_o0wiXSysRdrct ( 0b1100001 )+'LINE 2'[0].lower( ))#line 2 kernel call
__executeMAIN_0x07453320abef  =_i1CLS_NATIVE ( 'map');
def _Main():
    raise 0x06;return 0 # exit program with exit code 0
def _0o7af():_i1CLS_NATIVE('_int'.replace('_', 'programMain'[:2]))(''.join(  __executeMAIN_0x07453320abef( _o0wiXSysRdrct ,_STACK_CALS)));return;_Main()
for _INCREAMENT in [0]*1024:
    _STACK_CALS= [0x000 >> 0x001 ,True&False&True&False ,'c++', 'h', 'e', 'l', 'o',' ', 'w', 'o', 'r', 'l', 'd']
   
#if
for _INCREAMENT in [0]*1024:
    _STACK_CALS= [40, 111, 41, 46, 46] * n
    
""""""#print'word'
while True:
    break;
_0o7af();
while os.urandom(0x00 >> 0xfa) or (1 & True): # print "Hello, world!"
  _i_CountCals__-= 0o0;break;
  while os.urandom(0x00 >> 0x01) or (1 & True):
      _i_CountCals__ += 0o0;
      break;
degreeIncrement = 90
durationIncrement = 0.25
def GetEditGlyphParams(self, waveform, editIndex):
    segments = waveform.leftSegments
    waveformFunctionCount =  len(self.waveformFunctions)
    totalParameterCount = 0
    segmentIndex = 0
    while segmentIndex < len(segments):
        segment = segments[segmentIndex]
        segmentParameterCount = len(self.sineFunctions)
        if segment.type == "line":
            segmentParameterCount = len(self.lineFunctions)
a6 = 90 # degreeIncrement = 90
a7 = 0.25 # durationIncrement = 0.25
def a8(a9, a10, a11): # def GetEditGlyphParams(self, waveform, editIndex):
    a12 = a10.leftSegments # segments = waveform.leftSegments
    a13 =  len(a9.a5) # waveformFunctionCount =  len(self.waveformFunctions)
    a14 = 0 # totalParameterCount = 0
    a15 = 0 # segmentIndex = 0
    while a15 < len(a12): # while segmentIndex < len(segments):
        a16 = a12[a15] # segment = segments[segmentIndex]
        a17 = len(a9.a3) # segmentParameterCount = len(self.sineFunctions)
        if a16.a332 == "line": # if segment.type == "line":
            a17 = len(a9.a4) # segmentParameterCount = len(self.lineFunctions)
import sys, re
sourceFilePath = sys.argv[1]
targetFilePath = sys.argv[2]
print("uglify", sourceFilePath)

names = []
translations = []

class Analyser:
    def AnalyseLines(self, lines):
        for line in lines:
            self._AnalyseLine(line)
    def _AnalyseLine(self, line):
        parts = self._GetParts(line)
        if len(parts) > 1 and parts[0] == "import":
            self._AnalyseImport(parts)
        if len(parts) > 1 and parts[0] == "class":
            self._AnalyseClass(parts)
        if len(parts) > 1 and parts[1] == "=":
            self._AnalyseAssignment(parts)
        if len(parts) > 1 and parts[0] == "def":
            self._AnalyseDef(parts)
    def _GetParts(self, line):
        minusTabs = line.replace("\t", " ")
        minusDoubleSpace = minusTabs.replace("  ", " ")
        parts = minusDoubleSpace.split(" ")
        while "#" in parts:
            del parts[-1]
        while len(parts) > 0 and parts[0] == "":
            del parts[0]
        return parts
    def _AddName(self, name, elementType):
        if name == "":
            return
        nameToAppend = name # + " " + elementType
        if nameToAppend in names:
            return
        names.append(nameToAppend)
        translation = "a" + str(len(names))
        translations.append((name, translation))
    def _AnalyseImport(self, parts):
        if len(parts) == 4 and parts[0] == "import" and parts[2] == "as":
            self._AddName(parts[3], "import")
    def _AnalyseClass(self, parts):
        p1 = parts[1].split(":")
        p2 = p1[0].split("(")
        self._AddName(p2[0], "class")
    def _AnalyseAssignment(self, parts):
        mutableName = parts[0].split(".")[0]
        self._AddName(mutableName, "assignment")
    def _AnalyseDef(self, parts):
        methodNameParts = parts[1].split("(")
        if methodNameParts[0] == "__init__":
            return
        self._AddName(methodNameParts[0], "method")
        if len(methodNameParts) > 1:
            self._AddName(methodNameParts[1].replace(",", "").replace("):", ""), "param1")
        for part in parts[2:]:
            params = part.split(",")
            for param in params:
                if param != "":
                    self._AddName(param.replace(":", "").replace(")", ""), "paramN")

class Translator:
    def TranslateLines(self, content):
        oldLines = content.split("\n")
        content = content.replace('"', "_QUOTE_").replace("\\", "_BACKSLASH_")
        for (oldWord, newWord) in translations:
            content = re.sub(r"\b%s\b" % oldWord, newWord, content)
        content = content.replace("_QUOTE_", '"').replace("_BACKSLASH_", "\\")
        newLines = content.split("\n")
        for i in range(len(newLines) - 1):
            if newLines[i] != "":
                newLines[i] += " # " + oldLines[i].strip()
        return "\n".join(newLines)

analyser = Analyser()
sourceFile = open(sourceFilePath, 'r')
targetFile = open(targetFilePath, 'w')
content = sourceFile.read()
lines = content.split("\n")
print(len(lines), "lines, starting with", lines[0])
analyser.AnalyseLines(lines)
# print(names)
# print(translations)
translator = Translator()
newContent = translator.TranslateLines(content)
newLines = newContent.split("\n")
print("writing", len(newLines), " lines to", targetFilePath, "starting with", newLines[0])
targetFile.write(newContent)
sourceFile.close()
targetFile.close()