首页
论坛
专栏
课程

[翻译]使用HollowFind插件来检测各种进程注入技术

2019-7-27 13:44 2636

[翻译]使用HollowFind插件来检测各种进程注入技术

2019-7-27 13:44
2636

English :https://cysinfo.com/detecting-deceptive-hollowing-techniques/


本文将介绍几种不同类型的Process hollowing技术,这种技术被用来绕过、混淆、欺骗取证分析工具。


同时也会介绍如何使用Volatility的插件,HollowFind(https://github.com/monnappa22/HollowFind )来检测这些Process Hollowing攻击。


在介绍这些Process Hollowing技术之前,先让我们来看看最简单的Process Hollowing是如何工作,以及如何检测它。


这里我使用一个被Stuxnet(震网病毒)感染过的image进程内存dump文件来演示。


什么是Process Hollowing?


Process Hollowing 或 Hollow Process Injection 是一种代码注入技术,通俗来讲就是,在内存中,一个合法进程的代码数据,被替换成了恶意代码。


黑客将恶意代码注入一个合法进程中,通过这种方式可以让一个合法进程来执行恶意行为。优点就是被注入的进程路径依然指向原合法文件路径,有了合法进程的外壳,恶意代码可以绕过防火墙和一些主机防御系统。


假如,Svchost.exe进程的内容被替换了,该进程的路径仍然指向磁盘上未被替换前的svchost.exe,只有Svchost.exe在内存中的代码段内容被替换成了恶意代码,这样黑客就可以绕过一些取证软件。


Process Hollowing运行机制?


关于Process Hollowing的原理以及如何检测,已经在《Art Memory Forensics Detecting》https://www.amazon.com/Art-Memory-Forensics-Detecting-Paperback/dp/B00RI5ZKCI


这本书中解释的很清楚了,以及我的视频和demo中也有解释: https://cysinfo.com/7th-meetup-reversing-and-investigating-malware-evasive-tactics-hollow-process-injection/


下面介绍病毒木马是如何应用Process Hollowing技术的:假设有两个进程,A(恶意进程)和B(合法进程)

  • 进程A以挂起模式启动进程B,进程B的代码段被映射加载到内存中。同时PEB中的进程路径指向磁盘上的进程B文件。并且PEB.ImageBaseAddress指向合法进程B被加载到内存中的地方。
  • 进程A准备注入恶意代码,恶意代码可能来自木马进程的资源字段,也可以是磁盘上的某个文件。
  • 进程A如果知道进程B的内存加载基址,所以它可以取消映射进程B的代码段。进程A可以通过读取进程B的PEB.ImageBaseAddress来得到进程B的基址
  • 进程A然后释放合法进程的代码段
  • 进程A在进程B中重新申请带有读写执行权限的内存,这次内存申请,一般可以申请到之前释放的那块代码段内存的地址。
  • 进程A然后写入恶意的PE头和代码区段到进程B中申请的内存。
  • 进程A然后改变进程b中被挂起的线程起始地址,指向刚才申请的内存
  • 进程A然后恢复进程B中被挂起的线程,然后进程B开始执行恶意代码


使用内存取证工具检测Process Hollowing


这部分我们来看看如何检测Process Hollowing技术,因为代码注入是在内存中发生的,所以最好的方式是通过内存取证工具来检测。


Stuxnet(震网病毒)就是通过上面提到的步骤,实现了了Process Hollowing技术。这篇文章中有完整的分析报告,使用内存取证工具来详细分析震网病毒:http://mnin.blogspot.com/2011/06/examining-stuxnets-footprint-in-memory.html


但是这篇文章,我们只讲如何通过取证工具来检测Process Hollowing技术。


a)检测父子进程链


下面进程列表中,有两个可疑的lsass.exe进程(PID 868和 PID1928),这两个进程并不是由winlogon.exe或winitit.exe启动,而是由services.exe(PID 668)启动。


