2017-08-28 28 views
1

我有一個提升的過程,在用戶在UAC對話框中回答「是」後啓動。我該如何「解除」一個過程

該過程開始正常,一切按預期工作。

現在我需要在某個時候「解除」該進程,換句話說,進程應該不會像用戶正常啓動一樣提升。

示例場景

  • 用戶A登錄
  • 用戶A啓動過程P1,這將經由UAC
  • 高架過程P1 lauchches過程P2和P2 should'nt得以升高和升高應該在用戶A下再次運行。

有沒有辦法做到這一點?

+3

下運行「不升高」的過程不能在過程開始後改變進程的令牌。你可以做的是從你的升級過程中啓動一個新的升級過程。請參閱https://blogs.msdn.microsoft.com/oldnewthing/20131118-00/?p=2643和http://blogs.microsoft.co.il/sasha/2009/07/09/launch-a-process-作爲標準的用戶從 - 一個升高的過程/ –

+1

[本鏈接(https://blogs.msdn.microsoft.com/aaron_margosis/2009/06/06/faq-how-do-i-start-一個程序作爲桌面用戶從一個高架應用程序/)也是非常有用的。 –

+1

請參閱[此問題](https://stackoverflow.com/q/37948064/7571258)如何從高架創建未升級的過程。答案使用'IShellDispatch2'來完成。該工作原理類似的另一種方法是使用'CreateProcessWithTokenW'爲[在外殼的環境中創建一個新的進程(https://www.codeproject.com/Tips/23090/Creating-a-Process-with-Medium)。這可以更好地控制過程的創建方式。 – zett42

回答

3

高架進程已鏈接令牌 - 它指的是非高架用戶會話。

第一種方式:我們可以通過兩種方式使用此鏈接的標記

  1. 把它作爲TokenPrimary(對於這一點,我們需要有SE_TCB_PRIVILEGE 當我們查詢這個令牌)本
  2. 調用CreateProcessAsUser令牌。爲此,我們還需要 SE_ASSIGNPRIMARYTOKEN_PRIVILEGESE_INCREASE_QUOTA_PRIVILEGE
  3. 爲得到這一切的特權 - 枚舉進程,查詢它令牌, 如果進程令牌擁有這一切的特權3 - 模仿與 它,通話CreateProcessAsUser之前。因爲提升令牌有 SE_DEBUG_PRIVILEGE任務可能

第二種方式:

  1. 查詢從鏈接的標記登錄會話ID(從TOKEN_STATISTICSAuthenticationId

  2. 發現過程與流程令牌中的AuthenticationId相同。

  3. 使用此過程父進程的幫助 PROC_THREAD_ATTRIBUTE_PARENT_PROCESS

實施方式1:

static volatile UCHAR guz; 

ULONG RunNonElevated(HANDLE hToken, HANDLE hMyToken, PCWSTR lpApplicationName, PWSTR lpCommandLine) 
{ 
    ULONG err; 

    PVOID stack = alloca(guz); 

    ULONG cb = 0, rcb = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[SE_MAX_WELL_KNOWN_PRIVILEGE]); 

    union { 
     PVOID buf; 
     PTOKEN_PRIVILEGES ptp; 
    }; 

    do 
    { 
     if (cb < rcb) 
     { 
      cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack); 
     } 

     if (GetTokenInformation(hToken, TokenPrivileges, buf, cb, &rcb)) 
     { 
      if (ULONG PrivilegeCount = ptp->PrivilegeCount) 
      { 
       int n = 3; 
       BOOL fAdjust = FALSE; 

       PLUID_AND_ATTRIBUTES Privileges = ptp->Privileges; 
       do 
       { 
        switch (Privileges->Luid.LowPart) 
        { 
        case SE_ASSIGNPRIMARYTOKEN_PRIVILEGE: 
        case SE_INCREASE_QUOTA_PRIVILEGE: 
        case SE_TCB_PRIVILEGE: 
         if (!(Privileges->Attributes & SE_PRIVILEGE_ENABLED)) 
         { 
          Privileges->Attributes |= SE_PRIVILEGE_ENABLED; 
          fAdjust = TRUE; 
         } 

         if (!--n) 
         { 
          err = NOERROR; 

          if (DuplicateTokenEx(hToken, 
           TOKEN_ADJUST_PRIVILEGES|TOKEN_IMPERSONATE, 
           0, SecurityImpersonation, TokenImpersonation, 
           &hToken)) 
          { 
           if (fAdjust) 
           { 
            AdjustTokenPrivileges(hToken, FALSE, ptp, rcb, NULL, NULL); 
            err = GetLastError(); 
           } 

           if (err == NOERROR) 
           { 
            if (SetThreadToken(0, hToken)) 
            { 
             TOKEN_LINKED_TOKEN tlt; 
             if (GetTokenInformation(hMyToken, TokenLinkedToken, &tlt, sizeof(tlt), &rcb)) 
             { 
              STARTUPINFO si = { sizeof (si) }; 
              PROCESS_INFORMATION pi; 

              if (!CreateProcessAsUserW(tlt.LinkedToken, lpApplicationName, lpCommandLine, 
               NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) 
              { 
               err = GetLastError(); 
              } 

              CloseHandle(tlt.LinkedToken); 

              if (err == NOERROR) 
              { 
               CloseHandle(pi.hThread); 
               CloseHandle(pi.hProcess); 
              } 
             } 
             else 
             { 
              err = GetLastError(); 
             } 
             SetThreadToken(0, 0); 
            } 
            else 
            { 
             err = GetLastError(); 
            } 
           } 

           CloseHandle(hToken); 
          } 
          else 
          { 
           err = GetLastError(); 
          } 

          return err; 
         } 
        } 
       } while (Privileges++, --PrivilegeCount); 
      } 

      return ERROR_NOT_FOUND; 
     } 

    } while ((err = GetLastError()) == ERROR_INSUFFICIENT_BUFFER); 

    return err; 
} 

ULONG RunNonElevated(HANDLE hMyToken, PCWSTR lpApplicationName, PWSTR lpCommandLine) 
{ 
    static TOKEN_PRIVILEGES tp = { 
     1, { { { SE_DEBUG_PRIVILEGE } , SE_PRIVILEGE_ENABLED } } 
    }; 

    AdjustTokenPrivileges(hMyToken, FALSE, &tp, sizeof(tp), NULL, NULL); 

    ULONG err = NOERROR; 

    // much more effective of course use NtQuerySystemInformation(SystemProcessesAndThreadsInformation) here 
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0), hToken; 

    if (hSnapshot != INVALID_HANDLE_VALUE) 
    { 
     PROCESSENTRY32W pe = { sizeof(pe) }; 

     if (Process32FirstW(hSnapshot, &pe)) 
     { 
      err = ERROR_NOT_FOUND; 

      do 
      { 
       if (pe.th32ProcessID && pe.th32ParentProcessID) 
       { 
        if (HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pe.th32ProcessID)) 
        { 
         if (OpenProcessToken(hProcess, TOKEN_QUERY|TOKEN_DUPLICATE, &hToken)) 
         { 
          err = RunNonElevated(hToken, hMyToken, lpApplicationName, lpCommandLine); 
          CloseHandle(hToken); 
         } 
         else 
         { 
          err = GetLastError(); 
         } 
         CloseHandle(hProcess); 
        } 
        else 
        { 
         err = GetLastError(); 
        } 
       } 
      } while (err && Process32NextW(hSnapshot, &pe)); 
     } 
     else 
     { 
      err = GetLastError(); 
     } 
     CloseHandle(hSnapshot); 
    } 

    return err; 
} 

ULONG RunNonElevated(PCWSTR lpApplicationName, PWSTR lpCommandLine) 
{ 
    HANDLE hToken; 

    ULONG err = NOERROR; 

    if (OpenProcessToken(NtCurrentProcess(), TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES, &hToken)) 
    { 
     TOKEN_ELEVATION_TYPE tet; 

     ULONG rcb; 

     if (GetTokenInformation(hToken, ::TokenElevationType, &tet, sizeof(tet), &rcb)) 
     { 
      if (tet == TokenElevationTypeFull) 
      { 
       RunNonElevated(hToken, lpApplicationName, lpCommandLine); 
      } 
      else 
      { 
       err = ERROR_ALREADY_ASSIGNED; 
      } 
     } 
     else 
     { 
      err = GetLastError(); 
     } 

     CloseHandle(hToken); 
    } 
    else 
    { 
     err = GetLastError(); 
    } 

    return err; 
} 

實施方式2:

ULONG CreateProcessEx(HANDLE hProcess, 
         PCWSTR lpApplicationName, 
         PWSTR lpCommandLine) 
{ 

    SIZE_T Size = 0; 

    STARTUPINFOEX si = { sizeof(si) }; 
    PROCESS_INFORMATION pi; 

    InitializeProcThreadAttributeList(0, 1, 0, &Size); 

    ULONG err = GetLastError(); 

    if (err = ERROR_INSUFFICIENT_BUFFER) 
    { 
     si.lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)alloca(Size); 

     if (InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &Size)) 
     { 
      if (UpdateProcThreadAttribute(si.lpAttributeList, 0, 
       PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &hProcess, sizeof(hProcess), 0, 0) && 
       CreateProcessW(lpApplicationName, lpCommandLine, 0, 0, 0, 
       EXTENDED_STARTUPINFO_PRESENT, 0, 0, &si.StartupInfo, &pi)) 
      { 
       CloseHandle(pi.hThread); 
       CloseHandle(pi.hProcess); 
      } 
      else 
      { 
       err = GetLastError(); 
      } 

      DeleteProcThreadAttributeList(si.lpAttributeList); 
     } 
     else 
     { 
      err = GetLastError(); 
     } 
    } 
    else 
    { 
     err = GetLastError(); 
    } 

    return err; 
} 

