使用 pyinstaller 制作的 exe 文件被 Windows Defender 报告为病毒威胁

问题描述 投票:0回答:7

我正在尝试使用 pyinstaller 为学校项目创建一个 exe,但是 Windows Defender 似乎报告病毒威胁并阻止该文件。我想将此 exe 发送给其他人,但除非我修复此问题,否则我无法做到这一点。所以这些是我的疑问 - 为什么 exe 文件被报告为病毒? 对病毒总数的快速扫描表明 16 个引擎将此文件检测为特洛伊木马。另外,是否有任何方法可以防止 Windows Defender 或任何其他防病毒软件向用户发出病毒威胁警报,我的意思是,是否有任何方法可以使我的文件对防病毒软件来说看起来是安全的,以防它只是虚假威胁?如果这是不可能的,pyinstaller 的其他安全替代品是什么?我只是一个初学者,所以任何提示将不胜感激。谢谢。

编辑:根据@Pro Chess的要求,我包含了我的脚本。

import socket 
import threading
import pickle

class Server :
    def __init__(self) :
        self.HEADER = 64
        self.PORT = 5050
        self.SERVER =  socket.gethostbyname(socket.gethostname())
        self.ADDR = (self.SERVER, self.PORT)
        self.FORMAT = 'utf-8'
        self.DISCONNECT_MESSAGE = "!DISCONNECT"

        self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server.bind(self.ADDR)
        self.save_dict = {}

    def file_access(self) :
        with open("project_data\\savedata.dat","rb") as save_file :
            save_dict = pickle.load(save_file)
            return save_dict

    def file_dump(self) :
        with open("project_data\\savedata.dat","wb") as save_file :
            pickle.dump(self.save_dict,save_file)

    def recieve(self,conn) :
        msg_length = conn.recv(self.HEADER).decode(self.FORMAT)
        if msg_length:
            msg_length = int(msg_length)
            msg = conn.recv(msg_length).decode(self.FORMAT)
            return msg

    def handle_client(self,conn, addr):
        print(f"[NEW CONNECTION] {addr} connected.")

        connected = True
        while connected:
            try :
                self.save_dict = self.file_access()
                msg = self.recieve(conn)
                if msg == self.DISCONNECT_MESSAGE:
                    connected = False
                elif msg == "Save Data" :
                    player_id = conn.recv(5000)
                    try :
                        name,code = pickle.loads(player_id)
                    except EOFError :
                        pass
                    if (name,code) not in self.save_dict :
                        conn.send("Available".encode(self.FORMAT))
                        msg1 = self.recieve(conn)
                        if msg1 == "Game Data" :
                            game_data = conn.recv(5000)
                            #msg = pickle.loads(msg_data)
                            self.save_dict[(name,code)] = game_data
                            print(self.save_dict)
                            conn.send("Success".encode(self.FORMAT))
                    else :
                        conn.send("Exists".encode(self.FORMAT))
                        msg1 = self.recieve(conn)
                        if msg1 == "Game Data" :
                            game_data = conn.recv(5000)
                            self.save_dict[(name,code)] = game_data
                            conn.send("Success".encode(self.FORMAT))
                elif msg == "Wipe" :
                    self.save_dict.pop((name,code))
                    print(f"new dict is ",self.save_dict)
                elif msg == "Load" :
                    player_id = conn.recv(5000)
                    try :
                        name,code = pickle.loads(player_id)
                    except EOFError :
                        pass
                    if (name,code) in self.save_dict :
                        conn.send("Present".encode(self.FORMAT))
                        conn.send(self.save_dict[(name,code)])
                    else :
                        conn.send("Absent".encode(self.FORMAT))
                elif msg == "Check Data" :
                    player_id = conn.recv(5000)
                    try :
                        name,code = pickle.loads(player_id)
                    except EOFError :
                        pass
                    if (name,code) in self.save_dict :
                        conn.send("Exists".encode(self.FORMAT))
                    else :
                        conn.send("New".encode(self.FORMAT))
                self.file_dump()
            except ConnectionResetError :
                connected = False

        conn.close()
        print(f"[Terminated] connection terminated for {addr}")
            

    def start(self):
        self.server.listen()
        print(f"[LISTENING] Server is listening on {self.SERVER}")
        while True:
            conn, addr = self.server.accept()
            thread = threading.Thread(target=self.handle_client, args=(conn, addr))
            thread.start()
            print(f"[ACTIVE CONNECTIONS] {threading.activeCount() - 1}")


print("[STARTING] server is starting...")
server = Server()
server.start()

我使用套接字包在我的本地网络上运行服务器。

