C++ 是否有CreateProcessWithTokenW'的解决方案;s cmdline参数';最大长度是多少?
我试图在Windows7-10上从提升的进程创建一个不提升的进程 我使用以下内容作为参考: 现在,这个方法工作得非常好,但是由于可能的遗留检查,似乎C++ 是否有CreateProcessWithTokenW'的解决方案;s cmdline参数';最大长度是多少?,c++,winapi,C++,Winapi,我试图在Windows7-10上从提升的进程创建一个不提升的进程 我使用以下内容作为参考: 现在,这个方法工作得非常好,但是由于可能的遗留检查,似乎CreateProcessWithTokenW()只允许cmdline参数小于或等于1024个字符 我需要通过的cmdline远远不止此,这会导致E_INVALIDARG错误 有人遇到过和我一样的问题吗?如果是这样的话,您是如何解决这个绝对荒谬的1024个字符的限制的?对于提升(在同一会话中)的exec not提升进程,我们需要执行下一步: 通过
CreateProcessWithTokenW()
只允许cmdline
参数小于或等于1024个字符
我需要通过的cmdline
远远不止此,这会导致E_INVALIDARG
错误
有人遇到过和我一样的问题吗?如果是这样的话,您是如何解决这个绝对荒谬的1024个字符的限制的?对于提升(在同一会话中)的exec not提升进程,我们需要执行下一步:
- 通过从提升的令牌创建受限令牌
CreateRestrictedToken带有
LUA\u标记
- 在新令牌中设置中等完整性级别
- 调用
-注意CreateProcessAsUser
也许可以尝试改用
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
);