安全开发专题

1、自启动

1、课程目标

  1. 理解Windows系统自启动机制
  2. 掌握常见的自启动技术实现
  3. 实现多种自启动方法
  4. 了解自启动的检测和防护

2、名词解释

术语 全称 解释
Auto-run 自动运行 系统启动时自动执行程序
Registry 注册表 Windows系统配置数据库
Startup Folder 启动文件夹 用户登录时自动执行的程序目录
Service 服务 系统后台运行的程序
Persistence 持久化 保持程序持续运行的能力

3、技术原理

1. Windows自启动机制

用户级自启动:
HKCU\Software\Microsoft\Windows\CurrentVersion\Run
HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnce
%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup

系统级自启动:
HKLM\Software\Microsoft\Windows\CurrentVersion\Run
HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnce
HKLM\SYSTEM\CurrentControlSet\Services

其他自启动位置:
HKCU\Environment\UserInitMprLogonScript
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Shell
Scheduled Tasks

2. 自启动检测点

// 常见检测注册表项
const char* autorunKeys[] = {
    "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
    "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce",
    "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunServices",
    "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunServicesOnce",
    "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Shell",
    "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Userinit"
};

3、代码实现

1. 注册表自启动

// registry_autorun.cpp
// 注册表自启动实现

#include <windows.h>
#include <stdio.h>
#include <string>

// 添加注册表自启动项
bool AddRegistryAutorun(const char* appName, const char* appPath, bool systemWide = false) {
    HKEY hKey;
    const char* regPath = systemWide ? 
        "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run" :
        "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run";
    
    LONG result = RegOpenKeyExA(
        systemWide ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
        regPath,
        0,
        KEY_SET_VALUE,
        &hKey
    );
    
    if (result != ERROR_SUCCESS) {
        printf("[-] Failed to open registry key: %ld\n", result);
        return false;
    }
    
    result = RegSetValueExA(
        hKey,
        appName,
        0,
        REG_SZ,
        (const BYTE*)appPath,
        (DWORD)strlen(appPath) + 1
    );
    
    RegCloseKey(hKey);
    
    if (result == ERROR_SUCCESS) {
        printf("[+] Added registry autorun: %s\n", appName);
        return true;
    } else {
        printf("[-] Failed to set registry value: %ld\n", result);
        return false;
    }
}

// 删除注册表自启动项
bool RemoveRegistryAutorun(const char* appName, bool systemWide = false) {
    HKEY hKey;
    const char* regPath = systemWide ? 
        "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run" :
        "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run";
    
    LONG result = RegOpenKeyExA(
        systemWide ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
        regPath,
        0,
        KEY_SET_VALUE,
        &hKey
    );
    
    if (result != ERROR_SUCCESS) {
        return false;
    }
    
    result = RegDeleteValueA(hKey, appName);
    RegCloseKey(hKey);
    
    if (result == ERROR_SUCCESS) {
        printf("[+] Removed registry autorun: %s\n", appName);
        return true;
    }
    
    return false;
}

// 查询注册表自启动项
void ListRegistryAutorun(bool systemWide = false) {
    HKEY hKey;
    const char* regPath = systemWide ? 
        "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run" :
        "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run";
    
    LONG result = RegOpenKeyExA(
        systemWide ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
        regPath,
        0,
        KEY_READ,
        &hKey
    );
    
    if (result != ERROR_SUCCESS) {
        return;
    }
    
    printf("\n[%s] Registry Autorun Entries:\n", systemWide ? "System" : "User");
    printf("----------------------------------------\n");
    
    DWORD index = 0;
    char name[256];
    DWORD nameSize;
    BYTE value[1024];
    DWORD valueSize;
    DWORD valueType;
    
    while (true) {
        nameSize = sizeof(name);
        valueSize = sizeof(value);
        
        result = RegEnumValueA(
            hKey,
            index,
            name,
            &nameSize,
            NULL,
            &valueType,
            value,
            &valueSize
        );
        
        if (result == ERROR_NO_MORE_ITEMS) {
            break;
        }
        
        if (result == ERROR_SUCCESS) {
            printf("%-20s: %s\n", name, (char*)value);
        }
        
        index++;
    }
    
    RegCloseKey(hKey);
}

