自杀程序(VC)

转载一(测试过)

 

exe自删除(VC版本) [转贴 2008-05-18 17:07:53]    
我顶 字号:
 在开发程序过程中,有许多情况中都需要执行程序自己把自己从物理磁盘上删除,例如,卸装程序,一些黑客程序获取信息后自清除等,我们把这些具有自删除功能的程序统称为“自杀”程序。对于一名程序员,想必都有在程序中使用代码删除物理磁盘文件的经历吧,我们只需要简单的调用DeleteFile API函数就可以搞定,但是该函数并不能删除自己,当它执行删除自己时,将会导致出现“无法删除文件:拒绝访问。源文件可能正被使用”的错误提示,其原因是由于本程序在执行删除自己代码时仍处于内存中,在Windows中,不可以删除正在执行中的程序。 

    为了实现程序自删除功能,我们可以通过多进程的方法解决这个问题。可执行文件在结束返回前,创建一个运行命令窗口的新进程(在Windows98中为Command进程,在Windows2000/XP中为CMD进程),当然该命令窗口以隐藏方式执行,并通过传递参数执行删除功能。为了避免可执行文件的映像还在内存中就执行删除,需要把当前进程设置为实时优先级,而命令窗口进程设置为很低的IDLE优先级,这样首先可执行文件结束返回,再运行命令窗口的删除命令,就实现了该文件自身的删除功能。 

    下面我们就一起动手制作“自杀”(具有自删除功能)程序,程序在Visual C++6.0中开发编译。 

    首先,启动Visual C++6.0,新建一个MFC AppWizard(exe)类型的项目,项目名为SelfDelete,选择基于对话框模式创建程序框架。 

    接下来,打开资源编辑器,添加一个按钮控件,设置内容为开始“自杀”,如图一所示: 

    启动ClassWizard,为新添加的控件新建CLICK事件处理函数,再打开该函数,添加“自杀”代码如下: 

