Fork me on GitHub

分析恶意Windows程序


知识点

多数恶意代码运行在Windows上,因此对Windows变成概念的深刻理解会帮助我们识别出恶意代码在主机上感染的迹象,本章会介绍一些恶意代码使用Windows功能的独特方式,并且会讨论恶意代码是如何使用内核模式来实现额外功能与自身隐藏的。

Windows API:Windows API是一个广泛的功能集合,管理着恶意代码与微软程序库之间的交互方式,Windows API使用他自己的名字。例如DWORD和WORD类型分别标识32位与16位无符号整数。标准C类型如int、short等通常并不使用。Windows总体上使用匈牙利表达法,作为API函数的标识符,这个表达式使用一个前缀命名,如32位无符号整数变量会以dw开头。

类型和前缀 描述
WORD (w) 一个16位的无符号数值
DWORD (dw) 一个双字节、32位的无符号数值
Handles (H) 一个对象索引,句柄中存储的信息并没有文档化,而这一句句柄应该只被Windows API来操作。
Long Pointer (L) 一个指向零一类型的指针,例如LPByte是指向字节的指针,LPCSTR是一个执行字符串的指针,字符串通常是由LP作为前缀的,因为他们实际上是指针。偶尔也会看到Pointer(P)而不是LP作为另一类型的前缀,在32位系统里,他们和LP是一样的。
Callback 表示一个会被Windows API调用的函数。

句柄:句柄是在此操作系统中被打开或者被创建的项,句柄应用对象或者地址的情况很像指针你,但是与指针不同,不能用于数学操作。

文件系统函数:微软提供了多个函数来访问文件系统

函数 描述
CreateFile 这个函数被用来创建或者打开文件。它可以打开已经存在的文件,管道,流以及IO设备,还能创建新的文件。
ReadFile WriteFile 这些函数被用来对文件进行读和写。
CreateFileMapping MapViewOfFile 文件映射经常被恶意代码作者使用,因为他们允许将一个文件加载到内存中,以便操作简单,CreateFileMapping函数负责从磁盘上加载一个文件到内存中,MapViewOfFile函数则返回一个指向映射的基地址指针,在文件中的任意位置进行读取和写入。

特殊文件:Windows中有一些特殊的文件无法通过盘符和文件夹访问,但是这些文件可能提供对系统硬件和内部数据更强的访问能力,特殊文件可以作为字符串参数传递给热河文件操作函数,并像普通文件一样进行操作,有如下特殊文件类型:

特殊文件类型 描述
共享文件 共享文件是以\\serverName\share\\?\servername\share开头命名的特殊文件他们用来访问保存在共享目录中的目录或文件。\\?\前缀告诉操作系统禁用所有的字符串解析并允许访问长文件名。
通过名字空间访问 名字空间可以被认为是固定数目的文件夹,每一个文件夹中八平村不同类型的对象。底层的名字空间是NT名字空间,以前缀\开始。以前缀\\.\开始的Win32设备名字空间,可以被恶意代码用来访问物理设备,并且像一个文件进行读写操作。例如恶意代码使用\Device\PhysicalMemory来直接访问物理内存,这允许用户空间程序写到内核空间中。这个技术已经被恶意代码用来修改内核,并隐藏用户空间的程序。
备用数据流 备用数据流(ADS)特性允许附加数据到一个已存在的NTFS文件中,相当于添加一个文件到另一个文件中,这些额外数据在列一个目录时不会被显示出来,在显示文件内容时也不显示,只有在你访问流时才能显示。ADS数据流根据约定normalFile.txt:Stream:$DATA来命名,这允许一个程序去读写一个流。

Windows注册表:注册表用来保存操作系统与程序的配置信息,是揭示恶意代码感染迹象的很好来源,注册表有以下几个关键术语:

  • 根键:注册表被划分为成为根键的五个顶层节
  • 子键:一个子键就像是一个文件夹中的子文件夹
  • 键:一个键是一个注册表中的文件夹
  • 值项:一个值项是一个配对的名字或值
  • 值或数据:值或数据是存储在注册表项中的数据

注册表根键:注册表被划分为如下5个根键:

根键名称 作用
HKEY_LOCAL_MACHINE (HKLM) 保存对本地机器的全局设置
HKEY_CURRENT_USER (HKCU) 保存对当前用户的特定设置
HKEY_CLASS_ROOT 保存定义的类型信息
HKEY_CURRENT_CONFIG 保存关于当前硬件的设置
HKEY_USERS 定义默认用户、新用户以及以前用户的配置