2. 启动文件夹自启动

// startup_folder.cpp
// 启动文件夹自启动实现

#include <windows.h>
#include <shlobj.h>
#include <stdio.h>
#include <string>

// 获取启动文件夹路径
std::string GetStartupFolderPath(bool allUsers = false) {
    char path[MAX_PATH];
    
    if (allUsers) {
        // 所有用户启动文件夹
        if (SHGetSpecialFolderPathA(NULL, path, CSIDL_COMMON_STARTUP, FALSE)) {
            return std::string(path);
        }
    } else {
        // 当前用户启动文件夹
        if (SHGetSpecialFolderPathA(NULL, path, CSIDL_STARTUP, FALSE)) {
            return std::string(path);
        }
    }
    
    return "";
}

// 创建快捷方式
bool CreateShortcut(const char* targetPath, const char* shortcutPath, const char* description = NULL) {
    CoInitialize(NULL);
    
    IShellLinkA* pShellLink = NULL;
    HRESULT hr = CoCreateInstance(
        CLSID_ShellLink,
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_IShellLinkA,
        (LPVOID*)&pShellLink
    );
    
    if (SUCCEEDED(hr)) {
        IPersistFile* pPersistFile = NULL;
        
        pShellLink->SetPath(targetPath);
        if (description) {
            pShellLink->SetDescription(description);
        }
        
        hr = pShellLink->QueryInterface(IID_IPersistFile, (LPVOID*)&pPersistFile);
        
        if (SUCCEEDED(hr)) {
            wchar_t wsz[MAX_PATH];
            MultiByteToWideChar(CP_ACP, 0, shortcutPath, -1, wsz, MAX_PATH);
            
            hr = pPersistFile->Save(wsz, TRUE);
            pPersistFile->Release();
        }
        
        pShellLink->Release();
    }
    
    CoUninitialize();
    
    if (SUCCEEDED(hr)) {
        printf("[+] Created shortcut: %s\n", shortcutPath);
        return true;
    } else {
        printf("[-] Failed to create shortcut\n");
        return false;
    }
}

// 添加启动文件夹自启动
bool AddStartupFolderAutorun(const char* appName, const char* appPath, bool allUsers = false) {
    std::string startupPath = GetStartupFolderPath(allUsers);
    if (startupPath.empty()) {
        printf("[-] Failed to get startup folder path\n");
        return false;
    }
    
    std::string shortcutPath = startupPath + "\\" + std::string(appName) + ".lnk";
    
    return CreateShortcut(appPath, shortcutPath.c_str(), appName);
}

// 删除启动文件夹自启动
bool RemoveStartupFolderAutorun(const char* appName, bool allUsers = false) {
    std::string startupPath = GetStartupFolderPath(allUsers);
    if (startupPath.empty()) {
        return false;
    }
    
    std::string shortcutPath = startupPath + "\\" + std::string(appName) + ".lnk";
    
    if (DeleteFileA(shortcutPath.c_str())) {
        printf("[+] Removed startup shortcut: %s\n", appName);
        return true;
    }
    
    return false;
}

// 列出启动文件夹内容
void ListStartupFolder(bool allUsers = false) {
    std::string startupPath = GetStartupFolderPath(allUsers);
    if (startupPath.empty()) {
        return;
    }
    
    printf("\n[%s] Startup Folder Contents:\n", allUsers ? "All Users" : "Current User");
    printf("----------------------------------------\n");
    
    WIN32_FIND_DATAA findData;
    HANDLE hFind = FindFirstFileA((startupPath + "\\*").c_str(), &findData);
    
    if (hFind != INVALID_HANDLE_VALUE) {
        do {
            if (strcmp(findData.cFileName, ".") != 0 && 
                strcmp(findData.cFileName, "..") != 0) {
                printf("%s\n", findData.cFileName);
            }
        } while (FindNextFileA(hFind, &findData));
        
        FindClose(hFind);
    }
}

3. 服务自启动

// service_autorun.cpp
// 服务自启动实现

#include <windows.h>
#include <stdio.h>

