Windows RPC 计划任务(MS-TSCH协议)

Windows RPC 计划任务(MS-TSCH协议)

参考链接

https://github.com/Rvn0xsy/SchtaskCreator

实现目标

上一篇文章实现了自己调用自己编写的rpc接口,达到了远程调用的效果。
本篇目标尝试调用windows系统自身的rpc接口,实现在本地机器和远程机器创建计划任务

环境和文件

开发环境
    windows10
    visual studio 2019

需要建立的文件
    SchRpc.idl文件(下载链接:https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-tsch/96c9b399-c373-4490-b7f5-78ec3849444e)

第一步 编译SchRpc.idl文件




第二步 创建一个工程,使用上一步生成的文件

#include <stdio.h>
#include <taskschd.h>
#include "SchRpc.h"

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

#define MAX_LOADSTRING 2048
WCHAR szDefaultTaskXML[MAX_LOADSTRING];


void __RPC_FAR* __RPC_USER midl_user_allocate(size_t cBytes)
{
    return((void __RPC_FAR*) malloc(cBytes));
}

void __RPC_USER midl_user_free(void __RPC_FAR* p)
{
    free(p);
}

BOOL RegisterNewTask(PWCHAR username, PWCHAR password, PWCHAR domain, PWCHAR task_xml, PWCHAR ip_address, BOOL is_local, BOOL just_run) {
    RPC_STATUS status;
    RPC_WSTR StringBinding = NULL;
    RPC_BINDING_HANDLE Binding = NULL;
    PWCHAR ConnectProtocol = NULL;
    WCHAR ConnectRemoteProtocol[] = L"ncacn_ip_tcp";
    WCHAR ConnectLocalProtocol[] = L"ncalrpc";
    RPC_WSTR Hostname = NULL;
    SEC_WINNT_AUTH_IDENTITY_W Auth;

    if (lstrlenW(domain) == 0) {
        Auth.Domain = NULL;
        Auth.DomainLength = 0;
    }
    else {
        Auth.Domain = (RPC_WSTR)domain;
        Auth.DomainLength = lstrlenW(domain);
    }

    //判断是不是本地执行,组装相应的参数
    if (is_local) {
        ConnectProtocol = ConnectLocalProtocol;
    }
    else {
        ConnectProtocol = ConnectRemoteProtocol;
        Auth.User = (RPC_WSTR)username; // username
        Auth.Password = (RPC_WSTR)password; // password
        Auth.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
        Auth.UserLength = lstrlenW(username);
        Auth.PasswordLength = lstrlenW(password);
        Hostname = (RPC_WSTR)ip_address;
    }

    //1.RpcStringBindingCompose 函数创建字符串绑定句柄
    status = RpcStringBindingCompose(
        NULL,                        // Interface's GUID, will be handled by NdrClientCall
        (RPC_WSTR)ConnectProtocol,   // Protocol sequence
        Hostname,                    // Network address
        NULL,                        // Endpoint
        NULL,                        // No options here
        &StringBinding               // Output string binding
    );

    if (status != RPC_S_OK) {
        // printf("RpcStringBindingCompose failed - %x\n", status);
        return FALSE;
    }

    //2.RpcBindingFromStringBinding 函数从绑定句柄的字符串表示形式返回绑定句柄
    //  记得绑定成功的话,最后要释放绑定的句柄
    status = RpcBindingFromStringBinding(
        StringBinding,              // Previously created string binding  指向绑定句柄的字符串表示形式的指针
        &Binding                    // Output binding handle  返回指向服务器绑定句柄的指针
    );

    if (status != RPC_S_OK) {
        // printf("RpcBindingFromStringBindingA failed - %x\n", status);
        return FALSE;
    }
    // 3.如果不是本地认证,则采用网络认证获取成功的认证信息,为后续远程调用打下基础
    if (!is_local) {
        RpcTryExcept{
            //RpcBindingSetAuthInfo 函数设置绑定句柄的身份验证和授权信息(认证成功的凭证应该在Binding中)
            status = RpcBindingSetAuthInfo(
                    Binding,
                    Hostname,
                    RPC_C_AUTHN_LEVEL_DEFAULT,
                    RPC_C_AUTHN_DEFAULT,
                    &Auth,
                    NULL
                );
            if (status != RPC_S_OK)
            {
                // printf("RpcBindingSetAuthInfo failed - %d\n", status);
                return FALSE;
            }
        }
        RpcExcept(EXCEPTION_EXECUTE_HANDLER);
        {
            return FALSE;
        }
        RpcEndExcept
    }
    status = RpcStringFree(&StringBinding);  //释放句柄


    // 4.开始调用 计划任务
    RpcTryExcept
    {
        /*
         SchRpcCreateFolder  创建一个新文件夹
         HRESULT SchRpcCreateFolder(
           [in, string] const wchar_t* path,
           [in, string, unique] const wchar_t* sddl,
           [in] DWORD flags
         );
        */
        static const WCHAR Folder[] = L"\\Hello";
        SchRpcCreateFolder(Binding, Folder, NULL, 0);

        /*
        SchRpcRegisterTask 方法必须向服务器注册任务
         HRESULT SchRpcRegisterTask(
           [in, string, unique] const wchar_t* path,   句柄
           [in, string] const wchar_t* xml,   xml文件的计划任务
           [in] DWORD flags,
           [in, string, unique] const wchar_t* sddl,
           [in] DWORD logonType,
           [in] DWORD cCreds,
           [in, size_is(cCreds), unique] const TASK_USER_CRED* pCreds,
           [out, string] wchar_t** pActualPath,
           [out] PTASK_XML_ERROR_INFO* pErrorInfo
         );
        */
        static const WCHAR TaskPath[] = L"\\Hello\\TaskName";
        WCHAR* path = NULL;
        TASK_XML_ERROR_INFO* info = NULL;
        status = SchRpcRegisterTask(
            Binding,   //rpc调用多一个参数,手册中没有这个参数
            TaskPath,
            task_xml,
            TASK_CREATE | TASK_UPDATE,
            NULL,
            TASK_LOGON_NONE,
            0,
            NULL,
            &path,
            &info);

        if (status == RPC_S_OK && just_run) {
            GUID  pGuid;
            //立即运行
            status = SchRpcRun(Binding, TaskPath, NULL, NULL, TASK_RUN_IGNORE_CONSTRAINTS, NULL, NULL, &pGuid);
        }
    }
    RpcExcept(EXCEPTION_EXECUTE_HANDLER);
    {
        return FALSE;
    }
    RpcEndExcept
    {
    }

    if (status != RPC_S_OK) {
        return FALSE;
    }

    //释放绑定的句柄
    status = RpcBindingFree(&Binding);
    return TRUE;
}

