Community
    • Login

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

    Scheduled Pinned Locked Moved General Discussion
    32 Posts 5 Posters 13.4k Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • donhoD
      donho @dinkumoil
      last edited by

      @dinkumoil said:

      Oh, and I forgot to mention, there is the old Plugin Manager, the devs of it had to solve the same problem. Maybe have a look at their code.

      gpup.exe is launched without elevation, then it spawns itself (another instance) with the privileges rights to download & unzip and quit. The instance without elevation then relaunches Notepad++ without elevation.

      It’s full of hack, but I guess I have no choice :(

      Meta ChuhM 1 Reply Last reply Reply Quote 2
      • dinkumoilD
        dinkumoil
        last edited by

        @donho said:

        It’s full of hack, but I guess I have no choice :(

        Well, I would call it “skillful use of officially documented features”. In contrast, the methods suggested in the MSDN blog entries I’ve posted a link to would have been real dirty hacks.

        1 Reply Last reply Reply Quote 0
        • Meta ChuhM
          Meta Chuh moderator @donho
          last edited by

          @donho

          please try this from an elevated cmd or gup exec line:

          schtasks /create /tn "Notepad++ Update Reload" /tr "C:\Program Files\Notepad++\notepad++.exe" /sc once /st 23:59 /f && schtasks /run /tn "Notepad++ Update Reload" && schtasks /delete /TN "Notepad++ Update Reload" /f

          i remembered i had the same problem ages ago and solved it using the scheduled tasks
          this will create run once and delete one that uses the current user regardless of the elevation level of the parent task

          i’ve just tried it and drag and drop works, also @dinkumoil the uac in the task manager should be correct

          1 Reply Last reply Reply Quote 1
          • dinkumoilD
            dinkumoil
            last edited by

            @Meta-Chuh

            Yes, I remember. That was the way I suppressed UAC dialogs e.g. when starting elevated console windows around 10 years ago when I switched to Windows 7. It was the “I’m the admin, why should I been asked for approving admin tasks?”-attitude.

            But to use that from within an EXE - hmm, seems crude to me…

            Meta ChuhM 1 Reply Last reply Reply Quote 1
            • Meta ChuhM
              Meta Chuh moderator @dinkumoil
              last edited by

              @dinkumoil

              this is just to get things going right now.
              it’s to quickly test if using the task scheduler works 100% for all cases.

              if it does, we can create an ITaskService object unsing eg taskschd.h instead of a command line.

              if you have another working solution that is testable right now, don’t complain, try it, share it

              1 Reply Last reply Reply Quote 1
              • SinghRajenMS
                SinghRajenM moderator
                last edited by

                @donho
                Have looks at article by Raymond Chen.

                We already have a solution in place, but unfortunately that solution is in nsis. Look here. The idea is: Run a exe in explorer context.

                MS link: https://msdn.microsoft.com/library/dd940355
                MS sample: https://github.com/pauldotknopf/WindowsSDK7-Samples/tree/master/winui/shell/appplatform/ExecInExplorer

                Hope this will help you.

                1 Reply Last reply Reply Quote 2
                • SinghRajenMS
                  SinghRajenM moderator
                  last edited by

                  Also below can be used as simplest solution -

                  ShellExecute(nullptr, L"open", L"explorer.exe", L"C:\\Program Files\\Notepad++\\Notepad++.exe", nullptr, NULL);

                  donhoD 1 Reply Last reply Reply Quote 2
                  • SinghRajenMS
                    SinghRajenM moderator @donho
                    last edited by

                    @donho

                    @donho said:

                    @dinkumoil
                    Indeed.

                    @Meta-Chuh said:

                    possible solution:
                    execute runas /trustlevel:0x20000 “C:\Program Files (x86)\Notepad++\notepad++.exe”

                    Just tried this method and seems Admin mode is OFF.
                    However, drag & drop a file into edit zone (which is the original motivation to run Notepad++ under user level) is forbidden just like Admin mode is ON.

                    I will continue to search the alternative way.

                    Considering this scenario in mind, npp installer launches npp instance with same integrity level as explorer. Same is applicable here and drag n drop works fine using below method. So I feel, this should suit your requirement.

                    ShellExecute(nullptr, L"open", L"explorer.exe", L"C:\\Program Files\\Notepad++\\Notepad++.exe", nullptr, NULL);

                    1 Reply Last reply Reply Quote 3
                    • donhoD
                      donho @SinghRajenM
                      last edited by

                      @SinghRajenM said:

                      Also below can be used as simplest solution -

                      ShellExecute(nullptr, L"open", L"explorer.exe", L"C:\\Program Files\\Notepad++\\Notepad++.exe", nullptr, NULL);

                      Thank you for the info.
                      I do remember the solution you provide in NSIS and did try the line above - only explorer launched.

                      SinghRajenMS 1 Reply Last reply Reply Quote 0
                      • dinkumoilD
                        dinkumoil
                        last edited by

                        @donho

                        The last parameter has to be 1 = SW_SHOWNORMAL

                        1 Reply Last reply Reply Quote 1
                        • SinghRajenMS
                          SinghRajenM moderator @donho
                          last edited by SinghRajenM

                          @donho said:

                          @SinghRajenM said:

                          Also below can be used as simplest solution -

                          ShellExecute(nullptr, L"open", L"explorer.exe", L"C:\\Program Files\\Notepad++\\Notepad++.exe", nullptr, NULL);

                          Thank you for the info.
                          I do remember the solution you provide in NSIS and did try the line above - only explorer launched.

                          Interesting. It is working fine to me.

                          [Edit]:
                          @dinkumoil, nice catch. I’m using SW_SHOW

                          Meta ChuhM 1 Reply Last reply Reply Quote 1
                          • Meta ChuhM
                            Meta Chuh moderator @SinghRajenM
                            last edited by

                            @SinghRajenM

                            thx, very cool and easy just to execute via explorer.exe, iv’e just tried it.

                            i didn’t know that explorer.exe does not pass the elevation level to a spawn.

                            so simple and perfect 👍

                            SinghRajenMS 1 Reply Last reply Reply Quote 0
                            • SinghRajenMS
                              SinghRajenM moderator @Meta Chuh
                              last edited by

                              @Meta-Chuh Again it depends upon how explorer.exe is executed. In most of the cases explorer is not elevated unless user explicitly do so.

                              So if explorer is also elevated, then new exe also will be elevated yet. But it is expected in this case, because both will be at same integrity level which allows drag n drop.

                              https://paste.pics/e25eda50315a622bfda372343fd9b722

                              donhoD 1 Reply Last reply Reply Quote 0
                              • donhoD
                                donho @SinghRajenM
                                last edited by

                                @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 Reply Last reply Reply Quote 1
                                • rinku singhR
                                  rinku singh
                                  last edited by

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

                                  1 Reply Last reply Reply Quote 0
                                  • dinkumoilD
                                    dinkumoil
                                    last edited by

                                    @donho

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

                                    donhoD 1 Reply Last reply Reply Quote 2
                                    • donhoD
                                      donho @dinkumoil
                                      last edited by

                                      @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 Reply Last reply Reply Quote 0
                                      • donhoD
                                        donho
                                        last edited by

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

                                        1 Reply Last reply Reply Quote 1
                                        • SinghRajenMS
                                          SinghRajenM moderator @donho
                                          last edited by

                                          @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 Reply Last reply Reply Quote 4
                                          • dinkumoilD
                                            dinkumoil
                                            last edited by

                                            @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 Reply Last reply Reply Quote 2
                                            • First post
                                              Last post
                                            The Community of users of the Notepad++ text editor.
                                            Powered by NodeBB | Contributors