当前位置: 首页 > article >正文

【Rust调用Windows API】杀掉指定进程(包括兄弟进程、子进程、父进程)

前言

前面一篇文章写了使用Rust调用Windows API 获取正在运行的全部进程信息 ,本篇实现杀掉指定进程。

通过标准库可以管理当前进程创建的子进程,要 kill 掉子进程也比较容易,这里不赘述了,主要实现通过调用Windows API来杀掉兄弟进程、子进程,甚至通过提权可以杀掉父进程。

依赖

进程管理主要用到 processthreadsapi.h 头文件,详细的接口文档请前往微软官方文档查看。

Cargo.toml中添加 processthreadsapi 这个feature

winapi = { version = "0.3.9", features = ["processthreadsapi"] }

实现

大致步骤

  1. 获取指定进程的文件句柄
  2. 杀掉进程
  3. 释放进程句柄

提权:本篇只讲最简单的用户操作提权方法,调用Windows API提权的实现见本系列《Rust调用Windows API》后面的文章

获取进程句柄

进程句柄的获取需要调用 OpenProcess 这个函数

pub fn OpenProcess(
    dwDesiredAccess: DWORD,
    bInheritHandle: BOOL,
    dwProcessId: DWORD,
) -> HANDLE;

这个函数需要传入三个参数,主要关注第一个和第三个参数

  • dwDesiredAccess:对该进程的访问权限,多个权限用或位运算符|拼接,全部权限见官方文档。特例:如果调用方进程拥有并开启了 SeDebugPrivilege特权,此参数可以忽略,后续提权的方案也是通过获得该特权来实现对任意进程的完全访问,一般进程是没有这个特权的。
  • dwProcessId:指定进程的描述符,也就是进程PID

OpenProcess这个函数在日常开发中使用的频率是比较高的,每次使用需要的权限也不固定,因此这里我将第一个参数向外抛出,由调用方指定,下面是Rust调用实现

use winapi::shared::minwindef::DWORD;
use winapi::um::winnt::HANDLE;
use winapi::um::errhandlingapi::GetLastError;
use winapi::um::processthreadsapi::OpenProcess;

fn open_process(pid: DWORD, access_privilege: DWORD) -> Result<HANDLE, String> {
    unsafe {
        // https://learn.microsoft.com/zh-cn/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess
        let handle = OpenProcess(access_privilege, 0, pid);

        if handle.is_null() {
            //  https://learn.microsoft.com/zh-cn/windows/win32/debug/system-error-codes--0-499-
            return Err(format!("Could not open process {}, code: {}", pid, GetLastError()));
        }
        Ok(handle)
    }
}

杀掉进程

上一步获得了进程的句柄,直接调用 TerminateProcess 函数就可以了,在Rust中定义如下:

pubfn TerminateProcess(
    hProcess: HANDLE,
    uExitCode: UINT,
) -> BOOL;

参数解释:

  • hProcess:需要杀掉进程的句柄,前面通过 OpenProcess 获得
  • uExitCode:被杀掉进程的退出代码,和平时调用 exit(0) 传入的 0 含义一样,在winapi中通过 GetExitCodeProcess 函数可以查出被杀掉进程的退出代码

Rust调用实现:

use winapi::um::winnt::HANDLE;
use winapi::um::errhandlingapi::GetLastError;
use winapi::um::processthreadsapi::TerminateProcess;

fn kill_process(process_handle: HANDLE) -> Result<(), String> {
    unsafe {
        //  https://learn.microsoft.com/zh-cn/windows/win32/api/processthreadsapi/nf-processthreadsapi-terminateprocess
        let success = TerminateProcess(process_handle, 0);
        if success == 0 {
            CloseHandle(process_handle);
            return Err(format!("Could not terminate process, code: {}", GetLastError()));
        }
        CloseHandle(process_handle);
        Ok(())
    }
}

测试

下面写个简单的测试程序验证一下

