安全开发专题

2、自删除

1、课程目标

  1. 理解Windows文件删除机制
  2. 掌握程序自删除技术
  3. 实现安全的自删除功能
  4. 了解文件锁定和解锁技术

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:实现防重复删除

添加机制防止同一文件被多次删除。