零基础逆向工程39_Win32_13_进程创建_句柄表_挂起方式创建进程
1 进程的创建过程
打开系统 --> 双击要运行的程序 --> EXE开始执行
步骤一:
当系统启动后,创建一个进程:Explorer.exe(也就是桌面进程)
步骤二:
当用户双击某一个EXE时,Explorer 进程使用CreateProcess函数创建被双击的EXE,也就是说,我们在桌面上双
击创建的进程都是Explorer进程的子进程.
CreateProcess
BOOL CreateProcess(
LPCTSTR lpApplicationName, // name of executable module
LPTSTR lpCommandLine, // command line string
LPSECURITY_ATTRIBUTES lpProcessAttributes, // SD
LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD
BOOL bInheritHandles, // handle inheritance option
DWORD dwCreationFlags, // creation flags
LPVOID lpEnvironment, // new environment block
LPCTSTR lpCurrentDirectory, // current directory name
LPSTARTUPINFO lpStartupInfo, // startup information
LPPROCESS_INFORMATION lpProcessInformation // process information
);
1 创建内核对象

2 分配4GB的虚拟空间(Windows 32位)

3 创建进程的主线程
当进程的空间创建完毕,EXE与导入表中的DLL都正确加载完毕后,会创建一个线程。
当线程得到CPU的时候,程序就正开始指向了,EIP的初始值设定为:ImageBase+OEP。
HANDLE CreateThread(
PSECURITY_ATTRIBUTES psa,
DWORD cbStack,
PTHREAD_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;
也就是,CreateProcess的最后一个 OUT 参数
到此,整个进程创建结束了.
关于句柄和ID
1、都是系统分配的一个编号,句柄是客户程序使用 ID主要是系统调度时使用.
2、调用CloseHandle关闭进程或者线程句柄的时候,只是让内核计数器减少一个,并不是终止进程或者线程.进程或线程将继续运行,直到它自己终止运行。
3、进程ID与线程ID 是不可能相同。但不要通过进程或者线程的ID来操作进程或者线程,因为,这个编号是会重复使用的,也就是说,当你通过ID=100这个编号去访问一个进程的时候,它已经结束了,而且系统将这个编号赋给了另外一个进程或者线程.
2 进程终止
2.1 进程终止的三种方式:
VOID ExitProcess(UINT fuExitCode) //进程自己调用
BOOL TerminateProcess(HANDLE hProcess, UINT fuExitCode); //终止其他进程
ExitThread //终止进程中的所有线程,进程也会终止
2.2 获取进程的退出码:
BOOL GetExitCodeProcess(HANDLE hProcess,PDWORD pdwExitCode);
进程终止时相关操作:
1、进程中剩余的所有线程全部终止运行
2、进程指定的所有用户对象均被释放,所有内核对象均被关闭
3、进程内核对象的状态变成收到通知的状态
4、进程内核对象的使用计数递减1
3 句柄的继承
3.1 命令行参数的使用
char szBuffer[256] = {0};
memcpy(szBuffer,argv[1],8);
DWORD dwHandle = 0;
sscanf(szBuffer,"%x",&dwHandle);
printf("%s\n",argv[0]);
printf("%x\n",dwHandle);
getchar();
3.2 句柄的继承
进程A中的代码:
char szBuffer[256] = {0};
char szHandle[8] = {0};
//若要创建能继承的句柄,父进程必须指定一个SECURITY_ATTRIBUTES结构并对它进行初始化
//三个成员的意义:大小、默认安全属性、是否可以继承
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
//创建一个可以被继承的内核对象
HANDLE g_hEvent = CreateEvent(&sa, TRUE, FALSE, NULL);
//组织命令行参数
sprintf(szHandle,"%x",g_hEvent);
sprintf(szBuffer,"C:/z2.exe %s",szHandle);
//定义创建进程需要用的结构体
STARTUPINFO si = {0};
PROCESS_INFORMATION pi;
si.cb = sizeof(si);
//创建子进程
BOOL res = CreateProcess(
NULL,
szBuffer,
NULL,
NULL,
TRUE,
CREATE_NEW_CONSOLE,
NULL,
NULL, &si, &pi);
//设置事件为已通知
SetEvent(g_hEvent);
//关闭句柄 内核对象是否会被销毁?
CloseHandle(g_hEvent);
进程B中的代码:
char szBuffer[256] = {0};
memcpy(szBuffer,argv[1],8);
DWORD dwHandle = 0;
sscanf(szBuffer,"%x",&dwHandle);
printf("%s\n",argv[0]);
printf("%x\n",dwHandle);
HANDLE g_hEvent = (HANDLE)dwHandle;
printf("开始等待.....\n");
WaitForSingleObject(g_hEvent, INFINITE); //当事件变成已通知时
DWORD dwCode = GetLastError();
printf("等到消息.....%x\n",dwCode);
getchar();
4 以挂起方式创建进程
4.1 以挂起的方式创建进程,观察创建后的结果
STARTUPINFO ie_si = {0};
PROCESS_INFORMATION ie_pi;
ie_si.cb = sizeof(ie_si);
TCHAR szBuffer[256] = "C:\\notepad.exe";
CreateProcess(
NULL,
szBuffer,
NULL,
NULL,
FALSE,
CREATE_SUSPENDED,
NULL,
NULL,
&ie_si,
&ie_pi
);
//恢复执行
ResumeThread(ie_pi.hThread);
4.2 以挂起的方式创建进程,获取进程的ImageBase和AddressOfEntryPoint
STARTUPINFO ie_si = {0};
PROCESS_INFORMATION ie_pi;
ie_si.cb = sizeof(ie_si);
//以挂起的方式创建进程
TCHAR szBuffer[256] = "C:\\ipmsg.exe";
CreateProcess(
NULL, // name of executable module
szBuffer, // command line string
NULL,
NULL,
FALSE, // handle inheritance option
CREATE_SUSPENDED, // creation flags
NULL, // new environment block
NULL, // current directory name
&ie_si, // startup information
&ie_pi // process information
);
//获取外壳程序的入口点
CONTEXT contx;
contx.ContextFlags = CONTEXT_FULL;
GetThreadContext(ie_pi.hThread, &contx); //将ipmsg.exe的线程句柄写到contx中
//获取入口点
DWORD dwEntryPoint = contx.Eax;
//获取ImageBase
char* baseAddress = (CHAR *) contx.Ebx+8;
memset(szBuffer,0,256);
ReadProcessMemory(ie_pi.hProcess,baseAddress,szBuffer,4,NULL); //参数:要读的进程,从哪里开始读,存放到哪里,大小是多少,[out]真正读了多少个字节
ResumeThread(ie_pi.hThread);
零基础逆向工程39_Win32_13_进程创建_句柄表_挂起方式创建进程的更多相关文章
- 零基础逆向工程25_C++_02_类的成员权限_虚函数_模板
1 类的成员权限 1.1 小结: 1.对外提供的函数或者变量,发布成public的 但不能随意改动. 2.可能会变动的函数或者变量,定义成private的 这样编译器会在使用的时候做检测. 3.只有结 ...
- 零基础逆向工程23_PE结构07_重定位表_IAT表(待补充)
重定位表 待补充 IAT表 待补充
- 零基础逆向工程20_PE结构04_任意节空白区_新增节_扩大节添加代码
向代码节添加代码实现 作者经过一周不断的失败,再思考以及无数次调试终于实现. 思路:八个步骤 1. 文件拷到文件缓冲区(FileBuffer) //图示见(零基础逆向工程18之PE加载过程) 2. 文 ...
- 【布艺DIY】 零基础 做包包 2小时 就OK!_豆瓣
[布艺DIY] 零基础 做包包 2小时 就OK!_豆瓣 [布艺DIY] 零基础 做包包 2小时 就OK!
- EPROCESS 进程/线程优先级 句柄表 GDT LDT 页表 《寒江独钓》内核学习笔记(2)
在学习笔记(1)中,我们学习了IRP的数据结构的相关知识,接下来我们继续来学习内核中很重要的另一批数据结构: EPROCESS/KPROCESS/PEB.把它们放到一起是因为这三个数据结构及其外延和w ...
- win32进程概念之句柄表,以及内核对象.
句柄表跟内核对象 一丶什么是句柄表什么是内核对象. 1.句柄表的生成 我们知道.我们使用CreateProcess 的时候会返回一个进程句柄.以及线程句柄. 其实在调用CreateProcess的时候 ...
- 零基础逆向工程36_Win32_10_互斥体_互斥体与临界区的区别
1 引言 讲了第二个内核对象,互斥体.前面已经学过一个内核对象,线程.这节讲两个函数,WaitForSingleObject()和WaitForMultipleObjects().因此这两个函数是根据 ...
- 零基础逆向工程28_Win32_02_事件_消息_消息处理函数
1 第一个图形界面程序 步骤1:创建Windows应用程序 选择空项目 步骤2:在新建项窗口中选C++代码文件 创建一个新的cpp文件 步骤3:在新的cpp文件中添加:#include <Win ...
- salesforce零基础学习(一百一十一)custom metadata type数据获取方式更新
本篇参考: https://developer.salesforce.com/docs/atlas.en-us.234.0.apexref.meta/apexref/apex_methods_syst ...
随机推荐
- DockerFile一键搭建环境(一)
点击查看文件详情 FROM centos:7 COPY --chown=root:root nginx /etc/init.d/ Run set -ex \ && yum insta ...
- kuangbin专题十二 HDU1114 Piggy-Bank (完全背包)
Piggy-Bank Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total ...
- react 中文文档案例五 (循环列表)
function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) = ...
- Unity 动画系统 Animation 和 Animator的小实例
本文结合一个很简单的动画demo,分别采用2种方法,来对比Animation和Animator的使用方式: 方法1:单独使用Animation 方法2:Animation结合Animator 动画De ...
- php内置web server
今天刚开始正式学习PHP(之前有一点了解),推荐学习的网站是w3school.一开始不知道tomcat服务器不支持PHP脚本,直接把.php文件放到tomcat里面去运行,结果嵌入的php代码段没有什 ...
- java——ArrayList 的存在有什么意义?
好像所有的数据类型都可以用比如 TreeMap[] int[] Object[] 这种形式来创建自己的数组,那么ArrayList存在的意义是什么呢? 我只能想到这种:ArrayList可以存储多种 ...
- TCP Nagle算法以及延迟确认(即延迟回复ACK)的学习
TCP/IP协议中,无论发送多少数据,总是要在数据前面加上协议头,同时,对方接收到数据,也需要发送ACK表示确认.为了尽可能的利用网络带宽,TCP总是希望尽可能的发送足够大的数据. (一个连TCP接会 ...
- Naive Operations
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6315 学习博客:https://blog.csdn.net/SunMoonVocano/article ...
- inventor安装失败怎样卸载安装inventor 2019?
AUTODESK系列软件着实令人头疼,安装失败之后不能完全卸载!!!(比如maya,cad,3dsmax等).有时手动删除注册表重装之后还是会出现各种问题,每个版本的C++Runtime和.NET f ...
- Java基础02-变量
1.为什么要使用变量? 变量就是用来记忆数据的,它是一个记忆系统 2.什么是变量? 变量就是一个容器,用来装数据的,变量是放在内存里的. 比如:内存是酒店,变量名就是房间名,变量值就是住进房间的人 3 ...