Windows下实现EXE的自删除与自修改

自从开始实习就没有更新过blog了,加上软工、数据库、图形学乱七八糟的实验,有点忙不过来了。

本来一直在想以后做Linux相关的开发,周围认识的很多学长都走上了这条路,开始实习后却事与愿违搞起了Linux开发。其实说实话一直也不知道自己的兴趣点在哪里,工作了一个月后感觉可能还是桌面和互联网更适合自己,对于系统开发、运维这样的工作,干长时间可能会受不了……纠结啊

前两天和朋友聊到windows下一个程序如何删除自己,正好以前和同学讨论过这个问题,写出来凑个数。

其实真正的删除自己肯定是做不到的,至少用户态不行。windows下只要一个文件被某个进程打开就不能被删掉(Linux下可以删除任何打开的文件,只要有权限,而且一般不会影响程序的执行,因为文件系统会等到所有的打开的fd都释放后会才回收inode和data),所以一个windows进程在运行的时候是肯定不可以删除自己的可执行文件的,只能想一些旁门左道了。

Solution

方法其实很简单,就是在程序结束前开另一个进程去删自己,但是要求是自己删自己,所以只能借助系统utils。这时候就需要bat脚本来帮忙了。在CMD下删除一个文件很容易,一条del命令就搞定了,但是需要保证执行脚本的时候原进程已经结束运行了,一般来说用一条延时命令walk around“ping 127.0.0.1 -n 2”,2为秒数,然后用“&”连接del命令删除文件

ping 127.0.0.1 -n 2 >nul && del path/to/your/file.exe

更为保险的做法是在bat里用tasklist命令查看进程,循环直到找不到当前进程位置

原来的和同学讨论的是一个程序如何自己修改自己,做到单文件自动更新,实际上和自己删除自己是一个问题。无非就是先生成一个自身的副本,修改副本,再程序结束后用bat脚本覆盖自己就ok了,源代码如下

#include 
#include 

int main(int argc, char * argv[])
{
    char self[_MAX_PATH];  
    char swap[_MAX_PATH];
    
    // get the full path of myself
    GetModuleFileName(NULL, self, _MAX_PATH);

    // copy myself to a temp file for modify 
    strcpy(swap, self);
    strcat(swap, ".tmp"); // add .tmp postfix. better to use tempnam()
    CopyFile(self, swap, FALSE); 
    
    FILE * fp = fopen(swap, "ab");
    // pending whatever you want to the exe
    fwrite("Hack is not good, but i love it.", 32, 1, fp);
    fclose(fp);
    
    // "ping" is used for delay to wait the main process terminated.
    // "move /Y src dst" : overide whtout warnning
    // quotation marks are needed for paths which contain blank.
    char bat[2*_MAX_PATH + 30] = "cmd /c ping 127.0.0.1 -n 2 >nul && move /Y "";
    strcat(bat, swap);
    strcat(bat, """);
    strcat(bat, " "");
    strcat(bat, self);
    strcat(bat, """);  // bat += "pathtoswap" "pathtoself" 

    WinExec(bat, SW_HIDE); // Exec the bat script with window hiden

    return 0;
}

C库函数和win32 API混用,看着挺别扭,本来写的时候还想尝试一下匈牙利,被恶心到以后还是放弃了,还好用到的API都参数比较简单,自从大一的时候看到一个win32 API调用占了半屏后,对win32 API就深为恐惧,再加上满屏幕的大写,读起来简直就是噩梦…

Improvement

用ping命令延时只是一个walk around,在系统负载很重的情况下,2秒程序也未必退出了,所以应该寻找一个方法确定一个exe是否在运行。小研究了一下bat,发现通过tasklist命令和find命令可以搞定:

:loop
tasklist /NH | find /i "xxx.exe"
if %ERRORLEVEL% equ 1 (
goto loop
) else (
del pathtoyourfilexxx.exe
)
exit

ERRORLEVEL变量是上一条命令的返回值,不停的在进程列表里寻找xxx.exe直到找不到为止。

顺便bless一下灾区的同胞们还有但愿今天可以拿到工资….

This entry was posted in 技术学习. Bookmark the permalink.

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据