我是靠谱客的博主 俊逸黑夜,最近开发中收集的这篇文章主要介绍windows进程管理器_面向Windows,Linux,Mac ,安卓, 木马,密码破解内存提取基于KPCR结构的技术研究...,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

ae3df64d40bee361baeff95607646696.png

Windows内存分析原理

内存镜像存储的是二进制数据,内存取证分析的任务就是从这些貌似毫无意义的二进制数据中找到系统的运行信息。这些二进制数据从根本上说,其来源都是操作系统的内存分配。为何分配、如何分配以及何时分配内存使不同内存区域之间有了不同的含义。从取证的角度来说,了解内存数据的特征,可以推断出分配的内存区域的内容和其含义,从内存镜像文件中得到和标记特定的数据。进一步,如果熟悉操作系统的内部结构以及分配和释放内存的机制,将更加有助于深入地了解所获数据的背景,如该内存数据是否正在被系统使用,还是已经被系统释放等。

Windows的绝大部分代码是用C语言编写的,少部分是用C++编写的。只有那些需要直接与系统硬件打交道的部分,或者对性能极端敏感的操作系统部分,才是用汇编语言编写的。Windows内存分析的基本原理,就是根据Windows操作系统组件的数据结构(如结构体、链表、双向链表等)及其特征,在二进制镜像中确定其存储区域,并根据数据结构的特定含义,从内存数据中分析并获得更多可以表示系统运行状态的证据以及相关数据。

本文首先简要介绍了Windows操作系统的关键系统组件,帮助读者了解内存分析中采用的文件、对象或数据结构属于Windows操作系统的哪个组件,并在操作系统中有何作用;然后,介绍了两个内存分析工具(WMFT和volatility)进行内存分析的原理;最后,详细介绍了基于KPCR结构的内存分析方法。为深入实战Windows,Linux,Mac ,安卓, 木马,密码破解内存提取取证提供坚实理论。

1.1Windows操作系统关键组件

1.1.1Windows架构简介一个简化的Windows操作系统架构如图1-1所示。注意,这只是个基本架构,并没有显示所有的内容。例如,网络组件和各种类型的设备驱动程序层次等都没有显示。

图1-1中,线上面的方框代表了用户模式的进程,线下面的组件是内核模式的操作系统服务。用户模式的线程在一个受保护的进程地址空间中执行(不过,当它们在内核模式中执行时,可以访问系统空间)。因此,系统支持进程、服务进程、用户应用程序和环境子系统都有它们各自的私有进程地址空间。

7d4444ca00d6c82c3d5e34c5afc1a89e.png
图1-1简化的Windows架构

1.用户模式进程

(1)固定的系统支持进程,如登录管理(logon)、会话管理器(sessionmanager)等,它们并不是Windows服务,也就是说,它们不是由服务控制管理器启动的。

(2)服务进程宿纳的是Windows服务,如任务调度(Task Scheduler)、打印(Print Spooler)等,往往要求独立于用户登录而运行。

(3)用户应用程序。

(4)环境子系统服务器进程。这里的环境是指操作系统展示给用户或者程序员的个性化部分。包括Windows子系统、POSIX子系统、OS/2子系统。

2.Windows的内核模式组件

(1)Windows执行体(Executive):包含内存管理、进程和线程管理、安全性、I/O、网络和跨进程通信等基本的操作系统服务。

(2)Windows内核(Kernel):由一组低层次的操作系统功能构成,如线程调度(Thread Scheduling)、中断(Interrupt)、异常分发(Exception Dispatching)和多处理器同步。它也提供了一组例程和基本对象,执行体的其余部分利用这些例程和对象实现更高层次的功能。

(3)设备驱动程序(Device Driver):既包括硬件设备驱动程序,也包括文件系统和网络驱动程序之类的非硬件设备驱动程序。

(4)窗口和图形系统(Windowing and Graphics system):实现了图形用户界面GUI功能。

了解Windows的核心系统文件名称,有助于内存分析,因为有时会用到某些系统文件。Windows操作系统核心组件对应的文件如表1-1所示。

59dd7aca7ac5e35a635b4ec320611ee8.png
表1-1Windows操作系统核心组件对应的文件

了根据查找进程名称的字符串进行内存分析的方法,并开发了相应的内存分析工具WMFT。Mariusz Burdach的思路是首先根据进程名称,确定其EPROCESS结构的物理位置;然后对内存中的所有进程进行遍历;最后进一步提取相应的数据。

1.2.1原理

首先,每个Windows进程都是由一个行体进程(EPROCESS)结构表示的。EPROCESS结构中除了包含许多与进程有关的属性以外,还包含和指向了许多其他的相关数据结构。例如,每个进程都有一个或多个线程,这些线程由执行体线程(ETHREAD)结构表示。PEB中存放指向进程环境块的指针,进程环境块结构体中会保存大量的进程信息,包含执行映像加载器、堆管理器、DLL等信息。通过微软的系统调试工具WinDbg,可以查看EPROCESS结构体的具体成员。如下所示(有所删节)。

ae10912064632907dd184629ed5e702e.png
调试工具WinDbg

WMFT的方法基于以下几点。

(1)EPROCESS结构中有一个成员ActiveProcessLinks,为_LIST_ENTRY结构体,该结构体由两个指向_LIST_ENTRY结构的指针组成。

+0x000 Flink:Ptr32 LIST ENTRY

+0x004 Blink:Ptr32 LIST ENTRY

Windows系统通过该成员,构成了一个双向链表数据结构。该链表在Windows操作系统中,对应一个全局内核变量PsActiveProcessHead指向的链表。因此,只要定位其中一个进程块的地址,就可遍历系统中所有的进程。