void CSelfDeleteDlg::OnButton1()   
{   
   // TODO: Add your control notification handler code here   
   SHELLEXECUTEINFO sei; 
   TCHAR szModule [MAX_PATH],szComspec[MAX_PATH],szParams [MAX_PATH]; 
   //获取文件路径名 
   if((GetModuleFileName(0,szModule,MAX_PATH)!=0) && 
        (GetShortPathName(szModule,szModule,MAX_PATH)!=0) && 
            (GetEnvironmentVariable("COMSPEC",szComspec,MAX_PATH)!=0)) 
   {  //设置命令行参数。 
      lstrcpy(szParams,"/c del "); 
      lstrcat(szParams, szModule); 
      lstrcat(szParams, " > nul"); 

      //初始化SHELLEXECUTEINFO结构成员 
      sei.cbSize = sizeof(sei); //设置类型大小。 
      //命令窗口进程句柄,ShellExecuteEx函数执行时设置。 
      sei.hwnd = 0; 
      sei.lpVerb = "Open";        //执行动作为“打开执行”。 
      sei.lpFile = szComspec;      //执行程序文件全路径名称。 
      sei.lpParameters = szParams; //执行参数。 
      sei.lpDirectory = 0; 
      //显示方式,此处使用隐藏方式阻止出现命令窗口界面。 
      sei.nShow = SW_HIDE; 
      //设置为SellExecuteEx函数结束后进程退出。 
      sei.fMask = SEE_MASK_NOCLOSEPROCESS; 
      //创建执行命令窗口进程。 
      if(ShellExecuteEx(&sei)) 
      {  //设置命令行进程的执行级别为空闲执行,这使本程序有足够的时间从内存中退出。   
         SetPriorityClass(sei.hProcess,IDLE_PRIORITY_CLASS); 
         //设置本程序进程的执行级别为实时执行,这本程序马上获取CPU执行权,快速退出。   
         SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS); 
         SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_TIME_CRITICAL);   
         //通知Windows资源浏览器,本程序文件已经被删除。 
         SHChangeNotify(SHCNE_DELETE,SHCNF_PATH,szModule,0); 
         //执行退出程序 
         EndDialog(0); 
       } 
   } 


    如果上面代码中的注释还不能帮助你理解代码的意义,请不要着急,后面我们还要对这些代码做详细的讲解。现在,你可以开始编译该程序项目,运行一下程序,请在Windows资源浏览器中仔细观察程序文件,当你按下“开始自杀”按钮后几秒,该程序文件从Windows资源浏览器中消失了,这也正在本程序想要得到的效果。 
    体验了“自杀”程序的神奇之后,让我们回过头来好好的分析一下实现“自杀”功能的代码。   
    前面我们已经谈过,实现“自杀”功能的核心是在程序中创建一个命令窗口新进程,通过向命令窗口进程传递del命令和参数来删除程序文件。命令窗口程序是由环境变量COMSPEC定义的,Win9x/ME使用COMMAND.COM,WinNT/2K/XP使用CMD.COM。程序把命令字符串“/c del filename > nul”传递给命令窗口,其中filename是需要删除文件的全路径文件名,文件名需要转换为8.3格式;/c开关用于命令窗口退出。   
    在实现代码中,首先就需要获取当前程序模块的全路径,并将其转化为命令窗口需要的8.3格式。代码中GetModuleFileName(0,szModule,MAX_PATH)函数实现了获取当前程序模式的全路径名称,并存放到变量szModule中。接着使用GetShortPathName(szModule,szModule,MAX_PATH)函数将szModule变量中的程序模块全路径名称转换成命令窗口需要的8.3格式。另外,还调用GetEnvironmentVariable("COMSPEC",szComspec,MAX_PATH)函数从系统环境变量COMSPC中获取了命令窗口程序的全路径。接下来,需要将存放在变量szModule中的具有8.3格式的程序模块全路径字符串组合成命令字符串“/c del ”+szModule+ “> nul”。   
    有了这些信息之后,就可以调用ShellExecuteEx() API函数创建一个新的命令窗口进程,该函数需要一个SHELLEXECUTEINFO类型的参数,调用ShellExecuteEx()函数必须需要初始化这个类型参数,有关SHELLEXECUTEINFO类型的详细说明请参阅MSDN。本处通过该参数将命令窗口进程的执行动作设为Open、执行文件为命令窗口(路径由szComspec提供)、执行文件参数为上面组合而成的命令字符串、显示方式为隐藏方式(隐藏方式可以阻止出现命令窗口界面)。   
    命令窗口通过调用ShellExecuteEx()函数以单独的进程运行,它的窗口句柄在SHELLEXECTUEINFO结构中的成员变量hProcess定义。自删除需要解决一个特殊的问题,即主程序必须在命令窗口删除它之前退出并关闭其打开的文件句柄。为了做到这一点,我们必须同步两个独立、并行的进程:当前程序进程和命令窗口进程。这可以通过操作CPU资源优先级来临时降低命令窗口的运行优先级别。这样,主程序将分配到CPU的所有资源直到其正常退出,而阻塞其它任何命令窗口的执行直到主程序结束。下面代码实现调整两个进程的执行优先级:   
    //设置命令行进程的执行级别为空闲执行,  
    //这使本程序有足够的时间从内存中退出。   
    SetPriorityClass(sei.hProcess,IDLE_PRIORITY_CLASS);   
    //设置本程序进程的执行级别为实时执行,  
    //这本程序马上获取CPU执行权,快速退出。   
    SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS);   
    SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_TIME_CRITICAL);   

    到此,自杀”功能基本实现。最后还需要做的事是调用SHChangeNotify(SHCNE_DELETE,SHCNF_PATH,szModule,0) 函数通知Windows资源浏览器已成功删除了程序文件。如果用户当前Windows资源浏览器窗口正处于程序文件目录的话,这个通知是非常必要的,它会导致Windows资源浏览器马上从程序文件目录列表中删除该程序文件项。做完了以上工作,一定要调用退出程序的代码,此处使用了EndDialog()函数,如果不及时退出程序的话,命令窗口进程就不能正常删除程序文件,其原因在前面我们已经研究过。   
    当你阅读完本文之后,一定与我有一个共同的感受:“自杀”也同样如此精彩!
转载二(未测试,不过也挺好)

 

DeleteMe.CPP

 

