钢琴课迅雷下载:一个“自杀”程序的制作实录

来源:百度文库 编辑:中财网 时间:2024/04/29 23:36:29

一个“自杀”程序的制作实录  


每 次听到或看到“自杀”这个词,在我内心深处都会产生那种莫名的痛心与不安,引发起自己对生命价值的思考。自杀虽然是一种众人痛恨的行为,但对于那些对生活 极端失望并以生命存在而痛苦的人们,也许是一种最好解脱的办法。请大家不要被本人上面的言论影响到你的阅读情绪,“自杀”这个词永远不会与像热爱程序一样 热爱生活的程序员们相关联,我们本文探讨的“自杀”的执行者不是人类而是计算机程序。“自杀”程序是一个令所有电脑爱好者都心旷神怡的话题,下面就让我们 进入这个主题吧。

在开发程序过程中,有许多情况中都需要执行程序自己把自己从物理磁盘上删除,例如,卸装程序,一些黑客程序获取信息后自清除等,我们把这些具有自删除功能的程序统称为“自杀”程序。对于一名程序员,想必都有在程序中使用代码删除物理磁盘文件的经历吧,我们只需要简单的调用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); //设置类型大小。

       sei.hwnd = 0; //命令窗口进程句柄,ShellExecuteEx函数执行时设置。

       sei.lpVerb = "Open"; //执行动作为“打开执行”。

       sei.lpFile = szComspec; //执行程序文件全路径名称。

       sei.lpParameters = szParams; //执行参数。

       sei.lpDirectory = 0;

       sei.nShow = SW_HIDE; //显示方式,此处使用隐藏方式阻止出现命令窗口界面。

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

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

       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()函数,如果不及时退出程序的话,命令窗口进程就不能正常删除程序文件,其原因在前面我们已经研究过。

当你阅读完本文之后,一定与我有一个共同的感受:“自杀”也同样如此精彩!