(2)Smss.exe是会话管理器

(%SystemRoot%System32Smss.exe),是系统中创建的第一个用户模式进程。Smss.exe初始化完成后会在会话o的Csrss.exe实例的句柄上等待,如图1-2所示

。因此这两个进程的顺序是固定的,其链接关系也是固定的。链接关系如图1-3所示。

101e33e739ca7e6581b0490d27e46b89.png
图1-2 Smss.exe和Csrss.exe关系

343785502ca49a566845956654573217.png
图1-3 Smss.exe和Crss.exe进程间的链接关系

图1-3 Smss.exe和Crss.exe进程间的链接关系

Smss.exe的Flink指向Csrss.exe的ActiveProcessLinks结构,Csrss.exe的Blink指向Smss.exe的ActiveProcessLinks结构。

(3)“Smss.exe”“Csrss.exe”是其相应的EPROCESS结构中ImageFileName成员的值,数据类型为字符串。基于此,Mariusz Burdach给出了具体的遍历进程的方法。

(1)根据“Smss.exe”“Csrss.exe”字符串,确定其对应EPROCESS结构在内存镜像文件中的具体位置。在具体的内存镜像文件中,查找“Smss.exe”“Csrss.exe”字符串,得到其相应进程的EPROCESS结构在内存中的位置,减去ImageFileName在EPROCESS结构体中的偏移量(本章EPROCESS结构的示例中为ox16c)就可以得到Smss.exe和Csrss.exe相应的EPROCSS结构体在镜像文件中的起始位置Pos_smss和Pos_csrss。

(2)获取ActiveProcessLinks结构的地址Pos_smss和Pos_csrss加上ActiveProcessLinks成员在EPROCESS结构中的偏移量(本章实例中为oxob8)得到ActiveProcessLinks成员位置

Pos ActiveProcessLinks smss和Pos_ActiveProcessLinks_csrss。继而,可以根据

_LIST_ENTRY结构组成,从相应的位置获得Flink、Blink的相应值FLINK_smss、BLINK_smss。

(3)求虚拟地址与物理地址的偏移量(Rva)

Smss.exe的EPROCESS结构体中,ActiveProcessLinks成员的Flink指向的是Csrss.exe的EPROCESS结构体中ActiveProcessLinks成员,其存储的值为虚拟地址。而步骤(2)所得的Pos_ActiveProcessLinks_csrss是Csrss.exe的EPROCESS结构体中ActiveProcessLinks的物理地址。两者之间有一定规律性。

MariuszBurdach是如此计算Rva的。

Rva=Flink_smss-0x80000000-Pos_ActiveProcesslinks_crss减去0x80000000,是因为32 bit Windows虚拟内存的用户空间(0x00000000~0x7FFFFFFF)和内核空间(ox80000000~0XFFFFFFFF)管理方式。

(4)实现进程遍历

根据任一进程,如Smss.exe,通过其EPROCESS结构体的成员ActiveProcessLinks,获取FLink的值,通过步骤(3)计算得出的偏移量,就可以求出Flink所指的下一个进程块在内存镜像中的位置,不断重复,就实现了Windows操作系统进程的遍历。

5.2.2存在的不足

上述字符串查找的办法,在实际的物理内存分析方法中存在一定的问题,主要表现在以下两个方面。

(1)使用“Smss.exe”和“Csrss.exe”查找定位存在一定的不确定性,在实际实现过程中存在问题。

不同的操作系统版本中,EPROCESS结构是有差异的,难以分析和定义各个成员的偏移量。例如,ImageFileName的偏移是不确定的,最初的WMFT中的初始值设定是ox154,而在WindowsXPSP2下是0x174,在Windows 2003 SP2下是ox164等。该方法用到的ActiveProcessLinks等结构体的成员也存在这样的问题。因此,实际实现时,难以自动验证应该采用哪个偏移地址。再有,确定EPROCESS结构是根据“Smss.exe”和

“Csrss.exe”查找的。因此,可能找到很多个,如何确定查找到的字符串是否是EPROCESS结构中的ImageFileName,也有一定的难度。

(2)虚拟地址到物理地址转换问题。

该方法求Rva的步骤,实际上是简化了虚拟地址到物理地址转换的问题。由于Windows内存管理存在多种模式。以上步骤仅适用于系统空间采用大页模式的操作系统版本。上述原因导致使用WMFT工具前,需要手工配置rva、offset、initproc,因此,WMFT工具的使用存在很大的局限性。

1.3基于池特征扫描的内存分析方法

Aaron Walters提出可以根据执行体对象结构体的头部特征,进行Windows内存取证分析的方法,该方法应用在内存取证工具Volatitliy中,也称为Pool-Tag Scan方法[30]。

1.3.1Windows执行体对象

在Windows内部有3种类型的对象:执行体对象、内核对象和GDI/User对象。由前面可知,Windows操作系统提供了被称为执行体(Executive)的组件,提供内存管理、进程和线程管理、安全性、I/O、网络和跨进程通信等基本的操作系统服务。执行体对象是指由执行体的各个组件(如进程管理器、内存管理器、I/O子系统等)所实现的对象。内核对象是指由Windows内核实现的一组更为基本的对象。这些对象对用户模式的代码是不可见的,它们只是在执行体内部被创建和使用。而内核对象提供了最为基本的能力,如同步等,执行体对象正是建立在它们之上的。因此,许多执行体对象包含(封装)了一个或多个内核对象。

