进程的创建是一件相当复杂的事情,其中要包涵很多工作,我们可以通过反汇编来看看CreateProcess()。为了启动一个进程 可有以下几步:
1.可执行文件必须被以FILE_EXECYTE存取方式打开。
2.可执行映像必须被转载进RAM。
3.必须建立进程执行对象(EPROCESS、KPROCESS和PEB结构)。
4.必须为新建进程分配地址空间。
5.必须建立进程的主线程的线程执行对象(ETHREAD、KTHREAD和TEBstructures)。
6.必须为主线程分配堆栈。
7.必须建立进程的主线程的执行上下文。
8.必须通知Win32子系统有关该进程的创建情况。
下面我们来看一看CreateProcess()函数的一些参数
WINBASEAPI
BOOL
WINAPI
CreateProcessA(
__in_opt LPCSTR lpApplicationName, //可执行文件的文件名
__inout_opt LPSTR lpCommandLine, //命令行参数
__in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, //进程的安全属性
__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, //线程的安全属性
__in BOOL bInheritHandles, // 当前进程内的句柄可不可以被子进程继承
__in DWORD dwCreationFlags, //这个一会再说
__in_opt LPVOID lpEnvironment, // 是否使用本进程的环境变量,默认为NULL
__in_opt LPCSTR lpCurrentDirectory, // 是否使用本进程的驱动器和目录,默认为NULL
__in LPSTARTUPINFOA lpStartupInfo, // 这里边是一个STARTUPINFO结构体的对象
__out LPPROCESS_INFORMATION lpProcessInformation // 这里边是一个PROCESS_INFORMATION结构体的对象
);
STARTUPINFO结构体的具体内容如下:
typedef struct _STARTUPINFO {
// 是本结构的长度 ,一般情况下设为{ sizeof(STARTUOINFO) },为什么呢?原因是因为不同版本的此结构体他们的成员是不一定的
LPSTR lpReserved; // 被保留的字段
LPSTR lpDesktop; // 指定桌面的名称
LPSTR lpTitle; // 控制台应用程序的使用,指定控制台窗口标题
// 指定新创建窗口的位置坐标 和 大小信息
DWORD dwX;
DWORD dwY;
DWORD dwXSize;
DWORD dwYSize;
DWORD dwXCountChars; // 控制台程序使用,指定控制台窗口的行数
DWORD dwYCountChars; //
DWORD dwFillAttribute; // 控制台程序使用,指定控制台窗口的的背景色
DWORD dwFlags; // 标志 它的值决定了STARTUPINFO结构中哪个成员是有效的
WORD wShowWindow; // 窗口的显示方式
WORD cbReserved2; //
LPBYTE lpReserved2; //
HANDLE hStdInput; // 控制台程序使用,几个标准句柄
HANDLE hStdOutput; //
HANDLE hStdError; //
} STARTUPINFOA, *LPSTARTUPINFOA;
PROCESS_INFORMATION结构体的具体内容如下:
typedef struct _PROCESS_INFORMATION {
HANDLE hProcess; // 新建进程的内核句柄
HANDLE hThread; // 新建进程中主线程的内核句柄
DWORD dwProcessId; // 新建进程的ID
DWORD dwThreadId; // 新建进程的主线程ID
} PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;
下面贴出一段代码来看看创建进程的实例
#include "windows.h"
#include "iostream"
using namespace std;
int main()
{
char szCommandLine[]="cmd";
STARTUPINFO si={sizeof(si)};
PROCESS_INFORMATION pi;
si.dwFlags=STARTF_USESHOWWINDOW;
si.wShowWindow=TRUE;
BOOL bRet=::CreateProcess( NULL,
szCommandLine,
NULL,
NULL,
FALSE,
CREATE_NEW_CONSOLE,
NULL,
NULL,
&si,
&pi
);
if(bRet)
{
::CloseHandle(pi.hThread);
::CloseHandle(pi.hProcess);
printf("ProcessID %d \n",pi.dwProcessId);
printf("ThreadID %d \n",pi.dwThreadId);
}
return 0;
}
从CreateProcess()函数的最后两个参数的样子可以看出,&对象,一定是CreateProcess()把一些东西写进对象相应的结构中去了。
下面再来看一小段程序,它主要是用用来枚举系统中正在运行的进程的一些相关的信息
#include "windows.h"
#include "tlhelp32.h"
int main()
{
HANDLE hProcessSnap = NULL;
PROCESSENTRY32 pe32 = {0};
//获得句柄
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(hProcessSnap == (HANDLE)-1)
{
printf("\nCreateToolhelp32Snapshot()failed:%d",GetLastError());
return;
}
pe32.dwSize = sizeof(PROCESSENTRY32);
//列举所有进程名称
if (Process32First(hProcessSnap, &pe32))
{
do
{
printf("进程名称 %s 进程ID %u \n",pe32.szExeFile,pe32.th32ProcessID);
}
while (Process32Next(hProcessSnap, &pe32));//直到列举完毕
}
else
{
printf("\nProcess32Firstt() failed:%d",GetLastError());
}
//关闭句柄
CloseHandle (hProcessSnap);
return 0;
}
从倒数第12行可以看出,我们是从pe32对象的th32ProcessID成员中获得到当前系统正在运行的进程的一些信息的。当然了在整个的遍历的过程中,是通过
BOOL
WINAPI Process32Next(
__in
HANDLE
hSnapshot,
__out LPPROCESSENTRY32
);
函数来进行遍历的,当然了他遍历的是系统的快照,其中第一个参数便是一个系统快照的句柄,所以程序的最初是要创建系统快照,目的就是把当前系统内正在运行的进程通过快照捕获下来一份。
我们不得不看看PROCESSENTRY32是一个什么东东,他的内部都有哪些成员,这些成员都存储了什么东西。
typedef struct tagPROCESSENTRY32
{
DWORD dwSize; // 结构的长度,不需预先设置
DWORD cntUsage; // 进程的引用计数
DWORD th32ProcessID; // this process
ULONG_PTR th32DefaultHeapID; //进程默认堆的ID
DWORD th32ModuleID; // associated exe进程模块的ID
DWORD cntThreads; // 进程创建的线程数
DWORD th32ParentProcessID; // this process's parent process 进程的父线程ID
LONG pcPriClassBase; // Base priority of process's threads 进程创建的线程的基本优先级
DWORD dwFlags; // 内部使用
CHAR szExeFile[MAX_PATH]; // Path 进程对应的可执行文件名
} PROCESSENTRY32;
未完待续。。。。
标签:__,INFORMATION,HANDLE,来龙去脉,句柄,进程,DWORD From: https://blog.51cto.com/u_15872025/5845489