Community
    • 登入

    Launch a No Elevated Process from an Elevated Process in an easy way (Win32 API)

    已排程 已置頂 已鎖定 已移動 General Discussion
    32 貼文 5 Posters 15.5k 瀏覽
    正在載入更多貼文
    • 從舊到新
    • 從新到舊
    • 最多點贊
    回覆
    • 在新貼文中回覆
    登入後回覆
    此主題已被刪除。只有擁有主題管理權限的使用者可以查看。
    • donhoD
      donho @SinghRajenM
      最後由 編輯

      @SinghRajenM
      It seems your method doesn’t work only for me.
      I test it in notepad++ with NO elevation, the following code launch calc well:

      		case IDM_FILE_NEW:
      		{
      			//fileNew();
      			ShellExecute(nullptr, L"open", L"calc.exe", nullptr, nullptr, SW_SHOW);
      	
      		}
      		break;
      

      However, the following code launch only explorer:

      		case IDM_FILE_NEW:
      		{
      			//fileNew();
      			ShellExecute(nullptr, L"open", L"explorer.exe", L"calc.exe", nullptr, SW_SHOW);
      	
      		}
      		break;
      

      What am I missing?

      1 條回覆 最後回覆 回覆 引用 1
      • rinku singhR
        rinku singh
        最後由 編輯

        but i don’t know that code
        dism++ heve a method
        toolkit > god mode
        run program without right checking

        1 條回覆 最後回覆 回覆 引用 0
        • dinkumoilD
          dinkumoil
          最後由 編輯

          @donho

          You have to provide the fully qualified path to Calc.exe/Notepad++.exe.

          donhoD 1 條回覆 最後回覆 回覆 引用 2
          • donhoD
            donho @dinkumoil
            最後由 編輯

            @dinkumoil said:

            You have to provide the fully qualified path to Calc.exe/Notepad++.exe.

            Yes I did. The following code doesn’t work neither:

            case IDM_FILE_NEW:
            {
            	//fileNew();
            	::ShellExecuteA(NULL, "open", "explorer.exe", "C:\\sources\\notepad-plus-plus\\PowerEditor\\bin\\notepad++.exe -multiInst", "C:\\sources\\notepad-plus-plus\\PowerEditor\\bin\\", SW_SHOW);
            }
            break;
            
            SinghRajenMS 1 條回覆 最後回覆 回覆 引用 0
            • donhoD
              donho
              最後由 編輯

              Hmm…
              The following code works :
              ShellExecute(nullptr, L"open", L"explorer.exe", L"c:\\windows\\system32\\calc.exe", nullptr, SW_SHOW);

              1 條回覆 最後回覆 回覆 引用 1
              • SinghRajenMS
                SinghRajenM moderator @donho
                最後由 編輯

                @donho

                @donho said:

                @dinkumoil said:

                You have to provide the fully qualified path to Calc.exe/Notepad++.exe.

                Yes I did. The following code doesn’t work neither:

                case IDM_FILE_NEW:
                {
                	//fileNew();
                	::ShellExecuteA(NULL, "open", "explorer.exe", "C:\\sources\\notepad-plus-plus\\PowerEditor\\bin\\notepad++.exe -multiInst", "C:\\sources\\notepad-plus-plus\\PowerEditor\\bin\\", SW_SHOW);
                }
                break;
                

                As you know ShellExecute parameters,
                Command/operation => “open”
                Command Location/File => “explorer.exe”
                Command Parameters => “C:\sources\notepad-plus-plus\PowerEditor\bin\notepad++.exe -multiInst”

                So here problem is command parameter which includes another command parameter. Try without “-multiInst”. It should work.

                1 條回覆 最後回覆 回覆 引用 4
                • dinkumoilD
                  dinkumoil
                  最後由 編輯

                  @donho

                  In case it is important for you to be able to call Notepad++ with command line arguments - I’ve implemented the algorithm from my 2nd MSDN link provided above in C and wrapped it in a small demo program.

                  • It can start another program with the user rights of the desktop shell process if itself is elevated.
                  • It can start another program with the same user rights that itself runs under if it is not elevated.
                  • It can start another program with parameters.

                  Of course, it is not an oneliner and you have to change the implementation of error handling. The GetFullPath routine is not necessary.

                  I compiled it with MinGW. It has to be linked against Advapi32.lib and Kernel32.lib.

                  #define _WIN32_WINNT 0x0501
                  #define WIN32_LEAN_AND_MEAN
                  #define STRICT 1
                  
                  #define _UNICODE
                  #define UNICODE
                  
                  #include <sdkddkver.h>
                  
                  
                  /*******************************************************************************
                  Includes
                  *******************************************************************************/
                  
                  #include <windows.h>
                  
                  #include <stdlib.h>
                  #include <stdio.h>
                  
                  
                  
                  /*******************************************************************************
                  Prototypes
                  *******************************************************************************/
                  
                  BOOL   RunAsDesktopUser (LPCWSTR szApp, LPWSTR szCmdLine, LPCWSTR szCurrDir, STARTUPINFO *si, PROCESS_INFORMATION *pi);
                  BOOL   RunLoweredProcess(LPCWSTR szApp, LPWSTR szCmdLine, LPCWSTR szCurrDir, STARTUPINFO *si, PROCESS_INFORMATION *pi);
                  BOOL   RunProcess       (LPCWSTR szApp, LPWSTR szCmdLine, LPCWSTR szCurrDir, STARTUPINFO *si, PROCESS_INFORMATION *pi);
                  BOOL   SetPrivilege     (HANDLE hProcessToken, LPCWSTR lpszPrivilege, BOOL bEnablePrivilege);
                  BOOL   IsElevatedToken  (HANDLE hProcessToken);
                  LPWSTR GetFullPath      (LPCWSTR szFilePath);
                  
                  
                  
                  
                  /*******************************************************************************
                  Main program
                  *******************************************************************************/
                  
                  int wmain(int argc, WCHAR *argv[])
                  {
                    LPWSTR              fullPath    = NULL;
                    LPWSTR              commandLine = NULL;
                    STARTUPINFO         si          = {0};
                    PROCESS_INFORMATION pi          = {0};
                  
                    si.cb          = sizeof(si);
                    si.dwFlags     = STARTF_USESHOWWINDOW;
                    si.wShowWindow = SW_SHOWNORMAL;
                  
                    if ((fullPath = GetFullPath(L"%ProgramFiles(x86)%\\Notepad++\\notepad++.exe")) == NULL)
                    {
                      wprintf(L"File not found\n");
                      goto cleanup;
                    }
                  
                    commandLine = calloc(wcslen(fullPath) + 14, sizeof(*fullPath));
                    wsprintf(commandLine, L"\"%s\" %s", fullPath, L"-multiInst");
                  
                    if (RunAsDesktopUser(fullPath, commandLine, NULL, &si, &pi))
                    {
                      WaitForSingleObject(pi.hProcess, INFINITE);
                  
                      if (pi.hThread != NULL)
                        CloseHandle(pi.hThread);
                  
                      if (pi.hProcess != NULL)
                        CloseHandle(pi.hProcess);
                    }
                  
                  cleanup:
                    free(fullPath);
                    free(commandLine);
                  
                    return 0;
                  }
                  
                  
                  BOOL RunAsDesktopUser(LPCWSTR szApp, LPWSTR szCmdLine, LPCWSTR szCurrDir,
                                        STARTUPINFO *si, PROCESS_INFORMATION *pi)
                  {
                    BOOL   bRetVal       = FALSE;
                    HANDLE hProcessToken = NULL;
                  
                    // Retrieve process token of own process
                    if (!OpenProcessToken(GetCurrentProcess(),
                                          TOKEN_QUERY
                                           | TOKEN_ADJUST_PRIVILEGES,
                                          &hProcessToken))
                    {
                      wprintf(L"OpenProcessToken failed, error code: %u\n", GetLastError());
                      goto cleanup;
                    }
                  
                    // Check if own process is elevated
                    if (!IsElevatedToken(hProcessToken))
                    {
                      // Run process with user rights of own process
                      if (!(bRetVal = RunProcess(szApp, szCmdLine, szCurrDir, si, pi)))
                        goto cleanup;
                    }
                    else
                    {
                      // Add privilege SE_INCREASE_QUOTA_NAME to own process token
                      if (!(bRetVal = SetPrivilege(hProcessToken, SE_INCREASE_QUOTA_NAME, TRUE)))
                        goto cleanup;
                  
                      // Run process with user rights of desktop shell process
                      if (!(bRetVal = RunLoweredProcess(szApp, szCmdLine, szCurrDir, si, pi)))
                        goto cleanup;
                    }
                  
                    bRetVal = TRUE;
                  
                  cleanup:
                    CloseHandle(hProcessToken);
                  
                    return bRetVal;
                  }
                  
                  
                  BOOL RunProcess(LPCWSTR szApp, LPWSTR szCmdLine, LPCWSTR szCurrDir,
                                  STARTUPINFO *si, PROCESS_INFORMATION *pi)
                  {
                    // Start process with user rights of own process
                    if (!CreateProcess(szApp,
                                       szCmdLine,
                                       (LPSECURITY_ATTRIBUTES) NULL,
                                       (LPSECURITY_ATTRIBUTES) NULL,
                                       FALSE,
                                       0,
                                       (LPVOID) NULL,
                                       szCurrDir,
                                       si,
                                       pi))
                    {
                      wprintf(L"CreateProcess failed, error code: %u\n", GetLastError());
                      return FALSE;
                    }
                  
                    return TRUE;
                  }
                  
                  
                  BOOL RunLoweredProcess(LPCWSTR szApp, LPWSTR szCmdLine, LPCWSTR szCurrDir,
                                         STARTUPINFO *si, PROCESS_INFORMATION *pi)
                  {
                    BOOL   bRetVal            = FALSE;
                    HWND   hShellWnd          = NULL;
                    DWORD  dwShellProcessID   = 0;
                    HANDLE hShellProcess      = NULL;
                    HANDLE hShellProcessToken = NULL;
                    HANDLE hPrimaryToken      = NULL;
                  
                    // Retrieve handle of desktop shell window
                    if ((hShellWnd = GetShellWindow()) == NULL)
                    {
                      wprintf(L"GetShellWindow failed\n");
                      goto cleanup;
                    }
                  
                    // Retrieve process id of desktop shell window
                    GetWindowThreadProcessId(hShellWnd,
                                             &dwShellProcessID);
                  
                    if (dwShellProcessID == 0)
                    {
                      wprintf(L"GetWindowThreadProcessId failed\n");
                      goto cleanup;
                    }
                  
                    // Retrieve process handle of desktop shell process
                    hShellProcess = OpenProcess(PROCESS_QUERY_INFORMATION,
                                                FALSE,
                                                dwShellProcessID);
                  
                    if (hShellProcess == NULL)
                    {
                      wprintf(L"OpenProcess failed, error code: %u\n", GetLastError());
                      goto cleanup;
                    }
                  
                    // Retrieve process token of desktop shell process
                    if (!OpenProcessToken(hShellProcess,
                                          TOKEN_DUPLICATE,
                                          &hShellProcessToken))
                    {
                      wprintf(L"OpenProcessToken failed, error code: %u\n", GetLastError());
                      goto cleanup;
                    }
                  
                    // Duplicate process token of desktop shell process to a primary token
                    if (!DuplicateTokenEx(hShellProcessToken,
                                          TOKEN_QUERY
                                           | TOKEN_DUPLICATE
                                           | TOKEN_ASSIGN_PRIMARY
                                           | TOKEN_ADJUST_DEFAULT
                                           | TOKEN_ADJUST_SESSIONID,
                                          NULL,
                                          SecurityImpersonation,
                                          TokenPrimary,
                                          &hPrimaryToken))
                    {
                      wprintf(L"DuplicateTokenEx failed, error code: %u\n", GetLastError());
                      goto cleanup;
                    }
                  
                    // Start process with user rights of desktop shell process
                    if (!CreateProcessWithTokenW(hPrimaryToken,
                                                 0,
                                                 szApp,
                                                 szCmdLine,
                                                 0,
                                                 (LPVOID) NULL,
                                                 szCurrDir,
                                                 si,
                                                 pi))
                    {
                      wprintf(L"CreateProcessWithToken failed, error code: %u\n", GetLastError());
                      goto cleanup;
                    }
                  
                    bRetVal = TRUE;
                  
                  cleanup:
                    CloseHandle(hShellProcessToken);
                    CloseHandle(hPrimaryToken);
                    CloseHandle(hShellProcess);
                  
                    return bRetVal;
                  }
                  
                  
                  BOOL IsElevatedToken(HANDLE hProcessToken)
                  {
                    DWORD elevationType  = 0;
                    DWORD dwReturnLength = 0;
                  
                    if (!GetTokenInformation(hProcessToken,
                                             TokenElevationType,
                                             &elevationType,
                                             sizeof(elevationType),
                                             &dwReturnLength))
                    {
                      wprintf(L"GetTokenInformation failed, error code: %u", GetLastError());
                      return FALSE;
                    }
                    else
                    {
                      switch (elevationType)
                      {
                        case TokenElevationTypeDefault:
                          return FALSE;
                  
                        case TokenElevationTypeLimited:
                          return FALSE;
                  
                        case TokenElevationTypeFull:
                          return TRUE;
                  
                        default:
                          return FALSE;
                      }
                    }
                  }
                  
                  
                  BOOL SetPrivilege(HANDLE hProcessToken, LPCWSTR lpszPrivilege, BOOL bEnablePrivilege)
                  {
                    TOKEN_PRIVILEGES tp   = {0};
                    LUID             luid = {0};
                  
                    if (!LookupPrivilegeValue((LPCWSTR) NULL,
                                              lpszPrivilege,
                                              &luid))
                    {
                      wprintf(L"LookupPrivilegeValue, failed, error code: %u\n", GetLastError() );
                      return FALSE;
                    }
                  
                    tp.PrivilegeCount           = 1;
                    tp.Privileges[0].Luid       = luid;
                    tp.Privileges[0].Attributes = (bEnablePrivilege ? SE_PRIVILEGE_ENABLED : 0);
                  
                    if (!AdjustTokenPrivileges(hProcessToken,
                                               FALSE,
                                               &tp,
                                               0,
                                               (PTOKEN_PRIVILEGES) NULL,
                                               (PDWORD) NULL))
                    {
                      wprintf(L"AdjustTokenPrivileges failed, error code: %u\n", GetLastError() );
                      return FALSE;
                    }
                  
                    if (GetLastError() != ERROR_SUCCESS)
                    {
                      wprintf(L"AdjustTokenPrivileges failed to set the specified privilege.\n");
                      return FALSE;
                    }
                  
                    return TRUE;
                  }
                  
                  
                  LPWSTR GetFullPath(LPCWSTR szFilePath)
                  {
                    LPWSTR szPath    = (LPWSTR) szFilePath;
                    BOOL   bFreePath = FALSE;
                    LPWSTR szBuf     = NULL;
                    DWORD  dwBufLen  = 0;
                    DWORD  nCCh      = 0;
                  
                    // Expand environment variables
                    do
                    {
                      szBuf = (LPWSTR) realloc(szBuf, dwBufLen * sizeof(*szBuf));
                      nCCh  = ExpandEnvironmentStrings(szPath,
                                                       szBuf,
                                                       dwBufLen);
                  
                      if (nCCh == 0)        break;
                      if (nCCh == dwBufLen) break;
                  
                      dwBufLen = nCCh;
                    } while (TRUE);
                  
                    if (nCCh > 0)
                    {
                      szPath    = szBuf;
                      bFreePath = TRUE;
                    }
                  
                    // Search file name in PATH and current directory
                    szBuf    = NULL;
                    dwBufLen = 0;
                  
                    do
                    {
                      szBuf = (LPWSTR) realloc(szBuf, dwBufLen * sizeof(*szBuf));
                      nCCh  = SearchPath((LPCWSTR) NULL,
                                         szPath,
                                         (LPCWSTR) NULL,
                                         dwBufLen,
                                         szBuf,
                                         NULL);
                  
                      if (nCCh == 0)       break;
                      if (nCCh < dwBufLen) break;
                  
                      dwBufLen = nCCh;
                    } while (TRUE);
                  
                    if (bFreePath)
                      free(szPath);
                  
                    if (nCCh > 0)
                      return szBuf;
                    else
                      return NULL;
                  }
                  
                  1 條回覆 最後回覆 回覆 引用 2
                  • donhoD
                    donho
                    最後由 donho 編輯

                    @dinkumoil
                    Wow, it’s miles and miles of codes for just preventing from elevation ! I’ll try firstly One Line solution of @SinghRajenM .
                    Thank you.

                    1 條回覆 最後回覆 回覆 引用 1
                    • dinkumoilD
                      dinkumoil
                      最後由 編輯

                      @donho said:

                      I’ll try firstly One Line solution of @SinghRajenM .

                      Of course.

                      Wow, it’s miles and miles of codes

                      It’s not that bad, the absolutely core functionality is about to 90 lines of code which you can shorten even more.

                      for just preventing from elevation !

                      It’s not a “just”. For this functionality there is no ready-to-use Windows API. That the ShellExecute one-liner does the job is an undocumented feature and relies on the current implementation of Explorer.exe. And with this method it is not possible to start the unelevated process with parameters.

                      1 條回覆 最後回覆 回覆 引用 2
                      • donhoD
                        donho
                        最後由 編輯

                        The solution of @SinghRajenM is tested and works fine! Merged into the master of wingup:
                        https://github.com/notepad-plus-plus/wingup/commit/af34920693261307d34bb530622e6d70cbe875d2

                        Thank you @SinghRajenM for your hint and your solution (again, besides of NSIS).

                        1 條回覆 最後回覆 回覆 引用 6
                        • dinkumoilD
                          dinkumoil
                          最後由 dinkumoil 編輯

                          @donho

                          I have tested the ShellExec one-liner solution more thoroughly and noticed the following:

                          If a user wants to install a plugin, an UAC dialog pops up and requests for confirmation. After the plugin is installed Notepad++ restarts. So far so good.

                          If the user now wants to install another plugin, the plugin gets installed without an UAC dialog poping up, it is just done and Notepad++ restarts after that.

                          It seems like though Notepad++ obviously runs with user rights, it actually does not.

                          1 條回覆 最後回覆 回覆 引用 0
                          • dinkumoilD
                            dinkumoil
                            最後由 編輯

                            @donho

                            Sorry, I was wrong. I have tested with the wrong debug binary which hadn’t contained your last ShellExecute patch. Sorry for the inconvenience.

                            1 條回覆 最後回覆 回覆 引用 0
                            • 第一個貼文
                              最後的貼文
                            The Community of users of the Notepad++ text editor.
                            Powered by NodeBB | Contributors