Windows绝大多数代码由C语言编写,其中大量使用了C语言的结构体来组织相关数据和属性。其中,由Windows对象管理器(Object Manager,由NT内核模块实现的一个内核组件)进行管理的(创建、保护、删除等)结构体,称为执行体对象。严格意义上来说,只有当操作系统为一个结构体准备了用于管理诸如名称、访问控制、引用计数这些数据的各种头部时,该结构体才是真正意义上的执行体对象。因为执行体对象是对象管理器分配并创建的,所以所有的执行体对象都有类似的特征。例如,所有执行体对象的结构体都有前置头,而由其他子系统(如TCP/IP栈(tcpip.sys))分配的结构体就没有这些头部。大量的内存取证涉及定位和分析执行体对象。表1-2列举了内存取证中常用的Windows执行体对象,熟悉和理解这些对象对内存分析有很大的帮助。可以使用微软官方工具包SysInternals中的WinObj工具查看指定版本完整的Windows执行体对象。

b7f78345151b801164999a75985957b6.png
表1-2内存取证中常用的Windows执行体对象

1.3.2对象头部Object Header所有的执行体对象之间一个最显著的特征就是拥有一个对象头部(_OBJECT_HEADER)以及零个或者多个可选的头。对象头部在内存中位于执行体对象结构的最前面。同样,可选头部都是按固定的顺序排列在对象头部前面的。

如图5-4所示,如果给出了_OBJECT_HEADER地址,就能找到执行体对象结构(如图1-4中的_FILE_OBJECT),反之亦然。因为,二者在内存分配中是紧挨着的,并且每个操作系统中

_OBJECT_HEADER的大小都是一致的。可选头的存在与否依赖于对象头部的InfoMask成员。64bit Windows7中对象头部的完整结构如下。

23555afa6836b180eac16db7854b4813.png
图1-4(1)执行体对象及对象头部结构

4c7e69dd26221c156511d975cf8614e0.png
图1-4(2)执行体对象及对象头部

1.3.3可选头部

一个对象的可选头部包含用于描述该对象各种类型的元数据。因为它们是可选的,所以并不是所有类型的对象都拥有可选头部;甚至相同type对象的不同实例也可能包含可选头部的不同组合。例如,内核并不会跟踪Idle和System进程的配额统计(资源的使用状况),所以这两个_EPROCESS对象的结构体就没有_OBJECT_HEADER_QUOTA INFO头部。此外,一个被多个进程共享的互斥体仅需要一个名称。因此,已命名的互斥体就会有一个

_OBJECT_HEADER_NAME_INFO头部,而未命名的互斥体则没有。很多可选头部能够用于内存取证,内存取证分析中最常用的还是对象名称头部。

表1-3中列举出了64bit Windows7中的可选头部。如果某个对象的OBJECT_HEADER.InfoMask值被设置了位掩码,其值为表中这一列的值,那么就存在相应的可选头部。由前面的描述,可选头部位于OBJECTHEADER起始地址的负偏移处,具体偏移量依赖于其他头的存在以及它们的大小(表1-3中大小描述列)。

fd059920c615591bfeb03a9622bb1f0c.png
表1-3 64bit Windows7中的可选头部

1.3.4对象类型

_OBJECT_HEADER的TypeIndex成员是nt!ObTypeIndexTable-(一个type对象_OBJECT_TYPE的数组)的索引。由表5-2可以得知,type对象包含可以用来描述所有其他对象常见属性的元数据。该数据对内存取证来说至关重要,因为可以用它确定跟随在_OBJECT_HEADER后面对象的类型结构_OBJECT_TYPE。

例如,在内存分析的过程中,常常需要枚举句柄表中项。跟随在句柄对象头部后面数据的类型是任意的,可能是FILEOBJECT、EPROCESS或者其他的执行体对象。这时,可以通过定位Typelndex的值,然后找到该索引对应的_OBJECT_TYPE,最后得到其Name成员,从而确定需要分析的对象类型。

OB.JECT_TYPE结构体中的TypeInfo和Key成员还为内存取证提供了两条非常有价值的线索,从中可以确定在分页还是非分页内存中寻找特殊的4byte标记,从而定位特定对象类型的所有实例。

1.3.5内核池分配

在实际的取证分析中,需要根据某个特征来定位内存镜像文件中实际对象的数据结构存储位置,如果如1.3.4节根据简单的字符串搜索(如Proc标识进程、Token标识令牌),显然误报会很多。为了更加准确、更加健壮地定位对象的数据结构,就需要了解Windows操作系统对内存分配的相关概念和机理。

在Windows操作系统中,内核池(KernelPool)是操作系统为存储内核模式组件所请求的一系列内存,可以被分割为更小的内存块。内核池用于存储任何类型的数据,如NT内核模块、第三方设备驱动等。与堆比较相似,每个分配的内存块都有一个包含统计和调试信息的头(_POOL_HEADER),如图1-5所示。可以使用这些额外的数据推断出该内存块属于哪个驱动程序,并且还可以在一定程度上推断出包含该分配内存的结构或者对象的类型。深入理解内核池的技术细节,不仅仅对内存取证有用,对于内核池的漏洞利用也是非常有帮助的。

c4f43743f017e4b9b8a9c2e5d608cb95.png
图1-5位于池甲的执行体对家

1.3.6内核池分配的API函数

在创建一个执行体对象实例之前,操作系统会从内核池中分配一块足够大的内存来存放对象和它的头部。

通常在分配内核池时使用最多的API函数是ExAllocatePoolWithTag,函数原型如下。

51a7001c4b2d7fda31f6c32fcb745dfe.png

这个参数是枚举类型,它指定了用于分配的系统内存类型,NonPagedPool(0)和PagedPool(1)分别表示非分页内存和分页内存。由前文可知,可以通过定位特定对象的_OBJECT_TYPE、TypeInfo、PoolType成员加以区分。

