目录
1.然后我们创建一个可以被继承的内核对象,CreateEvent创建事件
4.再创建进程,注意:将创建结构体函数的第五个参数传参为TRUE,表示需要继承,否则即使前面指定了结构体来表示继承,也无法在子进程中继承到父进程的句柄表
5.SetEvent来修改状态,我们在子进程中接受命令行参数,并将命令行参数赋值给HANDLE类型的事件,来检测是否能WaitForSingleObject到
1.进程的创建过程
一、进程的创建过程
进程就是一个 4GB的空间,因为32位系统里面的寻址范围是2的32次方。Explorer.exe程序也是被操作系统的内核程序创建的,只不过该程序在创建完毕桌面程序后就退出了。
二、CreateProcess的做了什么
当要创建出一个进程时,会创建出一个内核对象,内核对象在内存中分配了4GB的虚拟内存空间,在高2G位置中,有一个句柄表。该句柄表在刚创建的时候是空的,但是在该进程中的主线程或子线程中有CreateProcess、CreateThread等创建内核对象的函数时,就会在句柄表的位置中添加句柄编号。
句柄标号其实是系统给内核对象地址的一个编号,因为不可能把内核对象真正的地址传递出去。
一个进程的创建就是在4GB中贴入各种exe、dll文件,因为一开始装载的地址是写死的,所以有可能会发生位置被占用的情况,因此需要重定位表来记录哪些需要被修改的位置,然后由操作系统来进行绝对地址的修改,并且有些exe或者dll中会调用其他dll中的函数,但是地址却没有写死,因此需要修改IAT表。
当贴块完毕后,就会创建一个主线程,再将EIP的初始值修改为ImageBase+OEP后就可以开始跑了
2.创建进程
// CreateProcess.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
int main(int argc, char* argv[])
{
STARTUPINFO si={0};
PROCESS_INFORMATION pi={0};
si.cb=sizeof(STARTUPINFO);
TCHAR szApplicationName[]=TEXT("c://program files//internet explorer//iexplore.exe");
BOOL ret=CreateProcess(
szApplicationName,
TEXT(" http://www.ifeng.com"),
NULL,
NULL,
FALSE,
CREATE_NEW_CONSOLE,
NULL,
NULL,&si,&pi);
printf("%x\t%x\t%x\t&x\n",pi.dwProcessId,pi.dwThreadId,pi.hProcess,pi.hThread);
return 0;
}
1.创建进程函数的第一个参数
第一个参数是进程模块的名字,在我们打开进程时,可以将进程名传参(可以是详细的也可以是单独一个进程名,系统会自动加上exe后缀名,但是会一层一层的在系统文件中查找),也可以传参为NULL,通过第二个参数进行打开进程
2.第二个参数
第二个参数时命令行参数,我们也可以将第一个参数传NULL,通过第二个参数进行传参
也可以第一个参数传参路径,第二个参数可以向进程传递参数,比如:打开网站某个网页
3.两个结构体
第一个结构体初始化后需要将第一个成员进行赋值
第二个结构体是一个out型参数,我们可以通过结构体得知进程的相关信息
3.进程终止
进程终止时的相关操作是操作系统在为我们做,我们只需大概了解
4.句柄的继承
现在我们创建两个进程来查看继承是否成功
父进程:Part_A:
// Patr_A.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
int main(int argc, char* argv[])
{
char szBuffer[256] = {0};
char szHandle[8] = {0};
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
HANDLE g_Event=CreateEvent(&sa,true,false,NULL);
sprintf(szHandle,"%x",g_Event);
sprintf(szBuffer,"C:/Part_B %s",szHandle);
STARTUPINFO si={0};
PROCESS_INFORMATION pi={0};
si.cb=sizeof(si);
BOOL ret=CreateProcess(
NULL,
szBuffer,
NULL,
NULL,
true,
CREATE_NEW_CONSOLE,
NULL,
NULL,&si,&pi);
SetEvent(g_Event);
CloseHandle(g_Event);
return 0;
}
我们要想实现父进程中的句柄表能够继承到子进程中,我们需要定义一个结构体并对齐进行初始化。
此处第三个成员赋值为TRUE表示父进程句柄表可以被继承(在后面创建子进程中还有个参数要定义,以此来表示需要继承父进程的句柄表)
1.然后我们创建一个可以被继承的内核对象,CreateEvent创建事件
2.再使用sprintf函数将数字转换为字符串
3.然后初始化创进程需要的结构体,而后创建结构体
4.再创建进程,注意:将创建结构体函数的第五个参数传参为TRUE,表示需要继承,否则即使前面指定了结构体来表示继承,也无法在子进程中继承到父进程的句柄表
5.SetEvent来修改状态,我们在子进程中接受命令行参数,并将命令行参数赋值给HANDLE类型的事件,来检测是否能WaitForSingleObject到
子进程:
// Part_B.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
int main(int argc, char* argv[])
{
TCHAR szBuffer[256]={0};
memcpy(szBuffer,argv[1],8);
DWORD Handle=0;
sscanf(szBuffer,"%x",&Handle);
printf("%s\n",argv[0]);
printf("%x\n",Handle);
HANDLE g_Event=(HANDLE)Handle;
printf("Lording.......\n");
WaitForSingleObject(g_Event,-1);
DWORD Code=GetLastError();
printf("Waiting successful!\n");
getchar();
return 0;
}
注意:我们在创建一个内核对象的时候会有一个计数器,当被使用的时候会+1,当我们CloseHandle的时候,只是计数器-1了,但是已成任然存在,Wai依旧能够等待到
连续两次Close Handle是无效的,因为第一次Close后就将句柄在句柄表当中抹除了,所以第二次关闭是无效的