// 安装服务
bool InstallService(const char* serviceName, const char* displayName, const char* binaryPath) {
    SC_HANDLE hSCManager = OpenSCManagerA(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
    if (!hSCManager) {
        printf("[-] Failed to open SC Manager\n");
        return false;
    }
    
    SC_HANDLE hService = CreateServiceA(
        hSCManager,
        serviceName,
        displayName,
        SERVICE_ALL_ACCESS,
        SERVICE_WIN32_OWN_PROCESS,
        SERVICE_AUTO_START,
        SERVICE_ERROR_NORMAL,
        binaryPath,
        NULL,
        NULL,
        NULL,
        NULL,
        NULL
    );
    
    if (hService) {
        printf("[+] Service installed: %s\n", serviceName);
        
        // 启动服务
        StartServiceA(hService, 0, NULL);
        printf("[+] Service started\n");
        
        CloseServiceHandle(hService);
        CloseServiceHandle(hSCManager);
        return true;
    } else {
        printf("[-] Failed to create service\n");
        CloseServiceHandle(hSCManager);
        return false;
    }
}

// 删除服务
bool UninstallService(const char* serviceName) {
    SC_HANDLE hSCManager = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
    if (!hSCManager) {
        return false;
    }
    
    SC_HANDLE hService = OpenServiceA(hSCManager, serviceName, SERVICE_STOP | DELETE);
    if (!hService) {
        CloseServiceHandle(hSCManager);
        return false;
    }
    
    // 停止服务
    SERVICE_STATUS status;
    ControlService(hService, SERVICE_CONTROL_STOP, &status);
    
    // 删除服务
    bool result = DeleteService(hService);
    
    if (result) {
        printf("[+] Service uninstalled: %s\n", serviceName);
    }
    
    CloseServiceHandle(hService);
    CloseServiceHandle(hSCManager);
    
    return result;
}

// 查询服务状态
void ListServices() {
    SC_HANDLE hSCManager = OpenSCManagerA(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
    if (!hSCManager) {
        return;
    }
    
    DWORD bytesNeeded, servicesReturned, resumeHandle = 0;
    
    // 第一次调用获取所需缓冲区大小
    EnumServicesStatusA(
        hSCManager,
        SERVICE_WIN32,
        SERVICE_STATE_ALL,
        NULL,
        0,
        &bytesNeeded,
        &servicesReturned,
        &resumeHandle
    );
    
    // 分配缓冲区
    LPBYTE buffer = new BYTE[bytesNeeded];
    
    if (EnumServicesStatusA(
        hSCManager,
        SERVICE_WIN32,
        SERVICE_STATE_ALL,
        (LPENUM_SERVICE_STATUSA)buffer,
        bytesNeeded,
        &bytesNeeded,
        &servicesReturned,
        &resumeHandle
    )) {
        LPENUM_SERVICE_STATUSA services = (LPENUM_SERVICE_STATUSA)buffer;
        
        printf("\nServices:\n");
        printf("----------------------------------------\n");
        
        for (DWORD i = 0; i < servicesReturned; i++) {
            const char* state = "Unknown";
            switch (services[i].ServiceStatus.dwCurrentState) {
                case SERVICE_RUNNING: state = "Running"; break;
                case SERVICE_STOPPED: state = "Stopped"; break;
                case SERVICE_PAUSED: state = "Paused"; break;
            }
            
            printf("%-20s %-15s %s\n",
                services[i].lpServiceName,
                state,
                services[i].lpDisplayName);
        }
    }
    
    delete[] buffer;
    CloseServiceHandle(hSCManager);
}

4. 计划任务自启动

// scheduled_task.cpp
// 计划任务自启动实现

#include <windows.h>
#include <taskschd.h>
#include <comdef.h>
#include <stdio.h>

#pragma comment(lib, "taskschd.lib")

// 创建计划任务
bool CreateScheduledTask(const char* taskName, const char* executablePath) {
    CoInitialize(NULL);
    
    ITaskService* pService = NULL;
    HRESULT hr = CoCreateInstance(
        CLSID_TaskScheduler,
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_ITaskService,
        (void**)&pService
    );
    
    if (FAILED(hr)) {
        CoUninitialize();
        return false;
    }
    
    hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t());
    if (FAILED(hr)) {
        pService->Release();
        CoUninitialize();
        return false;
    }
    
    ITaskFolder* pRootFolder = NULL;
    hr = pService->GetFolder(_bstr_t(L"\\"), &pRootFolder);
    if (FAILED(hr)) {
        pService->Release();
        CoUninitialize();
        return false;
    }
    
    // 创建任务定义
    ITaskDefinition* pTask = NULL;
    hr = pService->NewTask(0, &pTask);
    if (FAILED(hr)) {
        pRootFolder->Release();
        pService->Release();
        CoUninitialize();
        return false;
    }
    
    // 设置注册信息
    IRegistrationInfo* pRegInfo = NULL;
    pTask->get_RegistrationInfo(&pRegInfo);
    pRegInfo->put_Author(_bstr_t(L"System"));
    pRegInfo->Release();
    
    // 设置触发器
    ITriggerCollection* pTriggerCollection = NULL;
    pTask->get_Triggers(&pTriggerCollection);
    
    ITrigger* pTrigger = NULL;
    pTriggerCollection->Create(TASK_TRIGGER_LOGON, &pTrigger);
    pTrigger->Release();
    pTriggerCollection->Release();
    
    // 设置动作
    IActionCollection* pActionCollection = NULL;
    pTask->get_Actions(&pActionCollection);
    
    IAction* pAction = NULL;
    pActionCollection->Create(TASK_ACTION_EXEC, &pAction);
    
    IExecAction* pExecAction = NULL;
    pAction->QueryInterface(IID_IExecAction, (void**)&pExecAction);
    
    _bstr_t path(executablePath);
    pExecAction->put_Path(path);
    pExecAction->Release();
    pAction->Release();
    pActionCollection->Release();
    
    // 注册任务
    IRegisteredTask* pRegisteredTask = NULL;
    hr = pRootFolder->RegisterTaskDefinition(
        _bstr_t(taskName),
        pTask,
        TASK_CREATE_OR_UPDATE,
        _variant_t(),
        _variant_t(),
        TASK_LOGON_INTERACTIVE_TOKEN,
        _variant_t(L""),
        &pRegisteredTask
    );
    
    if (SUCCEEDED(hr)) {
        printf("[+] Scheduled task created: %s\n", taskName);
    }
    
    if (pRegisteredTask) pRegisteredTask->Release();
    pTask->Release();
    pRootFolder->Release();
    pService->Release();
    CoUninitialize();
    
    return SUCCEEDED(hr);
}

// 删除计划任务
bool DeleteScheduledTask(const char* taskName) {
    CoInitialize(NULL);
    
    ITaskService* pService = NULL;
    HRESULT hr = CoCreateInstance(
        CLSID_TaskScheduler,
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_ITaskService,
        (void**)&pService
    );
    
    if (FAILED(hr)) {
        CoUninitialize();
        return false;
    }
    
    hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t());
    if (FAILED(hr)) {
        pService->Release();
        CoUninitialize();
        return false;
    }
    
    ITaskFolder* pRootFolder = NULL;
    hr = pService->GetFolder(_bstr_t(L"\\"), &pRootFolder);
    if (FAILED(hr)) {
        pService->Release();
        CoUninitialize();
        return false;
    }
    
    hr = pRootFolder->DeleteTask(_bstr_t(taskName), 0);
    
    if (SUCCEEDED(hr)) {
        printf("[+] Scheduled task deleted: %s\n", taskName);
    }
    
    pRootFolder->Release();
    pService->Release();
    CoUninitialize();
    
    return SUCCEEDED(hr);
}