NumberOfBytes这个参数指定了要分配的字节数。驱动程序可以在调用ExAllocatePoolWithTag时直接指定需要存储在内存块中数据的大小。但是根据前面了解的知识,执行体对象有点不同,因为它们需要额外的空间来存储对象头部以及可选头部。位于内核中名称为ObCreateObject的函数是所有执行体对象被创建的关键点。它决定了被请求结构的大小(例如,64bit Windows 7中_EPROCESS的大小为1232 byte),并且在调用ExAllocatePoolWithTag之前OBJECT_HEADER和其他可选头部的大小会被加进去。

Tag参数指定了一个4byte的值,通常由ASCII码字符组成,唯一地表示该分配产生的代码路径。对执行体对象的这种情况来说,标志是从_OBJECT_TYPE的Key成员得到的,这也解释了为什么特定类型的所有对象的标志都一样。

假设某个进程想要使用WindowsAPI函数创建一个新的文件,将会按照以下步骤进行。

(1)该进程调用CreateFileA(ASCII)函数或者CreateFileW(Unicode)函数,二者都由kernel32.dl提供(2)创建文件的API转入ntdll.dll,然后在其中通过系统调用进入内核,接着到达原生态的NtCreateFile函数处。

(3)NtCreateFile将调用ObCreateObject请求一个新的文件对象类型。

(4)ObCreateObject计算_FILE_OBJECT的大小,包含需要为它的可选头部额外准备的空间。

(5)ObCreateObject找到文件对象对应的OBJECT_TYPE结构,并且确定为其分配的内存类型(分页内存不分页内存),确定需要用到的4 byte标记。

(6)指定合适的大小、内存类型、标记,从而调用ExAllocatePollWithTag。

经过以上步骤,一个全新的FILEOBJECT就存在于内存了,并且该分配的内存被指定了一个4byte值的标记。另外,还有一个指向对象头的指针会被添加到调用进程的句柄表中,并且一个系统范围内的池标记会在跟踪数据库中得到相应的更新,以及FILE_OBJECT的各个成员会被该文件所创建的路径和要求的访问权限(如读、写、删除)等初始化。使用相同的大小、标记以及内存类型的顺序进行内核池的分配,并不表示这些空间在内存中就是连续排列的。虽然操作系统会尝试将类似大小的内存块组合在一起,但如果所请求的大小没有可利用的空闲块,内核就会从下一个最大尺寸的组中选择一个块。这样,包含相同type对象的内存分配会被分散到整个内核池中。此外,这种内核池分配允许小一点的结构占据之前用于存储更大一些结构的内存块。

1-3.7内存池特征扫描

池特征扫描(Pool-Tag Scan),又称池扫描,是指寻找基于前面提到的4 byte标记分配的内存(如表5-4所示)。

47c48d1798a90ee774eeac5228198fce.png
表1-4常用对象扫描特征

这样通过搜索整个内存镜像文件中的Proc标记(与EPROCESS相关的4 byte标记),根据其特征判断是否是有效的_EPROCESS结构体,就可以找到系统中所有的进程(进程执行体对象)。与遍历系统活动进程双向链表的方式相比,这种方法可以找到系统中不再运行的进程或者已经结束运行的进程,有助于发现恶意进程。例如,使用直接内核对象修改(DKOM)技术的恶意代码会修改活动对象的链表,将根据特征扫描得到的进程列表与通过遍历链表方式得到的进程列表进行比较,就会发现那些故意将自己从双向链表中删除的正在运行的进程。

当执行池标记扫描的时候,4byte的标记只是分析的一个出发点。如果完全依赖于这4byte的标记,会得到大量的误报。所以,实际应用时需要以前面介绍过的知识为基础构建特征码。例如,可以根据分配的大小以及内存的类型(分页,非分页)等判断依据标记(Tag)找到的内存内容是否是有效的Windows对象结构体;又如,需要寻找一个1oo byte的_EPROCESS,而我们在一个30 byte的分配内存中找到了Proc,显然它不可能是一个真正的进程,因为该内存块太小。除了标记、大小、内存类型这些初始指标以外,这种方法允许为每种对象类型添加自定义的约束条件,并进行扩展。例如,如果一个进程创建的时间戳应该非零,就可以以这个条件来配置扫描器,这样扫描器就只会报告创建时间非零的项。

1-3.8内存池特征扫描的局限

内存池特征扫描的方法存在如下缺点。

(1)未使用池标记的内存。ExAllocatePoolWithTag是微软推荐内核驱动以及内核模式组件用来分配内存的API函数,但并不是唯一的选择。一些驱动程序还在使用ExAllocatePool这个函数,尽管这个函数已经过时,但在很多版本的Windows中仍然可以使用。这个API函数在分配内存的时候并不带内存池标记,即无法跟踪或者扫描这种内存。

(2)误报。因为内存池扫描技术是依赖Tag匹配的一种算法,所以误报是在所难免的。

(3)大池内存分配。内存池标记扫描技术仅仅针对小于4096 byte的内存块。幸运的是,所有执行体对象的大小都小于4096byte。

(4)任意的池标记。一个驱动在分配内存时用得最多的一个标记是“Ddk”。这个标记在整个操作系统中随处可见,并且第三方代码没有指定池标记的时候,操作系统也会加上。换句话说,如果一个恶意驱动使用了“Ddk”作为池标记,那么该内存块将会和其他内存块混合在一起。

(5)伪造和修改内存池标记。恶意程序可以编写一个驱动程序,伪造和修改一个对象来误导取证分析人员。因为池标记的引入是为了便于调试,它们的改变与否并不影响操作系统的稳定性。内核级别的Rootkit会尝试修改池标记(或者_POOL_HEADER中的其他值,如内存块的大小、内存类型),这对于实际运行的系统来说并没有什么明显的差异,但是这种修改会影响内存分析程序的结果。