pub fn test_kill() {
    print!("Please enter the PID of the process to be queried: ");
    stdout().flush().unwrap();
    let mut input = String::new();
    stdin().read_line(&mut input).unwrap();

    let pid = input.trim().parse::<i64>().unwrap() as DWORD;

    let process_handle = open_process(pid, PROCESS_TERMINATE).unwrap();

    print!("Are you sure you want to kill this process? (y/n): ");
    stdout().flush().unwrap();
    input.clear();
    stdin().read_line(&mut input).unwrap();

    if input.trim().eq("y") {
        match kill_process(process_handle) {
            Ok(_) => println!("Killed"),
            Err(e) => {
                eprintln!("Failed to kill process, code: {}", e);

                input.clear();
                stdin().read_line(&mut input).unwrap();
            }
        }
    } else {
        println!("Ignored")
    }
}

fn main() {
	test_kill();
}

然后在任务管理器中挑一个你当前用户启动的进程,例如我当前登录的用户是 Administrator,选 Everthing.exe 这个进程来测试杀掉它。

注意不能选用户名为SYSTEM的进程,前面有提到其他用户启动的进程或者守护进程或者系统进程需要有特殊权限才能杀掉,需要提权才能杀掉。

在这里插入图片描述
启动测试程序
在这里插入图片描述

再去任务管理器看发现已经不存在 Everthing.exe 这个进程了

提权

尝试不提权杀SYSTEM进程

依旧使用前面的测试程序,我们来尝试杀掉一个 SYSTEM 启动的进程。

注意!!!!! 这一步我们肯定是杀不掉的,因为没有提权处理,但下一步提权后就能真正杀死它了,要谨慎选择要被杀掉的进程,尽量选择一个无关紧要且自己很清楚怎么恢复的进程,否则操作失误可能导致你的电脑瘫痪!!!

这里我选向日葵的客户端,它即使被杀掉也没有太大关系,重新打开向日葵就可以恢复它。

在这里插入图片描述

再次执行前面的测试程序,发现提示了一个code为 5 的系统代码,这个代码就是指访问被拒绝,更多的系统代码见 官方系统错误代码文档

在这里插入图片描述

提权后杀SYSTEM进程

注意:这里只讲最简单的提权方式之一,代码提权方式见后续文章

先把测试进程打包成可执行程序

cargo build --release

第一次打包需要一两分钟编译时间,耐心等待一下,后续打包会使用缓存就很快了,打包完可执行程序就在 你的工程目录/target/release 下,例如我这里的程序叫 rust-learning.exe

右击它选择以管理员身份运行,管理员拥有最高权限,这也是最简单的一种提权方式,这里仅用这种方式验证提权带来的效果

在这里插入图片描述

系统会向你询问是否以管理员运行,然后输入前面的SYSTEM进程PID,这次就可以成功杀掉了

在这里插入图片描述


http://www.kler.cn/a/393314.html

相关文章:

  • odoo 17 后端路由接口认证自定义
  • 【机器学习】机器学习中用到的高等数学知识-2.概率论与统计 (Probability and Statistics)
  • 工业相机选取
  • 使用electron-egg把vue项目在linux Ubuntu环境下打包并安装运行
  • Java程序中如何输入数据
  • 外星人入侵
  • 人力资源招聘系统-提升招聘效率与质量的关键工具
  • Docker 部署Nacos 单机部署 MYSQL数据持久化
  • 计算机网络(4)之交换技术,分层技术和默认网关
  • 怎么在MindMaster里插入剪贴画?
  • c++ 二分查找
  • Mac Nginx 前端打包部署
  • Vue开发风格
  • Scala的Map集合练习
  • 关键字“退出、结束、跳过”(day13)
  • 2024 年 10 月区块链游戏研报:活跃用户与链上游戏生态的最新趋势解读
  • 飞牛私有云访问外网
  • Python发展历程·练习题 --- 《跟着小王学Python》
  • Golang | Leetcode Golang题解之第553题最优除法
  • 使用 Python 和 OpenCV 实现摄像头人脸检测并截图
  • 什么是RabbitMQ?
  • 搭建Python2和Python3虚拟环境
  • MySQL --- 自定义函数获取部门层级名称
  • 修改mysql默认字符集
  • C语言最简单的扫雷实现(解析加原码)
  • 各版本android studio下载地址