强制崩溃应用程序

14

我正在测试公司编写的一个应用程序。其中一个场景是,看看如果该应用程序崩溃会发生什么系统状态。是否有一种应用程序可以强制崩溃我的应用程序?我不想在代码本身中编写崩溃(例如空指针引用)。使用任务管理器来结束进程并不能产生相同的结果。


使用DLL注入可能是实现这一目标的可行途径,但我不知道是否已经有任何应用程序可以处理这个问题。 - Martin Ba
你不能在代码中间放置一个简单的exit()吗?或者这被认为是“崩溃”吗? - Raveline
系统状态是什么意思?通常情况下,当一个进程崩溃时,系统会清理所有使用的资源。但这可能不包括像数据库句柄之类的东西。你将如何检查系统状态? - Nick
崩溃是一个结果,你应该明确原因。 - mbq
11个回答

16

在Windows上,您可以将WinDbg附加到进程,损坏某些寄存器或内存并分离。例如,您可以将指令指针设置为某个活动应用程序线程的0。

windbg -pn notepad.exe

附加后,当前线程被设置为调试线程,所以您需要切换到应用程序线程以更新RIP寄存器并使其崩溃。

0:008> ~0s 
0:000> rip=0
0:000> qd

10
假设您正在使用Windows系统,请查看应用程序验证器
它可以进行错误注入(低资源模拟),使各种API调用失败,以可配置速率。例如:堆分配、虚拟分配、WaitForXxx、注册表API、文件系统API等等。
甚至可以在启动期间指定一个优雅期间(以毫秒为单位),在此期间不会注入任何故障。

不错,我不知道这个工具。看起来它可能非常有用! - Daniel Lidström

4
你可以使用winapiexec工具来实现这个功能:

winapiexec64.exe CreateRemoteThread ( OpenProcess 0x1F0FFF 0 1234 ) 0 0 0xDEAD 0 0 0

1234替换为进程ID,运行该命令,进程将崩溃。

3
最好的方法是从windows.h调用RaiseException API。
RaiseException(0x0000DEAD,0,0,0);

您可以在代码运行时链接到ntoskrnl.exe中的KeBugCheckEx(),并在您的代码中调用它。

示例:

#include <windows.h>
#include <iostream>
using namespace std;

int main()
{
    HINSTANCE h = LoadLibrary("ntoskrnl.exe");
    cout<<h<<endl;
    void* a;
    a = (void*) GetProcAddress(h,"KeBugCheckEx");
    int(*KeBugCheckEx)(ULONG,ULONG_PTR,ULONG_PTR,ULONG_PTR,ULONG_PTR);
    KeBugCheckEx = (int(*)(ULONG,ULONG_PTR,ULONG_PTR,ULONG_PTR,ULONG_PTR))a;

    cout << a;
    KeBugCheckEx(0,0,0,0,0); //crash in module ntoskrnl.exe means that call success!
}

RaiseException是一个合理的答案,针对一个稍微不同的问题:如果Windows应用程序检测到问题,它应该如何崩溃自己?尽管flags参数可能应该是EXCEPTION_NONCONTINUABLE而不是0。KeBugCheckEx会导致操作系统崩溃,这是过度杀伤力的,除非你从内核模式调用它并且崩溃系统是必要的以防止损坏。 - Adrian McCarthy
对于RaiseException解决方案,最好使用异常代码STATUS_FAIL_FAST_EXCEPTION(0xC0000409)。如果您想使用自己的自定义异常代码,请确保设置第29位(表示用户定义代码),并清除第28位(因为它被系统保留)。换句话说,您的异常代码应该以高四位中的0xE开头,例如0xE000DEAD。 - Adrian McCarthy

1

您没有说明您正在运行哪个操作系统,但如果是Linux(或其他类UNIX系统),您可以直接使用kill -9命令杀死进程。这个信号无法被捕获,会很快地终止您的进程。

如果您不在类UNIX系统上,我无法帮助您,抱歉,但您可能会在这里找到一些有用的信息(查找“taskkill”)。


1

如果系统运行在UNIX/Linux上,您可以向其发送一个信号:SIGQUIT应该会产生一个核心转储,您也可以发送SIGSEGV,如果您想测试它是否出现“分段错误”。它们分别是信号3和11。

如果系统是Windows,我不知道如何在不同的应用程序中引发信号,但如果您可以修改应用程序以处理特定的Windows消息编号,那么将调用raise(),您可以模拟这个过程。raise()会导致信号被引发,而无需编写执行非法操作的代码。然后,您可以向应用程序发布一条消息,该消息将具有引发此信号的处理程序。


看看我的关于RaiseException的帖子。打开它的进程,获取一些原始函数指针,或者只是破坏它的堆 :) - Петър Петров

1
你可以重载全局的 new 操作符。然后,你可以使用一个计数器,在特定的值时执行空指针解引用来强制应用程序崩溃。通过简单地更改何时执行解引用的值,你可以轻松地改变崩溃的时间。

0

“system state”在哪里定义?如果这是Unix,你可以向进程发送信号9...

如果真的需要,你可以将所有应用程序内存与另一个进程(或线程)共享,并让该线程随机写入一些不幸的内存位置的随机数据 - 我想NASA在其某些太空项目中就是这样做的,但我真的无法提供参考。

真正的问题是为什么你想这样做 - 你/真正/要测试什么?

例如,如果这是控制某些处方药医疗服务的程序...请对该服务进行单元测试,分析API并查找缺陷。


0

另一种方法是在良好的调试器中运行应用程序,将断点设置到特定的代码行,然后你的应用程序就会“崩溃”。这可能不会导致所有线程停止运行,这取决于所使用的调试器。或者,您可以在调试器中运行应用程序,并在一段时间后简单地“停止”应用程序。

这并不一定会导致内核杀死应用程序(可能会转储核心),但无论如何它都可能会达到您想要的效果。


0

编写一个缓冲区溢出攻击。

#include <string.h>

void doSomething(char *Overflow)
{
   char Buffer[1];
   strcpy(Buffer, Overflow);
}

int main()
{
   doSomething("Muhaha");
}

而且你的程序会崩溃


3
不幸的是,它不会以可靠的方式发生--这只是未定义的行为,可能并不总是导致崩溃。 - Stuart Golodetz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接