自启动技术详解
字数 1313 2025-08-09 13:33:47

Windows自启动技术详解

一、注册表自启动

1.1 注册表路径

Windows系统通过注册表实现程序自启动,主要路径包括:

用户级路径

  • HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run
  • HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce

管理员权限路径

  • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
  • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce
  • HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run

注意:在64位系统中,HKEY_LOCAL_MACHINE路径可能需要使用HKEY_LOCAL_MACHINE\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Run

1.2 实现代码

DWORD REUserRegedit(LPWSTR lpszValueName, LPWSTR lpszFileName) {
    HKEY hKey;
    
    // 尝试打开注册表键
    if (ERROR_SUCCESS != ::RegOpenKeyEx(HKEY_CURRENT_USER, 
        L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", 
        0, KEY_WRITE, &hKey)) {
        
        printf("[!] RegOpenKeyEx not found, try create keyvalue");
        
        // 如果不存在则创建
        if (ERROR_SUCCESS != ::RegCreateKeyW(HKEY_CURRENT_USER, 
            L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", 
            &hKey)) {
            printf("[!] RegCreateKeyW failed, error is : %d\n\n", GetLastError());
            return FALSE;
        } else {
            printf("[*] RegCreateKeyW successfully!\n\n");
        }
    } else {
        printf("[*] RegOpenKeyEx successfully!\n\n");
    }
    
    // 设置注册表值
    if (ERROR_SUCCESS != ::RegSetValueEx(hKey, lpszValueName, 0, REG_SZ, 
        (BYTE*)lpszFileName, (::lstrlenW(lpszFileName) + 16))) {
        ::RegCloseKey(hKey);
        printf("[!] RegSetValueEx failed, error is : %d\n\n", GetLastError());
        return FALSE;
    } else {
        printf("[*] RegSetValueEx successfully!\n\n");
    }
    
    ::RegCloseKey(hKey);
    return TRUE;
}

1.3 Run与RunOnce区别

  • Run目录下的注册表会一直存在,每次开机都会执行
  • RunOnce目录下的注册表在执行一次后会自动删除

二、快速启动目录

2.1 快速启动路径

默认路径为:
C:\Users\用户名\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup

2.2 实现代码

DWORD AutoSetup(char *lpszSrcFilePath, char *lpszDestFileName) {
    CHAR szStartupPath[MAX_PATH] = {0};
    CHAR szDestFilePath[MAX_PATH] = {0};
    
    // 获取快速启动目录
    if (FALSE == ::SHGetSpecialFolderPathA(NULL, szStartupPath, CSIDL_STARTUP, TRUE)) {
        printf("[!] Get szStartupPath failed, error is : %d\n\n", GetLastError());
        return FALSE;
    } else {
        printf("[*] The szStartupPath is : %s\n\n", szStartupPath);
    }
    
    // 拼接目标路径
    ::wsprintfA(szDestFilePath, "%s\\%s", szStartupPath, lpszDestFileName);
    
    // 复制文件到启动目录
    if (FALSE == ::CopyFileA(lpszSrcFilePath, szDestFilePath, FALSE)) {
        printf("[!] CopyFile failed, error is : %d\n\n", GetLastError());
        return FALSE;
    } else {
        printf("[*] CopyFile successfully!\n\n");
    }
    
    return TRUE;
}

三、计划任务

3.1 实现流程

  1. 初始化COM接口环境
  2. 创建任务服务实例并连接
  3. 获取根任务文件夹指针
  4. 创建任务定义对象
  5. 设置注册信息、作者信息
  6. 设置主题信息(登录类型与运行权限)
  7. 设置其他任务设置
  8. 创建执行动作(设置程序路径和参数)
  9. 创建触发器(如登录触发器)
  10. 注册计划任务

3.2 关键代码

// 初始化COM组件
HRESULT hr = ::CoInitialize(NULL);
if (FAILED(hr)) {
    printf("[!] CoInitialize failed\n\n", hr);
    return FALSE;
}

// 创建任务服务实例
hr = ::CoCreateInstance(CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER, 
    IID_ITaskService, (LPVOID*)(&m_lpITS));

