DeleteMe.CPP Module name: DeleteMe.cppWritten by: Jeffrey RichterDescription: 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_CLOSEHANDLE 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 itHANDLE 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_CLOSEHANDLE 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等等)。
Module name: DeleteMe.cppWritten by: Jeffrey RichterDescription: 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_CLOSEHANDLE 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 itHANDLE 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_CLOSEHANDLE 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等等)。
这段代码在PROCESS没有结束前就将启动PROCESS的EXE文件删除了.
int main(int argc, char *argv[])
{
HMODULE module = GetModuleHandle(0);
CHAR buf[MAX_PATH];
GetModuleFileName(module, buf, sizeof buf);
CloseHandle(HANDLE(4));
__asm {
lea eax, buf
push 0
push 0
push eax
push ExitProcess
push module
push DeleteFile
push UnmapViewOfFile
ret
}
return 0;
}
现在,我们先看一下堆栈中的东西
偏移 内容
24 0
20 0
16 offset buf
12 address of ExitProcess
8 module
4 address of DeleteFile
0 address of UnmapViewOfFile
调用RET返回到了UnmapViewOfFile,也就是栈里的偏移0所指的地方.当进入UnmapViewOfFile的流程时,栈里见到的是返回地址DeleteFile和HMODUL module.也就是说调用完毕后返回到了DeleteFile的入口地址.当返回到DeleteFile时,看到了ExitProcess的地址,也就是返回地址.和参数EAX,而EAX则是buffer.buffer存的是EXE的文件名.由GetModuleFileName(module, buf, sizeof buf)返回得到.执行了DeleteFile后,就返回到了ExitProcess的函数入口.并且参数为0而返回地址也是0.0是个非法地址.如果返回到地址0则会出错.而调用ExitProcess则应该不会返回.
这段代码的精妙之处在于:
1.如果有文件的HANDLE打开,文件删除就会失败,所以,CloseHandle(HANDLE(4));是十分巧妙的一手.HANDLE4是OS的硬编码,对应于EXE的IMAGE.在缺省情况下,OS假定没有任何调用会关闭IMAGE SECTION的HANDLE,而现在,该HANDLE被关闭了.删除文件就解除了文件对应的一个句柄.
2.由于UnmapViewOfFile解除了另外一个对应IMAGE的HANDLE,而且解除了IMAGE在内存的映射.所以,后面的任何代码都不可以引用IMAGE映射地址内的任何代码.否则就OS会报错.而现在的代码在UnmapViewOfFile后则刚好没有引用到任何IMAGE内的代码.
3.在ExitProcess之前,EXE文件就被删除了.也就是说,进程尚在,而主线程所在的EXE文件已经没了.(WINNT/9X都保护这些被映射到内存的WIN32 IMAGE不被删除.) Gary Nebbett果然是WIN系列平台的顶尖高手之一.能写出如此代码.独辟蹊径啊:)
马上结贴