现在的位置: 首页 > 综合 > 正文

VC 程序自删除功能的实现

2013年10月11日 ⁄ 综合 ⁄ 共 3631字 ⁄ 字号 评论关闭

http://jackaldire.com/201004/exe-self-delete-and-self-modify/

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

 

方法其实很简单,就是在程序结束前开另一个进程去删自己,但是要求是自己删自己,所以只能借助系统utils。这时候就需要bat脚本来帮忙了。在CMD下删除一个文件很容易,一条del命令就搞定了,但是需要保证执行脚本的时候原进程已经结束运行了,一般来说用一条延时命令walk aroundping 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 <windows.h>

#include <stdio.h>

 

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 += "path/to/swap" "path/to/self"

 

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

 

    return 0;

}

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

:loop

tasklist /NH | find /i "xxx.exe"

if %ERRORLEVEL% equ 1 (

goto loop

) else (

del path/to/your/file/xxx.exe

)

exit

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

 

// 通用自删除

网上看了一些自删除的文章, 比较复杂的是使用汇编, 但最重要的是使用汇编的方法不是总是有效。

反而使用命令行的却更有效和简单。

// 基本原理就是利用命令行来删除文件

// C:/WINDOWS/system32/cmd.exe /c del "E:/CODE_T~1/asm/del_self.exe"

// 方法1

void DelSel2()

{

    // 采用批处理

    SHELLEXECUTEINFO ExeInfo;

    TCHAR     ExePath[MAX_PATH] = {0};

    TCHAR     ParamPath[MAX_PATH] = {0};

    TCHAR     ComposePath[MAX_PATH] = {0};

      

    GetModuleFileName(NULL,ExePath,MAX_PATH);

    GetShortPathName(ExePath,ExePath,MAX_PATH);

    GetEnvironmentVariable(_T("COMSPEC"),ComposePath,MAX_PATH);

    _tcscpy(ParamPath,_T("/c del "));

    _tcscat(ParamPath,ExePath);

    _tcscat(ParamPath,_T(" > nul"));

    ZeroMemory(&ExeInfo,sizeof(ExeInfo));

    ExeInfo.cbSize = sizeof(ExeInfo);

    ExeInfo.hwnd = 0; 

    ExeInfo.lpVerb = _T("Open");                //执行动作,打开

    ExeInfo.lpFile = ComposePath;                //执行文件全路径名称

    ExeInfo.lpParameters = ParamPath;             //执行参数

    ExeInfo.nShow = SW_HIDE;                     //执行方式,隐藏窗口。

    ExeInfo.fMask = SEE_MASK_NOCLOSEPROCESS;     //设置为ShellExecute函数结束后进程退出。

    //创建执行命令窗口进程

    if (ShellExecuteEx(&ExeInfo))

    {

       //设置命令行进程级别为空闲基本,这使得本程序有足够的时间退出。

       SetPriorityClass(ExeInfo.hProcess,IDLE_PRIORITY_CLASS);

       //设置本程序进程基本为实时执行,快速退出。

       SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS);

       SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_TIME_CRITICAL);

       //通知资源管理器,本程序删除

       SHChangeNotify(SHCNE_DELETE,SHCNF_PATH,ExePath,NULL);

    }

}

 

// 方法2

BOOL SelfDelete()

{

   TCHAR szFile[MAX_PATH], szCmd[MAX_PATH];

   if((GetModuleFileName(0,szFile,MAX_PATH)!=0) && (GetShortPathName(szFile,szFile,MAX_PATH)!=0))

   {

        lstrcpy(szCmd,"/c del ");

        lstrcat(szCmd,szFile);

        lstrcat(szCmd," >> NUL");

 

        if((GetEnvironmentVariable("ComSpec",szFile,MAX_PATH)!=0) && ((INT)ShellExecute(0,0,szFile,szCmd,0,SW_HIDE)>32))

           return TRUE;

    }

   return FALSE;

}

 

 

// 方法3

WinExec((std::string("cmd /c del ") + _pgmptr).c_str(),0);

 

 

【上篇】
【下篇】

抱歉!评论已关闭.