这就是一种检测Process Hollow技术的方法,在干净的系统环境中, 在Vista之前的系统lsass.exe的父进程是winlogon.exe,而在Vista以及之后的系统中lsass.exe的父进程是wininit.exe






b) 通过比较PEB和VAD结构来检测


Hollow Process Injection 也可以通过比较PEB(Process Environment Block)和VAD(Virtual Address Descriptor)结构。


PEB结构位于进程内存中,该结构中保存着当前进程的磁盘绝对路径,以及内存加载基址。


而VAD结构位于内核内存中,包含进程连续虚拟内存空间分配信息,如果加载了可执行文件,则VAD节点中会记录有关可执行文件的起始地址,结束地址,和完整路径信息。


通过比较两个结构的差异,可以检测到该进程是否被注入了


在下面截图中,通过dlllist插件来查看lsass.exe(PID868)的全路径,以及基址(0x1000000)


这些信息是dlllist插件是从lsass.exe进程的PEB中获取的


下面截图中,使用ldrmodules插件查看模块列表时(位于内核中VAD的内容),没有显示lsass.exe模块的全路径,这是因为病毒取消映射了原来lsass.exe进程内存,


导致后面新申请的0x1000000内存中的内容和lsass.exe这个文件无关,所以也就不显示了。通过这点可以给我们一些提示,该进程是否被注入了




c)检测可疑内存保护属性


Hollow Process Injection 同样可以通过查看可以可疑内存的保护属性。


通过malfind插件(用来查找可疑内存保护属性)可以看到lsass.exe进程中0x1000000内存的保护属性为读写执行。


由于0x1000000是lsass.exe的基址,说明该进程没有被正常加载,(被注入了恶意代码)。任何可执行文件正常加载到内存后会有一个PAGE_EXECUTE_WRITECOPY的内存保护属性。


这点更加说明lsass.exe(PID868)进程被加载到0x1000000是有问题的





使用HollowFind插件自动检测Process Hollowing


HollowFind是一个Volatility插件,通过对比PEB和AVD中的差异来检测Process Hollowing。


下面截图展示如何使用HollowFind来检测一个被Stuxnet感染过的内存镜像,并识别出了两个可疑的进程lsass.exe(PID1928和 PID868)。


并且还检测到了可疑的内存保护属性(PAGE_EXECUTE_READWRITE),以及PEB和VAD中进程路径的差异,最后还会显示反汇编入口点的反汇编代码, 可以看到在入口点有个跳转jmp 0x1003121




一旦这个插件发现了Process Hollow,还会显示当前进程中是否有相同的Process Hollow。


在下面截图中,注意两个lsass.exe进程(PID 868和PID 1928)与之关联的父进程services.exe(PID 668),


表示两个lsass.exe并不是正常启动的进程。而正常的系统进程lsass.exe的父进程是winlogon.exe(PID 624)。


HollowFind插件同时还检测到了可疑的内存,可以帮我我们识别被注入的代码。


下面截图中发现的可疑内存地址一个是0x1000000(可执行文件的基址),还有一个地址是0x80000,同时在这两个地址中找到了PE文件,并且内存的保护属性被设置成了PAGE_EXECUTE_READWRITE权限,


表示一个可执行文件被注入到这个地址中了。


我们可以使用 - D 参数来把0x80000这块可疑内存dump下来,然后提交打破VirusTotal上,VT扫描结果显示它就是Stuxnet震网病毒




不同类型的Process Hollwing


这部分我们来看看病毒木马使用的其它类型的Process hollwing技术,并解释为何这些技术会混淆分析人员以及欺骗取证工具。


同样我们也是展示如何使用hollwfind来检测这些攻击


a)案例1:木马Skeeyah中使用的Process Hollowing(申请不同的地址,修改PEB)


Skeeyah使用了上面提到过的步骤,但是有一点不同,木马以挂起模式创建Svchost.exe进程,并加载到地址0x0100000,如下所示:


木马通过读取系统进程svchost.exe的PEB.ImageBaseAddress,来得到进程加载基址,然后释放这块内存,如下所示:


然后在系统进程中申请读写执行权限的内存,不过申请的地址(0x400000)不同,然后拷贝可执行程序到申请的内存中


然后木马会修改系统进程PEB结构中的ImageBaseAddress字段的值,为新申请的那块内存地址(0x0400000)。


这个操作将svchost.exe进程的基址从0x1000000修改成了0x040000(包含恶意可执行文件)


木马随后通过SetThreadContext函数将CONTEXT.EAX修改为注入pe的入口地址,然后恢复线程时,svchost.exe将从恶意pe入口点开始执行。



这种类型的Process Hollowing可以通过比较PEB和VAD来检测。下面截图中,通过dlllist插件可以看到svchost.exe(PID 1824)进程的全路径,和基址(0x00400000)



而 ldrmodules插件没有找到任何svchost.exe这个模块入口相关信息。因为当木马hollow系统进程svchost.exe后,这个模块从VAD链表中被移除了。

通过对比这个差异信息,也可以确认程序被hollow注入了。



上面这种对比差异,已经在HollowFind插件中实现了。


在下面截图中,展示通过该插件来检测出被Hollow的进程svchost.exe(PID 1824),同时也检测出了在VAD中没有找到svchost.exe模块的入口。


同样还显示出了PEB和VAD结构的对比的差异,PEB中显示出了svchost.exe被注入后新基址0x00400000,以及内存保护属性。




在HollowFind插件检测到存在Holloed进程的时候,同时还会显示出当前进程列表中相似的进程。


在下面截图中,被注入的进程svchost.exe(PID 1824)没有显示出父进程名字,是因为它的父进程已经退出了。


而其它正常的系统进程svchost.exe的都是同一个父进程services.exe(PID 696),注意这里也显示了进程创建时间的差异。


在正常的系统环境中,svchost.exe的父进程应该是services.exe,通过这点可以判断svchost.exe(PID 1824)是恶意的。HollowFind插件同时还检测到了被注入恶意代码的可疑内存区域。



b)案例2:非进程挖空(申请不同的地址,修改PEB)


在这个案例中,我们来看看另一个木马样本,同样也使用了另外一种Process Hollowing,它会导致一些插件检测的结果出现差异,可能是用来迷惑分析人员或取证工具。


首先来看看这个病毒是如何工作的,木马以挂起模式创建svchost.exe进程,并加载到地址0x01000000,如下图所示:




木马样本然后在0x00400000地址上申请了一块RWX权限的内存,这次这个木马并没有像其它病毒一样:“取消映射被挂起的svchost.exe进程基址上的内存0x01000000”


而是保留了源svchost.exe进程基址上的内存。


木马把一个pe文件写入到目标系统进程svchost.exe新申请的内存地址(0x00400000)中。


木马然后通过SetThreadContext函数,修改了被挂起进程svchost.exe的 CONTEXT.EAX的值,指向注入到0x0040000中pe的入口点,然后恢复线程执行。


这个样本所使用技术,并没有挖空进程内存,但是只通过修改PEB,就欺骗了一些插件。在下面截图中,dlllist插件显示了svchost.exe(PID 2020)的基址在0x0040000。


而基于VAD的ldrmodules插件显示的模块列表中,svchost.exe进程的基址却是0x1000000。


除了通过两个插件可以看到同一个模块基址的差异,我们可以看到svchost.exe模块中的Inload InInit InMem这3列属性,显示为False


意味着这个svchost.exe模块可能是个隐藏的模块(这个隐藏模块的现象是假的,因为我们通过dlllist这个插件是可以看到svchost.exe模块的存在)。


同一个进程,两个插件检测出来的基址不同,这可能会让一些安全分析人员感到困惑。正常的反映可能是依赖于ldrmodules的输出结果。


因为ldrmodules的输出结果是从内核结构链表中读取出来的。正因此,可能会给人一种svchost.exe模块可能被断链了的错觉。




