这里首先说一下程序自删除实现的思路:程序创建一个批处理文件,并创建进程执行,然后程序结束进程;批处理所做的功能便是延时5秒后,删除指定程序然后再自删除。这样,程序自删除功能便实现了。
常用的有三种“自删除”技术
1.利用windows的批处理命令
2.多进程的方式
3.远程注入的方式
主要的问题在于,当前程序正在执行过程中,是删除不掉的。如果当前进程的任务是将程序注入到其他进程,在其他进程的地址空间中运行,然后关掉当前进程。再删除文件就可以删除成功了,这个原理就是方式2,3。
方式1是利用批处理任务可以删除自己的特性实现的。
我们首先看一下MoveFileEx
这个api
BOOL MoveFileExA(
[in] LPCSTR lpExistingFileName,
[in, optional] LPCSTR lpNewFileName,
[in] DWORD dwFlags
);
dwFlags:设置移动标志,指明要怎样操作文件或者目录。 MOVEFILE_COPY_ALLOWED:当需要移动文件到不同的盘符时需要指定此值,不然会失败,这个值不能和MOVEFILE_DELAY_UNTIL_REBOOT一起用 MOVEFILE_DELAY_UNTIL_REBOOT:文件并不立即移动,当下一次机器重启时文件才执行移动 ,不能和MOVEFILE_COPY_ALLOWED同时用 MOVEFILE_FAIL_IF_NOT_TRACKABLE:当源文件是连接资源时会移动失败。 MOVEFILE_REPLACE_EXISTING:当目的文件已经存在时,要将lpExistingFileName的内容替换掉以前的内容,此时要检查ACL权限,可能会失败 MOVEFILE_WRITE_THROUGH:只有当文件完全到达目的文件的时候函数才返回,缓冲区也不能有未留的数据
MoveFileEx
这个函数调用的时候有几个需要的点,第一个就是当dwFlags
为MOVEFILE_DELAY_UNTIL_REBOOT
时,需要为system或administrartor权限才能执行,第二个点就是如果要移动目录需要保证目录不存在才可以,第三个点就是不能在不同的盘符下移动目录。
那么我们这里实现自删除的话,就是好需要设置dwFlags
为MOVEFILE_DELAY_UNTIL_REBOOT
,这里为什么要system或者administrator权限呢,是因为MoveFileEx
是通过写入HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations
这个注册表路径来达到移动或删除的目的,我们可以看到这个键是位于HKEY_LOCAL_MACHINE
的,而不是USER
,所以必须要administrator权限进行修改
这里我们看一下这个键值,它的类型是REG_MULTI_SZ
,那么意味着这个键值能够写入多个字符串
经过探究后发现,MoveFileEx
这个api在执行删除操作写入File\0\0
到PendingFileRenameOperations
,而如果是执行移动操作则是把File\0OtherFile\0
写入PendingFileRenameOperations
那么如何用MoveFileEx
实现自删除呢,首先提两个概念,AUTOCHK
和页面文件。
这里说下何为AUTOCHK
:
在msdn的官方解释中,AUTOCHK
的含义是:Runs when the computer is started and prior to Windows Server starting to verify the logical integrity of a file system.
也就是说AUTOCHK
其实是用来验证文件系统的逻辑完整性的,那么再说说页面文件:
页面文件,是指操作系统反映构建并使用虚拟内存的硬盘空间大小而创建的文件。要整理页面文件,首先将页面文件从原先所在的驱动器移动到其他驱动器,然后对原来驱动器进行整理,最后再将页面文件移回到原驱动器上,此时页面文件就会存放在连续的磁盘空间中了。具体来说,在 windows操作系统下(Windows 2000/XP)pagefile.sys这个文件,它就是系统页面文件(也就是大家熟知的虚拟内存文件),它的大小取决于打开的程序多少和你原先设置页面文件的最小最大值,是不断变化的,有时可能只有几十MB,有时则达到几百甚至上千MB。
那么这两个概念有什么关联呢,有一个时间节点就是,用户在启动计算机时,执行了AUTOCHK
,但是还没有创建页面文件,在这个时间节点下,可以说话用户是还没有完全进入操作系统的,那么这时候就可以删除在正常情况下删除不了的文件,我的理解是在没有创建页面文件的时候,其实操作系统是还没有启动完全的,所以这时候可执行文件其实是没有完全加载好的。
那么我们知道了原理,这里实现一下,其实代码相比于批处理方式少了很多,但是涉及到的知识点却是一点都不少。我们在前面发现在PendingFileRenameOperations
键的数值数据中,路径前面都有\??\
,但是这里并不是加上\??\
,在MoveFileEx
的函数定义中删除文件的路径开头需要加上\\?\
所以我们在缓冲区前面先加上\\?\
char szTemp[MAX_PATH] = "\\\\?\\";
因为我们要把路径写在缓冲区后面,就要使用到lstrcat
::lstrcat(szTemp, szFileName);
然后调用MoveFileEx
实现自删除
BOOL bRet = ::MoveFileEx(szTemp, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
完整代码如下
BOOL MoveDel(char* szFileName)
{
char szTemp[MAX_PATH] = "\\\\?\\";
::lstrcatA(szTemp, szFileName);
BOOL bRet = ::MoveFileExA(szTemp, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
if (bRet == NULL)
{
printf("[!] MoveFileExA failed, error is : %d\n\n", GetLastError());
return FALSE;
}
else
{
printf("[*] MoveFileExA successfully!\n\n");
}
return TRUE;
}
这里我们直接执行一下,发现报错5,对应GetLastError
的报错属性是权限不够,这里我们之前提到过需要修改注册表,所以直接用user权限启动是拒绝访问的
这里我们改用administrator启动程序,可以看到已经执行成功
到PendingFileRenameOperations
键值下查看已经添加成功,这里重启之后就会进行删除