I have recently been doing some research on windows services, and have been working on some command line parsing, so while experimenting I thought of a nice little trick to run a process in the System account (And have the window be displayed) without using PsExec -sid
Involves:
1. sc.exe - Manages windows service
2. net.exe - start windows service
3. cmd.exe - Runs the application
Command (Copy and paste in command prompt or the run dialog) - This will run calc.exe
|
A path with quotes: The /" = a quote (quotes would be needed for paths with spaces, but this is just an example)
Note: Copy and paste this one into cmd.exe or a batch(.bat) file, because the run dialog will not translate the /" escape chars.
|
So how does it work?
1. The & symbol tells cmd.exe to parse treat the text that follows as if it were a new line in a batch file (It basically is a new line delimiter which allows multiple commands to be combined into 1 line)
To break it down:
o Create Service - sc create -- binPath= "cmd /c start calc" type= own type= interact
o Start Service net start -- (This could also be done with: sc start --)
o Delete Service sc delete --
2. Variables:
o Service Name: --
o App to run: calc
3. How it works:
o cmd /c - allows us to pass in parameters to cmd (Without this initial part, it will work if you copy & paste in cmd.exe, but not in the Run Dialog. So this fixes it)
o sc create binPath= - Since cmd.exe does not respond to service commands, when the SCM runs the app in binPath (Reg = ImagePath) then it will terminate it, when not responding in a timely fasion, therefore cmd.exe cannot be used. It has to call something else which in this case is calc.exe
o sc create type= This one took a while to figure out. The inital problem is the Window Station in which cmd.exe is launched in (which in turn is inherited by calc.exe (its child process)). Luckily after reading Mark's Windows Internals e4, I was able to solve it by specifying the service as being Interactive. (Experimenting, it actually has to be BOTH interactive(256) and own(16) (256|16 = 272) . Basically what this allows is for the windows to run in /WinSta0/Default (The current user's desktop, allowing the window to be displayed.) After some research from being frustrated that sc would not accept type =own|interact, I found out that it allows us to specify it again, and instead of overwriting Type (dword) it bitwise-ORs it (Adds it). Problems Solved!
o net start - start the service (probably calls StartService)
o cmd.exe runs with the command line (CL) of start [File] in which start probably calls ShellExecute (Its ashame that MS didn't allow start to specify a SW_* commands (like hide). Although it does allowing us to min/max windows. cmd.exe opens the app/file, the SCM terminates cmd.exe for not responding in a timely fashion to its commands, and the window is now shown to the user.
o sc delete - Finally we clean up our path by removing the service
This is just a useful trick I thought I would share. Feedback is welcome.
Feel free to give it a shot and copy & paste that command in the run dialog. (Check the process's account either using TaskMgr or PE :P)
I wonder if in vista this makes UAC mad, haha.
-Matt
Update:
To make this work on paths with spaces, the start command needs to be changed from start calc to start "" calc. The other way works but as soon as you give start a path with spaces in it, it will not properly work, and I forgot about that until now.
The other day I finally solved that nagging problem by using start /? and studying its commands. Apparently start's first parameter is the CreateProcess's WindowTitle parameter, inwhich if you specify a path like "C:/Documents and Settings/app.exe" a console windows will open with the title C:/Documents. To Fix this we must specify start "" "C:/Documents and Settings/app.exe"
(Yes start requires quotes be supplied for paths with spaces)
The problem is the 2 quotes within those quotes for binPath is not playing nice with cmd.exe. Usually you can use the ^ symbol to have cmd print in that special character but for some reason it is not working. I will try to figure this out later, perhaps by setting a variable or something.
Update 2: (11-30-08)
To use quotes in the path, I wasn't thinking straight and you can use the C-language escape sequence /"
Ex:
binPath= "cmd /c start /"/" /"calc/""
Which will translate to having an image path of:
cmd /c start "" "calc"