ULONG CreateProcessEx(LUID AuthenticationId, 
         PCWSTR lpApplicationName, 
         PWSTR lpCommandLine) 
{ 
    ULONG err = ERROR_NOT_FOUND; 

    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 

    if (hSnapshot != INVALID_HANDLE_VALUE) 
    { 
     PROCESSENTRY32W pe = { sizeof(pe) }; 

     ULONG rcb; 

     if (Process32First(hSnapshot, &pe)) 
     { 
      err = ERROR_NOT_FOUND; 
      BOOL found = FALSE; 

      do 
      { 
       if (pe.th32ProcessID && pe.th32ParentProcessID) 
       { 
        if (HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION|PROCESS_CREATE_PROCESS, FALSE, pe.th32ProcessID)) 
        { 
         HANDLE hToken;     

         if (OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) 
         { 
          TOKEN_STATISTICS ts; 

          if (GetTokenInformation(hToken, TokenStatistics, &ts, sizeof(ts), &rcb)) 
          { 
           if (ts.AuthenticationId.LowPart == AuthenticationId.LowPart && 
            ts.AuthenticationId.HighPart == AuthenticationId.HighPart) 
           { 
            found = TRUE; 

            err = CreateProcessEx(hProcess, 
             lpApplicationName, 
             lpCommandLine); 
           } 
          } 
          CloseHandle(hToken); 
         } 

         CloseHandle(hProcess); 
        } 
       } 

      } while (!found && Process32Next(hSnapshot, &pe)); 
     } 
     else 
     { 
      err = GetLastError(); 
     } 

     CloseHandle(hSnapshot); 
    } 
    else 
    { 
     err = GetLastError(); 
    } 

    return err; 
} 

