如何将用户返回到状态,他们是在冒充之前?

时间:2016-06-05 08:58:04

标签: c++ service impersonation

我想在我的项目中使用模拟来正确地在服务中运行它。

我看到一些代码执行类似的操作:

获取explorer.exe PID,然后OpenProcess获取该PID和DuplicateTokenEx

之后,代码CreateThread然后SetThreadTokenResumeThread

这是代码:

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使用保留的令牌。

现在我希望你能帮助我做到这一点。

1 个答案:

答案 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()。您不需要创建新线程只是为了使用模拟。