在C语言中编写一个自毁程序是否有可能?

11

是否可能编写一个 C 程序,在执行后删除自己(二进制文件),并成功终止程序?如果可以,最简单的方法是什么?


3
可能可以编写一个程序来删除.exe文件或其他文件,但在某些环境中,操作系统在执行该文件时会锁定它,因此可能需要绕过一些障碍。 - Hot Licks
5个回答

15
是的。
#include <unistd.h>
int main(int argc, char* argv[])
{
  return unlink(argv[0]);
}

(已经测试并且有效。)

请注意,如果argv [0]不指向二进制文件(由调用者重写),这将无法正常工作。同样,如果通过符号链接运行,则将删除符号链接而不是二进制文件。

此外,如果该文件具有多个硬链接,则只会删除调用的链接。


6
这里涉及到通常的问题,关于argv[0]作为二进制文件路径的可靠性。POSIX规定它应该指向二进制文件,但不强制要求,并且API允许程序将其设置为其他内容。最终结果是,这通常有效,但不可靠。此外,即使您有正确的路径,该二进制文件可能会在多个位置上进行硬链接。 - dmckee --- ex-moderator kitten
实际上不起作用。@LuchianGrigore是正确的,在调用unlink之后添加一个sleep(30),然后在程序休眠时在另一个终端中运行“lsof”(这是*nix实用程序),您将看到操作系统仍然打开文件的句柄。该文件已从“ls”中消失,但在程序结束并且操作系统关闭其句柄之前,它仍然存在。 - SoapBox
1
@SoapBox - 是的,它会。执行完成后,它是否从文件系统中消失了?至少这就是我想要做的事情。 - Alex Coplan
1
@dmckee 我对处理那种情况的示例很感兴趣。 - blueshift
1
如果这是一个suid-root二进制文件试图删除自身,那么这个答案可能会非常有趣...;-) - R.. GitHub STOP HELPING ICE
显示剩余2条评论

5

我不知道是否有一种真正独立于平台的便捷方式,但是您没有指定平台独立性,因此可以尝试以下Linux风格的代码:

#include <stdio.h>
#include <unistd.h>

int main(int argc, char **argv) {
    printf("Read carefully!  You cannot print this message again.\n");
    return unlink(argv[0]);
}

这与您想要的有多接近?

11
这是我见过的传递给main()函数的参数中最古怪的输入方式。 - blueshift
2
这些是非标准的 main 参数。顺便说一下,这只会使得你的示例代码更难让新手理解... - Oliver Charlesworth
应广大要求,我现在正在修改我的答案![但是我要注意的是,在这个特定的例子中,如果我没有在int argc之前加上__attribute__((unused)),我的GCC 4.4编译器(如果使用了-Wall-Wextra开关)会发出警告。原因当然是因为argc在这里未被使用。] - thb
@OliCharlesworth 是一个标准的坚持者。我也一直认为自己是,直到遇见他,但他把它提升到了另一个层次。如果不是他的评论,我会说将变量参数作为常量参数接收是程序员的自由,并且在不打算改变它们时最好将大多数对象设置为const。然而,我的const可能存在一些隐藏的问题,Oli看到了,而我没有。尽管如此,我的const已经成为了干扰,所以我已经将它们移除了。无论如何,它们并不是我的答案的重点。 - thb
1
在实践中,这种情况不会有任何影响。但是在一般情况下,T **不能转换为const T **,因此最好不要混淆两者。 - Oliver Charlesworth
1
今天我学到了一些东西。@OliCharlesworth 早先指出 http://c-faq.com/ansi/constmismatch.html,解释了他的观点。有趣。 - thb

2
如果您的操作系统允许运行程序删除自己的二进制文件,那么只需查找文件删除的API或执行相应的system()命令即可。
如果操作系统不允许这样做,您的程序(我们称之为A)可以构建另一个包含另一个程序(我们称之为B)的二进制文件。然后,A将立即退出。
程序B将有一个单独的循环检查A是否仍在运行,一旦A退出,B将删除A的二进制文件。

1
好的,任务是杀死A,不是吗?B可以休息在某个临时文件夹中,等待有时被清除。 - Imp
如果目标是销毁原始文件的任何证据,那么这肯定会起作用。 - Alex Coplan
@DavidSouther 顶一下,因为Jargon File传奇引用很经典。 - blueshift
3
好的,为了销毁任何证据,我们还应该在磁盘上文件的原始位置写入一些零。 - Imp

0
你可以尝试删除程序中的可执行文件(FILE*等)...但是考虑到该可执行文件是正在运行的,这可能不起作用。我认为这就像吃自己一样,据我所知是不可能的,但你可以尝试使用我上面提到的方法。

0

我认为这取决于您使用的平台。基本上,一旦可执行文件被加载,对二进制文件的任何后续更改都不会影响正在运行的程序。在Unix中,情况是如此的,并且您可以使用unlink系统调用。

我不确定Windows是否也是如此。可能不允许删除可执行映像。您可以尝试在Windows中使用DeleteFile() API。


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