5. 统一自启动管理器

// autorun_manager.cpp
// 统一自启动管理器

#include <windows.h>
#include <stdio.h>
#include <string>
#include <vector>

// 自启动方法枚举
enum class AutorunMethod {
    RegistryCurrentUser,
    RegistryLocalMachine,
    StartupFolderCurrentUser,
    StartupFolderAllUsers,
    Service,
    ScheduledTask
};

// 自启动管理器
class AutorunManager {
private:
    std::string m_appName;
    std::string m_appPath;
    
public:
    AutorunManager(const char* appName, const char* appPath) 
        : m_appName(appName), m_appPath(appPath) {}
    
    // 添加自启动
    bool AddAutorun(AutorunMethod method) {
        switch (method) {
            case AutorunMethod::RegistryCurrentUser:
                return AddRegistryAutorun(m_appName.c_str(), m_appPath.c_str(), false);
                
            case AutorunMethod::RegistryLocalMachine:
                return AddRegistryAutorun(m_appName.c_str(), m_appPath.c_str(), true);
                
            case AutorunMethod::StartupFolderCurrentUser:
                return AddStartupFolderAutorun(m_appName.c_str(), m_appPath.c_str(), false);
                
            case AutorunMethod::StartupFolderAllUsers:
                return AddStartupFolderAutorun(m_appName.c_str(), m_appPath.c_str(), true);
                
            case AutorunMethod::Service: {
                std::string serviceName = "AutoRun_" + m_appName;
                return InstallService(serviceName.c_str(), m_appName.c_str(), m_appPath.c_str());
            }
            
            case AutorunMethod::ScheduledTask: {
                std::string taskName = "AutoRun_" + m_appName;
                return CreateScheduledTask(taskName.c_str(), m_appPath.c_str());
            }
        }
        
        return false;
    }
    