int main()
{
    WCHAR szUsername[100] = L"administrator";
    WCHAR szPassword[100] = L"123456";
    WCHAR szIPAddress[100] = L"192.168.139.122";
    WCHAR szTaskXML[MAX_LOADSTRING] = L"<Task xmlns=\"http://schemas.microsoft.com/windows/2004/02/mit/task\"><RegistrationInfo><Date>2005-10-11T13:21:17-08:00</Date><Author>AuthorName</Author><Version>1.0.0</Version><Description>Notepad starts every day.</Description></RegistrationInfo><Triggers><CalendarTrigger><StartBoundary>2005-10-11T13:21:17-08:00</StartBoundary><EndBoundary>2006-01-01T00:00:00-08:00</EndBoundary><Repetition><Interval>PT1M</Interval><Duration>PT4M</Duration></Repetition><ScheduleByDay><DaysInterval>1</DaysInterval></ScheduleByDay></CalendarTrigger></Triggers><Principals><Principal id=\"LocalSystem\"><UserId>S-1-5-18</UserId><RunLevel>HighestAvailable</RunLevel></Principal></Principals><Settings><Enabled>true</Enabled><AllowStartOnDemand>true</AllowStartOnDemand><AllowHardTerminate>true</AllowHardTerminate></Settings><Actions><Exec><Command>notepad.exe</Command></Exec></Actions></Task>";
    WCHAR szDomain[100] = { 0 };
    
    // 开始本地执行(需要管理员权限)
#if 0
    if (RegisterNewTask(NULL, NULL, NULL, szTaskXML, NULL, TRUE, TRUE)) {
        printf("[*] 本地执行计划任务  ==>  立即执行成功");
    }
#endif // 0


#if 1
    //远程执行
    if (RegisterNewTask(szUsername, szPassword, szDomain, szTaskXML, szIPAddress, FALSE, TRUE)) {
        printf("[*] 远程执行计划任务  ==>  立即执行成功");
    }
#endif // 0

    return 0;
}

本地和远程执行效果

posted @ 2022-11-27 20:28  是谁走漏了消息  阅读(865)  评论(0编辑  收藏  举报