2013-12-09 63 views
3

我的windows应用程序可能需要某些部分的管理权限。 对于这些情况,我想要求用户输入管理员凭据,并使用下面的代码来冒充管理员:窗户的奇怪行为冒充

BOOL impersonate(LPTSTR lpszUsername, LPTSTR lpszDomain, LPTSTR lpszPassword) { 

    BOOL ret = LogonUser(lpszUsername, 
         lpszDomain, 
         lpszPassword, 
         LOGON32_LOGON_INTERACTIVE, 
         LOGON32_PROVIDER_DEFAULT, 
         &hToken); 
    if (ret != TRUE) return FALSE; 

    OutputDebugString (L"step 1"); 

    ret = ImpersonateLoggedOnUser(hToken); 
    if (ret != TRUE) return FALSE; 

    OutputDebugString(L"step 2"); 

    return IsUserAdmin() 
} 

其中函数IsUserAdmin()has been taken from MSDN,并进入如下:

BOOL IsUserAdmin(VOID) { 
    BOOL b; 
    SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; 
    PSID AdministratorsGroup; 
    b = AllocateAndInitializeSid(&NtAuthority, 
            2, 
            SECURITY_BUILTIN_DOMAIN_RID, 
            DOMAIN_ALIAS_RID_ADMINS, 
            0, 0, 0, 0, 0, 0, 
            &AdministratorsGroup); 
    if (b) { 
     if (!CheckTokenMembership(NULL, AdministratorsGroup, &b)) { 
      b = FALSE; 
     } 
     FreeSid(AdministratorsGroup); 
    } 

    return(b); 
} 

场景1:
从管理员帐户运行应用程序。

  1. 调用IsUserAdmin()=>返回TRUE(好)

  2. 电话冒充( “非管理员用户”, “域”, “密码”)=>返回FALSE(好!)

方案2:
运行从非管理员帐户的应用程序,使用从runas.exe管理员帐户。

  1. 调用IsUserAdmin()=>返回FALSE(好)

  2. 电话冒充( “管理员”, “域名”, “密码”)=>返回FALSE(不太好!)

方案3:
运行从非管理员accou应用直接 NT。

  1. 调用IsUserAdmin()=>返回FALSE(好)

  2. 电话冒充( “管理员”, “域名”, “密码”)=>返回FALSE(不太好!)

所有情况都打印step 1step 2

据我所知,上面应该有保证模拟,鉴于合法凭证。我在这里错过了什么?

+1

你说的'假冒()'返回FALSE,但你没有指明究竟是失败的。如果'LogonUser()'失败,'ImpersonateLoggedOnUser()'失败,'AllocateAndInitializeSid()'失败,或者'CheckTokenMembership()'失败,''impersonate()'有4个失败点可以返回FALSE。您需要调试您的代码并准确找出实际失败的内容。 –

回答

3

在执行需要管理员权限的任务之前,您确实不应该可编程地检查管理员权限。只需无条件地尝试任务,并让API告诉您任务是否由于权限不足而失败,如果是,那么您可以决定是否仅以失败的方式使任务失败,或者提示用户输入凭据并再次尝试任务。

如果您尝试使用UAC进行游戏,您应该做的是将您的管理代码作为单独的进程或COM对象实现,然后可以在需要时以高级状态运行该进程/ COM,而无需提升你的主流程。让操作系统在操作系统需要时提示用户输入管理员凭据(并决定该提示的外观),不要自己手动执行。

1

雷米的答案是现货,你试图做的不是你的方案的正确解决方案。但是,根据文档,您的代码应该按照预期工作。似乎有两个原因,为什么它不:

  1. 看来,违背了文件,你不能模拟在更高模拟级别比SecurityIdentification通过LogonUser获得令牌未持有SeImpersonatePrivilege。 [测试在Windows 7 SP1 64位。]

  2. 如果传递NULL的令牌和线程的模拟级别SecurityIdentificationCheckTokenMembership功能不能正常工作。 [同上]

您可以解决问题2很轻松地通过使用OpenThreadToken明确提取模拟令牌,而不是通过NULL作为标记,如下图所示。或者,您可以使用DuplicateToken复制主令牌,并将复制的令牌传递给CheckTokenMembership。如果你只想检查令牌的内容,那将是一个更有效的解决方案。

我不知道任何解决问题1的方法,除了在新的上下文中启动子进程来代表您完成工作。当然,正如雷米指出的那样,这就是你应该做的。

下面是一些代码,我在测试中使用,以供参考:

#include <Windows.h> 

#include <stdio.h> 
#include <conio.h> 

void fail(wchar_t * err) 
{ 
    DWORD dw = GetLastError(); 
    printf("%ws: %u\n", err, dw); 
    ExitProcess(1); 
} 

void impersonate(LPTSTR lpszUsername, LPTSTR lpszDomain, LPTSTR lpszPassword) 
{ 
    HANDLE hToken, hImpToken2; 
    BOOL b; 
    SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; 
    PSID AdministratorsGroup; 
    DWORD dwLen; 
    SECURITY_IMPERSONATION_LEVEL imp_level; 

    if (!LogonUser(lpszUsername, 
     lpszDomain, 
     lpszPassword, 
     LOGON32_LOGON_INTERACTIVE, 
     LOGON32_PROVIDER_DEFAULT, 
     &hToken)) fail(L"LogonUser"); 

    if (!ImpersonateLoggedOnUser(hToken)) 
     fail(L"ImpersonateLoggedOnUser"); 

    if (!OpenThreadToken(GetCurrentThread(), MAXIMUM_ALLOWED, TRUE, 
     &hImpToken2)) 
     fail(L"OpenThreadToken"); 

    if (!GetTokenInformation(hImpToken2, TokenImpersonationLevel, 
     &imp_level, sizeof(imp_level), &dwLen)) 
     fail(L"GetTokenInformation"); 

    printf("Impersonation level: %u\n", imp_level); 

    if (!AllocateAndInitializeSid(&NtAuthority, 
            2, 
            SECURITY_BUILTIN_DOMAIN_RID, 
            DOMAIN_ALIAS_RID_ADMINS, 
            0, 0, 0, 0, 0, 0, 
            &AdministratorsGroup)) 
     fail(L"AllocateAndInitializeSid"); 

    if (!CheckTokenMembership(hImpToken2, AdministratorsGroup, &b)) 
     fail(L"CheckTokenMembership"); 

    if (!b) fail(L"membership"); 
} 

int main(int argc, char ** argv) 
{ 
    wchar_t password[1024]; 
    wchar_t * ptr; 

    for (ptr = password;; ptr++) 
    { 
     *ptr = _getwch(); 
     if (*ptr == 13) break; 
    } 

    *ptr = '\0'; 

    impersonate(L"Administrator", NULL, password); 

    return 0; 
}