python python-3.x windows exe pyinstaller
7个回答
16
投票

方法一

一个可能的解决方案是加密您的代码。有多种方法可以加密您的代码。但最简单的一种是使用

base64
或基本上转换
text-to-binary
编码。并且你需要确保没有特殊字符,因为base64只有这个字符集。 您可以在此处查看 Base64 表 https://en.wikipedia.org/wiki/Base64

import base64

your_code = base64.b64encode(b"""

# All your code goes in here.  

import socket 
import threading
import pickle

class Server :
    def __init__(self) :
        self.HEADER = 64
        self.PORT = 5050
        self.SERVER =  socket.gethostbyname(socket.gethostname())
        self.ADDR = (self.SERVER, self.PORT)
        self.FORMAT = 'utf-8'
        self.DISCONNECT_MESSAGE = "!DISCONNECT"
# Continue your code...
""")

exec(base64.b64decode(your_code))

此技术用于黑客攻击和其他恶意目的,以避免防病毒软件将其检测为恶意软件。这可能对你有用。尝试重新编译它。让我们知道它是否有效。

方法2

如果上述方法不起作用,请尝试此方法。此方法使用

fernet cryptography
。这意味着代码加密得更严格,使得
anti-virus software
比第一种方法更难以将其识别为恶意软件。为此,您需要一个名为
cryptography
https://pypi.org/project/cryptography/

的 python 模块
from cryptography.fernet import Fernet
import base64

code = b"""

import socket 
import threading
import pickle

class Server :
    def __init__(self) :
        self.HEADER = 64
        self.PORT = 5050
        self.SERVER =  socket.gethostbyname(socket.gethostname())
        self.ADDR = (self.SERVER, self.PORT)
        self.FORMAT = 'utf-8'
        self.DISCONNECT_MESSAGE = "!DISCONNECT"

        self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server.bind(self.ADDR)
        self.save_dict = {}

    def file_access(self) :
        with open("project_data\\savedata.dat","rb") as save_file :
            save_dict = pickle.load(save_file)
            return save_dict

    def file_dump(self) :
        with open("project_data\\savedata.dat","wb") as save_file :
            pickle.dump(self.save_dict,save_file)

    def recieve(self,conn) :
        msg_length = conn.recv(self.HEADER).decode(self.FORMAT)
        if msg_length:
            msg_length = int(msg_length)
            msg = conn.recv(msg_length).decode(self.FORMAT)
            return msg

    def handle_client(self,conn, addr):
        print(f"[NEW CONNECTION] {addr} connected.")

        connected = True
        while connected:
            try :
                self.save_dict = self.file_access()
                msg = self.recieve(conn)
                if msg == self.DISCONNECT_MESSAGE:
                    connected = False
                elif msg == "Save Data" :
                    player_id = conn.recv(5000)
                    try :
                        name,code = pickle.loads(player_id)
                    except EOFError :
                        pass
                    if (name,code) not in self.save_dict :
                        conn.send("Available".encode(self.FORMAT))
                        msg1 = self.recieve(conn)
                        if msg1 == "Game Data" :
                            game_data = conn.recv(5000)
                            #msg = pickle.loads(msg_data)
                            self.save_dict[(name,code)] = game_data
                            print(self.save_dict)
                            conn.send("Success".encode(self.FORMAT))
                    else :
                        conn.send("Exists".encode(self.FORMAT))
                        msg1 = self.recieve(conn)
                        if msg1 == "Game Data" :
                            game_data = conn.recv(5000)
                            self.save_dict[(name,code)] = game_data
                            conn.send("Success".encode(self.FORMAT))
                elif msg == "Wipe" :
                    self.save_dict.pop((name,code))
                    print(f"new dict is ",self.save_dict)
                elif msg == "Load" :
                    player_id = conn.recv(5000)
                    try :
                        name,code = pickle.loads(player_id)
                    except EOFError :
                        pass
                    if (name,code) in self.save_dict :
                        conn.send("Present".encode(self.FORMAT))
                        conn.send(self.save_dict[(name,code)])
                    else :
                        conn.send("Absent".encode(self.FORMAT))
                elif msg == "Check Data" :
                    player_id = conn.recv(5000)
                    try :
                        name,code = pickle.loads(player_id)
                    except EOFError :
                        pass
                    if (name,code) in self.save_dict :
                        conn.send("Exists".encode(self.FORMAT))
                    else :
                        conn.send("New".encode(self.FORMAT))
                self.file_dump()
            except ConnectionResetError :
                connected = False

        conn.close()
        print(f"[Terminated] connection terminated for {addr}")
            

    def start(self):
        self.server.listen()
        print(f"[LISTENING] Server is listening on {self.SERVER}")
        while True:
            conn, addr = self.server.accept()
            thread = threading.Thread(target=self.handle_client, args=(conn, addr))
            thread.start()
            print(f"[ACTIVE CONNECTIONS] {threading.activeCount() - 1}")


print("[STARTING] server is starting...")
server = Server()
server.start()

"""

