首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >CreateProcessWithTokenW的cmdline参数的最大长度有解决办法吗?

CreateProcessWithTokenW的cmdline参数的最大长度有解决办法吗?
EN

Stack Overflow用户
提问于 2017-06-29 19:14:35
回答 2查看 1.3K关注 0票数 1

我试图从Windows7-10上的提升进程创建一个未提升的进程。

我使用以下内容作为参考:

FAQ:我如何从一个提升的应用程序作为桌面用户启动一个程序?

现在,这个方法工作得很好,但是由于可能的遗留检查,看来CreateProcessWithTokenW()只允许cmdline参数小于或等于1024个字符。

我需要通过的cmdline远不止此,这会导致E_INVALIDARG错误。

有没有人遇到过和我一样的问题?如果是这样的话,你是如何解决这个绝对荒谬的1024字符限制的?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-12-23 08:10:49

也许试着用CreateProcessAsUserW()代替?我知道它需要特殊的特权,但是如果您的进程是作为管理员运行的,那么有一种方法可以克服它。

其想法是在调用API之前模拟一个强大的令牌。强大的令牌被定义为,一个拥有所有需要的特权的令牌,

首先,通过API (如NtQuerySystemInformation() )枚举进程ID。对于每个进程ID,打开进程令牌并使用GetTokenInformation(hToken, TokenPrivileges, ...)获取令牌拥有哪些特权的信息。如果令牌拥有我们想要的所有特权,我们可以通过DuplicateTokenEx(..., TokenImpersonation, &hTokenImp)从它复制一个模拟令牌(当然也停止枚举)。

现在我们有了强大的令牌,我们将检查它所需的特权,查看它们是否都启用了。使用PrivilegeCheck()检查状态,并用AdjustTokenPrivileges()启用状态。最后,让当前线程通过SetThreadToken(NULL, hTokenImp)模拟令牌,任意调用CreateProcessAsUserW(),并通过SetThreadToken(NULL, NULL)停止模拟。

至于CreateProcessAsUserW()的令牌,我建议您通过WTSQueryUserToken()使用当前用户会话的主令牌,因为即使您执行OTS高程,它也会按预期工作。上一次,我尝试使用这里描述的链接令牌,发现它不适用于OTS提升。

这里是ANSI C中的一个测试代码,当作为管理员运行时,它将运行另一个自身的实例,并且显示命令行的长度。是的,CreateProcessAsUserW()支持超过1024的命令行.:)

代码语言:javascript
复制
#include <stdio.h>
#include <Windows.h>
#include <objbase.h>
#include "EnumProcessesId.h"

#define MY_LuidEqual(a, b)  \
    ( ((a)->HighPart == (b)->HighPart) && ((a)->LowPart == (b)->LowPart) )

static LPVOID MyAllocZero(SIZE_T cb)
{
    LPVOID ptr = CoTaskMemAlloc(cb);
    if (ptr) { ZeroMemory(ptr, cb); }
    return ptr;
}
static void MyFree(LPVOID ptr)
{
    CoTaskMemFree(ptr);
}

static DWORD MyWTSGetActiveConsoleSessionId(void)
{
    typedef DWORD(WINAPI *fn_t)(void);
    fn_t fn = (fn_t)GetProcAddress(LoadLibraryA("kernel32"),
        "WTSGetActiveConsoleSessionId");
    if (fn) { return fn(); }
    return 0;
}

static BOOL MyWTSQueryUserToken(DWORD sessId, HANDLE *phToken)
{
    typedef BOOL(WINAPI *fn_t)(DWORD, HANDLE*);
    fn_t fn = (fn_t)GetProcAddress(LoadLibraryA("wtsapi32"),
        "WTSQueryUserToken");
    if (fn) {
        return fn(sessId, phToken);
    }
    return FALSE;
}

static BOOL MyPrivIsEnabled(HANDLE hToken, LUID const *pPrivLuid)
{
    BOOL isEnabled = FALSE;
    PRIVILEGE_SET ps = { 0 };
    ps.PrivilegeCount = 1;
    ps.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT;
    PrivilegeCheck(hToken, &ps, &isEnabled);
    if (!isEnabled) {
        ps.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
        PrivilegeCheck(hToken, &ps, &isEnabled);
    }
    return isEnabled;
}

static HRESULT MyEnablePriv(HANDLE hToken, LUID const *pPrivLuid, BOOL enable)
{
    BOOL ok = FALSE;
    TOKEN_PRIVILEGES tp = { 0 };
    tp.PrivilegeCount = 1;
    tp.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0;
    tp.Privileges[0].Luid = *pPrivLuid;
    ok = AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
    return ok ? S_OK : HRESULT_FROM_WIN32(GetLastError());
}

typedef struct {
    /* in : */
    LUID const *pLuidAPT;
    LUID const *pLuidIQN;
    LUID const *pLuidTCB;
    /* out : */
    HANDLE hptPowerful;
} MyEnumPowerfulTokenData_t;

