win32笔记-进程
了解进程
在win32中,要想把exe程序运行起来,就必须将程序加载到内存中,当程序被双击运行起来以后,这时才能被叫做进程。现在的计算机是多线程操作系统,可以在计算机的任务管理器看到当前的所有进程。
- 进程,可以为当前程序提供所需的资源,如:数据、代码等等
每一个进程都有自己的4GB的虚拟地址空间
进程内存空间地址的划分
| 分区 | x86 32位windows |
|---|---|
| 空指针赋值区 | 0x00000000 - 0x0000FFFF |
| 用户模式区 | 0x00010000 - 0x7FFEFFFF |
| 64KB禁用区 | 0x7FFF0000 - 0x7FFFFFFF |
| 内核 | 0x80000000 - 0xFFFFFFFF |
- 在空指针赋值区和64KB禁用区,可以简单的理解为从来没有被使用的区域,包括操作系统和应用软件都不会使用它。
进程的创建
任何进程都是别的进程创建的,而第一个进程起源于操作系统,比如双击运行一个exe文件,进程explorer.exe通过调用CreateProcess()创建了一个新的进程
进程创建过程
- 映射EXE文件
- 创建内核对象EPROCESS
- 映射系统DLL(ntdll.dll)
- 创建线程内核对象ETHREAD
- 系统启动线程(映射DLL(ntdll.LdrlnitializeThunk),线程开始执行)

一个有趣的事情就是如果运行程序A.exe,但是等他在系统启动线程时,用B程序里面的数据和代码在进程里面替换A程序的数据和代码,然后你会惊奇的发现,B程序成功的跑起来了,但是在任务管理器界面只能看到A程序的进程,而看不到B程序的进程,实际上,A程序的进程就是替换后的B程序的进程,这非常好玩。试想一下,如果将B程序换成病毒,A程序伪装成系统程序(如service.exe),那么就无法手动结束A程序,因为其受到系统的保护,实际运行的是病毒程序,并且可能还判断不出A程序就是病毒换了的程序。这就是狸猫换太子。
另一个就是游戏外挂的运行原理,就是系统启动线程之前,注入自己的外挂dll,但是游戏肯定会不有一个xx.dll用来检测,防止dll注入,事实上,只要在这个xx.dll检测文件映射之前,先行注入外挂dll,就可以达到防止检测注入的目的,归根到底,xx.dll用来检测注入,其实其本身也是代码和数据。
win32笔记-创建进程
前言
之前已经学习过什么是进程,知道一个进程是别的程序创建出来的,那么我们自己如何创建一个进程呢?下面就用代码来详细演示。
代码
1 |
|
实例代码演示创建了一个chrome.exe的进程,浏览器一般传入参数是网站网址。
win32笔记-句柄
什么是内核对象
像进程、线程、文件、互斥体、事件等在内核都有一个相对应的结构体,这些结构体由内核负责管理。我们管这样的对象叫做内核对象。

比如,当应用层创建创建进程时,相应在内核层会有一个EPROCESS的结构体与之对应,线程、文件、互斥体、事件等也是同理。
如何管理内核对象
如果,现在有一个进程,在内核层一定有一个与之对应的E-PROCESS结构体内核对象。现在,分别依次调用createProcess,CreateThread,createEvent,createFile等函数,在内核里面肯定会有与之相对应的结构体

为了保证内核结构和系统的安全性,系统不会直接提供内核结构的地址给用户层直接操作。但是,为了操作,系统会提供一张表,使得内核结构和一个唯一的编号对应。每一个进程都有一个句柄表。

这个编号,也就是句柄,通过对句柄的操作间接对内核结构操作。
1 |
|
多进程共享一个内核对象
前面,知道了CreateProcess可以创建一个进程,如果这个行为在A进程里面发生的,也就是说,在A进程里面调用了CreateProcess创建了一个A的子进程,那么,这个子进程能否被另一个进程B共享呢?答案是肯定的。

如果,在B进程里面也CreateProcess,也会创建一个进程,当然,与A的子进程没有一点关系,因为这是它自己创建的进程;要想有关系,就必须通过OpenProcess,这样,就有了关系。但需要注意的是,这时,A、B进程都有一个句柄表,都有一个句柄同时指向A创建的子进程A,不过,这两个编号不同,这两个句柄并不相同,只是指向结果一样,能够同时操作同一个内核对象。
其次,这个子进程的内核对象自己有一个计数器,这个计数器是用来记录当前一共有多少进程对其进行掌控,操作。如上图,当A进程CreateProcess创建了一个进程的内核对象,这个计数器会记录1,当B进程OpenProcess,这个计数器会变成2,依次类推。这样做的意义,就得当A进程CloseHandle,计数器会减1,但是这个进程不会死亡,当B进程也CloseHandle,计数器变为0,没有进程把控对应它,这时,才会死亡。所有内核对象都一样,但是有一个内核对象除外,就是线程。
每一个进程都有一个线程,进程是靠线程支持的,如果仅仅释放进程句柄,释放线程句柄,计时器为0了,但达不到使得进程死亡的目的,因为线程还没有被终止。
句柄是否可以被继承
简单来说,是可以的。前提是,父进程调用createProcess,CreateThread,createEvent,createFile等函数必须将将其是否可以被继承关系描述为允许继承,那么,当父进程创建一个子进程时,这个子进程,就会继承得到父进程允许继承的句柄。