用 Python 控制系统进程
由于注册表几乎可以决定整个操作系统的运行,因此它成为安全工具与恶意软件对抗的主要战场之一。除了注册表之外,对系统进程的控制也是安全工具和恶意软件的必争之地。这里我们首先要了解程序和进程的区别。程序是静态的,进程是动态的。进程可以分为系统进程和用户进程。凡是用于完成操作系统的各种功能的进程就是系统进程,它们就是处于运行状态下的操作系统本身,用户进程就是所有由用户启动的进程。
psutil
库是一个跨平台库,它能够轻松实现获取系统运行的进程和系统利用率(包括CPU,内存、磁盘、网络等)信息。它主要用于系统监控、性能分析、进程管理等。psutil 库几乎支持当前所有的主流操作系统。使用psutil库查看所有逃程的命令如下。
psutil.pids()
这个函数的返回值为当前运行的进程的pid,在 psutil库中还可以根据一个进程的pid获取以下详细信息。
p = psutil.Process(pid)
p.name() #进程名
p.exe() #进程的bin路径
p.cwd() #进程的工作目录的绝对路径
p.status() #进程状态
p.create_time() #进程创建时间
p.uids() #进程的uid信息
p.gids() #进程的gid信息
p.cpu_times() #进程的CPU时间信息
p.memory_percent() #进程内存利用率
下面我们来编写一个可以列举出操作系统运行的所有进程的程序。
import psutil
print("-----显示所有进程------")
#显示进程信息
pids = psutil.pids()
for pid in pids:
p = psutil.Process(pid)
#通过pid显示进程名称
process_name = p.name()
print("Process name is: %s,pid is: %s" % (process_name,pid))
执行该程序之后就可以看到一个类似任务管理器的进程列表,如图7-36所示。
安全工具与恶意软件都会试图去结束对方,如果知道了一个进程的pid或者名称,那么就可以在Python程序中结束它。例如这里我们运行测试程序“测试窗口.exe”,然后启动任务管理器,可以看到它所对应进程的名称,Windows中的任务管理器如图7-37所示。
图]7-37Windows中的任务管理器
这里我们可以使用signal
模块来结束整个进程, signal模块负责Python程序内部的信号处理。典型的操作包括信号处理函数、暂停并等待信号,以及定时发出 SIGALRM等。signal模块包含以下方法:
signal.SIGHUP 连接挂断;
signal.SIGILL 非法指令;
signal.SIGINT 终止进程;
signal.SIGTSTP 暂停进程;
signal.SIGKILL 杀死进程(此信号不能被捕获或忽略);
signal.SIGQUIT 终端退出;
signal.SIGTERM 终止信号,软件终止信号;
signal.SIGALRM 闹钟信号,由signal.alarm()发起;
signal.SIGCONT 继续执行暂停进程。
虽然signal模块是Python中的模块,但是其主要面向的是UNIX、Linux 和l macOS等操作系统。由于 Windows内核对信号机制的支持不充分,因此在 Windows中的 Python不能完全发挥信号系统的功能。
我们现在就使用signal模块编写一个结束指定名称进程的程序。
❗管理员权限运行
import psutil
import os
import signal
print("-------------结束进程-------------")
pids = psutil.pids()
for pid in pids:
p = psutil.Process(pid)
process_name = p.name()
if '测试窗口.exe' == process_name:
print("结束进程: name(%s)-pid(%s)" % (process_name, pid))
os.kill(pid, signal.SIGTERM)
exit(0)
执行该程序之后,可以看到它已经成功地结束了“测试窗口.exe”,如图7-38所示。
os模块中提供了一个结束进程的函数os.kill(),该函数模拟传统的UNIX函数发送信号给进程,其中包含两个参数:一个是进程名,即所要接收信号的进程;另一个是所要进行的操作,常用取值为SIGINT(中断进程)、SIGTERM(进程终止信号)和 SIGKILL(杀死进程)。
这里需要注意的一个问题是,虽然 os.kill(pid,signal.SIGINT)成功结束了该进程,但是os.Kill()函数并不能在Windows中正常工作,比如在Windows 中将 signal.SIGINT 替换为SIGKILL,系统就会报错,但是在Linux 中却可以正常运行。所以在 Windows 中可以改用os.popen('taskkill.exe /pid:'+str(pid)来结束一个进程,该方法其实就是使用“taskkill”命令来结束进程的。