C++ 是否有CreateProcessWithTokenW'的解决方案;s cmdline参数';最大长度是多少?

C++ 是否有CreateProcessWithTokenW'的解决方案;s cmdline参数';最大长度是多少?,c++,winapi,C++,Winapi,我试图在Windows7-10上从提升的进程创建一个不提升的进程 我使用以下内容作为参考: 现在,这个方法工作得非常好,但是由于可能的遗留检查,似乎CreateProcessWithTokenW()只允许cmdline参数小于或等于1024个字符 我需要通过的cmdline远远不止此,这会导致E_INVALIDARG错误 有人遇到过和我一样的问题吗?如果是这样的话,您是如何解决这个绝对荒谬的1024个字符的限制的?对于提升(在同一会话中)的exec not提升进程,我们需要执行下一步: 通过

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

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

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

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


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

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

  • 通过从提升的令牌创建受限令牌 CreateRestrictedToken带有
    LUA\u标记
  • 在新令牌中设置中等完整性级别
  • 调用
    CreateProcessAsUser
    -注意
如果hToken是调用方主令牌的受限版本,则 SE_ASSIGNPRIMARYTOKEN_名称权限不是必需的


也许可以尝试改用
CreateProcessAsUserW()
?我知道这需要特权,但如果您的进程是以管理员身份运行的,那么有一种方法可以克服它

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

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

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

至于
CreateProcessAsUserW()
的令牌,我建议您通过
WTSQueryUserToken()
使用当前用户会话的主令牌,因为即使您这样做,它也会按预期工作。上一次我尝试使用如上所述的链接令牌,发现它无法用于OTS提升

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


我对NT安全系统一无所知。尽管如此,如果所有其他方法都失败,我想您可能会尝试一个包装器可执行文件,通过
CreateProcessWithTokenW
启动,并通过另一个不同的通道转发命令行。请改用
CreateProcessAsUser
。我发现
CreateProcessWithTokenW()
仅限于1024个字符,这很奇怪,考虑到这一点。但是,这就是文件所说的,随它去吧。如果您对正在启动的EXE的源进行控制,您可能需要考虑通过<代码> CREATPROCEDURATION…()> CreateProcessAsUser >代码> API来传递其他大数据的方法。然而,根据文章,这个非提升的代码段可以工作,它需要一个不同的特权。令牌\u权限仅允许1个权限计数。如果你知道一种拥有多重特权的方法,那就太好了appreciated@J.M-如果hToken是主叫令牌的受限版本,则不需要SE_ASSIGNPRIMARYTOKEN_NAME权限。-如果您想从自己的提升创建非提升流程-您不需要特殊权限,我将在下周回去工作时对此进行研究。非常感谢你的帮助!我会随时告诉你最新消息:非常感谢你。您的实现似乎创造了奇迹!问题,我当前的“EnumProcessId”使用EnumProcessId,只调用每个进程ID上的回调。是否真的有必要在当时运行的每个进程上调用该函数?@J.M不是每个进程。当回调返回
FALSE
时,您不必再调用它。MyEnumPowerfulTokenProc的最终目标是获得一个强大的令牌。如果令牌在那里,就没有必要再调用它了。
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;
}
#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;
}
/* 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
);