如何让指定 Windows 程序崩溃

ops/2024/10/19 2:22:40/

一、为何要把人家搞崩溃

看到这个标题,大家可能觉得奇怪,为什么要让指定程序崩溃呢,难道是想作恶吗?😓

哈哈,绝对不是,真实原因是这样的。如果大家用过 Windows 电脑,可能见过类似下面这样的软件崩溃提示框。

QQ
微信
迅雷
WPS​​​
百度网盘
百度如流

Windows 上软件通常会做一个崩溃捕捉的功能。在软件发生崩溃时,弹出个友好的提示框,先道个歉(的确是自己错了嘛,对吧),然后提示框关闭的时候,还会主动帮用户重启软件,多贴心。同时,也会将一些崩溃信息上传到服务端,服务端对这些崩溃进行分类,然后按照崩溃数目对崩溃类型进行排序,最后开发人员按顺序修复。因此,当我们开发、测试崩溃捕捉功能时,自然就经常需要让自己的程序发生崩溃

为了达到这个目的,一般的做法是临时在程序中加入引发异常的代码。这种做法只在临时测试版本中有效,在正式版本中无法进行验证。另外一种方法是加入一个隐藏开关的逻辑,但这样会带到正式版本中,有风险。另外,我们也需要参考下别人的这个功能,所以也希望可以随心所欲地让别人的软件崩溃,但是别人的软件我们可没法修改代码。所以,最好的方法是在不修改任何代码的情况下,能够让指定程序崩溃,指哪打哪。下面就介绍两种这样的方法。

二、代码注入

试想,如果我们可以将一段有问题、会引起崩溃的代码,注入到指定进程并运行,这样,此进程必崩无疑。

注入代码的方法有很多种,比如全局钩子、APC 注入、远程线程等。这里,我们介绍经典的远程线程注入的方法。

顾名思义,远程线程就是指一个进程在另一个进程的虚拟地址空间中创建线程,然后运行指定代码。当然,这里我们为了搞崩溃别的进程,这个指定的代码就可以是一段会引起异常的代码。

创建远程线程可以用 CreateRemoteThread 函数,原型如下。

HANDLE CreateRemoteThread([in] HANDLE hProcess,[in] LPSECURITY_ATTRIBUTES lpThreadAttributes,[in] SIZE_T dwStackSize,[in] LPTHREAD_START_ROUTINE lpStartAddress,[in] LPVOID lpParameter,[in] DWORD dwCreationFlags,[out] LPDWORD lpThreadId
);

我们来看看关键参数 lpStartAddress,这个参数指定远程线程的入口点地址,这个地址必须是在目标进程的地址空间中。在本文的特殊需求下,我们并不需要传一个实际可执行的地址,只需要传入 0 即可。这样的话,该线程会尝试从 0 地址处执行。

Windows 进程的虚拟地址空间中有一个特殊的区间,叫空指针赋值分区,从地址 0x00000000 到 0x0000FFFF。如果线程试图读写位于这一分区内的地址,就会引发访问违规,随即导致程序崩溃——哈哈,这就达到了我们的目的。

主要流程

核心代码

constint pid = <目标进程 PID>;
const DWORD desiredAccess = PROCESS_CREATE_THREAD |PROCESS_QUERY_INFORMATION |PROCESS_VM_OPERATION |PROCESS_VM_WRITE |PROCESS_VM_READ;
// 打开进程,获得句柄
const HANDLE hProcess = OpenProcess(desiredAccess, FALSE, pid);
// 创建远程线程
CreateRemoteThread(hProcess, nullptr, 0, 0, nullptr, 0, nullptr);
// 关闭进程句柄
CloseHandle(hProcess);

三、修改指令指针寄存器法

这个方法更直接更暴力,它劫持 CPU 的指令指针寄存器 RIP 或 EIP,使其直接指向 0 地址处。

RIP 是 x64 架构中的 64 位寄存器,存储着 CPU 要执行的下一条指令的地址,EIP 是对应的 x86 架构中的 32 位寄存器。如果下一条指令从 0 地址处开始执行,同前一个方法一样,必然引起访问违规,进而导致崩溃

指令指针寄存器存放在线程的 CONTEXT 结构体中,可以用 GetThreadContext 获取指定线程的 CONTEXT,然后修改指令指针寄存器的值后,再通过 SetThreadContext 替换原始的 CONTEXT。