ULONG CreateProcessEx(PCWSTR lpApplicationName, 
         PWSTR lpCommandLine) 
{ 
    HANDLE hToken; 

    ULONG err = NOERROR; 

    if (OpenProcessToken(NtCurrentProcess(), TOKEN_QUERY, &hToken)) 
    { 
     union { 
      TOKEN_ELEVATION_TYPE tet; 
      TOKEN_LINKED_TOKEN tlt; 
     }; 

     ULONG rcb; 

     if (GetTokenInformation(hToken, TokenElevationType, &tet, sizeof(tet), &rcb)) 
     { 
      if (tet == TokenElevationTypeFull) 
      { 
       if (GetTokenInformation(hToken, TokenLinkedToken, &tlt, sizeof(tlt), &rcb)) 
       { 
        TOKEN_STATISTICS ts; 

        BOOL fOk = GetTokenInformation(tlt.LinkedToken, TokenStatistics, &ts, sizeof(ts), &rcb); 

        CloseHandle(tlt.LinkedToken); 

        if (fOk) 
        { 
         err = CreateProcessEx(ts.AuthenticationId, 
          lpApplicationName, 
          lpCommandLine); 
        } 
        else 
        { 
         err = GetLastError(); 
        } 
       } 
       else 
       { 
        err = GetLastError(); 
       } 
      } 
      else 
      { 
       err = ERROR_ALREADY_ASSIGNED; 
      } 
     } 
     else 
     { 
      err = GetLastError(); 
     } 

     CloseHandle(hToken); 
    } 
    else 
    { 
     err = GetLastError(); 
    } 

    return err; 
} 

