众所周知,在Windows操作系统中,某些进程显得极为耀眼和特殊,如csrss.exe
smss.exe
wininit.exe
因为你一旦结束它们电脑就会蓝屏死机(BSOD)
为什么?
因为这些进程对于 Windows 的运行至关重要,没有它们,很多事情都无法进行。那么操作系统是如何知道一个进程是重要的呢?内定?举荐?征辟?门荫入仕?让我们一探究竟,揭开这一层神秘的面纱
为了方便一些读者的水平,让我们从最基础的聊起。
程序到底是什么?
我们常听到“数据结构+算法=程序”的说法,但为什么是“数据结构”而不是“数据+算法”呢?
原因在于,数据本身是非常底层的概念。数据仅仅是字符、字符串、整数、浮点数等基本元素。我们可以利用这些数据编写公式,但要实现复杂的算法,数据的组织形式就变得至关重要。
例如,简单的排序算法或二分查找算法都有一个基本要求:数据需要有特定的组织形式。比如,二分查找需要数据是有序的,并且能通过索引随机访问。而链表只能顺序访问,因此无法在链表上实现二分查找。
因此,算法必须与数据结构相结合。没有合适的数据结构,算法的实现将变得困难(除了某些数学算法,如辗转相除法)。
“数据结构+算法”是否足够呢?
显然还不够。在这个层面,我们只看到了一些按照一定规律排列的数据以及处理这些数据的算法。
这就像你在工地上看到一个花名册,上面有50万人。要算工钱或事故率也许够了,但如果要安排具体的工作,比如让某些人挖坑、某些人垒墙,就显得复杂得多。你需要将这些工人按职业、等级、任务等分类,然后安排他们的工作。
同样,在程序中,面对复杂的任务,我们需要的不仅仅是数据和算法。我们需要一种机制,将算法和数据结构结合在一起。面向对象编程提供了一种基础设施,将“算法”与“对象”绑定在一起,从而简化了任务分配和执行。
例如,你可以将每个工人视为一个“对象”,然后通过调用对象的方法来执行任务。你不需要详细了解每个工人应该做什么,只需调用相应的方法,工人就会知道自己该做什么。这样,整个系统就能井然有序地运行。
秩序井然
面向对象的优势在于能够将数据和相关操作紧密绑定,使得代码组织更加有序,井井有条。你不再需要逐一检查每个函数的功能,只需调用对象的方法,相关的操作就会自动执行,从而使得系统更加高效、简洁。
以上,所以IT领域的人会经常听到这么一句话:万物皆对象
Windows中的对象
操作系统本质上也是程序,那么势必包含我们如上所学的“对象”。在Windows中,对象是位于内存中的表示系统资源的数据结构,比如有文件对象、磁盘对象、进程对象、令牌对象、窗口对象、计时器对象等等,可以用微软的sysinternals套件的winobj工具查看这些对象类型:
套件下载地址:https://live.sysinternals.com/
这些对象一般按类别来说又分为三组:
- User 对象(用户对象)
- GDI 对象(图形界面对象(或 GDI 对象))
- Kernel 对象(内核对象)
系统使用用户对象进行窗口管理,GDI 对象进行图形管理,内核对象用于内存管理、进程执行和进程间通信 (IPC) 。
用户对象包括:Hook、Icon、Menu、Window等。
图形界面对象包括:Bitmap、Brush、Font、Pen、Metafile等。
内核对象包括Token、Desktop、Event、File、Heap、Module、Mutex、Pipe、进程、线程、信号量、窗口站等。
看到这里,聪明的小伙伴也明白了,我们要研究的东东正是这个内核进程对象。要查看这个对象结构我们可以通过Vergilius Project项目:
也可以手动使用windbg工具dt(display type)出来:
EPROCESS内核结构,它保存有关正在运行的进程的信息,它的Flags成员是一个联合体,其中包含一个BreakOnTermination位。这一位可以通过逻辑操作AND 0x00002000
或C语言中的常量PS_PROCESS_FLAGS_BREAK_ON_TERMINATION
来访问。
每个进程终止都会调用到Windows API的TerminateProcess
函数 ,而这个函数最终会通过一层层包装进入到内核层的PspTerminateProcess
函数,让我们逆向这个函数,可以看到在进程结束时,会检查EPROCESS::Flags,如果设置了这个位,将会执行KeBugCheckEx进行蓝屏
所以如果我们把任意一个普通进程结构的这一位置于1,就可以让这个平平无奇的进程逆天改命
ULONG BreakOnTermination = (setCritical) ? 1 : 0;
NTSTATUS status = NtSetInfoProcess(hProcess, ProcessBreakOnTermination, &BreakOnTermination, sizeof(ULONG));
例如,让我们运行记事本,并通过其名字将其变身为天命进程:
对抗defender:
没变身之前会被秒
变身之后,金刚不坏
信 安 考 证
CISP、PTE、PTS、DSG、IRE、IRS、NISP、PMP、CCSK、CISSP、ISO27001... |