    // 移除自启动
    bool RemoveAutorun(AutorunMethod method) {
        switch (method) {
            case AutorunMethod::RegistryCurrentUser:
                return RemoveRegistryAutorun(m_appName.c_str(), false);
                
            case AutorunMethod::RegistryLocalMachine:
                return RemoveRegistryAutorun(m_appName.c_str(), true);
                
            case AutorunMethod::StartupFolderCurrentUser:
                return RemoveStartupFolderAutorun(m_appName.c_str(), false);
                
            case AutorunMethod::StartupFolderAllUsers:
                return RemoveStartupFolderAutorun(m_appName.c_str(), true);
                
            case AutorunMethod::Service: {
                std::string serviceName = "AutoRun_" + m_appName;
                return UninstallService(serviceName.c_str());
            }
            
            case AutorunMethod::ScheduledTask: {
                std::string taskName = "AutoRun_" + m_appName;
                return DeleteScheduledTask(taskName.c_str());
            }
        }
        
        return false;
    }
    
    // 列出所有自启动项
    void ListAllAutoruns() {
        printf("========================================\n");
        printf("     Autorun Items Summary              \n");
        printf("========================================\n");
        
        ListRegistryAutorun(false);  // HKCU
        ListRegistryAutorun(true);   // HKLM
        ListStartupFolder(false);    // Current User
        ListStartupFolder(true);     // All Users
        ListServices();
    }
};

// 测试函数
void TestAutorun() {
    printf("=== Autorun Test ===\n");
    
    char appPath[MAX_PATH];
    GetModuleFileNameA(NULL, appPath, MAX_PATH);
    
    AutorunManager manager("TestApp", appPath);
    
    // 测试添加自启动
    printf("[*] Adding registry autorun (current user)...\n");
    manager.AddAutorun(AutorunMethod::RegistryCurrentUser);
    
    printf("[*] Adding startup folder autorun...\n");
    manager.AddAutorun(AutorunMethod::StartupFolderCurrentUser);
    
    // 显示当前自启动项
    manager.ListAllAutoruns();
    
    // 测试移除
    printf("\n[*] Removing autorun items...\n");
    manager.RemoveAutorun(AutorunMethod::RegistryCurrentUser);
    manager.RemoveAutorun(AutorunMethod::StartupFolderCurrentUser);
    
    printf("[*] Test completed\n");
}

int main() {
    printf("========================================\n");
    printf("     Autorun Implementation Demo        \n");
    printf("========================================\n\n");
    
    TestAutorun();
    
    return 0;
}

6、课后作业

6.1、作业1:实现多方法组合自启动

设计一个能够同时使用多种方法确保自启动的机制。

6.2、作业2:添加自启动隐蔽性

实现隐藏自启动项的方法,避免被安全软件轻易发现。

6.3、作业3:实现自启动检测和清除

开发一个工具,能够检测和清除各种自启动项。