的環境變量不僅取決於從用戶SID但的SessionID太多,因爲有些變量是每個會話。
我們可以在註冊表中查看HKEY_USERS\<SID>\Volatile Environment
用戶環境變量。和SessionId
這裏存在子密鑰。下的子鍵 - 每個會話變量
所以CreateEnvironmentBlock
必須做下一個 - 獲取用戶SID從令牌,開放HKEY_USERS\<SID>\Volatile Environment
鍵,查詢它的值。
則必須查詢通過GetTokenInformation(hToken, TokenSessionId,)
和查詢Volatile Environment\SessionId
子鍵SessionId
從令牌。
但由於錯誤系統使用SessionId
從當前進程PEB而不是從它獲取它的標記。下一個代碼是在系統DLL:
WCHAR buf[MAX_PATH];
StringCchPrintfW(buf, RTL_NUMBER_OF(buf),
L"%s\\%d", L"Volatile Environment", RtlGetCurrentPeb()->SessionId);
MOV RAX,GS:[60H] // RAX - > PEB
2c0h這在PEB偏移的SessionID的
當您從服務中執行應用程序 - PEB
中的SessionId
爲0時,結果CLIENTNAME
和SESSIONNAME
未添加到環境塊中。
這是常見的系統錯誤。爲測試你可以運行兩個cmd.exe
- 一個沒有提升(執行從explorer.exe)和一個作爲管理員(執行從svchost.exe -k netsvcs),然後運行在兩個set
命令 - 它顯示環境字符串。你可以注意到在沒有提升cmd.exe
存在字符串SESSIONNAME=Console
(或SESSIONNAME=RDP-Tcp#N
如果你從rdp運行它)和,如果你在rdp,CLIENTNAME=DESKTOP-xxx
。但在提升(作爲管理員運行)cmd.exe - 沒有這個字符串。這是因爲從的svchost.exe -k netsvcs具有SessionId
== 0
用於修復被稱爲CreateEnvironmentBlock
這可以是2路:
容易,但不正確:
_PEB* peb = RtlGetCurrentPeb();
DWORD _SessionId = peb->SessionId, SessionId, rcb;
if (GetTokenInformation(hToken, TokenSessionId, &SessionId, sizeof(SessionId), &rcb))
{
peb->SessionId = SessionId;
}
PVOID Environment;
BOOL fOk = CreateEnvironmentBlock(&Environment, hToken, FALSE);
peb->SessionId = _SessionId;
想法這裏 - 臨時替代SessionId
PEB到SessionId
從令牌。這將是工作。 bu在這裏壞 - 如果另一個並行線程將使用SessionId
在PEB?
另一種方式,相對較大的代碼,但正確 - 你自己通過SessionId
子鍵和擴展環境塊。
void AddSessionEnv(HANDLE hToken, PVOID Environment, PVOID* pNewEnvironment)
{
SIZE_T cb = 1, len;
PWSTR sz = (PWSTR)Environment;
while (*sz)
{
len = wcslen(sz) + 1;
sz += len;
cb += len;
}
DWORD SessionId, rcb;
if (GetTokenInformation(hToken, TokenSessionId, &SessionId, sizeof(SessionId), &rcb))
{
PROFILEINFO pi = { sizeof(pi), PI_NOUI, L"*" };
if (LoadUserProfileW(hToken, &pi))
{
WCHAR SubKey[48];
swprintf(SubKey, L"Volatile Environment\\%d", SessionId);
HKEY hKey;
if (ERROR_SUCCESS == RegOpenKeyExW((HKEY)pi.hProfile, SubKey, 0, KEY_READ, &hKey))
{
cb *= sizeof(WCHAR);
ULONG cbNeed = 0x200, cbAllocated;
PVOID NewEnvironment;
do
{
if (NewEnvironment = LocalAlloc(0, cb + (cbAllocated = cbNeed)))
{
cbNeed = AddSessionEnv(hKey, (PWSTR)NewEnvironment, cbAllocated);
if (cbNeed && cbAllocated >= cbNeed)
{
memcpy((PBYTE)NewEnvironment + cbNeed, Environment, cb);
*pNewEnvironment = NewEnvironment;
break;
}
LocalFree(NewEnvironment);
}
} while (cbNeed);
RegCloseKey(hKey);
}
UnloadUserProfile(hToken, pi.hProfile);
}
}
}
static volatile UCHAR guz;
ULONG AddSessionEnv(HANDLE hKey, PWSTR sz, ULONG Length)
{
LONG status;
PVOID stack = alloca(guz);
ULONG TotalLength = 0, DataLength, Index = 0, cb = 0, rcb = sizeof(KEY_VALUE_FULL_INFORMATION) + 256;
union {
PVOID buf;
PKEY_VALUE_FULL_INFORMATION pkvfi;
};
do
{
do
{
if (cb < rcb) cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
if (0 <= (status = ZwEnumerateValueKey(hKey, Index, KeyValueFullInformation, buf, cb, &rcb)) &&
pkvfi->Type == REG_SZ &&
(DataLength = pkvfi->DataLength) &&
!(DataLength & (sizeof(WCHAR) - 1)))
{
static const UNICODE_STRING CharSet = { 2 * sizeof(WCHAR), 2 * sizeof(WCHAR), L"="};
USHORT NonInclusivePrefixLength;
UNICODE_STRING Name = { (USHORT)pkvfi->NameLength, Name.Length, pkvfi->Name };
// not add strings which containing 0 or `=` symbol or emply
if (Name.Length && RtlFindCharInUnicodeString(0, &Name, &CharSet, &NonInclusivePrefixLength) == STATUS_NOT_FOUND)
{
UNICODE_STRING Value = {
(USHORT)DataLength,
Value.Length,
(PWSTR)RtlOffsetToPointer(pkvfi, pkvfi->DataOffset)
};
PWSTR szEnd = (PWSTR)RtlOffsetToPointer(Value.Buffer, DataLength - sizeof(WCHAR));
if (!*szEnd) Value.Length -= sizeof(WCHAR);
// not add empty strings or containing 0 or `=` symbol
if (Value.Length && RtlFindCharInUnicodeString(0, &Value, &CharSet, &NonInclusivePrefixLength) == STATUS_NOT_FOUND)
{
ULONG cbNeed = Name.Length + 2 * sizeof(WCHAR) + Value.Length;
if (Length >= cbNeed)
{
sz += 1 + swprintf(sz, L"%wZ=%wZ", &Name, &Value), Length -= cbNeed;
}
else
{
Length = 0;
}
TotalLength += cbNeed;
}
}
}
} while (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL);
Index++;
} while (status != STATUS_NO_MORE_ENTRIES);
return TotalLength;
}
,並使用此代碼:
PVOID Environment, NewEnvironment = 0;
if (CreateEnvironmentBlock(&Environment, hToken, FALSE))
{
AddSessionEnv(hToken, Environment, &NewEnvironment);
CreateProcessAsUserW(hToken, *, CREATE_UNICODE_ENVIRONMENT,
NewEnvironment ? NewEnvironment : Environment, *);
if (NewEnvironment)
{
LocalFree(NewEnvironment);
}
DestroyEnvironmentBlock(Environment);
}
的RtlFindCharInUnicodeString
的定義,我用,對於舒適
enum {
RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END = 1,
RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET = 2,
RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE = 4
};
NTSYSAPI
NTSTATUS
NTAPI
RtlFindCharInUnicodeString(
ULONG Flags,
PCUNICODE_STRING StringToSearch,
PCUNICODE_STRING CharSet,
USHORT *NonInclusivePrefixLength
);
你叫'CreateEnvironmentBlock' - 所以有什麼問題的樣子 - 是'newEnvironment'中存在'CLIENTNAME'字符串?和'我把這個令牌轉換成一個主令牌' - 'WTSQueryUserToken'獲得主訪問令牌 - 所以沒有必要轉換 – RbMm
@RbMm我會寫一些代碼,通過'newEnvironment'數組。如果我使用'DuplicateTokenEx'將主令牌轉換爲主令牌,會造成一些傷害嗎? – wolf633
不,如果你打電話給'DuplicateTokenEx'm但是爲了你需要複製它,這將不會有什麼壞處?你可以像從WTSQueryUserToken中返回一樣使用它。你需要看'PWSTR sz =(PWSTR)lpEnvironment; \t \t \t而(* SZ) \t \t \t { \t \t \t \t DbgPrint( 「%S \ n」 個,SZ); \t \t \t \t sz + = wcslen(sz)+ 1; \t \t \t}'是'CLIENTNAME'出現。如果它沒有出現在塊中 - 它將不會出現在子進程中。如果它存在 - 可能是你不使用'CreateProcessAsUser'中的'CREATE_UNICODE_ENVIRONMENT'標誌 – RbMm