1.4基于KPCR结构的方法

本文提出一种新的方法来寻找进程块、系统驱动和进行地址转换,我们称之为基于KPCR结构的方法[31]。它主要包括以下几步。

1.4.1KPCR结构体的查找

由于需要支持有多个CPU,Windows内核中为此定义了一套以处理器控制区(KPCR,Processor Control Region)为枢纽的数据结构,使每个CPU都有个KPCR结构,用来保存与线程切换有关的全局信息。

KPCR结构的定义可在Ntddk.h中找到,在不同操作系统版本中,其寻找方法不同。

WindowsXP操作系统下,该结构位于线性地址OxFFDFFooo处。在线性地址0xFFDFF120处可找到KPRCB(Kernel Processor Control Block)结构,指向该结构的指针存放在KPCR结构。KPCR和KPRCB在线性空间中的位置一般不会随Windows版本变动而改变。用WinDbg显示KPCR内容的片段如图1-6所示。

edf008fc491943bace5ceda799ccf688.png
图1-6 KPCR结构

因此可以推断出,在物理内存镜像文件中,0xffdff000和0xffdffi20是在一起的,而且它们一般不会随着Windows版本变动而改变。基于这个原因,只要查找二进制字符串

“00dfffe0fidfff”在文件中的位置,再减去0x1c就得到KPCR结构的物理地址。

32 bit Windows Vista操作系统及其以上版本,KPCR结构的线性地址不固定,因此,我们改进了原来的寻找方法。

(1)32bit操作系统下改进的KPCR结构查找方法

以32bit Windows7操作系统为例,用WinDbg显示KPCR内容的片段如图1-7所示。

7caf625bcbacbfd0927a4c69e2325339.png
图1-7 32bit Windows7中的KPCR结构

从中可以推断出,在物理内存镜像文件中,SelfPcr和Prcb两个成员是紧挨着的,而且它们一般不会随着Windows版本变动而改变。基于这个原因,在32bit操作系统中,只要查找满足以下条件的二进制串在文件中的位置,再减去SelfPcr成员在KPCR中的偏移ox1c,就得到KPCR结构的物理地址。设SelfPcr成员的值是ValSelfPcr,其在内存镜像文件中的物理位置是Pos SetfPcr;Prcb成员的值是ValPrcb,其在内存镜像文件中的物理位置是PosPrcb,需要满足的条件表示如下。

如图1-7所示,SelfPcr和Prcb这两个4byte的二进制字符串相邻,第一个字符串在内存镜像文件中是00AC3684,它对应的值是0x8436ac00;第二个字符串在内存镜像文件中是20AD3684,它对应的值是0x8436ad20。式(1)表示,第二个字符串表示的值与第一个字符串表示的值相减等于0x120;式(2)表示,第二个二进制字符串所在位置(示例中的位置是ox8436ac20)减去第一个二进制字符串所在位置(示例中的位置是0x8436ac1c)为0x04;式(3)表示,第一个二进制字符串所在位置(示例中的位置是0x8436ac1c)减去0x1c,然后和0x1000做“与”操作,所得的值应该与第一个二进制字符串表示的值(示例中的值是0x8436ac00)和0x1o00做“与”操作所得的值相等。

(2)64bit操作系统下改进的KPCR结构查找办法64bit版本的操作系统下,KPCR结构的线性地址也不再固定。基于32bit操作系统下改进的KPCR查找办法,以某台64bit Windows7操作系统的计算机为例,说明64bit版本的操作系统下KPCR查找办法。

用WinDbg显示KPCR内容的片段如图1-8所示。

be4e6132f497e04185a82a61a7ae956e.png
图1-8 64bit Windows7中的KPCR结构

该结构位于线性地址0xFFFFF800045EFE00处。在线性地址0xFFFFF800045EFF80处可找到KPRCB结构,指向该结构的指针存放在KPCR结构。因此可以推断出,在物理内存镜像文件中,0xFFFFF800045EFE00和0xFFFFF800045EFF80是在一起的,而且它们一般不会随着Windows版本变动而改变。基于这个原因,在64bit操作系统中,只要查找满足以下条件的二进制串在文件中的位置,再减去0x18就得到KPCR结构的物理地址。

设SelfPcr成员的值是ValSelfPcr,其在内存镜像文件中的物理位置是PosSelfPcr;Prcb成员的值是ValPrcb,其在内存镜像文件中的物理位置是PosPrcb,需要满足的条件表示如下。

如图1-8所示,SelfPcr和Prcb这两个8byte的二进制字符串相邻,第一个字符串在内存镜像文件中是00FE5E0400F8FFFF,它对应的值是0xFFFFF800045EFE00;第二个字符串在内存镜像文件中是80FF5E0400F8FFFF,它对应的值是0xFFFFF800045EFF80。式(4)表示,第二个字符串表示的值与第一个字符串表示的值相减等于0x180;式(5)表示,第二个二进制字符串所在位置(示例中的位置是0xFFFFF800045EFE18)减去第一个二进制字符串所在位置(示例中的位置是0xFFFFF800045EFE20)为0x08;式(6)表示,第一个二进制字符串所在位置(示例中的位置是0xFFFFF800045EFE18)减去0x18,然后和0x1000做“与”操作,所得的值应该与第一个二进制字符串表示的值(示例中的值是0xFFFFF800045EFE00)和0x1000做“与”操作所得的值相等。