key = Fernet.generate_key()
encryption_type = Fernet(key)
encrypted_message = encryption_type.encrypt(code)

decrypted_message = encryption_type.decrypt(encrypted_message)

exec(decrypted_message)

这次编译好的

exe
上传到https://www.virustotal.com/gui/效果比较好

方法 3 - 使用另一种方法来冻结你的代码

有很多方法可以将代码转换为

exe
。另一种最流行的冻结代码的方法是使用
py2exe
从 pypi 网站安装模块。

  1. 在主代码文件所在的目录中创建一个名为
    setup.py
    的新 python 文件。然后将以下内容粘贴到您的
    setup.py
    文件中。
from distutils.core import setup
import py2exe

setup(console=['main.py'])
  1. 打开cmd并输入

    python setup.py py2exe

  2. 一段时间后,将创建一个名为

    dist
    的文件夹。它将包含您的
    exe
    .

    的所有依赖项
  3. 现在您可以通过压缩来压缩该文件并将其发送给其他人。另一种可能的解决方案是使用像 InnoSetup 这样的编译器将所有

    exe
    和依赖项编译到单个
    msi
    文件中。


3
投票

检查

.exe
文件夹中是否创建了任何
temp
文件。如果是,那么这将是您的防病毒软件检测到恶意软件的原因之一。
通常,如果程序访问临时文件夹,它将被视为潜在有害的应用程序并被标记。这是恶意软件的行为,它获得了对 temp 的访问权限,并开始从 temp 控制电脑。
这就是为什么如果您观察到,如果您运行防病毒软件,它会清除临时文件夹,因为临时文件夹中包含了大部分废话。
确保在临时文件夹中放置no可执行文件。


2
投票

UTF-8 问题已解决

如果代码中有任何 UTF-8 字符,转换为字节不起作用。

SyntaxError: bytes can only contain ASCII literal characters.

解决这个

import base64

def encode(data):
    try:
        # Standard Base64 Encoding
        encodedBytes = base64.b64encode(data.encode("utf-8"))
        return str(encodedBytes, "utf-8")
    except:
        return ""
    
def decode(data):
    try:
        message_bytes = base64.b64decode(data)
        return message_bytes.decode('utf-8')
    except:
        return ""

your_code = encode("""

# coding: utf-8

# In[2]:


import os
import requests
import time
import pickle



Your code here.........
""")

exec(decode(your_code))

2
投票

出现此问题是因为

pyinstaller
编译类似于木马,而Windows Defender将exe文件识别为恶意文件。 如果您使用
nuitka
来编译代码,这个问题就可以解决。我建议你读一下这篇文章。 https://github.com/Nuitka/Nuitka 祝你有美好的一天。


2
投票

我遇到了同样的问题,然后我发现,这只是因为我使用了文档字符串来进行多行注释,
如果你有它,骑上它,你会没事的

“”” 代码在这里………… ”””


1
投票

使用

pyinstaller -F
选项进行编译时,我遇到了同样的问题(将所有内容都放在一个 exe 文件中,而不是包含大量文件的文件夹中)。

使用此选项,病毒总得分为 12/70。

我在没有

-F
选项的情况下再次执行了此操作:结果更大(从 9MB 到 20MB),但病毒总得分现在为 2/70。


0
投票

我将方法 1 和方法 2 结合在一起,以便针对此问题提供强大的包罗万象。

这是代码:

from cryptography.fernet import Fernet
import base64

code = base64.b64encode (b"""

# my code goes here

""")

key = Fernet.generate_key()
encryption_type = Fernet(key)
encrypted_message = encryption_type.encrypt(code)

decrypted_message = encryption_type.decrypt(encrypted_message)

exec(base64.b64decode(decrypted_message))

从 VSCode 运行时可以完美执行代码,但是当使用 Nuitka 使用以下编译命令编译成单个文件时,它不会运行:

python -m nuitka --standalone --onefile --enable-plugin=pyqt6 --include-data-files="tolerance.ui=tolerance.ui" --include-data-files="toleranceicon.png=toleranceicon.png" --windows-disable-console --windows-icon-from-ico=toleranceicon.ico tolerance.py

有什么想法可以解释为什么这在编译时不起作用吗?

© www.soinside.com 2019 - 2024. All rights reserved.