安全开发专题
2、自删除
1、课程目标
- 理解Windows文件删除机制
- 掌握程序自删除技术
- 实现安全的自删除功能
- 了解文件锁定和解锁技术
2、名词解释
| 术语 | 全称 | 解释 |
|---|---|---|
| Self-Deletion | 自删除 | 程序删除自身文件 |
| File Locking | 文件锁定 | 文件被进程占用无法删除 |
| Unlocking | 解锁 | 释放文件占用 |
| Delayed Deletion | 延迟删除 | 系统重启时删除文件 |
3、技术原理
1. Windows文件删除机制
正常删除流程:
1. 检查文件是否被占用
2. 检查访问权限
3. 从文件系统中移除
4. 释放磁盘空间
自删除挑战:
┌─────────────────────────────────────┐
│ 程序正在运行 → 文件被锁定 │
├─────────────────────────────────────┤
│ 无法直接删除自身 │
├─────────────────────────────────────┤
│ 需要特殊技巧绕过锁定 │
└─────────────────────────────────────┘
2. 自删除技术方案
方案1: MoveFileEx延迟删除
MoveFileEx(source, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
方案2: 创建批处理文件
创建.bat文件执行删除命令,然后执行
方案3: 文件句柄复制
使用NtCreateProcessEx复制句柄实现分离
方案4: 进程替换
替换当前进程映像后删除原文件
3、代码实现
1. 基础自删除实现
// self_delete.cpp
// 程序自删除实现
#include <windows.h>
#include <stdio.h>
#include <string>
// 方法1: 使用MoveFileEx延迟删除
bool SelfDeleteOnReboot() {
char selfPath[MAX_PATH];
if (!GetModuleFileNameA(NULL, selfPath, MAX_PATH)) {
return false;
}
// 设置重启时删除
if (MoveFileExA(selfPath, NULL, MOVEFILE_DELAY_UNTIL_REBOOT)) {
printf("[+] Scheduled self-deletion on reboot\n");
return true;
} else {
printf("[-] Failed to schedule self-deletion: %lu\n", GetLastError());
return false;
}
}
// 方法2: 创建批处理文件删除
bool SelfDeleteViaBatch() {
char selfPath[MAX_PATH];
if (!GetModuleFileNameA(NULL, selfPath, MAX_PATH)) {
return false;
}
// 创建临时批处理文件
char tempPath[MAX_PATH];
if (!GetTempPathA(MAX_PATH, tempPath)) {
return false;
}
char batchFile[MAX_PATH];
sprintf_s(batchFile, "%sdelself.bat", tempPath);
FILE* fp = fopen(batchFile, "w");
if (!fp) {
return false;
}
// 写入批处理内容
fprintf(fp, "@echo off\n");
fprintf(fp, "timeout /t 2 /nobreak >nul\n"); // 等待2秒
fprintf(fp, "del \"%s\"\n", selfPath); // 删除自身
fprintf(fp, "del \"%%~f0\"\n"); // 删除批处理文件
fclose(fp);
// 执行批处理文件
ShellExecuteA(NULL, "open", batchFile, NULL, NULL, SW_HIDE);
printf("[+] Self-deletion batch file created and executed\n");
return true;
}
// 方法3: 使用CMD命令删除
bool SelfDeleteViaCmd() {
char selfPath[MAX_PATH];
if (!GetModuleFileNameA(NULL, selfPath, MAX_PATH)) {
return false;
}
// 构造CMD命令
char cmdLine[1024];
sprintf_s(cmdLine,
"cmd.exe /c timeout /t 3 /nobreak >nul & del \"%s\" & exit",
selfPath);
// 创建隐藏进程执行删除
STARTUPINFOA si = { sizeof(STARTUPINFOA) };
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
PROCESS_INFORMATION pi;
if (CreateProcessA(NULL, cmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
printf("[+] Self-deletion command executed\n");
return true;
}
return false;
}
// 方法4: 释放资源后删除
bool SelfDeleteAfterCleanup() {
char selfPath[MAX_PATH];
if (!GetModuleFileNameA(NULL, selfPath, MAX_PATH)) {
return false;
}
// 这里可以添加资源清理代码
// 例如:关闭文件句柄、网络连接等
// 尝试直接删除
if (DeleteFileA(selfPath)) {
printf("[+] Self-deleted immediately\n");
return true;
}
// 如果失败,使用其他方法
printf("[-] Immediate deletion failed, trying alternative methods\n");
return SelfDeleteViaBatch();
}
2. 高级自删除技术
// advanced_self_delete.cpp
// 高级自删除技术
#include <windows.h>
#include <winternl.h>
#include <stdio.h>
// 方法5: 使用文件句柄技巧
bool SelfDeleteViaHandleTrick() {
char selfPath[MAX_PATH];
GetModuleFileNameA(NULL, selfPath, MAX_PATH);
// 打开自身文件
HANDLE hFile = CreateFileA(
selfPath,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hFile == INVALID_HANDLE_VALUE) {
return false;
}
// 设置文件信息使其看起来已被删除
FILE_DISPOSITION_INFORMATION fileInfo;
fileInfo.DeleteFile = TRUE;
NTSTATUS status = NtSetInformationFile(
hFile,
&(IO_STATUS_BLOCK){0},
&fileInfo,
sizeof(fileInfo),
FileDispositionInformation
);
CloseHandle(hFile);
if (status == 0) {
printf("[+] Self-deleted via handle trick\n");
return true;
}
return false;
}
// 方法6: 创建傀儡进程删除
bool SelfDeleteViaPuppetProcess() {
char selfPath[MAX_PATH];
GetModuleFileNameA(NULL, selfPath, MAX_PATH);
// 创建傀儡进程(可以是系统进程的副本)
STARTUPINFOA si = { sizeof(STARTUPINFOA) };
PROCESS_INFORMATION pi;
// 使用notepad作为傀儡进程示例
if (CreateProcessA("C:\\Windows\\System32\\notepad.exe", NULL,
NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
// 等待傀儡进程启动
Sleep(1000);
// 注入删除代码到傀儡进程
// 这里简化处理,实际需要注入代码
// 发送删除命令
char cmd[512];
sprintf_s(cmd, "del \"%s\"", selfPath);
WinExec(cmd, SW_HIDE);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
printf("[+] Self-deletion delegated to puppet process\n");
return true;
}
return false;
}
// 方法7: 使用WMI删除
bool SelfDeleteViaWMI() {
// 这需要COM初始化和WMI接口调用
// 简化示例
char selfPath[MAX_PATH];
GetModuleFileNameA(NULL, selfPath, MAX_PATH);
char wmiCmd[512];
sprintf_s(wmiCmd,
"wmic process where \"name='explorer.exe'\" call create \"cmd.exe /c del \\\"%s\\\"\"",
selfPath);
WinExec(wmiCmd, SW_HIDE);
printf("[+] Self-deletion command sent via WMI\n");
return true;
}
// 方法8: 使用PowerShell删除
bool SelfDeleteViaPowerShell() {
char selfPath[MAX_PATH];
GetModuleFileNameA(NULL, selfPath, MAX_PATH);
char psCmd[1024];
sprintf_s(psCmd,
"powershell -WindowStyle Hidden -Command \"Start-Sleep 2; Remove-Item -Path '%s' -Force\"",
selfPath);
WinExec(psCmd, SW_HIDE);
printf("[+] Self-deletion command sent via PowerShell\n");
return true;
}
3. 安全自删除实现
// secure_self_delete.cpp
// 安全自删除实现
#include <windows.h>
#include <stdio.h>
#include <string>
#include <vector>
// 文件擦除结构
typedef struct _FILE_ERASE_INFO {
std::string filePath;
int passes;
bool verify;
} FILE_ERASE_INFO;
// 安全擦除文件内容
bool SecureEraseFile(const char* filePath, int passes = 3) {
HANDLE hFile = CreateFileA(
filePath,
GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hFile == INVALID_HANDLE_VALUE) {
return false;
}
// 获取文件大小
LARGE_INTEGER fileSize;
if (!GetFileSizeEx(hFile, &fileSize)) {
CloseHandle(hFile);
return false;
}
// 多次覆写
std::vector<BYTE> buffer(4096);
for (int pass = 0; pass < passes; pass++) {
// 设置不同的覆写模式
BYTE pattern = (pass % 2 == 0) ? 0x00 : 0xFF;
if (pass == passes - 1) pattern = 0x55; // 最后一次使用特定模式
memset(buffer.data(), pattern, buffer.size());
// 回到文件开头
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
ULONGLONG remaining = fileSize.QuadPart;
while (remaining > 0) {
DWORD toWrite = (DWORD)min(remaining, (ULONGLONG)buffer.size());
DWORD written;
if (!WriteFile(hFile, buffer.data(), toWrite, &written, NULL)) {
CloseHandle(hFile);
return false;
}
remaining -= written;
}
// 刷新到磁盘
FlushFileBuffers(hFile);
}
CloseHandle(hFile);
printf("[+] File securely erased: %s\n", filePath);
return true;
}
// 获取文件属性
DWORD GetFileAttributesSafe(const char* filePath) {
DWORD attrs = GetFileAttributesA(filePath);
if (attrs == INVALID_FILE_ATTRIBUTES) {
printf("[-] Failed to get file attributes: %lu\n", GetLastError());
}
return attrs;
}
// 设置文件属性
bool SetFileAttributesSafe(const char* filePath, DWORD attrs) {
if (!SetFileAttributesA(filePath, attrs)) {
printf("[-] Failed to set file attributes: %lu\n", GetLastError());
return false;
}
return true;
}
// 隐藏文件
bool HideFile(const char* filePath) {
DWORD attrs = GetFileAttributesSafe(filePath);
if (attrs == INVALID_FILE_ATTRIBUTES) {
return false;
}
// 添加隐藏和系统属性
attrs |= FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
return SetFileAttributesSafe(filePath, attrs);
}
// 恢复文件属性
bool RestoreFileAttributes(const char* filePath, DWORD originalAttrs) {
return SetFileAttributesSafe(filePath, originalAttrs);
}
// 安全自删除主函数
bool SecureSelfDelete(bool eraseContent = true, bool hideFirst = true) {
char selfPath[MAX_PATH];
if (!GetModuleFileNameA(NULL, selfPath, MAX_PATH)) {
return false;
}
printf("[*] Performing secure self-deletion of: %s\n", selfPath);
// 保存原始属性
DWORD originalAttrs = GetFileAttributesSafe(selfPath);
// 隐藏文件
if (hideFirst) {
HideFile(selfPath);
printf("[+] File hidden\n");
}
// 安全擦除内容
if (eraseContent) {
if (SecureEraseFile(selfPath, 3)) {
printf("[+] File content securely erased\n");
}
}
// 恢复原始属性(如果需要)
// RestoreFileAttributes(selfPath, originalAttrs);
// 使用最可靠的删除方法
bool deleted = SelfDeleteOnReboot();
if (!deleted) {
deleted = SelfDeleteViaBatch();
}
if (!deleted) {
deleted = SelfDeleteViaCmd();
}
if (deleted) {
printf("[+] Secure self-deletion initiated\n");
} else {
printf("[-] Failed to initiate self-deletion\n");
}
return deleted;
}
// 自删除前的清理工作
void PreDeletionCleanup() {
// 关闭可能的文件句柄
// 清理注册表项
// 断开网络连接
// 停止相关服务
printf("[*] Pre-deletion cleanup completed\n");
}
// 延迟自删除(等待一段时间后删除)
bool DelayedSelfDelete(DWORD delaySeconds) {
char selfPath[MAX_PATH];
GetModuleFileNameA(NULL, selfPath, MAX_PATH);
char cmd[512];
sprintf_s(cmd,
"cmd.exe /c timeout /t %lu /nobreak >nul & del \"%s\" & exit",
delaySeconds, selfPath);
STARTUPINFOA si = { sizeof(STARTUPINFOA) };
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
PROCESS_INFORMATION pi;
if (CreateProcessA(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
printf("[+] Delayed self-deletion scheduled (%lu seconds)\n", delaySeconds);
return true;
}
return false;
}
4. 自删除管理器
// delete_manager.cpp
// 自删除管理器
#include <windows.h>
#include <stdio.h>
#include <string>
// 自删除方法枚举
enum class DeleteMethod {
Immediate,
OnReboot,
ViaBatch,
ViaCmd,
ViaPowerShell,
ViaWMI,
Secure,
Delayed
};
// 自删除管理器
class SelfDeleteManager {
private:
std::string m_selfPath;
public:
SelfDeleteManager() {
char path[MAX_PATH];
GetModuleFileNameA(NULL, path, MAX_PATH);
m_selfPath = path;
}
// 执行自删除
bool Execute(DeleteMethod method, DWORD delaySeconds = 0) {
printf("[*] Executing self-deletion using method: %d\n", (int)method);
switch (method) {
case DeleteMethod::Immediate:
return SelfDeleteAfterCleanup();
case DeleteMethod::OnReboot:
return SelfDeleteOnReboot();
case DeleteMethod::ViaBatch:
return SelfDeleteViaBatch();
case DeleteMethod::ViaCmd:
return SelfDeleteViaCmd();
case DeleteMethod::ViaPowerShell:
return SelfDeleteViaPowerShell();
case DeleteMethod::ViaWMI:
return SelfDeleteViaWMI();
case DeleteMethod::Secure:
PreDeletionCleanup();
return SecureSelfDelete(true, true);
case DeleteMethod::Delayed:
return DelayedSelfDelete(delaySeconds);
}
return false;
}
// 获取自身路径
const std::string& GetSelfPath() const {
return m_selfPath;
}
// 验证文件是否存在
bool FileExists() const {
DWORD attrs = GetFileAttributesA(m_selfPath.c_str());
return (attrs != INVALID_FILE_ATTRIBUTES);
}
};
// 测试函数
void TestSelfDeletion() {
printf("=== Self-Deletion Test ===\n");
SelfDeleteManager manager;
if (!manager.FileExists()) {
printf("[-] Self file not found\n");
return;
}
printf("[*] Self path: %s\n", manager.GetSelfPath().c_str());
// 测试各种删除方法(注意:实际测试时要小心)
printf("[*] Testing self-deletion methods...\n");
// 测试延迟删除(安全)
if (manager.Execute(DeleteMethod::Delayed, 5)) {
printf("[+] Delayed deletion scheduled\n");
}
printf("[*] Test completed\n");
}
int main() {
printf("========================================\n");
printf(" Self-Deletion Implementation \n");
printf("========================================\n\n");
TestSelfDeletion();
// 注意:不要在实际测试中执行真正的自删除!
printf("\n[WARNING] Actual self-deletion is disabled in this test.\n");
printf("Enable specific methods carefully in production code.\n");
return 0;
}
5、课后作业
5.1、作业1:实现多层自删除
设计一个多层次的自删除机制,确保即使某一层失败也能成功删除。
5.2、作业2:添加自删除验证
实现自删除后的验证机制,确认文件确实已被删除。
5.3、作业3:实现防重复删除
添加机制防止同一文件被多次删除。