我想在我的项目中使用模拟来正确地在服务中运行它。
我看到一些代码执行类似的操作:
获取explorer.exe
PID,然后OpenProcess
获取该PID和DuplicateTokenEx
之后,代码CreateThread
然后SetThreadToken
和ResumeThread
这是代码:
HANDLE ExplorerToken(VOID)
{
PROCESSENTRY32W procEntry;
HANDLE Snap = NULL;
HANDLE Process = NULL;
HANDLE PToken = NULL;
LPCWSTR TProce = L"explorer.exe";
DWORD TargetSID = -1;
DWORD SId = -1;
DWORD TargetPID = -1;
BOOL WellDone = TRUE;
HANDLE ExplorerToken = NULL;
if(ExplorerToken != NULL)
{
return ExplorerToken;
}
SId = WTSGetActiveConsoleSessionId();
procEntry.dwSize = sizeof(PROCESSENTRY32W);
Snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (!Process32FirstW(Snap, &procEntry))
{
WellDone = FALSE;
}
do
{
if (lstrcmpiW(procEntry.szExeFile, TProce) == 0)
{
if (ProcessIdToSessionId(procEntry.th32ProcessID, &TargetSID) && TargetSID == SId)
{
TargetPID = procEntry.th32ProcessID;
break;
}
}
} while (Process32NextW(Snap, &procEntry));
if(TargetPID == -1)
{
WellDone = FALSE;
}
Process = OpenProcess(MAXIMUM_ALLOWED, FALSE, TargetPID);
if(!OpenProcessToken(Process, MAXIMUM_ALLOWED, &PToken))
{
WellDone = FALSE;
}
if(!DuplicateTokenEx(PToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenImpersonation, &ExplorerToken))
{
WellDone = FALSE;
}
if(WellDone == FALSE)
{
return NULL;
}
else
{
return ExplorerToken;
}
}
VOID CcCryptUnprotectData(LPVOID data)
{
PCUD_PARAMS pCudParams;
pCudParams = (PCUD_PARAMS)data;
pCudParams->bRetVal = pCudParams->fp_CryptUnprotectData(
pCudParams->pDataIn,
pCudParams->ppszDataDescr,
pCudParams->pOptionalEntropy,
pCudParams->pvReserved,
pCudParams->pPromptStruct,
pCudParams->dwFlags,
pCudParams->pDataOut);
}
BOOL _CryptUnprotectData(__in DATA_BLOB *pDataIn, __out_opt LPWSTR *ppszDataDescr, __in_opt DATA_BLOB *pOptionalEntropy,
__in PVOID pvReserved, __in_opt CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct, __in DWORD dwFlags, __out DATA_BLOB *pDataOut )
{
HANDLE ThreadHandle;
CUD_PARAMS cudParams;
DWORD ThreadIdArray = 0;
HMODULE hmCrypt32 = NULL;
HANDLE ExplorerToken;
cudParams.pDataIn = pDataIn;
cudParams.ppszDataDescr = ppszDataDescr;
cudParams.pOptionalEntropy = pOptionalEntropy;
cudParams.pvReserved = pvReserved;
cudParams.pPromptStruct = pPromptStruct;
cudParams.dwFlags = dwFlags;
cudParams.pDataOut = pDataOut;
cudParams.bRetVal = FALSE;
if(MyCryptUnprotectData_OutlookPassword == NULL)
{
if(hmCrypt32 == NULL)
{
hmCrypt32 = LoadLibraryW(L"Crypt32.dll");
}
MyCryptUnprotectData_OutlookPassword = (BOOL (WINAPI* )(DATA_BLOB *pDataIn, LPWSTR *ppszDataDescr, DATA_BLOB *pOptionalEntropy, PVOID pvReserved, CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct, DWORD dwFlags, DATA_BLOB *pDataOut))GetProcAddress(hmCrypt32, "CryptUnprotectData");
}
cudParams.fp_CryptUnprotectData = MyCryptUnprotectData_OutlookPassword;
ExplorerToken = ExplorerToken();
if(ExplorerToken == NULL)
{
return FALSE;
}
ThreadHandle = CreateThread(NULL,
0, // use default stack size
(LPTHREAD_START_ROUTINE)CcCryptUnprotectData, // thread function name
(LPVOID)&cudParams, // argument to thread function
CREATE_SUSPENDED,
&ThreadIdArray);
if(ThreadHandle == NULL)
{
return FALSE;
}
if(!SetThreadToken(&ThreadHandle, ExplorerToken))
{
return FALSE;
}
ResumeThread(ThreadHandle);
WaitForSingleObject(ThreadHandle, INFINITE);
return cudParams.bRetVal;
}
我使用此代码并完成我的工作,现在我想让用户返回状态,他们在模仿之前
我知道我应该在SetThreadToken
之前保留句柄,然后在我完成工作之后,再次SetThreadToken
使用保留的令牌。
现在我希望你能帮助我做到这一点。
答案 0 :(得分:2)
获取explorer.exe PID,然后使用该PID和DuplicateTokenEx
获取OpenProcess
这是获取会话用户令牌的非常旧(Win9x)方法。由于您已经在使用WTS API,因此请使用import { Directive, Attribute, ViewContainerRef, DynamicComponentLoader } from '@angular/core';
import { Router, Routes, RouterOutletMap } from '@angular/router';
import { RouterOutlet } from '@angular/router/src/directives/router_outlet';
@Directive({
selector: 'router-outlet'
})
export class RouterOutletDirective extends RouterOutlet {
constructor(parentOutletMap: RouterOutletMap, _location: ViewContainerRef, name: string) {
super(parentOutletMap, _location, name);
console.log( parentOutletMap );
}
activate() {
console.log('Activate');
}
}
,并将其传递给您要模拟的会话ID。
之后,代码CreateThread,然后是SetThreadToken和ResumeThread。
另一种选择是将用户令牌传递给WTSQueryUserToken()
lpParameter
中的线程,然后线程可以在开始运行后调用ImpersonateLoggedOnUser()
。
我使用此代码并完成我的工作,现在我想将用户返回到状态,他们在模仿之前
如果一个线程需要在终止之前停止模拟,它应该调用RevertToSelf()
。如果模拟应该持续到线程终止,则无需手动停止模拟。
我知道我应该在SetThreadToken之前保留句柄,然后在我完成我的工作之后,再次使用保留的令牌设置SetThreadToken。
如果线程已经模仿一个用户,然后需要停止模拟或冒充其他用户,那么这很有用,之后需要再次冒充第一个用户。但是你的例子并没有这样做。
现在,话虽如此,你的CreateThread()
函数正在泄漏线程对象,因为它在_CryptUnprotectData()
完成后没有调用CloseHandle()
。但更重要的是,创建新线程然后使调用线程阻塞直到新线程终止是浪费的开销。调用线程也可以直接完成工作。在您的示例中,WaitForSingleObject()
可以完全省略_CryptUnprotectData()
,只需直接致电CreateThread()
,即可调用fp_CryptUnprotectData()
/ ImpersonateLoggedOnUser()
。您不需要创建新线程只是为了使用模拟。