static BOOL CALLBACK MyEnumPowerfulTokenProc(DWORD pid, void * user)
{
    DWORD const ProcessQueryLimitedInfo = 0x1000;
    MyEnumPowerfulTokenData_t *pData = user;
    BOOL ok = FALSE, wantContinue = TRUE;
    HANDLE hProc = NULL;
    HANDLE hProcToken = NULL;
    DWORD i = 0, cbTP = 0;
    TOKEN_PRIVILEGES *pTP = NULL;
    BOOL gotAPT = FALSE, gotIQN = FALSE, gotTCB = FALSE;

    /* Get process token */
    hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
    if (!hProc) {
        hProc = OpenProcess(ProcessQueryLimitedInfo, FALSE, pid);
    }
    if (!hProc) goto eof;
    ok = OpenProcessToken(hProc, TOKEN_QUERY | TOKEN_DUPLICATE, &hProcToken);
    if (!ok) goto eof;

    /* Check if token possesses desired privileges */
    GetTokenInformation(hProcToken, TokenPrivileges, NULL, 0, &cbTP);
    if (!cbTP) goto eof;
    pTP = MyAllocZero(cbTP);
    if (!pTP) goto eof;
    ok = GetTokenInformation(hProcToken, TokenPrivileges, pTP, cbTP, &cbTP);
    if (!ok) goto eof;
    for (i = 0; i < pTP->PrivilegeCount; ++i)
    {
        LUID const *pThat = &(pTP->Privileges[i].Luid);
        if (gotAPT && gotIQN && gotTCB) {
            wantContinue = FALSE;
            pData->hptPowerful = hProcToken;
            hProcToken = NULL; /* to avoid eof CloseHandle() */
            break;
        }
        else if (!gotAPT && MY_LuidEqual(pThat, pData->pLuidAPT)) {
            gotAPT = TRUE;
        }
        else if (!gotIQN && MY_LuidEqual(pThat, pData->pLuidIQN)) {
            gotIQN = TRUE;
        }
        else if (!gotTCB && MY_LuidEqual(pThat, pData->pLuidTCB)) {
            gotTCB = TRUE;
        }
    }
eof:
    if (pTP) { MyFree(pTP); }
    if (hProcToken) { CloseHandle(hProcToken); }
    if (hProc) { CloseHandle(hProc); }
    return wantContinue;
}

static HRESULT MyCreateProcess(LPWSTR szCmdLine)
{
    HRESULT hr = 0;
    BOOL ok = FALSE;
    LUID luidAPT = { 0 }; /* SE_ASSIGNPRIMARYTOKEN_NAME */
    LUID luidIQN = { 0 }; /* SE_INCREASE_QUOTA_NAME */
    LUID luidTCB = { 0 }; /* SE_TCB_NAME */
    MyEnumPowerfulTokenData_t enumData = { 0 };
    HANDLE hptPowerful = NULL; /* primary/process token */
    HANDLE hitPowerful = NULL; /* impersonation token */
    HANDLE hptCurrSessUser = NULL;
    DWORD dwCurrSessId = 0;
    STARTUPINFOW si = { sizeof(si) };
    PROCESS_INFORMATION pi = { 0 };

    ok = LookupPrivilegeValue(NULL, SE_ASSIGNPRIMARYTOKEN_NAME, &luidAPT)
        && LookupPrivilegeValue(NULL, SE_INCREASE_QUOTA_NAME, &luidIQN)
        && LookupPrivilegeValue(NULL, SE_TCB_NAME, &luidTCB);
    if (!ok) {
        hr = HRESULT_FROM_WIN32(GetLastError()); goto eof;
    }
    enumData.pLuidAPT = &luidAPT;
    enumData.pLuidIQN = &luidIQN;
    enumData.pLuidTCB = &luidTCB;
    hr = EnumProcessesId_WinNT(MyEnumPowerfulTokenProc, &enumData);
    if (FAILED(hr)) goto eof;
    hptPowerful = enumData.hptPowerful;
    if (!hptPowerful) {
        hr = E_UNEXPECTED; goto eof;
    }

    ok = DuplicateTokenEx(hptPowerful, TOKEN_ADJUST_PRIVILEGES | TOKEN_IMPERSONATE,
        NULL, SecurityImpersonation, TokenImpersonation, &hitPowerful);
    if (!ok) {
        hr = HRESULT_FROM_WIN32(GetLastError()); goto eof;
    }
    if (!MyPrivIsEnabled(hitPowerful, &luidAPT))
    {
        hr = MyEnablePriv(hitPowerful, &luidAPT, TRUE);
        if (FAILED(hr)) goto eof;
    }
    if (!MyPrivIsEnabled(hitPowerful, &luidIQN))
    {
        hr = MyEnablePriv(hitPowerful, &luidIQN, TRUE);
        if (FAILED(hr)) goto eof;
    }
    if (!MyPrivIsEnabled(hitPowerful, &luidTCB))
    {
        hr = MyEnablePriv(hitPowerful, &luidTCB, TRUE);
        if (FAILED(hr)) goto eof;
    }
    ok = SetThreadToken(NULL, hitPowerful);
    if (!ok) {
        hr = HRESULT_FROM_WIN32(GetLastError()); goto eof;
    }

    dwCurrSessId = MyWTSGetActiveConsoleSessionId();
    ok = MyWTSQueryUserToken(dwCurrSessId, &hptCurrSessUser);
    if (!ok) {
        hr = HRESULT_FROM_WIN32(GetLastError()); goto eof;
    }
    ok = CreateProcessAsUserW(hptCurrSessUser, NULL, szCmdLine, 0, 0, 0, 0, 0, 0, &si, &pi);
    if (!ok) {
        hr = HRESULT_FROM_WIN32(GetLastError()); goto eof;
    }

eof:
    SetThreadToken(NULL, NULL);
    if (hptCurrSessUser) { CloseHandle(hptCurrSessUser); }
    if (hitPowerful) { CloseHandle(hitPowerful); }
    if (hptPowerful) { CloseHandle(hptPowerful); }
    if (FAILED(hr)) {
        printf("HRESULT = 0x%.8X \n", hr);
    }
    return 0;
}