让我们来基于这个ldrmodules(0x01000000)报告的内容,进一步分析,看看能发现什么。首先我们重点分析基址为0x01000000的svchost.exe模块,后面再分析基址为0x00400000的svchost.exe模块。


我们可以使用dllmudp插件来把0x0100000这个基址上的svchost.exe模块dump下来,它支持通过基址来dump。然后使用file命令确认是个pe文件。


提交dump后的pe文件到VT上查看扫描结果,并没有任何一家报毒


使用strings命令来提取dump文件的字符串信息时,整个pe文件值发现了9行字符串信息,所以我们刚才dump的svchost.exe模块是正常的!!


通过malfind插件来找到有可疑的内存保护属性的内存块时,并没有在0x01000000地址上发现任何可疑的内存保护属性,但是却在0x00400000地址上发现了,这个内存地址上保存的正是注入的恶意PE。


我们之前使用dlllist插件可以检测到svchost.exe的基址指向了这个地址,说明恶意代码在0x00400000上,而不是0x01000000.


现在让我们把svchose.exe进程在0x00400000上的这个模块dump下来,然后上传到VT扫描结果显示,这是个恶意的文件





从dump下来的文件中提取字符串,可以看到一些相关的C2 IP地址



目前我们知道了有时候木马会用一些欺骗的手段导致不同的插件检测的结果不同,以及混淆安全分析人员,欺骗以及一些依赖内核结构的插件。


使用HollowFind插件就可以通过对比PBE和VAD帮我们自动发现两个结构数据中的差异。下面截图中展示了hollowfind插件检测到了两个结构中基址和内存保护属性的差异。


可以让分析人员快速找到异常的部分。这个例子中,尽管我们已经通过插件知道了内存保护属性和基址不同,插件还为我们显示出了在0x00400000这个地址上有个PE。




HollowFind插件还为我们显示了相似的进程,可疑内存。可以通过比较父进程的差异,进程创建时间的差异,来辨别是否异常。


c)案例3:Kuluoz木马实现的Process Hollow(修改入口点地址)


和之前的案例一样,Kuluoz木马通过挂起的方式,创建Svchost.exe进程


Kuluoz并没有使用VirtualAllocEx和WriteProcessMemory函数,而是用了另一种技巧:

  • 首先在自己的进程中创建一个section
  • 然后拷贝shellcode到创建的section中
  • 使用NtMapViewOfSection函数以RWX权限映射这块内存到svchost.exe进程中



svchost.exe会申请一块内存(0x60000)来保存映射过来的数据


木马然后在自己进程中创建了第二个section,然后把svchost.exe的内容拷贝到该seciton中,并修改了拷贝的svchost.exe的入口点处7个字节。


然后通过取消映射的方式将原svshost.exe进程0x120000加载基址上的内存释放掉,此时svchost.exe进程被挖空了。


注意下面截图中,svchost.exe原本的加载基址0x120000已经不见了


木马然后将修改后的svchost.exe再次通过映射到方式,映射到原svchost.exe进程中的0x120000地址上。



此时原svchost.exe进程上0x120000上的数据又被恢复了,只是入口处7字节数据被修改了。


通过对比正常的svchost.exe系统进程(左图)和被挂起的svchost.exe进程(右图),可以发现入口点处7字节差异


通过反汇编有差异的7字节数据,可以发现原来是在入口点劫持了执行,利用ret指令,变相跳转到了0x60000(第一次映射进来的shellcode)中执行去了。


木马然后恢复被挂起的svchost进程执行,执行时就会直接跳转到shellcode中执行恶意代码了。


让我们在内存中来看看感染了Kulouz木马后,能找到什么可疑特征。


在上一个案例中,我们通过对比dlllist和ldrmodules这两个插件的检测记过的差异,可以找到可疑的svchosts.exe进程。


在本案例中,尽管可疑的svchost.ex进程入口点被修改了7字节。但并非就认为它完全是恶意的。注意下面截图中svchost.exe进程的路径和基址(0x00a00000)


dlllist插件查看进程



使用ldrmodules插件查看svchost.exe进程