和測試:

WCHAR ApplicationName[MAX_PATH]; 

if (GetEnvironmentVariableW(L"ComSpec", ApplicationName, RTL_NUMBER_OF(ApplicationName))) 
{ 
    WCHAR cmdline[] = L"cmd.exe /k whoami /priv /groups\r\n"; 
    CreateProcessEx(ApplicationName, cmdline); 
    RunNonElevated(ApplicationName, cmdline); 
} 

的方式#2相同的登錄ID(AuthenticationId)在我們鏈接的標記理論,我們不能發現的過程。但方式#1總是必須工作。總是存在的系統進程,其中有SeTcbPrivilege(用於獲取鏈接令牌的主要形式)+ SeAssignPrimaryTokenPrivilege(對於CreateProcessAsUser)(SeIncreaseQuotaPrivilege)在msdn中監聽CreateProcessAsUser的典型需求,但在我的測試中,即使未啓用此權限,也可以工作。但是所有系統進程(運行爲LocalSystem)都具有令牌中的這3個特權(從smss.exe開始),並且一些系統進程始終在系統中運行。

這樣的方式#1必須永遠不會失敗和首選。我們也可以在這裏使用例如來自我們的進程的繼承句柄,用於與子進程交互。這在#2方面是不可能的。它顯示了相當的圖片


在開始的完整性,我們檢查TOKEN_ELEVATION_TYPE,做的工作,只有當它是TokenElevationTypeFull。如果TokenElevationTypeLimited我們沒有提升過程 - 所以沒有任何待辦事項。 情況下TokenElevationTypeDefault意味着或UAC如果關閉(LUA禁用)或我們運行內置的管理員,和Lua沒有此帳戶(所以所有的進程被「架空」,或更確切地說它的令牌不通過CreateRestrictedToken(..LUA_TOKEN..)過濾)過濾令牌 - 在這情況下,也沒有任何意義嘗試這個用戶

+0

相當完整的答案。我需要詳細檢查這一點。無論如何Upvoted。謝謝 –

+0

@MichaelWalz存在其他一種方式(較短的代碼) - 通過'CreateRestrictedToken(hToken,LUA_TOKEN,0,0,0,0,0,&hLowToken)'(在自己的進程標記上)'設置'TokenIntegrityLevel'代替' WinMediumLabelSid'和最後''CreateProcessAsUser'帶這個標記(*如果hToken是調用者的主標記的受限版本,則不需要'SE_ASSIGNPRIMARYTOKEN_NAME'特權*)。但進程將在另一個登錄會話中運行。結果所有控制檯應用程序無法運行(分配控制檯),但說記事本和GUI應用程序運行良好 – RbMm

+1

聰明。但是,可能存在邊緣情況,目前沒有您想要的令牌運行的進程。 –