Windows自删除技术

通过两种方式实现自删除,第一种方式是通过调用MoveFileEx,第二种方式是程序释放批处理脚本后,用批处理脚本删除程序自身并让批处理自我删除。

0x01 自删除技术

A) MoveFileEx方式

BOOL MoveFileEx(
  LPCTSTR lpExistingFileName,
  LPCTSTR lpNewFileName,
  DWORD  dwFlags
);

其函数原型非常简单,该函数原本用于移动文件。

第一个参数lpExistingFileName是需要被移动的文件路径

第二个参数lpNewFileName是新的位置的路径

第三个参数dwFlags是标志,这个参数比较复杂下面来着重介绍

MOVEFILE_COPY_ALLOWED: 如果文件被从C盘移动到D盘即不同卷之间移动则内部移动方式转成复制后删除

MOVEFILE_WRITE_THROUGH: 在完成移动前MoveFilEx处于阻塞状态

着重讲一下这个参数:

MOVEFILE_DELAY_UNTIL_REBOOT: 

1. 这个参数只能用于管理员权限执行时。

2. 这个参数是将移动操作延迟到重新启动计算机后执行。

3. 这种移动操作执行的非常早,位于AUTOCHK执行之后,页文件创建之间。只需要知道这操作执行很早就可以。

4. 在ANSI的函数版本中该函数路径最大字符限制是MAX_PATH个即260。如果你在路径前加上\\?\前缀并且使用Unicode版本的MoveFileEx则最大字符数可以变成32,767个宽字符。特别注意的是自从Win10 v1607后可以选择不加这个前缀也可以突破MAX_PATH个字符限制。

深入探究MOVEFILE_DELAY_UNTIL_REBOOT:

这个参数实际上是对注册表进行了操作,假设程序无法访问注册表那也就无法执行删除操作,MoveFileEx通过写入

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations

来达到重启移动或者删除的目的,这也是加了这个参数需要管理员权限的原因,因为访问HKEY_LOCAL_MACHINE根键下的子键需要系统管理员权限。

并且执行重启后移动和重启后删除的格式是不一样的,可以看到PendingFileRenameOperations值的类型是REG_MULTI_SZ,意味着可以写入多个字符串。

假设是重启后删除操作,MoveFileEx会把szDstFile\0\0写入PendingFileRenameOperations

而如果是重启后移动操作,MoveFileEx会把szSrcFile\0szDstFile\0写入PendingFileRenameOperations

接下去看一下代码:

 
BOOL SelfDel(LPCTSTR pszFileName) {
	TCHAR szTemp[MAX_PATH] = "\\\\?\\"; // 这个\\?\是有选择性的加入,如果你是Win10系统
	_tcscat_s(szTemp, _countof(szTemp) * sizeof(TCHAR), pszFileName);
 
	return(MoveFileEx(szTemp, NULL, MOVEFILE_DELAY_UNTIL_REBOOT));
}

代码非常简单但是里面内容却很多。

B) 批处理方式

批处理实现自启动的优势更大,它无需重启并且不需要管理员权限。实现原理主要是用代码创建的BAT脚本,并利用脚本的del %0可以删除自身以及删除其他文件的特性实现的。

首先来看一下这个bat脚本:

@echo off                       # 不显示脚本执行时产生的内容

choice /t 1 /d y /n > nul   # 这条命令下面讲

del xxx.exe                     # 删除xxx.exe, xxx.exe代表要删除的可执行文件的名称

del %0                           # 删除自身

这里主要来讲一下choice这个命令,这个命令主要是起到延时的作用以确保下面的删除操作能够完成。先看一下cmd帮助文档:

下面我用我的话来讲述一下这里需要用到的参数的作用

/t参数: 这个参数后面跟一个数字n,表示等待n秒,choice会给出一个选择框让你选一个答案,如下:

上面的/t 5就是等待5秒,在这5秒内你要选择Y, N, C中的一个输入并回车,如果你在5秒内没有输入,那系统就会默认帮你选择Y,你也可以自己设定默认值

/d参数: 这个参数后面可以跟y, n, c分别代表3个回答,d代表default,意味着默认选项,在有限时间内没有选择那就会默认选择这个参数的设置,比如我这里是/d y,所以如下:

系统默认帮我选择了Y的答案。

/c参数: 回答的总数最多有Y,N,C三种,你不可以有更多回答,但是你可以减少,/c参数就是让你选择答案数目,比如我用

/c yn的话,那结果就会变成下面那样:

问题的答案就成了Y和N两个选项了,这次我/d n意味着默认是N答案,5秒后我没有回答,系统自动帮我回答了N并且脱离了阻塞态。

我觉得这个脚本的其他应该没什么问题。接下去看看代码:

#include <windows.h>
#include <tchar.h>
#include <cstdio>
#include <shlobj.h>
#include <StrSafe.h>
 
// 创建批处理脚本代码
BOOL CreateChoiceBat() {
	TCHAR szBat[MAX_PATH] = {0};
	TCHAR szCurrentFileName[MAX_PATH] = { 0 };
	HANDLE hFile = NULL;
	/*
		@echo off
		choice /t 5 /d y /n > nul || ping 127.0.0.1 /n 5 > nul
		del *.exe
		del %0
	*/
	GetModuleFileName(NULL, szCurrentFileName, _countof(szCurrentFileName) * sizeof(TCHAR));
	StringCchPrintf(szBat, _countof(szBat) * sizeof(TCHAR), "@echo off\r\nchoice /t 1 /d y /n > nul\r\ndel %s\r\ndel %%0\r\n", szCurrentFileName);
	hFile = CreateFile("del.bat", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if (INVALID_HANDLE_VALUE == hFile) {
		_tprintf("%d", GetLastError());
		return(FALSE);
	}
		
	DWORD dwWritten = 0;
	if (FALSE == WriteFile(hFile, szBat, sizeof(TCHAR) * _tcslen(szBat), &dwWritten, NULL))
		return(FALSE);
	CloseHandle(hFile);
 
	return(TRUE);
}
 
// 创建运行自删除脚本的CMD进程
BOOL SelfDelete() {
	BOOL bRet = FALSE;
	TCHAR szCurrentDirectory[MAX_PATH] = {0};
	TCHAR szBatFileName[MAX_PATH] = {0};
	TCHAR szCmd[MAX_PATH] = { 0 };
	LPTSTR pStr = NULL;
	GetModuleFileName(NULL, szCurrentDirectory, _countof(szCurrentDirectory) * sizeof(TCHAR));
	if (NULL == (pStr = _tcsrchr(szCurrentDirectory, '\\')))
		return(FALSE);
	*pStr = '\0';
	StringCchPrintf(szBatFileName, _countof(szBatFileName) * sizeof(TCHAR), "%s\\del.bat", szCurrentDirectory);
	StringCchPrintf(szCmd, _countof(szCmd) * sizeof(TCHAR), "cmd /c call \"%s\"", szBatFileName);
	
	if (CreateChoiceBat()) {
		STARTUPINFO si = {0};
		PROCESS_INFORMATION pi = {0};
 
		si.cb = sizeof(si);
		si.dwFlags = STARTF_USESHOWWINDOW;
		si.wShowWindow = SW_HIDE;
		BOOL fOk = CreateProcess(NULL, szCmd, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
		if (fOk) {
			CloseHandle(pi.hProcess);
			CloseHandle(pi.hThread);
			ExitProcess(NULL);
		}
	}
	else
		return(FALSE);
 
	return(TRUE);
}
 
int _tmain() {
 
	SelfDelete();
 
	system("pause");
	return(0);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值