// 连接到任务服务
hr = m_lpITS->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t());

// 获取根任务文件夹指针
hr = m_lpITS->GetFolder(_bstr_t("\\"), &m_lpRootFolder);

// 创建任务定义
ITaskDefinition *pTaskDefinition = NULL;
HRESULT hr = m_lpITS->NewTask(0, &pTaskDefinition);

// 设置注册信息
IRegistrationInfo *pRegInfo = NULL;
CComVariant variantAuthor(NULL);
variantAuthor = lpszAuthor;
hr = pTaskDefinition->get_RegistrationInfo(&pRegInfo);
hr = pRegInfo->put_Author(variantAuthor.bstrVal);
pRegInfo->Release();

// 设置执行动作
IActionCollection *pActionCollect = NULL;
hr = pTaskDefinition->get_Actions(&pActionCollect);
IAction *pAction = NULL;
hr = pActionCollect->Create(TASK_ACTION_EXEC, &pAction);
pActionCollect->Release();

// 设置程序路径和参数
IExecAction *pExecAction = NULL;
hr = pAction->QueryInterface(IID_IExecAction, (PVOID *)(&pExecAction));
pAction->Release();
variantProgramPath = lpszProgramPath;
variantParameters = lpszParameters;
pExecAction->put_Path(variantProgramPath.bstrVal);
pExecAction->put_Arguments(variantParameters.bstrVal);
pExecAction->Release();

// 创建触发器
ITriggerCollection *pTriggers = NULL;
hr = pTaskDefinition->get_Triggers(&pTriggers);
ITrigger *pTrigger = NULL;
hr = pTriggers->Create(TASK_TRIGGER_LOGON, &pTrigger);

// 注册计划任务
IRegisteredTask *pRegisteredTask = NULL;
CComVariant variantTaskName(NULL);
variantTaskName = lpszTaskName;
hr = m_lpRootFolder->RegisterTaskDefinition(variantTaskName.bstrVal, 
    pTaskDefinition, TASK_CREATE_OR_UPDATE, _variant_t(), _variant_t(), 
    TASK_LOGON_INTERACTIVE_TOKEN, _variant_t(""), &pRegisteredTask);

3.3 删除计划任务

BOOL CMyTaskSchedule::Delete(char *lpszTaskName) {
    if (NULL == m_lpRootFolder) {
        return FALSE;
    }
    
    CComVariant variantTaskName(NULL);
    variantTaskName = lpszTaskName;
    
    HRESULT hr = m_lpRootFolder->DeleteTask(variantTaskName.bstrVal, 0);
    if (FAILED(hr)) {
        return FALSE;
    }
    
    return TRUE;
}

四、系统服务

4.1 系统服务特点

  • 运行在session 0
  • 不同会话间相互独立,不能直接通信
  • 不能显示程序界面

4.2 服务管理操作

// 打开服务控制管理器
SC_HANDLE shOSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

// 创建服务
SC_HANDLE shCS = ::CreateServiceA(shOSCM, szName, szName,
    SERVICE_ALL_ACCESS,
    SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
    SERVICE_AUTO_START,  // 或 SERVICE_DEMAND_START 手动启动
    SERVICE_ERROR_NORMAL,
    lpszDriverPath, NULL, NULL, NULL, NULL, NULL);

// 启动服务
::StartService(shCS, 0, NULL);

// 停止服务
SERVICE_STATUS ss;
::ControlService(shCS, SERVICE_CONTROL_STOP, &ss);

// 删除服务
::DeleteService(shCS);

// 关闭句柄
::CloseServiceHandle(shCS);
::CloseServiceHandle(shOSCM);

4.3 服务程序结构

// 服务入口函数表
SERVICE_TABLE_ENTRY stDispatchTable[] = {
    {g_szServiceName, (LPSERVICE_MAIN_FUNCTION)ServiceMain},
    {NULL, NULL}
};

// 连接服务控制管理器
::StartServiceCtrlDispatcher(stDispatchTable);

