dcsimg
Results 1 to 13 of 13
  1. #1

    Thread Starter
    Lively Member
    Join Date
    Feb 2015
    Posts
    68

    Shell With Administrative Rights

    I have a nifty Shell system that I am getting ready to put into the CodeBank but I have one question that I can't find an answer to.

    I use CreateProcess for most of the shelling options but since CreateProcess doesn't deal with UAC's it cannot be used to elevate for shelling with Administrative rights. So I use ShellExecuteEx when I need to raise privilege to run as an administrator. All of that works fine except when I use ShellExecuteEx I can't communicate with the shelled-to process when its rights are elevated. Normally when I use ShellExecuteEx I can get a handle to the process using hProcess which is in the UDT ShellExecuteInfo but whenever I tell ShellExecuteEx to raise privilege the variable hProcess always returns 0 so I don't get a handle. I have read in several places that this is intentional so that normal processes can't communicate with elevated processes. I can't find that definitively anywhere though and I am hoping someone on the forum has successfully dealt with this.

    Mainly what this does is it prevents me from doing a wait until execution is complete before returning control to the shelling program. I can do that fine with CreateProcess and I can do it with ShellExecuteEx as long as there is no elevation.

    Can anyone steer me in the right direction to deal with this? I can think of several workarounds but they get pretty messy quickly.

  2. #2
    Addicted Member
    Join Date
    Jun 2015
    Posts
    201

    Re: Shell With Administrative Rights

    You should still be able to get the pid of the process, then you could just use WTSEnumerateProcesses or CreateToolhelpSnapshot to loop and see if that process id is still active without having to open a handle to the process itself. It might also be able to open a handle to it with only some minimal permissions level.

    Another technique, If the elevated process calls ChangeWindowMessageFilter you can add windows messages which will make it through across elevation levels to manually ping each other back and forth but unless your actually exchanging data you might as well just use a shared registry key or file or something but this gets messy if the elevated app crashs and doesnt cleanup the file marker.

    A global mutex with appropriate permissions would probably do the trick too

  3. #3
    Lively Member
    Join Date
    Aug 2017
    Posts
    97

    Re: Shell With Administrative Rights

    Quote Originally Posted by MountainMan View Post
    All of that works fine except when I use ShellExecuteEx I can't communicate with the shelled-to process when its rights are elevated. Normally when I use ShellExecuteEx I can get a handle to the process using hProcess which is in the UDT ShellExecuteInfo but whenever I tell ShellExecuteEx to raise privilege the variable hProcess always returns 0 so I don't get a handle.

    . . .

    Mainly what this does is it prevents me from doing a wait until execution is complete before returning control to the shelling program. I can do that fine with CreateProcess and I can do it with ShellExecuteEx as long as there is no elevation.
    Using the implementation here, I couldn't replicate your issue. It does fail to launch an elevated instance of certain programs (it appears to be mainly 64-bit executables in the 64-bit System32 directory) but for most 32- and 64-bit applications that I've tested, it successfully launches them elevated and a valid hProcess is also returned. I have tested it in XP x86, Vista x86, 7 x86 & x64 and 10 x64.

  4. #4
    PowerPoster
    Join Date
    Feb 2006
    Posts
    18,802

    Re: Shell With Administrative Rights

    As far as I can tell the hProcess from a ShellExecuteEx() call will be valid as long as you passed the SEE_MASK_NOCLOSEPROCESS flag and the request to Shell32 actually spawned a process.

    I see nothing to suggest there should be any issues due to a WOW64 (32-bit) process requesting the spawning of a 64-bit process.

    The hProcess might indeed be shielded from the requesting process if the spawned process is protected using UIPI, but you'd sort of expect that.

  5. #5

    Thread Starter
    Lively Member
    Join Date
    Feb 2015
    Posts
    68

    Re: Shell With Administrative Rights

    There are two scenarios where you don't get a handle to the new process. First, if you use ShellExecuteEx and you "shell" to what you think is anew process it may very well be that the process is already running and if so, ShellExecuteEx does not return a handle. Obviously this can cause a problem if you are doing a Shell & Wait type of routine. This is not dependent upon running an elevated process or not; it simply happens when you run a process already running that doesn't spawn a new process. Specifying Excel, Word, PowerPoint and Access cause this to happen. There are commandline switches you can use for each of them to force a new instance (that works fine unless you want to start a program by specifying a document name and then you are not sure what program the user has set up to open that program so you can't use commandline switches...).

    The other issue appears to happen when I elevate and run certain programs. For example, I use ShellExecuteEx to spawn a (hopefully) new version of CMD.EXE to run a command. If I do this without elevation I get a handle; if I do it with elevation I don't get a handle. So this appears to be a problem with elevation which is why I asked the question. I took dz32's suggestion in the 2nd post and I now fetch the PID of the new process (it is a child of the one shelling) and I have a loop where I monitor whether the PID is still in existence. When it goes away the program has finished. I am still trying to figure out exactly what causes this elevation problem of not reporting a handle when the shelled-to process is clearly a new instance.

    BTW, if you try to run something that you think is in the Windows\System you may be fooled. When running a 32-bit process like VB6, Windows automatically redirects any calls to executables to Windows\SysWOW64. My new routine gives you the option to not let Windows do that redirection but I am not going to release the code until I solve the handle issue above. Thanks for your comments.

  6. #6
    Fanatic Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    566

    Re: Shell With Administrative Rights

    Did you try setting SEE_MASK_NOASYNC flag?

    Something like
    thinBasic Code:
    1. '--- big snip
    2.             With uShell
    3.                 .cbSize = Len(uShell)
    4.                 .fMask = SEE_MASK_NOCLOSEPROCESS Or SEE_MASK_NOASYNC Or SEE_MASK_FLAG_NO_UI
    5.                 .lpVerb = "runas"
    6.                 .lpFile = sFile
    7.                 .lpParameters = Parameters
    8.                 .nShow = IIf(StartHidden, SW_HIDE, SW_SHOWDEFAULT)
    9.             End With
    cheers,
    </wqw>

  7. #7
    Lively Member
    Join Date
    Aug 2017
    Posts
    97

    Re: Shell With Administrative Rights

    Quote Originally Posted by MountainMan View Post
    BTW, if you try to run something that you think is in the Windows\System you may be fooled. When running a 32-bit process like VB6, Windows automatically redirects any calls to executables to Windows\SysWOW64.
    Yeah, I'm aware of that. Rather than employing the potentially problematic Wow64*Wow64FsRedirection functions, I've decided to use the SysNative alias instead when attempting to access the real System32 directory on a 64-bit OS.

    Quote Originally Posted by MSDN
    File System Redirector

    32-bit applications can access the native system directory by substituting %windir%\Sysnative for %windir%\System32. WOW64 recognizes Sysnative as a special alias used to indicate that the file system should not redirect the access. This mechanism is flexible and easy to use, therefore, it is the recommended mechanism to bypass file system redirection. Note that 64-bit applications cannot use the Sysnative alias as it is a virtual directory not a real one.

    Windows Server 2003 and Windows XP: The Sysnative alias was added starting with Windows Vista.
    Quote Originally Posted by Raymond Chen
    Windows Confidential: History—the Long Way Through

    But wait, there's still more. What if you want to access the real 64-bit system directory from a 32-bit process? File system redirection will take your attempt to access the C:\Windows\System32 directory and redirect it to the C:\Windows\SysWOW64 directory. Programmatically, you can use functions with unwieldy names like Wow64*Disable*Wow64*Fs*Redirection, but those disable redirection for all operations until re-enabled, which causes trouble if you're doing anything more complicated than opening a single file, because a complex operation may result in multiple files being accessed and possibly even worker threads being created. Instead of using a gross switch like disabling file system redirection, you can use the special C:\Windows\SysNative virtual directory. When a 32-bit process tries to access the C:\Windows\SysNative directory, the operations are redirected to the real C:\Windows\System32 directory. A local solution to a local problem.
    Quote Originally Posted by MountainMan View Post
    For example, I use ShellExecuteEx to spawn a (hopefully) new version of CMD.EXE to run a command. If I do this without elevation I get a handle; if I do it with elevation I don't get a handle.
    I've tried CMD.EXE too (both 32-bit and 64-bit via the aforementioned alias; confirmed thru Process Hacker) and the only time I didn't get an hProcess was when shelling an elevated instance of the 64-bit version of CMD.EXE from an unelevated process. Actually, the ShellExecuteEx call failed and both Err.LastDllError and SHELLEXECUTEINFO.hInstApp returned (a confusing) error #3: "The system cannot find the path specified." Maybe that's why you're not getting a handle. As I hinted above, spawning an elevated 64-bit program that's residing in the System32 directory from an unelevated 32-bit process is apparently not allowed.

  8. #8

    Thread Starter
    Lively Member
    Join Date
    Feb 2015
    Posts
    68

    Re: Shell With Administrative Rights

    The spawn actually worked (elevated CMD.EXE from unelevated 32-bit VB6 or unelevated 32-bit Excel). I do not get an error (ShellExecuteEx return is <> 0) and I don't get a handle (ShellExecuteInfo member hProcess = 0).

  9. #9

    Thread Starter
    Lively Member
    Join Date
    Feb 2015
    Posts
    68

    Re: Shell With Administrative Rights

    Also, the documentation for the Wow64DisableWow64FsRedirection function to disable redirection says "Disables file system redirection for the calling thread. File system redirection is enabled by default." I believe by spawning a new process or joining another process we go to a different thread so the redirection should have nothing to do with anything except the thread that made the call to either CreateProcess or ShellExecuteEx. If you return right after the call you can/should re-enable it and if you pause until the spawned program ends and then returns then you can turn it back on for your original thread then too. I don't see the problem either way. The only potential for problem would seem to be if the spawned program somehow communicates back to the calling thread and has it do something but in that case you wrote the calling thread code so you could easily turn redirection back on then too. Am I missing something?

  10. #10

    Thread Starter
    Lively Member
    Join Date
    Feb 2015
    Posts
    68

    Re: Shell With Administrative Rights

    Also, SysNative restricts the code to Vista+. Everything I have runs in XP+ and if I can get it working without SysNative then I keep my code being XP+...

  11. #11
    Lively Member
    Join Date
    Aug 2017
    Posts
    97

    Re: Shell With Administrative Rights

    Quote Originally Posted by MountainMan View Post
    The spawn actually worked (elevated CMD.EXE from unelevated 32-bit VB6 or unelevated 32-bit Excel). I do not get an error (ShellExecuteEx return is <> 0) and I don't get a handle (ShellExecuteInfo member hProcess = 0).
    Is CMD.EXE 32-bit or 64-bit?

    BTW, I forgot to mention that the demo in the thread I've linked to has an app manifest with a requestedExecutionLevel element (meaning the EXE does not experience file system virtualization). I've added supportedOS Ids from Vista to 10, but it made no noticeable difference in program behavior.

    Quote Originally Posted by MountainMan View Post
    Am I missing something?
    Well, I'm not certain of this, but I believe ShellExecuteEx does a lot of things behind-the-scenes. I've not tested this, but it's possible that something might fail when file system redirection is turned off. Again, I'm not totally sure ShellExecuteEx is safe to call when FS redirection is disabled, so I decided it would be best to err on the side of caution. However, if you can demonstrate otherwise, I would be interested to see your proof.

  12. #12

    Thread Starter
    Lively Member
    Join Date
    Feb 2015
    Posts
    68

    Re: Shell With Administrative Rights

    I found my problem and now everything works okay. I am working up some samples and I will be putting this into the Code library within the next 24 hours.

    My shelling procedures use CreateProcess at times and ShellExecuteEx at other times. For example ShellExecuteEx is the route to go if you want to raise administrative privileges. The following is about the calls to ShellExecuteEx and in particular the fMask parameter of ShellExecuteInfo.

    I found that if SEE_MASK_ASYNCOK is set then ShellExecuteEx always causes a return of 0 for the handle. This causes a couple of problems because the return is very quick (almost instantaneous) and especially if you bump admin privilege it takes time for the user to agree to the bump in privilege but meanwhile the routine has returned before the real child has started (the little program that prompts for the user to agree to the bump is called consent.exe and the "real" child does not start until the user clicks OK to the request prompt to raise admin privilege). In general I have the option for the programmer to set how long to wait to give the child process the chance to exit but now I only set SEE_MASK_ASYNCOK when I set the timeout value to 0 (quick return and I don't expect a handle anyway).

    I was also headed down the road of a complicated solution of tracking child processes before and after the call to ShellExecuteEx to find which process ID (PID) was new and then waiting until that PID went away (program exit) but I also found that if I set SEE_MASK_WAITFORINPUTIDLE then I don't need to do that because the ShellExecuteEx function waits for up to a minute to let the user choose to allow the admin privilege bump before it returns.

    So the long and short of it is that I get handles now for all cases (elevated or not) except when I specify a timeout value of 0. Thanks for the input on this thread.

  13. #13
    Fanatic Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    566

    Re: Shell With Administrative Rights

    This is from shellapi.h
    C Code:
    1. #if (NTDDI_VERSION >= NTDDI_WIN2K)
    2. #define SEE_MASK_WAITFORINPUTIDLE  0x02000000
    3. #endif // (NTDDI_VERSION >= NTDDI_WIN2K)
    . . . so the flag is safe since win2k.

    I'm still using WaitForInputIdle directly with the added benefit of specifying explicit timeout like this
    thinBasic Code:
    1. '--- snip
    2.         With uShell
    3.             .cbSize = Len(uShell)
    4.             .fMask = SEE_MASK_NOCLOSEPROCESS Or SEE_MASK_NOASYNC Or SEE_MASK_FLAG_NO_UI
    5.             .hWnd = 0
    6.             .lpVerb = "open"
    7.             .lpFile = sUrl
    8.             .lpParameters = vbNullString
    9.             .nShow = SW_SHOWDEFAULT
    10.         End With
    11.         If ShellExecuteEx(uShell) = 0 Then
    12.             LastDllError = Err.LastDllError
    13.         Else
    14.             Call WaitForInputIdle(uShell.hProcess, 5000)
    15.             Call CloseHandle(uShell.hProcess)
    16.         End If
    . . . but 5000 is pretty random for sure.

    cheers,
    </wqw>

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Featured


Click Here to Expand Forum to Full Width


×
We have made updates to our Privacy Policy to reflect the implementation of the General Data Protection Regulation.