KPCR结构包含有KPRCB、内核变量块(KdVersionBlock)、TSS等信息,这些信息将会在内存分析中起到重要作用。例如,KPRCB中有指向当前KTHREAD的指针,通过当前的ETHREAD基地址就可以知道当前运行的线程是哪个。通过这个线程还可以查找出当前活动的所有线程。

1.4.2虚拟地址到物理地址转换

由于在内存中存储的地址一般都是虚拟地址,而物理内存中地址的定位是物理地址,因此计算虚拟地址(线性地址)到物理地址的影射关系是内存分析的关键。例如,得到KdVersionBlock的地址是ox8054d238,但找不到这个地址在物理内存镜像文件中的位置,这个虚拟地址也就毫无用处。因此,虚拟地址到物理地址的映射计算问题是内存分析的一个关键问题。

下面的虚拟地址到物理地址的映射计算需要用到一个基本规则。

规则在同一个虚拟地址页面上的内容,也在同一个物理页面中。

从Windows内存管理机制中可以了解到,计算系统的页目录基地址是计算内存映射的关键。由于内存中存在很多个页目录,而且页目录是难以定位的,因此直接通过字符串查找是很难找到系统页目录的。在物理内存管理中,页的大小一般分为4MB、2MB、4kB,都大于或等于0x1000(4kB)。根据上述基本规则,虚拟地址0xffdff000~0xffdff应该是映射到同一个物理内存页上的,而0xffdfff再加上1,就可能不和0xffdff000在同一物理内存页中。如果在0xffdff000~0xffdfffff中找到指向系统页目录基地址的指针就会解决地址映射的问题。

Intel处理器的详细地址转换方式参见第2章,几种常见地址转换方式如图1-9~图1-13所示。

d86b5d1cd7eb63b156a559041b71ffc9.png
图1-9页大小4kB的地址转换

ae338d5170701b2587114c2a9baa779a.png
图1-10页大小4MB的地址转换

f4f5d79fa6e172afb6ae00d86f4deb1b.png
图1-11 PAE下,页大小为4kB的地址转换

7e12f88430f56d0fee819194ec70d2cd.png
图1-12 PAE机制下,页大小为2MB的地址转换

2a33b1436b863d96e29bc7eae6fb04d1.png
图1-13PSE-36机制下的地址转换

可以看到,在地址转换中CR3寄存器的重要性,它记录了页目录基地址(或页目录指针基地址,或PLM4基地址),找到它是实现地址转换的基础。

Windows在内存管理和进程切换过程中,都是使用寄存器CR3来保存各个进程的页目录基地址。事实上,在64bit模式下,CR3指向的是PML4表基地址。当启用物理地址扩展(PAE)时,CR3引用页目录指针基地址;当禁用物理地址扩展时,CR3引用页目录基地址。找到CR3寄存器中的内容,是计算出虚拟地址对应的物理地址转换的第一步。

当找到CR3寄存器中的内容后,需要判断分页模式,即使用哪种机制进行分页?页的大小?它所指向的是页目录,还是页目录指针基地址?完成这步工作后,就可以实现虚拟地址到物理地址的转换。

1-4-3CR3寄存器中的内容的查找

在图1-6中看到结构KPCR中有TSS成员,其结构是一个ktss,其中,记录有CR3寄存器的内容。通过它有可能找到当前现成的页目录基地址,但问题是它的虚拟地址是0x80042000,它实际对应的物理地址无法计算。

KPRCB的结构成员ProcessorState是一个KPROCESSOR_STATE结构,它的起始地址是0xFFDFF13C,在其0x2cc处是SpecialRegisters成员,在SpecialRegisters偏移地址为0x08处就是CR3寄存器。通过分析发现,该处保存的总是系统进程的页目录信息,当禁用物理地址扩展时,保存的就是系统进程页目录的基地址。它的虚拟地址是0xffdfff410,根据1.4.2节中的基本规则,知道它和0xffdff000在同一个物理页内,所以它的物理地址等于0xffdff000的物理地址加上0x410。从这个地址开始的4 byte内容就是CR3寄存器中的内容。

在1.4.1节中介绍的某台64bit Windows7操作系统的计算机中,KPRCB的结构成员ProcessorState是一个KPROCESSOR_STATE结构(如图5-14所示),它的起始地址是0xFFFFF800045EFF80+0x40,在其0x0处是SpecialRegisters成员,在SpecialRegisters偏移地址为0x10处就是CR3寄存器(如图1-15所示)。通过分析发现,该处保存的总是系统进程的页目录信息,当禁用物理地址扩展时,保存的就是系统进程页目录的基地址。它的虚拟地址是0xFFFFF800045EFF80+0x40+0x10,根据1.4.2节中的基本规则,知道它和0xFFFFF800045EFE00在同一个物理页内,所以它的物理地址=0xFFFFF800045EFE00的物理地址+0x180+0x40+0x10。从这个地址开始的8byte内容就是CR3寄存器中的内容。

82db3d7dc5019cd5a33fdc790f83fd6e.png
图1-14 64bit Windows7中的_KPRCB结构

8bafa6c64844a89028416bf54edfe31d.png
图1-15 64bit Windows7中的SpecialRegisters结构

1.4.4根据CR3寄存器中的内容实现地址转换

根据Intel 64 andIA-32Architectures SoftwareDeveloper's Manual,分页方式和页的大小主要由CR4寄存器的PAE标志位、PSE标志位,以及页目录的PS标志位等决定。但Windows在实现过程中,却不是完全按这些实施的。例如,在PAE模式下,CR4寄存器的内容依然为0,而且同一目录下,指向或通过页表指向的物理内存页的大小也可能不同。通过研究发现,使用以下过程可以确定分页方式和页的大小。