// 服务主函数
void __stdcall ServiceMain(DWORD dwArgc, char *lpszArgv) {
    g_ServiceStatus.dwServiceType = SERVICE_WIN32;
    g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
    g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
    g_ServiceStatus.dwWin32ExitCode = 0;
    g_ServiceStatus.dwServiceSpecificExitCode = 0;
    g_ServiceStatus.dwCheckPoint = 0;
    g_ServiceStatus.dwWaitHint = 0;
    
    // 注册控制处理程序
    g_ServiceStatusHandle = ::RegisterServiceCtrlHandler(g_szServiceName, ServiceCtrlHandle);
    
    // 设置运行状态
    g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
    g_ServiceStatus.dwCheckPoint = 0;
    g_ServiceStatus.dwWaitHint = 0;
    ::SetServiceStatus(g_ServiceStatusHandle, &g_ServiceStatus);
    
    // 服务主循环
    while(TRUE) {
        Sleep(5000);
        DoTask();
    }
}

// 服务控制处理函数
void __stdcall ServiceCtrlHandle(DWORD dwOperateCode) {
    switch(dwOperateCode) {
        case SERVICE_CONTROL_PAUSE:  // 暂停
            g_ServiceStatus.dwCurrentState = SERVICE_PAUSED;
            break;
        case SERVICE_CONTROL_CONTINUE:  // 继续
            g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
            break;
        case SERVICE_CONTROL_STOP:  // 停止
            g_ServiceStatus.dwWin32ExitCode = 0;
            g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
            g_ServiceStatus.dwCheckPoint = 0;
            g_ServiceStatus.dwWaitHint = 0;
            ::SetServiceStatus(g_ServiceStatusHandle, &g_ServiceStatus);
            break;
        case SERVICE_CONTROL_INTERROGATE:  // 询问
            break;
        default:
            break;
    }
}

五、总结对比

自启动方式 权限要求 持久性 实现复杂度 适用场景
注册表(Run) 用户/管理员 持久 简单 常规程序自启动
注册表(RunOnce) 用户/管理员 单次 简单 安装程序、一次性任务
快速启动目录 用户 持久 最简单 用户级程序自启动
计划任务 管理员 持久 复杂 需要触发条件的自启动
系统服务 管理员 持久 最复杂 后台服务、守护进程

选择自启动方式时应根据程序的实际需求和运行环境综合考虑。

Windows自启动技术详解 一、注册表自启动 1.1 注册表路径 Windows系统通过注册表实现程序自启动,主要路径包括: 用户级路径 : HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce 管理员权限路径 : HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run 注意:在64位系统中, HKEY_LOCAL_MACHINE 路径可能需要使用 HKEY_LOCAL_MACHINE\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Run 1.2 实现代码 1.3 Run与RunOnce区别 Run 目录下的注册表会一直存在,每次开机都会执行 RunOnce 目录下的注册表在执行一次后会自动删除 二、快速启动目录 2.1 快速启动路径 默认路径为: C:\Users\用户名\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup 2.2 实现代码 三、计划任务 3.1 实现流程 初始化COM接口环境 创建任务服务实例并连接 获取根任务文件夹指针 创建任务定义对象 设置注册信息、作者信息 设置主题信息(登录类型与运行权限) 设置其他任务设置 创建执行动作(设置程序路径和参数) 创建触发器(如登录触发器) 注册计划任务 3.2 关键代码 3.3 删除计划任务 四、系统服务 4.1 系统服务特点 运行在session 0 不同会话间相互独立,不能直接通信 不能显示程序界面 4.2 服务管理操作 4.3 服务程序结构 五、总结对比 | 自启动方式 | 权限要求 | 持久性 | 实现复杂度 | 适用场景 | |------------|----------|--------|------------|----------| | 注册表(Run) | 用户/管理员 | 持久 | 简单 | 常规程序自启动 | | 注册表(RunOnce) | 用户/管理员 | 单次 | 简单 | 安装程序、一次性任务 | | 快速启动目录 | 用户 | 持久 | 最简单 | 用户级程序自启动 | | 计划任务 | 管理员 | 持久 | 复杂 | 需要触发条件的自启动 | | 系统服务 | 管理员 | 持久 | 最复杂 | 后台服务、守护进程 | 选择自启动方式时应根据程序的实际需求和运行环境综合考虑。