逆向分析课程最后的作业是分析一个病毒,在看的过程中发现了一个我不太熟悉的代码注入的方式,遂记录一下,并于写此文与大家分享。这是微步沙箱的一个病毒行为分析图,可以看到该病毒有三层组成。第一层的大概的行为是,ccsuka.exe的资源节里面放了一个加密的PE文件,它首先挂起创建了一个自身的子进程,然后做了一个PE映像切换。即把这个子进程的PE映像卸载了,然后把这个藏在资源节里面的PE文件一步步的写入这个子进程的空间里,最后修改子进程的EIP,并恢复运行。这个技术大家可以在《逆向工程核心原理》的第56章学习到。第二层的大概行为是,创建一个wuaclt.exe进程(这玩意似乎是管Windows更新用的),然后往里面注入一些恶意代码,然后运行。由于打眼一看上去,这部分基本上就是使用了ZwCreateSection()与ZwMapViewOfSection()这俩API来干的这件事情,所以很容易就能看出大概就是用了NtCreateSection + NtMapViewOfSection Code Injection技术。简单来说就是先创建一块共享内存,然后在病毒进程和傀儡进程中都映射这块共享内存,随后病毒进程就可以把恶意代码写到这块共享内存中,实现将恶意代码注入到傀儡进程中的目的,最后在傀儡进程中创建一个线程运行恶意代码即可。由于此阶段的目标是找到第三层即wuaclt.exe进程在运行什么恶意代码,所以我的思路就是看这个创建线程的地址是哪里,然后顺着这块地址往上分析看这块地址上映射的恶意代码是第二层的哪块代码即可。但是标完API(这个病毒的API都是运行后动态获取的)以后,我发现在CreateProcessW()与ZwResumeThread()之间并没有常见的创建远程线程的API,也没有SetThreadContext()这种修改线程EIP的API。但是肯定得有地方是要改wuaclt.exe进程的控制流的,要不然也不会运行注入进去的恶意代码。而且这个病毒用了三次ZwCreateSection(),创建了三个共享内存。总体看下来比较令人迷惑,所以花了点时间仔细的看了看其具体的代码逻辑。
下面称第二层的ccsuka.exe为病毒进程,第三层的wuaclt.exe为傀儡进程。第23行获取了病毒进程的进程基址,第36行获取到了傀儡程序的文件句柄。第44行的ZwCreateSection()的主要作用为读取傀儡程序的内容。这里值得注意的是,第一个ZwCreateSection()的第六个参数为SEC_IMAGE,即0x1000000,并且第7个参数为傀儡程序的文件句柄。这相当于将傀儡程序的PE文件加载到了一段共享内存中,并进行了相应的映射(即PE文件从磁盘加载到内存时进行的映射),这样就可以在后面直接把这个映射后的PE文件进行一些修改后直接再写回到挂起的傀儡程序中。在第52行的ZwMapViewOfSection()把存有傀儡程序的共享内存映射到病毒进程的内存中,然后在第58获取了傀儡程序的PE可选头的地址。第59行获取了傀儡程序PE映像的大小,作为下面创建共享内存大小的参数,第60行获取的是傀儡程序的入口点的地址。第61行的ZwCreateSection()创建了与傀儡程序PE映像一样大小的第二块共享内存,第69行同样把这块共享内存映射到病毒进程中,第75行把上文得到的傀儡程序拷贝到这块共享内存中。同样,第77行以病毒进程的PE映像为大小,创建了第三块共享内存,并将这块共享内存映射到病毒进程中(第81行),然后将病毒进程的PE映像拷贝到这块共享内存中(第83行)。第86行创建傀儡进程,并将装有病毒进程的PE映像的共享内存映射到傀儡进程中(第93行)。这里注意的BaseAddress_3变量已于第91行清零了,执行完第93行代码后,BaseAddress_3变量中保存的值为第三块共享内存(内有病毒进程的PE映像)在傀儡进程映射的地址。第106到第109行将傀儡程序的PE映像(保存在第二块共享内存中)的入口点处的代码修改为push一个函数地址,然后再ret,实际上就是跳转到这个函数地址(这个retaddr实际上是上层函数传入的一个病毒进程中的一个函数的地址)。第111行获取傀儡进程的线程上下文,第113行实际上是计算了傀儡进程的基址,然后在第114行卸载掉傀儡进程的PE映像,在118行把第二块共享内存(即修改过入口点处代码的傀儡进程PE映像)映射到傀儡进程的基址上,这里其实有点类似于PE映像切换技术。这里注意ZwMapViewOfSection()的第三个参数BaseAddress,如果该值为NULL,则接收映射过来的共享内存的地址,如果不为NULL,则在指定位置映射共享内存。最后恢复线程,傀儡进程会跳转到第三块共享内存(病毒进程PE映像)中的相应函数代码处执行。
总的来说,其实还是用的NtCreateSection()+NtMapViewOfSection()的组合来进行代码注入。但是是通过修改傀儡进程入口点处的代码,让其跳转到注入的恶意代码的位置处运行的方式来修改傀儡进程的控制流的,而不是通过创建远程线程。并且修改傀儡进程入口点处的代码使用的也是共享内存技术,而不是赤裸裸的WriteProcessMemory()API。这样做的好处是,少用了一个创建远程线程的API,使恶意代码更加的隐蔽。最后感谢大家的阅读,笔者学疏才浅,若有差错,恳请各位斧正。参考
看雪ID:危楼高百尺
https://bbs.pediy.com/user-home-926584.htm
*本文由看雪论坛 危楼高百尺 原创,转载请注明来自看雪社区。