One of the things I constantly tell Windows users to do when they ask me how to make the best Win32 application they possibly can is to try running the application under the most restrictive privileges possible. However, I realized that most people having to ask that question really have no idea how to go about doing that. So I'm going to cover what exactly that entails. Note, what I'm not going to cover is how to actually set up a restricted access account (a bit of googling will show you how to do that). What I am going to show you is how to launch a program in a restricted manner without having to make a different account at all.
Before we go diving right into code, I'd like to discuss the theory behind what we're going to do. Windows has a very powerful, albeit obtuse, security framework. We are going to tap into that framework to launch an application with restricted rights. By restricting the rights of the application, we have essentially made a little sandbox to play within. It means that the application isn't able to write files everywhere, or access every registry key, etc. Basically, even if you're running as admin with full privs, the application will have as few privs as possible.
The basic idea behind this concept is that we want to create a process using a different security context than that of the caller. This is done by using CreateProcessAsUser, which allows you to specify a token representing a user. This can seem misleading though, since the user doesn't have to be a phsyical account on the machine. We're going to make a "user" up on the fly which has no account (or system overhead associated with having an account). The way this user gets set up depends on whether you're running Windows Vista, or not. If you're on Vista (or higher), we accomplish this goal with the kernel's built-in "integrity level" mechanisms. On non-Vista machines, we accomplish it by creating what's known as a "restricted" token. The results will not be the same; integrity levels are a more severe lock-down than restricted tokens. But either mechanism provides the most "locked-down" you can get an application to be.
Let's take a look at the restricted token style of lock-down first. The ultimate driving force behind this mechanism is a call to CreateRestrictedToken. In order for us to make the call, we first have to get the current application's token. This is easy enough to do with a call to OpenProcessToken. The next step in the process is to create a list of access rights to remove from the current token. Access rights are exposed via a data structure known as a "SID" on Windows. I won't go into much detail about how to manually construct a SID (which is how I solve the problem), but suffice it to say that you can either manually create a SID, or you can have the OS create one for you by using a call to CreateWellKnownSID. The only SID we're really interested in removing is the Administrator rights, and so we create a pointer to a SID which represents the admin account. We use this SID in our call to CreateRestrictedToken by passing it in as the parameter for SIDs to disable.
The Vista way to get a restricted token is similarly easy to accomplish. And I should note that you can use the "old" style as well; it still works. It's just not as restrictive as the low integrity level is. Similar to how we made a restricted token above, we need to start off with the current process' token. However, we need to actually duplicate this token before we can set the integrity level on it. The reason for this is so that we aren't setting the integrity level *for the current application* -- we want to set it for a child process to be made later! Once you've duplicated the process token, we're ready to modify it using the SetTokenInformation API. We use this to set the integrity level to low (normal applications are run as Medium, admin apps are run as High, and OS services are run as System).
So now that we've seen the two ways to create a restricted access token, the rest of the process is anti-climactic. It's simply a call to CreateProcessAsUser and passing in the restricted access token. This will launch the application you specify using the restricted access rights on the token you provide.
Today was theory, but next time, we'll look at practice.
As a matter of interest, does the IDE create a process for the DEBUG build with the same access the IDE is running with?
That's a good question -- the IDE launches applications with the FolderItem.Launch command, which ends up calling thru to the ShellExecute Win32 API. That API ends up using CreateProcess to do all of the heavy lifting for it, which runs in the security context of the calling application. So that means the new process is launched with the same permissions as the IDE.