主要流程

核心代码

// 打开目标进程的一个线程,获得线程句柄,threadId 为该线程的 id
const DWORD desiredAccess = THREAD_GET_CONTEXT |THREAD_SET_CONTEXT |                 THREAD_QUERY_INFORMATION;
const HANDLE hThread = OpenThread(desiredAccess, FALSE, threadId);
// 获取线程 CONTEXT 之前,必须先挂起该线程
SuspendThread(hThread);
// 获取线程 CONTEXT
CONTEXT context = {0};
context.ContextFlags = CONTEXT_ALL;
GetThreadContext(hThread, &context);
// 根据目标进程位数的不同,修改 RIP 或 EIP
#ifdef _WIN64
context.Rip = 0;
#else
context.Eip = 0;
#endif
// 替换 CONTEXT
SetThreadContext(hThread, &context);
// 恢复线程
ResumeThread(hThread);
// 关闭线程句柄
CloseHandle(hThread);

四、效果演示

说了这么多,咱们实践一把,以微信为例,使用代码注入法,传入微信进程 ID,可以看到微信瞬间崩溃,弹出了崩溃提示框。😂😂😂

五、总结

通过这两种方法,我们就可以在不修改任何代码的前提下,做到让指定程序崩溃,方便了开发和测试工作。顺带也可以感受到 Windows 上一个程序的能力之大、破坏力之强,这也是黑客比较青睐 Windows 的原因之一。


http://www.ppmy.cn/ops/2970.html

相关文章

Linux安装docker(含Centos系统和Ubuntu系统)

一、Centos系统 1. 卸载旧版本依赖 sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine 2. 设置仓库 安装所需的软件包。yum-utils 提供了 yum-config-manager &…

FFmpeg: 自实现ijkplayer播放器--05ijkplayer–连接UI界面和ffplay.c

文章目录 ijkplayer时序图消息循环--回调函数实现播放器播放时状态转换播放停止ijkmediaPlay成员变量成员函数ijkplayer时序图 stream_open: frame_queue_init packet_queue_init init_clock 创建read_thread线程 创建video_refresh_thread线程 消息循环–回调函数实现 ui 和…

万兆以太网MAC设计(3)MAC_RX模块添加CRC

文章目录 前言一、并行CRC处理二、添加CRC处理的MAC_RX模块三、总结 前言 上文介绍的MAC_RX模块实现了接受字节对齐的功能&#xff0c;但是尾端存在4字节CRC校验未处理。 一、并行CRC处理 前面在千兆以太网里对CRC代码和使用进行了介绍&#xff0c;千兆里面数据是一个一个by…

外包干了7个月,技术退步明显。。。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;19年通过校招进入广州某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…

【MIT6.824】lab2C-persistence, lab2D-log compaction 实现笔记

引言 lab2C的实验要求如下 Complete the functions persist() and readPersist() in raft.go by adding code to save and restore persistent state. You will need to encode (or “serialize”) the state as an array of bytes in order to pass it to the Persister. Us…

[C++][算法基础]判定二分图(染色法)

给定一个 n 个点 m 条边的无向图&#xff0c;图中可能存在重边和自环。 请你判断这个图是否是二分图。 输入格式 第一行包含两个整数 n 和 m。 接下来 m 行&#xff0c;每行包含两个整数 u 和 v&#xff0c;表示点 u 和点 v 之间存在一条边。 输出格式 如果给定图是二分图…

python requests几点代理相关

1&#xff0c;很多人&#xff0c;包括我&#xff0c;应该只知道requests默认只是支持http代理&#xff0c;有没密码验证都一样。但是&#xff0c;其实呢&#xff0c;最新的requests已经支持 sock5 代理了&#xff0c;也支持密码认证&#xff1b; 2&#xff0c;如果要让request…

学习笔记——微信小程序var与let、bindtap与bindinput、全局变量与局部变量的区别

1、var与let的区别 var申明的为全局变量&#xff0c;作用域为所在的函数内&#xff0c;其他函数调用会出现变量未定义的报错 let声明的为局部变量&#xff0c;只会作用于最近的{}中&#xff0c;其他区域无法调用 2、全局变量与局部变量 全局变量是在整个小程序运行周期内都…