一个常用的子键:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run这个子键包含了当一个用户登陆时被自动启动的可执行程序,恶意代码可能会向次子键中添加键值来实现恶意代码的持久化驻留。

常用的注册表函数:以下是一些常见的注册表函数:

函数 作用
RegOpenKeyEx 打开一个注册表进行编辑和查询。有些函数允许你查询和编辑一个注册表键而不用先打开它,但是大多数程序还是会先使用这个函数
RegSetValueEx 添加一个新值到注册表,并设置它的数值
RegSetValue 返回注册表中一个值项的数值

注册表脚本:注册表脚本以.reg为文件后缀,当用户双击此文件时,他会自动恩据自身的内容来修改注册表,此类文件内容类似如下:

1
2
3
4
Windows Registry Editer Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run]
"MaliciousValue"="C:\Windows\evil.exe

伯克利兼容套接字:伯克利兼容套接字的网络功能是由Windows中的Winsock库实现的,主要在ws2_32.dll中。在所有的库函数中,socketconnectbindlistenacceptsendrecv是最常用的,如下是这些函数的描述:

函数 描述
socket 创建一个套接字
bind 将一个套接字绑定到一个特定端口
listen 一个套接字即将进入监听,等待入站连接
accept 向一个远程套接字打开一个连接,并接收连接
connect 向一个远程套接字打开一个连接,远程套接字必须在等待连接
recv 从远程套接字接收数据
send 发送数据至远程套接字

WinINET API:这是一个保存在Wininet.dll中的比伯克利套接字更高一层的API,实现了应用层的协议,函数如下:

函数 作用
InternetOpen 初始化一个到互联网的连接
InternetOpenURL 访问一个URL
InternetReadFile 从互联网中下载数据

进程:一个进程是Windows正在执行的程序,Windows使用进程作为管理资源的容器。

创建进程:恶意代码最常使用CreatPrcess来创建一个进程,这个函数有很多参数,并且调用者有很多控制它如何被创建的方法。

线程:线程是执行代码的容器,线程才是Windows操作系统真正要执行的内容。线程是被CPU执行的独立的指令序列,而不需要等待其他的线程。

创建线程:CreateThread函数被用来创建一个新线程。函数的调用者指定一个调用地址。

互斥量:互斥量是全局对象,用于协调多个进程和线程,其主要控制共享资源段额访问,并且经常被恶意代码所使用,同一时刻,只有一个线程拥有一个互斥量。线程通过一个对WaitForSingleObject的调用来获取对互斥量的访问,当一个线程完成对互斥量的使用后,使用ReleaseMutex函数来释放互斥量。一个互斥量由CreateMutex函数进行创建,进程可以通过OpenMutex来调用获取另一个进程中互斥量的句柄。

服务:恶意代码执行附加代码的另一种方式是将他们以服务形式安装,Windows允许通过使用服务,来使任务作为后台应用程序运行,而不需要他们自己的进程或线程,代码被Windows服务管理器调度和运行,但是没有用户的输入。下列是一些关于服务的Windows API 函数:

函数 描述
OpenSCManager 返回一个服务控制管理器的句柄,它被用来进行所有后续与服务相关的函数的调用。所有要和服务交互的代码都会调用这个函数。
CreateServices 添加一个新服务到服务控制管理器,并允许调用者指定服务是否在引导使自动启动或者必须手动启动。
StartService 启动一个服务,并且仅在服务被设置成手动启动时使用。

组件对象模型:微软组件对象模型(COM)是一个接口标准,它使得不同软件组件在不知道其他代码的接口规范时相互之间可以调用。每一个使用COM的线程,必须在调用任何其他COM库函数之前,至少调用一次OleInitializeConInitializeEx函数。所以,我们可以通过搜索程序的这两个调用来判断程序是否使用了COM功能。

COM服务器恶意代码:有些恶意代码通过实现一个恶意COM服务器来实现监控互联网流量,跟踪浏览器使用并不使用恶意代码自身的进程,这个服务器很容易被检测,因为它包含如下的函数:

DlCanUnloadNowDllGetClassObjectDllInstallDllRegisterServerDllUnregisterServer

内核与用户模式:几乎所有代码都运行在用户模式,除了操作系统和硬件驱动运行在内核模式,通常,用户模式不能直接访问硬件,并且智能访问CPU上多有寄存器和可用指令的一个子集,为了在用户模式下改变内核中的状态,你必须依赖Windows API。所有运行在内核的进程共享资源和内存地址。内核模式的代码有更少的安全检查。

原生API:原声API使用来和Windows进行交互的底层API,多用于恶意代码,调用原生API可以绕过普通的Windows API。

课后练习

Lab7-1

