一、进程的生命周期
1.1 进程的创建过程
步骤一:当系统启动后,创建一个进程,Explorer.exe 也就是桌面进程
步骤二:当用户双击某一个EXE时,Explorer进程 使用CreateProcess()
函数创建被双击的EXE,也就是说,我们在桌面上双击创建的进程都是Explorer进程的子进程。
任何一个进程都需要由别的进程创建它,但在进程创建后,父进程的销毁与否与进程无关。
1.2 CreateProcess()
做了什么
BOOL CreateProcess(
LPCSTR lpApplicationName,
LPSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCSTR lpCurrentDirectory,
LPSTARTUPINFOA lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
1.2.1 创建内核对象
注意:进程是一个空间的概念,而线程才是真正执行的代码
句柄表
每个进程在高2G的空间中,有着一个句柄表,刚创建时是空的。
创建内核对象时,句柄表中会存储内核对象相关信息,例如内核对象句柄
,内核地址
,和继承属性
。
比如:
CreateProcess CreateMutex
CreateThread CreateFile
CreateEvent CreateFileMapping
1.2.2 分配4GB的虚拟空间(Windows 32位)
NULL指针使用
int* pnSomeInteger = (int*) malloc(sizeof(int));
*pnSomeInteger = 5;
用户区
-
将EXE拉伸,存储到指定的位置
-
遍历EXE导入表,将需要的DLL拉伸存储到指定位置。如果位置被占用,换个地方并且通过DLL的重定位表,修改全局变量。
-
DLL如果引用了其他的DLL,递归第二步
-
修复EXE/DLL中的IAT表
-
创建线程、设置线程CONTEXT 开始执行
1.2.3 创建进程的主线程
当进程的空间创建完毕,EXE与导入表中的DLL都真确加载完毕后,会创建一个线程。
当线程得到CPU的时候,程序就开始指向了EIP的初始值设定为:ImageBase + OEP
。
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES psa,
DWORD cdStack,
PIHREAD_START_ROUTINE pfnStartAddr,
PVOID pvParam,
DWORD fdwCreate,
PDWORD pdwThreadID
);
当进程创建成功后,会将进程句柄、主进程句柄、进程ID以及主线程ID存储在
typedef struct _PROCESS_INFORMATION {
HANDLE hProcess; //进程句柄
HANDLE hThread; //主进程句柄
DWORD dwProcessId; //进程ID
DWORD dwThreadId; //线程ID
} PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;
也就是:CreateProcess()
的最后一个 OUT 参数
到此,整个进程创建就结束了
1.3 终止进程
1.3.1 终止线程的三种方式
//进程自己调用
VOID ExitProcess(UINT fuExitCode);
//终止其他进程
BOOL TerminateProcess(HANDLE hProcess, UINT fuExitCode);
//终止进程中的所有线程,进程也会终止
ExitThread();
1.3.2 获取进程的退出码
BOOL GetExitCodeProcess(HANDLE hProcess, PDWORD pdwExitCode);
1.3.3 进程终止时相关操作
- 进程中剩余的所有线程全部终止运行
- 进程指定的所有用户对象均被释放,所有内核对象均被关闭
- 进程内核对象的状态变成收到通知的状态
- 进程内核对象的使用计数递减1
1.4 内核对象 句柄和ID的区别
- 都是系统分配的一个编号
- 句柄是客户程序使用的,ID主要是系统调度时使用的。
CloseHandle()
关闭内核对象句柄的本质:- 让内核计数器减一,在该进程的句柄表中删除该内核对象,并不是终止或结束进程。
- 当内核计数器为0时,该内核对象才会自己终止运行。
- 在一个进程中,多次调用
CloseHandle()
关闭内核对象句柄时无用的;
在第一个调用时,该内核对象就从该进程的句柄表中删除了,后面的所有调用都是无用的。
- 进程ID与线程ID是不可能相同的。但不要通过进程或者线程ID来操作进程或者线程。
- 因为ÿ