第1步根据CR3寄存器的内容找到它指向的物理地址。第2步判断该地址处的第一个字节,如果不是0x01,则转到第3步;如果是oxo1,则表明使用PAE方式,从这个地址开始的8byte是页目录指针。根据待转换的虚拟地址的第31~30 bit选择页目录指针(按图5-11或图5-12的方式换算)。例如,如果待转换的地址是0x8054c2b8,则页目录指针表的第三项(每项8byte)为指向页目录的指针,根据这个指针找到页目录基地址。

根据页目录基地址和虚拟地址的第21~20bit确定待转换虚拟地址对应的页目录项。例如,如果待转换的地址是ox8054c2b8,则第21~29bit是000000010(0x02),则从页目录基地址加上8×2开始的8个字节就是所找的页目录项。

判断该页目录项第一个字节的最高位,如果是“1”,则按如图5-12所示的进行地址转换;如果是“0”,则按图5-11所示的进行地址转换。

第3步判断该地址处的第一个字节最高位,如果是“1”,则表明使用的大页模式,按图5-10进行地址转换;如果是“0”,则表明它指向页表,可按图5-9进行地址转换。

1-4.5内核变量的查找

上面讲述了如何查找KPCR结构。在KPCR结构中有内核变量块(KdVersionBlock),它是指向KdVersionBlock的指针(线性地址)。通过5.4.4节中地址转换步骤,将KdVersionBlock的指针地址转换成物理地址。根据物理地址就可以在内存镜像文件找到KdVersionBlock(这个变量以后的版本没有了)。在图1-16中,KdVersionBlock的虚拟地址是0x8054d238,根据地址映射关系,可以计算出其地址为0x0054d238。在WinDbg中使用dt命令显示内容,如图1-16所示。

a78c30dda7d4ec34d4e97c2c44c583fc.png
图1-16_DBGKD_GET_VERSION64结构

再经过地址转换,就可以计算出系统进程的基地址是0x4d8000,PsLoadedModuleList的物理地址是0x55b620。根据PsLoadedModuleList就可以找到所有加载的驱动程序。

KdVersionBlock在_DBGKD_GET_VERSION64之后,对应的内核变量分别如下。

211dec8874605d0f475317b0a85124a5.png

这些内核变量在内存分析中起到非常重要的作用。例如,变量PsActiveProcessHead指向系统进程的ActiveProcessLinks,再根据系统进程的ActiveProcessLinks就可以搜索出所有的活动进程。从ActiveProcessLinks到进程的起始地址的计算过程如下。

从ActiveProcessLinks到进程的起始地址一般为0x88,但也有很少的版本为0x98。研究目前的版本可以发现,一般进程起始处的4个字节为0x03001b00。这样,如果从PsActiveProcessHead的物理地址减去ox88所得地址开始的前4个字节为0x03001b00,则这个地址就是进程的起始地址;如果不是,判断从

PsActiveProcessHead的物理地址减去0x08所得地址开始的4个字节为0x03001e00,则该地址为该进程的起始地址。有了进程信息,就可以搜索出所有的线程信息。

通过研究发现,根据系统进程的句柄表

HANDLETABLE可以找到系统进程打开的DLL、FILE、DEIVCE、KEY、EVENT等对象,也可以找到驱动程序(DRIVER)。本文将以后介绍根据进程HANDLETABLE分析对象的过程。

从64bit Windows7的KPCR结构图(图1-8)中可以看到,Windows7及其以上版本的KdVersionBlock指针的值为null,此时,无法通过KdVersionBlock结构,获取所需要的内核变量。可以用以下方法获取进程信息。

从KPRCB结构图(图1-14)中可以看到,有个名为CurrentThread的变量。可以通过该变量获取操作系统版本信息和CurrentThread变量指向kthread结构,该结构的偏移0x70处有指向KPROCESS的指针,之后通过一系列的地址转换,可以判断操作系统版本。根据操作系统版本,确定EPROCESS结构体的组成。

由KTHREAD结构体得到操作系统版本的过程如图1-17所示。

73118570101ee23b10a0efb94b81144d.png
图1-17由KTHREAD结构体

得到操作系统版本通过图1-17中结构可以看出,EPROCESS结构体和KPROCESS结构体的虚拟地址是相同的。因此,可直接通过KPROCESS结构体的地址得到EPROCESS结构体的地址。最后,根据EPROCESS结构体遍历所有进程。

1.5本文总结

本文首先简要介绍了Windows操作系统的关键系统组件,了解内存分析中采用的文件、对象或数据结构属于Windows操作系统的哪个组件,并在操作系统中有何作用;然后分别介绍了Mariusz Burdach查找操作系统关键进程名称开始内存分析的原理;Volatility框架中根据Windows内核对象在内存池分配中的特征进行扫描从而进行内存分析的原理;最后,详细介绍提出的一种基于KPCR结构的内存分析方法,为深入实战Windows,Linux,Mac ,安卓, 木马,密码破解内存提取取证提供坚实理论。

谢谢转发及关注,版权所有,禁止转载!

参考文献

[1] Intel@64 andIA-32 architecturesoftware developer's manual: volume 3A[S]. Intel Corporation,2011.

[2] ARM Cortex-A17 MPCoreprocessortechnical reference manual[S]. ARM Corporate,2014.

[3] INOUE H, ADELSTEIN F, JOYCE R A. Visualization in testing a volatile memory forensic tool[J]. Digital Investigation,2011,8(8):S42-S51.

[4] PADALA P. Playing with ptrace[M]. Houston: Linux Journal,2002.

[5] MCDOWN R J, VAROL C, CARVAJAL L, et al. In-depth analysis of computer memory acquisition software for forensic purposes[J]. Journal of Forensic Sciences,2015,61(S):110.