分析在文件Lab07-01.exe中发现的恶意代码。

问题

1.当计算机重启后,这个程序如何确保他的继续运行(达到持久化驻留)?

通过分析恶意代码main函数看到如下代码:

1
2
3
lea     eax, [esp+10h+ServiceStartTable]
mov [esp+10h+ServiceStartTable.lpServiceName], offset aMalservice ; "MalService"
push eax ; lpServiceStartTable

可见这个程序通过创建一个名为MalService的服务来实现持久化驻留。

2.为什么这个程序会使用一个互斥量?

程序通过使用HGL345作为互斥量来防止程序对服务的重复创建。

3.可以用来检测这个程序的基于主机的特征是什么?

互斥量HGL345

创建服务MalService

4.检测这个恶意代码的基于网络的特征是什么?

程序使用Internet Explorer 8.0http://www.malwareanalysisbook.com发起连接。

5.这个程序的目的是什么?

程序创建20个线程对http://www.malwareanalysisbook.com建立远程连接。可能使为了发动DDOS攻击。

6.这个程序什么时候完成执行?

从2100年开始就不会停止。

Lab7-2

分析在文件Lab07-02.exe中发现的恶意代码。

问题

1.这个程序如何完成持久化驻留?

本程序无持久化驻留措施。

2.这个程序的目的是什么?

1
2
.data:00403010 psz:                                    ; DATA XREF: _main+3C↑o
.data:00403010 text "UTF-16LE", 'http://www.malwareanalysisbook.com/ad.html',0

通过查看函数参数 CoCreateInstance(&rclsid, 0, 4u, &riid, &ppv);rclsid为:

1
2
?? ?? ?? ?? 00 00 00 00  01 DF 02 00 00 00 00 00  ????............
C0 00 00 00 00 00 00 46 61 16 0C D3 AF CD D0 11 .......Fa..盈 托 .

按照大端序的顺序可得rclsid0002DF01-0000-0000-C000-000000000046

1
2
C0 00 00 00 00 00 00 46  61 16 0C D3 AF CD D0 11  .......Fa..盈 托 .
8A 3E 00 C0 4F C9 E2 6E FF FF FF FF 80 11 40 00 ...繭 赦 n....€.@.

同理riidD30C1661-CDAF-11D0-8A3E-00C04FC9E26E

在注册表中查询这两个值:

因此这个此程序使用IE打开一个ad.html的页面。

3.这个程序什么时候完成执行?

显示广告之后便执行完成。

Lab7-3

对于这个实验,我们在执行前获取到恶意的可执行程序,Lab07-03.exe,以及DLL,Lab07-03.dll。声明这一点很重要,这是因为恶意代码一旦运行可能会发生改变。两个文件在受害者机器上的同一个目录下被发现,如果你运行这个程序,你应该确保两个此文件在分析机器上的同一个目录中。一个以127开始的IP字符串连接到了本地机器。(在这个恶意代码的实际版本中,这个地址会连接到一个远程机器,但是我们已经将他设置成连接本地主机来保护你。)

这个实验可能比前面的那些有更大的挑战。你将需要使用静态额动态的方法的组合,并聚焦在全局视图上,避免陷入细节。

问题

1.这个程序如何完成持久化驻留,来确保在计算机重启后它能继续运行?

1
2
3
4
5
.data:00403010 dword_403010    dd 'nrek'               ; DATA XREF: sub_4010A0+EC↑o
.data:00403010 ; _main+1A8↑r
.data:00403014 dword_403014 dd '231e' ; DATA XREF: _main+1B9↑r
.data:00403018 dword_403018 dd 'lld.' ; DATA XREF: _main+1C2↑r
.data:0040301C dword_40301C dd 0

通过函数的调用,可以看到以上字符串拼接起来就是kerne123.dll,程序使用CopyFile函数创建C:\\windows\\system32\\kerne132.dll

2.这个恶意代码的两个明显的基于主机的特征是什么?

  • 创建了一个文件C:\\windows\\system32\\kerne132.dll
  • 创建了一个互斥量SADFHUHF

3.这个程序的目的是什么?

程序将所有用到此DLL的程序进行修改,并向Lab07-03.dll文件中新增导入表,使得原本kernel32.dll的导出函数在此DLL文件中同样适用。通过这个DLL文件作为后门来执行命令或者进行休眠。

4.一旦这个恶意代码被安装,你如何移除它?

通过PE系统修改正常的kernel32.dll文件为kerne123.dll并替换掉恶意文件,或者通过脚本将恶意代码修改的数据改成正常数据。


本章结束🎊

您的支持是我最大的动力🍉