[Autogenerated] I typically find it useful to write some code to see
how things work under the covers a little bit.
So let's see how to use the create process API to create a process,
what is the result of that process creation?
So I'm going to launch visual studio here in my Windows 11 machine.
I'm going to create a new project.
Let me do find new project here.
I'm going to look for a simple console application here using a C plus plus,
so you might need to do some filtering here just to look
for C++ that's the new uh project dialog,
which is not very useful or not very good as it used to
be in the previous to the 2019 days.
Anyway, here's a console application for C++ Let me click next.
Let me create an application that's going to be called,
simply create process, I think that would be a good name.
And let me just put it somewhere more convenient,
more convenient location like C dev let me click the create button here.
What we get from the project wizard here is some simple startup
code we can we can get into which just gives us a very simple
hello world text here and includes.
I'll stream.
That's the only file that we have here and we have some
comments here provided by by visual students.
We just remove every here I'm going to add and include for
Windows dot H because this is the main include for all the
Windows or most of the Windows standard.
APIs I'm going to add include for stds for using print if I don't really
like this see out thing and the I'll stream but I'm going to just use STD
Io and so what I want to do here is to call the create process function
which is a significant function you can see it has a nine parameters which
is quite quite a number.
It returns a boolean that indicates whether the creation of the process
succeeds or fails notice by the way that create process,
not a function really,
but a macro that expands to create process W because we know that most
of the windows API functions that have string as part of their
parameters are actually two sets of functions with an A suffix and w
suffix for asking and wide for unicode.
We've seen that in the debugger in the previous course so I can use the macro
because by default it's going to be expanded to unicode,
which is what we want but we can even use the full function
name explicitly by just using the W version.
That's fine as well.
And so the return value here is the Boolean indicating
whether we have succeeded in creations.
Let's grab that Boolean here and start adding parameters to the
create process API I'm not going to go over all these parameters in
too much detail but I'll give you enough information to understand
the call to create process.
This is of course all properly documented in the Microsoft documentation.
The first two parameters are strings called application name and command
line but they're actually more flexible than that.
And the first string is a constant string that's
supposed to point to some executable.
And the second parameter could be the rest of the command line but in fact we
can use the second parameter only to provide a name of an executable and the
command line and they're treated a bit differently.
So the first parameter,
if you just specify a simple name like Notepad it's not going to look anywhere
except for the current directory of the process if you specify that with the
second parameter is actually going to look in other directories such as the
system 32 directory where Notepad is likely to be located and that's why it's
mostly more um easy or easier to use.
The second parameter when we want to look up things such as a Notepad
let me use note that here is a demonstration by using l Notepad here to
specify the unicode string to let the compiler to convert that literal
string from asking into unicode.
And and that's because we're calling the create process W function,
which is the way to go and you can see here that
Visual Studio seems to be unhappy.
You can see the reds quickly here which indicates Visual Studio
is not too happy about what I'm doing here.
And the problem is that we can see the string here is a pointer to
a wide string but it's not a constant pointer.
And because we'd only literal strings are in the read only memory trying to
provide that as as a read write memory is not going to compile.
I can force it by just putting a pointer to wide string here forcefully
and the compiler will have to obey IntelliJ However,
at runtime it's actually this memory is actually being used by the API
and written to the same value that it's already there.
It's kind of weird,
weird behavior for the create process W function and that would
cause an access violation exception because that memory doesn't
have a read write permissions, but only read permissions.
And so in order to solve this in a more elegant way or perhaps a simpler way,
I'm just going to create the actual path here in a local variable.
And local variables which are always on the stack are always read.
Right?
So all the stack memories always read.
Right.
So it's going to be perfectly fine to provide.
Name here as the parameter to create process in order to create a note.
But process here, notice,
I don't even have to add an extension if there's no extension.
The create process function is nice enough to add an e x e extension in general.
The extension doesn't really mean anything.
You can create an executable that has an abc extension or whatever you like.
And the Colonel doesn't really care,
but in most cases we do have an executable extension.
The next two parameters are called the uh,
process attributes and thread attributes,
which is of type, security attributes.
And this is a optional data structure that contains
security descriptor information.
But for our purposes we're not going to use that for now.
I'm going to specify now here, by the way,
I am using the C++ null pointer keyword,
C++ 11 null pointer keyword.
If you don't care about C++ you can also use the null macro,
the classic macro in C but I'm going to keep that because it's more
elegant and technically even a bit more correct.
Although in a foreign behavior perspective, it's exactly the same.
The next parameter is called inherit handle it has to
do with something called handle, inheritance,
something we'll discuss in the future course for now
let me just specify false here.
The next parameter is called creation.
Flags and contains a bunch of flags we can specify
to customize process creation.
So for example, one thing we can do is use a constant called create suspended.
We should create the process and in fact the first thread in a suspended state,
so the process will be sort of ready to go.
But the first thread is not yet going to execute any code and this is sometimes
useful and sometimes useful for malicious purposes as well.
Another option that used to change the priority class of the process.
This is something I mentioned briefly,
which is about the based priority for all the threads in the process,
something we'll discuss in the future course as well.
So I can specify the default priority class that I like and of course
we can combine multiple flags if you wanted to.
The documentation lists all the other flags and there's quite a bit of
flags there that you are welcome to look up yourself.
The next parameter is going to be a pointer to the environment block.
So this is the way to specify the environment variables
to be used by the target process.
And so it's possible to be the build environment block.
Data structure contains the environment variables
would like the new process to use.
The simplest option here is to specify final,
which will simply copy the environment variables used by the
parent process to the newly created process,
which we're going to use here as well.
The next parameter is called the current directory.
This allows us to specify current directory for the new
process before that process gets created.
And the current directory is one thing that is used as
part of the default search path for DLS,
which I'll describe in the next clip.
So for now I'm going to specify now here indicating just
use the same current directory as we have in our current
uh current creative process.
And finally we have last two parameters which are data structures.
We need to provide one of them is an input data structure
called startup info and the second one is an output data
structure called process information.
So I'm going to just put the addresses of these data
structures of hosts will have to create them.
So here's start a pinfall and start a pinfall has another
set of members that can be used to further customize
process creation in various ways.
I'm not going to go over that here,
but the minimum thing we have to do is to zero out this data structure and
put the size of the data structure in the first member of the data
structure that has the name C b short for count of bytes so I can do
something like this like using ma'am set here,
20 out the structure, this is important.
Otherwise it will be garbage values there in the data
structure which would cause process, sorry,
create process to a likely to actually fail and then I need to specify
the size of the data structure using this kind of code and putting the
size in the first member in the startup info.
Data structure is a very common way for Windows to provide
versioning So if a future version would increase the members
provide extra members for this data structure.
The size will be increased but only for new clients that
know that the size is actually bigger.
And so when the size is smaller,
the API knows not to look at the extra members because apparently
the client was compiled as an order client and has no idea that
there actually are any extra members.
So this is what we have to do here.
And there's a simpler way to do that.
Which is just by using this kind of initialization with size of S.
I,
which actually specifies that as the first member and zeros
out the rest of the members automatically.
This is part of the C standard,
so it's a more elegant way to do these two operations.
In one simple ______,
the second structure is called process information
and this is an output structure.
So there's no need to to initialize that in any way
it's going to be returned as a result.
If indeed we get a successful status here.
If the process is created successfully.
If not, then we can display some kind of error saying error creating process,
we can display the error number,
which is the number return from the function get last error,
which always or in most APIs returns the last error that occurred when when
some API function was invoked from the current threat we've seen already in
the previous course that the last area is actually stored in the threat
environment block And essentially we're done.
Well, not really done.
We have to take care of the successful case in in an appropriate way.
So let's do that and see what we get back.
If we get the process successfully created, we'll get back the process I.
D.
Which is the same thing we should be able to see in task manager for instance.
And also the thread I.
D.
Of the first process.
Sorry,
of the first thread in the process this is provided as
as part of the process information, data structure.
We can see here the process I.
D.
And the thread ID.
So let me just display those and then the other two members will get in process
information or to open handles to the process and thread.
And these handles are all powerful handles that we see very soon,
which allow me allows me to do anything I want really with
these processes with process and thread.
But for now let's just use the close handle API to properly
close the handles to this uh to this process and thread
objects as I don't need them anymore.
This is not strictly necessary ba because when we exit our own
creator process all the handles in the handle table are going
to be closed anyway by the kernel.
Something we'll discuss a bit later when we talk about process destruction.
But let me just do that to make it more explicit.
And to kind of get into the habit of closing handles
once I don't need them anymore.
So let's see if this code actually compiles.
Let me compile the code by using the build build solution option.
You can see it compiles just fine, creates an executable here,
ready to go in the next clip, we'll run it and see what we get.