[6] CARRIER B D, GRAND J.A hardware-based memory acquisition procedure for digital investigations[J]. Journal of Digital Investigation,2004,1(1):50-60.

[6] RUFF N. Windows memory forensics[J]. Journal in Computer Virology,2008,4(2):83-100.

[8] BOCK B. Firewire-based physical security attacks on Windows 7, EFS and bitlocker[J]. Secure Business Austria Research Lab,20o9.

[9] BOILEAU A. Hit by a bus: physical access attacks with firewire[C]//Conference of the Ruxcon.2006.

[10] BALOGHS. Memory acquisition by using network card[J]. Journal of Cyber Security,2014,3(1):65-76.

11] WANG J, ZHANG F W, SUN K. et al. Firmware-assisted memory acquisition and analysis tools for digital forensics[C]//Conference of the SADFE.2011:1-5.

[12] ZHANG B, WANG X, LAI R, et al. Evaluating and optimizing I/O virtualization in kernel-based virtual machine(KVM)[J]. Lecture NotesinComputer Science,2010,6289:220-231

[18] WOJTCZUK R, RUTKOWSKA J. Following the white rabbit: software attacks against Intel(R) VT-d technology[J]. Matrix,2011:1-27.

[13]MORGAN B,AVERLANT G,ALATA E,et al.Bypassing DMA remapping with DMA[C]//Symposium sur le Securitedes Technologies de Informatino et des Communications.2016.

[14]MORGAN B,ERIC ALATA,NICOMETTE V,et al.IOMMU protection against I/O attacks:a vulnerability and a proof of concept[J].Journal of the Brazilian Computer Society,2018,24(1):2.

[15]BAUMANN A,PEINADO M,HUNT G.Shielding applications from an untrusted cloud with haven[C]//OSDI.2014.

[16]SERGEI A,BOHDAN T,FRANZ G,et al.SCONE:secure Linux containers with Intel SGX[C]//OSDI.2016.

[17]HALDERMANJA,SCHOEN SD,HENINGER N,et al.Lest we remember:cold-boot attacks on encryption keys[J].Communications of the ACM,2009,52(5).

[18]陈恒.计算机取证物理内存镜像获取技术的研究与实现[D].济南:山东轻工业学院,2009.

[19]王连海.基于物理内存分析的在线取证模型与方法的研究[D].济南:山东大学,2014.

[20]SCHATZ B.Body snatcher:towards reliable volatile memory acquisition by software procedure[J].Digital Investigation,2007(4):130-134. [27]VOMEL S,STUTTGEN J.An evaluation platform for forensic memory acquisition software[J].Digital Investigation,2013(10):30-40.

[21]RUSSINOVICH M,SOLOMON D,IONESCUA,著.深入解析Windows操作系统(上)第六版[M].北京:电子工业出版社,2014.

[22]郭牧,王连海.基于KPCR结构的Windows物理内存分析方法[J].计算机工程与应用

,2009,45(18):74-77.

[23]LIGHM H,CASEA,LEVY J,et al.The art of memory forensics:detecting malware and threats in Windows,Linux,and Mac memory[M].John Wiley&Sons,2014.

[31]RUICHAO Z,LIANHAI W,SHUHUI Z.Windows memory analysis based on KPCR[C]//Fifth International Conference on Information Assurance and Security.2009.

[24]SOLOMON D,RUSSINOVICH M.Windows Internals 6th edition part2[M].Microsoft Press,2012.

[25]CARVEY H.The Windows registry as a forensicresource[J].Digital Investigation,2005,2(3):201-205..

[26]ZHANG S H,WANG L H,ZHANG L.Extracting windows registry information from physical memory[C]//2o113rd International Conference on ComputerResearch and Development.2011:85-89.

[27]WANG L H,XU LJ,ZHANG S H.A method on extracting network connection information from64-bit Windows 7

memoryimages[J].China Communications,2010,6:44-51.

[28]XUL J,WANG L H,ZHANG L.Acquisition of network connection status information from physical memory on windows vista operating system[J].China Communications,2010,6:71-77.

[29]SCHUSTER A.The impact of Microsoft Windows pool allocation strategies on memoryforensics[J].Digital Investigation,2008.340.

[30]BAAR R B V,ALINK W,BALLEGOOIJA R V.Forensic memory analysis:files mapped in memory[J].Digital Investigation,2008,5:52-57.

[31]KORNBLUM J D.Using every part of the buffalo in Windows memory analysis[J].Digital Investigation,2007,4(1):24-29.[40]MAUERER W.深入Linux内核架构[M].北京:人民邮电出版社,2010.

[32]ZHANG S H,MENG X,WANG L H.An adaptive approach for Linux memory analysis based on kernel code reconstruction[J].Eurasip Journal on Information Security,2016,(1):14.

[33]BAAR R B V,ALINK W,BALLEGOOJA R V.Forensic memory analysis:files mapped in memory[J].Digital Investigation,2008,5:52-57.

[34]CASE A,CRISTINA A,MARZIALE L,et al.FACE:automated digital evidence discovery and correlation.Digital Investigation,2008.

[35]BURDACH M.Digital forensics of the physical memory[J].Warsaw University,2013,1(3):386-398.

最后

以上就是俊逸黑夜为你收集整理的windows进程管理器_面向Windows,Linux,Mac ,安卓, 木马,密码破解内存提取基于KPCR结构的技术研究...的全部内容,希望文章能够帮你解决windows进程管理器_面向Windows,Linux,Mac ,安卓, 木马,密码破解内存提取基于KPCR结构的技术研究...所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(40)

评论列表共有 0 条评论

立即
投稿
返回
顶部