Module name: DeleteMe.cpp

Written by: Jeffrey Richter

Description: Allows an EXEcutable file to delete itself

********************************************************************/

 

#include <Windows.h>

#include <stdlib.h>

#include <tchar.h>

 

/

 

int WINAPI WinMain(HINSTANCE h, HINSTANCE b, LPSTR psz, int n) {

 

// Is this the Original EXE or the clone EXE?

// If the command-line 1 argument, this is the Original EXE

// If the command-line >1 argument, this is the clone EXE

 

if (__argc == 1) {

 

// Original EXE: Spawn clone EXE to delete this EXE

// Copy this EXEcutable image into the user's temp directory

 

TCHAR szPathOrig[_MAX_PATH], szPathClone[_MAX_PATH];

GetModuleFileName(NULL, szPathOrig, _MAX_PATH);

GetTempPath(_MAX_PATH, szPathClone);

GetTempFileName(szPathClone, __TEXT("Del"), 0, szPathClone);

CopyFile(szPathOrig, szPathClone, FALSE);

 

//***注意了***:

// Open the clone EXE using FILE_FLAG_DELETE_ON_CLOSE

HANDLE hfile = CreateFile(szPathClone, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL);

 

// Spawn the clone EXE passing it our EXE's process handle

// and the full path name to the Original EXE file.

TCHAR szCmdLine[512];

HANDLE hProcessOrig = OpenProcess(SYNCHRONIZE, TRUE, GetCurrentProcessId());

wsprintf(szCmdLine, __TEXT("%s %d /"%s/""), szPathClone, hProcessOrig, szPathOrig);

STARTUPINFO si;

ZeroMemory(&si, sizeof(si));

si.cb = sizeof(si);

PROCESS_INFORMATION pi;

CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);

CloseHandle(hProcessOrig);

CloseHandle(hfile);

 

// This original process can now terminate.

} else {

 

// Clone EXE: When original EXE terminates, delete it

HANDLE hProcessOrig = (HANDLE) _ttoi(__targv[1]);

WaitForSingleObject(hProcessOrig, INFINITE);

CloseHandle(hProcessOrig);

DeleteFile(__targv[2]);

// Insert code here to remove the subdirectory too (if desired).

 

// The system will delete the clone EXE automatically

// because it was opened with FILE_FLAG_DELETE_ON_CLOSE

}

return(0);

}

 

看懂了吗?

 

这一段程序思路很简单:不是不能在运行时直接删除本身吗?好,那么程序先复制(CLONE)一个自己,用复制品起动另一个进程,然后自己结束运行,则原来的EXE文件不被系统保护.这时由新进程作为杀手删除原来的EXE文件,并且继续完成程序其他的功能。

 

新进程在运行结束后,复制品被自动删除。这又是值得介绍的一个把戏了,注意:

// Open the clone EXE using FILE_FLAG_DELETE_ON_CLOSE

HANDLE hfile = CreateFile(szPathClone, 0, FILE_SHARE_READ, NULL,OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL);

这里面的FILE_FLAG_DELETE_ON_CLOSE标志,这个标志是告诉操作系统,当和这个文件相关的所有句柄都被关闭之后(包括上面这个CREATEFILE创建的句炳),就把这个文件删除。几乎所有的临时文件在创建时,都指明了这个标志。

另外要注意的是:在复制品进程对原始程序操刀之前,应该等待原进程退出.在这里用的是进程同步技术.用

HANDLE hProcessOrig = OpenProcess(SYNCHRONIZE, TRUE,GetCurrentProcessId());

得到原进程句柄.SYNCHRONICE标志在NT下有效,作用是使OpenProcess得到的句柄可以做为同步对象.复制品进程用WaitForSingleObject函数进行同步,然后一个DeleteFile,以及进行其它销毁证据(Jeffrey说:比如删目录)的工作,打完收工!

 

程序是基于CONSOLE的,通过传入的参数确定是原始的进程还是复制品新进程,并且得到需要操作的目标文件的信息(主要是路径),复制品放在系统的TEMP目录(GetTempPath得到),你也可以随便找个你认为安全的地方(比如:WINDOWS/SYSTEM32等等)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值