int main(int argc, char **argv)
{
    if (argc > 1)
    {
        WCHAR szMsg[999] = {0};
        wsprintfW(szMsg,
            L"lstrlenW(GetCommandLineW()) = %i \n",
            lstrlenW(GetCommandLineW()));
        MessageBoxW(NULL, szMsg, L"Test", MB_ICONINFORMATION);
    }
    else
    {
        WCHAR szMyExePath[MAX_PATH] = {0};
        WCHAR szCmdLine[9999] = {0}, *p;
        GetModuleFileNameW(NULL, szMyExePath, MAX_PATH);
        wsprintfW(szCmdLine, L"\"%s\" ", szMyExePath);
        for (p = szCmdLine; *p; ++p);
        while (p < (szCmdLine + 9999 - 1))
        {
            *p++ = 'a';
        }
        MyCreateProcess(szCmdLine);
    }
    return 0;
}

我将把EnumProcessesId_WinNT()的实现留给您。该功能的原型是:

代码语言:javascript
复制
/* return TRUE to continue */
typedef BOOL(CALLBACK *EnumProcessesId_Callback_t)
    (DWORD pid, void * user);

EXTERN_C
HRESULT __stdcall
EnumProcessesId_WinNT(
    EnumProcessesId_Callback_t fnCallback,
    void *user
);
票数 0
EN

Stack Overflow用户

发布于 2017-06-30 19:36:15

对于执行从我们的提升(在同一会话中)提升的进程,我们需要做下一步:

  • 使用CreateRestrictedToken和LUA_TOKEN从我们的提升令牌创建受限令牌
  • 在新令牌中设置中等干扰级别
  • 呼叫CreateProcessAsUser -注意

如果hToken是调用方主令牌的受限版本,则不需要SE_ASSIGNPRIMARYTOKEN_NAME特权。

代码语言:javascript
复制
ULONG LowExec(PCWSTR lpApplicationName, PWSTR lpCommandLine)
{
    HANDLE hToken, hLowToken;

    ULONG cb = GetSidLengthRequired(1);

    TOKEN_MANDATORY_LABEL tml = { { (PSID)alloca(cb) } };

    ULONG dwError = NOERROR;

    if (CreateWellKnownSid(WinMediumLabelSid, 0, tml.Label.Sid, &cb) &&
        OpenProcessToken(NtCurrentProcess(), TOKEN_DUPLICATE | TOKEN_QUERY | 
        TOKEN_ADJUST_DEFAULT | TOKEN_ASSIGN_PRIMARY, &hToken))
    {
        BOOL fOk = CreateRestrictedToken(hToken, LUA_TOKEN, 0, 0, 0, 0, 0, 0, &hLowToken);

        if (!fOk)
        {
            dwError = GetLastError();
        }

        CloseHandle(hToken);

        if (fOk)
        {
            if (SetTokenInformation(hLowToken, ::TokenIntegrityLevel, &tml, sizeof(tml)))
            {
                STARTUPINFOW si = { sizeof(si)};
                PROCESS_INFORMATION pi;

                if (CreateProcessAsUser(hLowToken, lpApplicationName, lpCommandLine, 0, 0, TRUE, 0, 0, 0, &si, &pi))
                {
                    CloseHandle(pi.hThread);
                    CloseHandle(pi.hProcess);
                }
                else
                {
                    dwError = GetLastError();
                }
            }
            else
            {
                dwError = GetLastError();
            }

            CloseHandle(hLowToken);
        }
    }
    else
    {
        dwError = GetLastError();
    }

    return dwError;
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44833235

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档