使用malfind插件插件可以检测到svchost.exe基址的内存保护属性是异常的。说明这个进程并不是被系统正常加载启动的。

如果你dump该进程,你会发现你在浪费时间分析一个正常的svchost.exe,除了入口点修改的那三条汇编指令,剩下的指令全都和正常的svchost.exe相同。


那么如何找到真正恶意的代码呢?malfind插件同样也找到了另一块可疑的内存地址0x60000,尽管这块可疑内存上并不是一个完整的PE文件,而是shellcode。


我们知道svchost.exe入口点会跳转到这里来执行。


尽管malfind可以轻易帮我找到0x60000这块可疑的内存,但是安全分析人员仍有可能会忽略掉,0x60000内存上的内容(除非分析人员了解这种注入技术)。


让我们来看看HollowFind插件如何帮助我们找到可疑的信息,下面截图中显示了它发现了无效的eEXE内存保护属性,以及路径差异。


并且显示了入口点处的反汇编,这可以帮助我们直接发现入口处被修改的跳转到0x60000(push 0x60000;ret;)



hollowfind插件还帮我们显示了相似的svchost.exe进程,我们可以直接发现可疑的svchost.exe的父进程是order.exe,以及创建时间的不同。


同时可疑内存检测,帮我们直接列出了0x60000这块被注入shellcode的内存


d)案例4:修改Kuluoz木马增强伪装性(修改内存保护属性为PAGE_EXECUTE_WRITECOPY)


通过案例3我们知道Kuluoz木马虽然可以躲避一些分析,但是仍然可以通过可疑的内存保护属性(PAGE_EXECUTE_READWRITE)来检测到它。


如果我们修改那块可疑内存的保护属性,然后再运行它,就能绕过malfind插件的检测。


为了增强隐蔽性,通过修改Kuluoz木马的代码来做两件事:

  • 以挂起模式创建explorer.exe进程,而不是svchost.exe。 因为explorer.exe的父进程是userinit.exe,它在系统启动时,做完要做的事情,就自己退出了。所以我们看到exolorer.exe的时候,是没有父进程的。如果我们木马进程创建挂起的explorer.exe进程,然后注入恶意代码,恢复explorer.exe执行后,木马退出自己的进程。 这样被注入explorer.exe就变成了没有父进程了。 可以绕过哪些基于父进程来检测的插件。


  •   之前提过,Kuluoz木马会创建一块section包含shellcode的内存,然后通过NtMapViewOfSection函数将这块内存以RWX权限映射到远程进程中。如果我们映射内存时,以PAGE_EXECUTE_WRITECOPY属性来映射。


就可以绕过malfind插件。问题是微软并没有为VirtualAllocEx函数中提供Flag为PAGE_EXECUTE_WRITECOPY这样的参数。不过可以在native NtMapViewOfSection函数中使用这个Flag



Kuluoz木马以挂起方式创建explorer.exe,进程加载到基址0x570000,内存属性为PAGE_EXECUTE_WRITECOPY(WCX)因为此时进程是正常加载的。




木马在自己进程空间内创建一块section,然后将shellcode拷贝到section中。然后将这块内存映射到explorer.exe进程中,此时并不是以RWX(0x40)权限映射的,而是WCX(0x80)权限。

最终这块内存被映射到explorer进程中的0x60000地址上。



同样套路,然后木马在自己进程中创建第二个section,将explorer.exe拷贝到第二个section内存中,然后修改入口处7字节。


然后将原explorer进程中的基址处(0x570000)内存取消映射(释放掉),此时explorer进程映射的静态pe内容已经被释放了。


跟案例3的套路一样,木马再将自己内存中备份的explorer.exe内存,再次映射到原explorer基址上(0x00570000)


唯一的差距就是入口7字节被修改了



然后木马恢复explorer进程为运行状态。explorer运行后,入口点代码直接跳转到第一次映射的shellcode内存地址(0x60000)上执行


然后我们来看看修改过的木马,是否能绕过malfind插件的检测。


