On
Windows, use the
CreateProcess( )
API function to load and execute a new
program. Alternatively, use the CreateProcessAsUser(
)
API function to load and execute a new
program with a primary access token other than the one in use by the
current program.
The Win32 API provides several functions for executing new programs.
In the days of the Win16 API, the proper way to execute a new program
was to call WinExec( )
. While this function still exists in the
Win32 API as a wrapper around CreateProcess( )
for
compatibility reasons, its use is deprecated, and new programs should
call CreateProcess( )
directly instead.
A powerful but extremely dangerous API function
that is popular among developers is ShellExecute(
)
. This function is implemented as a wrapper
around CreateProcess( )
, and it does exactly what
we’re about to advise against
doing with CreateProcess( )
—but
we’re getting a bit ahead of ourselves.
One of the reasons ShellExecute( )
is so popular
is that virtually anything can be executed with the API. If the file
to execute as passed to ShellExecute( )
is not
actually executable, the API will search the registry looking for the
right application to launch the file. For example, if you pass it a
filename with a .TXT extension, the filename
will probably start Notepad with the specified file loaded. While
this can be an incredibly handy feature, it’s also a
disaster waiting to happen. Users can configure their own file
associations, and there is no guarantee that you’ll
get the expected behavior when you execute a program this way.
Another problem is that because users can configure their own file
associations, an attacker can do so as well, causing your program to
end up doing something completely unexpected and potentially
disastrous.
The safest way to execute a new program is to use either
CreateProcess( )
or CreateProcessAsUser(
)
. These two functions share a very similar signature:
BOOL CreateProcess(LPCTSTR lpApplicationName, LPTSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation); BOOL CreateProcessAsUser(HANDLE hToken, LPCTSTR lpApplicationName, LPTSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation);
The two most important arguments for the purposes of proper secure
use of CreateProcess( )
or
CreateProcessAsUser( )
are
lpApplicationName
and
lpCommandLine
. All of the other arguments are well
documented in the Microsoft Platform SDK.
-
lpApplicationName
Name of the program to execute. The program may be specified as an absolute or relative path, but you should never specify the program to execute in any way other than as a fully qualified absolute path and filename. This argument may also be specified as
NULL
, in which case the program to execute is determined from thelpCommandLine
argument.-
lpCommandLine
Any command-line arguments to pass to the new program. If there are no arguments to pass, this argument may be specified as
NULL
, butlpApplicationName
andlpCommandLine
cannot both beNULL
. IflpApplicationName
is specified asNULL
, the program to execute is taken from this argument. Everything up to the first space is interpreted as part of the filename of the program to execute. If the filename to execute has a space in its name, it must be quoted. IflpApplicationName
is not specified asNULL
,lpCommandLine
should not contain the filename to execute, but instead contain only the arguments to pass to the program on its command line.
By far, the biggest mistake that developers make when using
CreateProcess( )
or CreateProcessAsUser(
)
is to specify lpApplicationName
as
NULL
and fail to enclose the program name portion
of lpCommandLine
in quotes. As a rule, you should
never specify lpApplicationName
as
NULL
. Always specify the filename of the program
to execute in lpApplicationName
rather than
letting Windows try to figure out what you mean from
lpCommandLine
.
Get Secure Programming Cookbook for C and C++ now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.