Search code examples
pythonpython-3.xwindowsexepyinstaller

exe file made with pyinstaller being reported as a virus threat by windows defender


I'm trying to create an exe using pyinstaller for a school project but, windows defender seems to report a virus threat and blocks the file. I want to send this exe to some other people but i wouldn't be able to do that unless I fix this. So these are my queries- Why does the exe file get reported as a virus? A quick scan on virus total says that 16 engines detect this file as a Trojan. Also, is there any way to prevent windows defender or any other antivirus from alerting users of a virus threat , I mean, is there any way to make my file look safe to antiviruses in case it was just a false threat? And in case that is not possible, what are the other safe alternatives to pyinstaller? I'm just a beginner so any tips would be really appreciated. Thanks.

EDIT: as requested by @Pro Chess, ive included my script.

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()

Ive used the socket package to run a server on my local network.


Solution

  • METHOD 1

    A possible solution for this would be to encrypt your code. There are several ways of encrypting your code. But the easiest one is to use base64 or basically converting text-to-binary encoding. and you need to make sure that there is no special character because base64 only have this charachter set. You can check here the base64 table 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))
    

    This technique is used for hacking and other malicious purposes to avoid anti-virus software detecting it as a malware. This might work for you. Try recompiling it. Let us know if it works.

    METHOD 2

    If the above method doesn't work, try out this method. This method uses fernet cryptography. This means that the code is more tightly encrypted makes it even difficult for the anti-virus software to recognize this as a malware than the first method. For this, you need a python module called cryptography https://pypi.org/project/cryptography/

    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)
    

    This time the compiled exe was uploaded to https://www.virustotal.com/gui/ and the results were better

    METHOD 3 - Use another method to freeze your code

    There are many methods to convert your code to an exe. Another most popular way to freeze your code is to use py2exe. Install the module from the pypi website.

    1. Create a new python file called setup.py in the same directory as your main code file. Then paste following in your setup.py file.
    from distutils.core import setup
    import py2exe
    
    setup(console=['main.py'])
    
    1. Open cmd and type python setup.py py2exe

    2. After a while, a folder named dist will be created. It will contain all dependencies for your exe.

    3. Now you can compress this file by zipping it and send it to another person. Another possible solution is to use a compiler like InnoSetup to compile all your exe and the dependencies into a single msi file.