下面截图中显示了两个exolorer.exe进程,它们的父进程都早已经退出了。所以此时我们不能基于父进程来检测了。


但是还是有一些方法可以检测的,比如发现系统中有多个explorer进程时,可以查看exploer进程的创建时间来判断。


通过dlllist插件来查看进程explorer进程的模块,检测结果显示explorer进程的基址在0x00570000上。


但是使用ldrmodules插件来检测模块列表,并过滤0x00570000这个基址时,并没有显示explorer.exe的全路径,是因为原explorer.EXE基址上的内存被释放后,又被重新申请到了。


通过比较dlllist插件(PEB)和ldrmodules插件(VAD)的结果差异,可以发现这个可以作为一个判断可疑的点。


但是如果你dump进程内存来分析,除了可以得到一个可疑跳转指令,并没有其他恶意行为。


运行malfind插件时,只发现了一块可疑内存在0x570000地址上。此时并没有发现位于0x60000上的恶意代码,因我我们将恶意代码部分的保护属性修改成了PAGE_EXECUTE_WRITECOPY,


malfind不会检测存在这种类型保护属性的内存。


通过这种方法,通过这种方式可以混淆安全分析人员以为0x570000上的内存有问题。然后dump并分析它。但实际存在shellcode的内存0x60000并没有找到。


hollowfind插件就是用来检测各种类型的进程注入。hollowfind插件会检测所有可疑的内存保护属性(带执行属性的)。下面截图中显示了hollowfind找到了explorer.exe进程(PID 2588),


同时也找到了入口点的差异,跳转到0x60000shellcode的指令。



下面截图中,hollowfind插件显示了相似的进程以及可疑的内存区域,同时也认为0x60000地址是可疑的,因为这块内存上没有包含一个PE文件却存在PAGE_EXECUTE_WRITECOPY属性。


e)案例5:Kronos木马中实现的进程注入(修改内存保护属性为PAGE_EXECUTE_WRITECOPY)


几天前,我发现一个名为Kronos的木马使用了以上一个案例中类似的手段,这个样本注入到了explorer.exe进程,然后修改了explorer入口点的地方为跳转指令,跳转到一处内存属性为PAGE_EXECUTE_WRITECOPY的地址上执行。


虽然在注入到exolorer.exe后,然后恢复进程运行后,进程崩溃了,此时仍旧可以保存dump来分析一下。


运行HollowFind插件来检测被kronos感染过的内存dump文件,检测到了可疑的进程和入口一个跳转指令,尝试跳到0x6f60b地址上执行。 


这个插件同时也检测到了可疑内存区域0x60000,这里保存的是一个pe文件,但是并不是在内存中展开的。并且有PAGE_EXECUTE_WRITECOPY属性。


实验证明,通过注入代码到内存属性为PAGE_EXECUTE_WRITECOPY的内存中,使用hollowfind插件仍然可以有效检测这类代码注入攻击。


总结


Process Hollowing是一种将恶意代码注入到系统进程中执行的技术,看起来黑客通过使用不同类型的进程注入方式,不仅要注入系统进程,还要保持自身隐蔽性,来对抗取证工具、欺骗安全分析人员。


但是从应急响应的角度来看,了解这种隐藏方式的原理非常有必要。了解这些技术有助于我们更好的应对此类木马攻击。


HollowFind插件就是用来专门检测这些注入技术,插件通过查找VAD和PEB中的差异来检测此类攻击,还分反汇编入口点的地址来检测是否存在可疑跳转指令,并展示任何可能存在注入代码的可疑内存信息。




[公告]安全服务和外包项目请将项目需求发到看雪企服平台:https://qifu.kanxue.com

最新回复 (3)
xiaofu 8 2019-7-27 15:34
2
0
nice~
kingswb 2019-7-28 07:24
3
0
留名,学习了
113254.. 2019-8-3 22:26
4
0
这个注入有什么关系吗 我萌新
游客
登录 | 注册 方可回帖
返回