在本文中,我们将详细介绍如何逆向一个流行的反病毒引擎,并对其进行“扩展”。在创建新的反病毒特征值(Anti-virus Signature)之后,就可以通过杀毒软件来对我们指定的机密文件实现自动检测。
背景
在抵御恶意代码的持久战中,反病毒产品占据了主力地位。然而有趣的是,这些反病毒产品的特点往往与高级网络情报监控工具的特点有许多共同之处。例如,持久性、可扩展性、高级扫描能力、自我防御机制等,具体如下:
1、持久性:反病毒产品需要确保其能够始终运行,通常会将一些基础组件隐藏在比常规用户更高级别的位置。
2、扫描:反病毒产品设计的目的,就在于监测并扫描全部文件,包括文档这类不可执行的文件。
3、自动更新:反病毒产品经常需要自动更新各种组件,例如最新的特征库,这些组件会以不透明的方式进行功能上的扩展,即通常所说的“更新病毒库”。
4、上传文件:反病毒产品可能会上传可疑文件,以进行进一步分析。
5、自我防御和反分析机制:反病毒产品通常会采用先进的自我防御机制,来防范逆向工程分析。
在这里,我们重点关注反病毒特征值。我们所研究的特征值应该具有如下特点:
1、每天更新;
2、以加密方式传输,并且以加密方式保存在磁盘上;
3、面向特定地区或特定客户端,进行有针对性的更新;
4、独立存在,不包含在反病毒产品的源代码之中。
换而言之,如果要分析具有上述特性的特征值,可以说是一个相当复杂的任务。那么,是否存在一种可能,让我们将反病毒产品当作完美的网络情报监控工具来使用?
在最近的新闻中,我们看到:有人指责知名网络安全公司卡巴斯基旗下的反病毒软件,会检测NSA的机密文档,并将其泄漏给俄罗斯。这个新闻使我眼前一亮。当然,我不想对这一事件发表评论,但是我非常好奇,是否可以从技术上实现这一点。
具体而言,我想尝试一下是否在不修改可执行代码的前提下,是否能够将文档的特征值添加到卡巴斯基反病毒产品之中,从而让反病毒引擎帮助我们自动检测机密文档,并对其进行标记,从而帮助我们获得这些文档。
我的目标非常简单:对卡巴斯基产品进行逆向分析,从而掌握其原理。并且创建一个新特征值,用于标记机密文件。
对卡巴斯基的分析过程
我们将针对macOS系统上最新版本的卡巴斯基网络安全软件进行分析。在下载之后,我们进行安装,它会安装多种组建,其中包括内核扩展组件、守护进程组件以及各种用户组件。
$ ps aux | grep -i kaspersky
root 975 /Library/Application Support/Kaspersky Lab/KAV/Binaries/kav -r -bl
user 1599 /Applications/Kaspersky Anti-Virus For Mac.app/Contents/MacOS/kav_app
user 1116 /Library/Application Support/Kaspersky Lab/KAV/Applications/Kaspersky Anti-Virus Agent.app/Contents/MacOS/kav_agent
我们可以进行大致对守护进程进行分类(/Library/Application Support/Kaspersky Lab/KAV/Binaries/kav),找到负责病毒扫描及检测逻辑核心的代码,并将其作为我们要逆向的目标。
当前的反病毒产品非常复杂,而卡巴斯基可能是其中最为复杂的一个。因此,要成功掌握其对特征值的检测方式和扫描逻辑,是一个非常具有挑战性的任务。但幸运的是,在这个世界上还有像29A、VXer、z0mbie这样的大神们和《Antivirus Hacker’s Handbook》(作者:Joxean Koret)这样的教程存在,我们要特别感谢他们所提供的帮助!
尽管安装程序附带了内置的特征值,但与其他反病毒软件相同,卡巴斯基反病毒引擎会定期检查新的特征值并进行更新。
让我们仔细研究一下这个过程。
当新的特征值可用时,会由kav守护进程从卡巴斯基更新服务器(例如dnl-03.geo.kaspersky.com)进行下载:
对于上述信息,不要觉得奇怪,因为这些特征值已经以特定的方式进行了压缩和加密。
当客户端收到更新的内容后,首先会将特征值存储在/private/tmp/temporaryFolder/updates/kdb/i386/文件夹中,然后安装
# fs_usage -w -f filesystem
05:51:32.804433 stat64 /private/tmp/temporaryFolder/updates/kdb/i386/base010c.kdc 0.000003 kav.11742
05:51:32.804440 open F=80 (R_____) /private/tmp/temporaryFolder/updates/kdb/i386/base010c.kdc
# tail -f /Library/Logs/Kaspersky\ Lab/kav_daemon_2017-11-01-091336_pid_02464.log
05:53:01.704 13365 INF updater [updater_facade_ai.cpp:345] Publishing journal event with code: 1408419436, core code: 107, defaultLocalization: File updated, param1: /Library/Application Support/Kaspersky Lab/KAV/Bases/KLAVA/base011b.kdc, param2:
05:53:02.277 11764 INF bl [ReportsWriter] sqlite query processed: 'insert into "UpdaterFileUpdatedEvent" values (6159,0,'/Library/Application Support/Kaspersky Lab/KAV/Bases/KLAVA/base011b.kdc',13);'
05:53:02.277 11764 INF bl [ReportsWriter] sqlite query processed: 'insert into "UpdaterFileUpdatedEvent" values (6160,0,'/Library/Application Support/Kaspersky Lab/KAV/Bases/KLAVA/base011c.kdc',13);'
# hexdump -C /private/tmp/temporaryFolder/updates/kdb/i386/base010c.kdc
00000000 55 50 44 53 cc 65 02 00 00 00 02 00 1f 8b 08 00 |UPDS.e..........|
00000010 00 00 00 00 00 0b 74 9d 07 d8 db d4 f9 f6 83 1d |......t.........|
00000020 c8 09 a3 ec b4 10 66 28 ab ac 24 8c b0 21 83 0c |......f(..$..!..|
00000030 32 08 49 08 10 a6 24 cb b6 3c 24 db f2 26 6c 08 |2.I...$..<$..&l.|
00000040 7b af b0 cb 86 b2 09 1b ca 0a a3 94 51 f6 0a a5 |{...........Q...|
00000050 ec b2 f7 28 04 c8 f7 bb e5 a4 7f 4e bf 8b 5c 97 |...(.......N..\.|
00000060 6e 59 ef 6d eb 3c 92 ce 39 cf 3c ca f8 51 23 87 |nY.m.<..9.<..Q#.|
00000070 f4 e9 b3 64 9f 5f ff db 80 83 cb fd 54 b2 1d b7 |...d._......T...|
在守护进程运行时,似乎这些特征值会存储在kavbase_00000000缓存文件中。举例来说,在这里我们就可以找到EICAR特征值(欧洲反计算机病毒协会用于测试的特征值)“X5O!P%@AP[4PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*h”:
# grep -r EICAR-STANDARD-ANTIVIRUS-TEST /Library/Application\ Support/Kaspersky\ Lab/
Binary file /Library/Application Support/Kaspersky Lab//KAV/Bases/Cache/kavbase_00000000 matches
# strings -a /Library/Application Support/Kaspersky Lab//KAV/Bases/Cache/kavbase_00000000
..
X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*h
通过lsof命令,我们可以确认卡巴斯基守护进程已经打开了这个文件:
# lsof -p 508 | grep kavbase_00000000
kav 975 root /Library/Application Support/Kaspersky Lab/KAV/Bases/Cache/kavbase_00000000
kav 975 root /Library/Application Support/Kaspersky Lab/KAV/Bases/Cache/kavbase_00000000.lck_00000002
此前,研究人员们(比如z0mbie)针对卡巴斯基特征值所专有的文件格式,已经编写过一个可以对其进行解密和解压缩操作的解析器。但是这些工具只有Windows版本,并且可能已经有一些过时。尽管我们有能力将这些工具移植到macOS系统上,同时也可以对其进行更新,但是我还是决定采取更简单的方式来实现,即在内存中对特征值进行修改操作。尽管这种方法并不具有持久性,但它却能完全绕过破解卡巴斯基特有文件格式的这一过程,最终殊途同归——可以让我们成功创建一个能检测机密文档的特征值。
为了实现我们的目标,目前为止我们已经知道加密后的特征值是从卡巴斯基服务器上下载的,并在安装之后由其守护进程kav来使用。我们可以创建一个文本文件,在其中写入EICAR特征值,关闭文件并保存(例如可以存为test.txt),以此来证明kav的作用。
# fs_usage -w -f filesystem
07:07:13.240475 open F=83 (R_____) /Users/user/Documents/test.txt kav.4343
07:07:13.242416 read F=83 B=0x44 kav.4343
07:07:17.597921 unlink /Users/user/Documents/test.txt kav.4343
我们很容易发现,kav会打开该文件,并读取整个文件(共有0x44字节),逐字节对其进行扫描,一旦检测到匹配某条特征值后,就会立即将其删除。
在处理另一个文档(dontScanMe.rtf)的过程中,我们发现,当文档被修改时,卡巴斯基也会打开该文档并读取其内容,我们推测可能是为了扫描其中是否被添加了新的恶意内容:
# fs_usage -w -f filesystem
09:21:42.208362 open F=82 (R_____) /Users/user/Desktop/dontScanMe.rtf kav.4343
09:25:00.937012 lseek F=82 O=0x00000000 kav.4343
09:25:00.937032 read F=82 B=0x15d kav.4343
除了确认kav确实是执行扫描的组件以外,我们在此次实验中,还确认了卡巴斯基会主动扫描全部文档,以查找存在风险的模式。
当然,扫描具有恶意模式的文件也是反病毒产品的职责之一。所以从逻辑上来看,反病毒产品应该对可能被恶意利用或包含恶意代码的文档进行检测。所以,它扫描文档的这一行为不应该被质疑。与此同时,由于反病毒引擎对所有文档都会进行扫描,这也就意味着我们应该可以利用这一特性,生成并使用一个可以用来检测文档密级的特征值。
早期的反病毒引擎只能够扫描简单的模式,现代的反病毒产品与之相比更加智能化。正如Joxean在其《Antivirus Hacker’s Handbook》一书中所说的那样,卡巴斯基的扫描逻辑相当复杂。具体而言,卡巴斯基对一个特征值的检测,不仅会检测其简单的模式,同时还会对可执行代码进行检测(即检测例程)。这样一来,反病毒产品就包含了强大且复杂的检测逻辑,并突破了“特征值”在传统上的定义。这些将被更新到客户端的“可执行”特征值,需要动态链接到防病毒软件的内核。Koret在文章中提出:“在解密和解压缩之后,这些文件会相互链接,新生成的二进制文件形成新的内核,同时所有的插件将会静态链接到内核上。”这也就意味着,卡巴斯基已经实现了完整意义上的加载器和链接器(Loader/Linker)。
你也许会认为,以特定国家为目标的恶意软件(Nation-state malware)代码是唯一有能力从远程服务器下载加密载荷并在内存中执行的代码。然而,像卡巴斯基这样的高级反病毒产品,就有充分的理由来使用这样的功能。除了保护其特征值不被恶意软件破坏之外,这样的功能还可以降低内存消耗,并带来更快的启动速度。
为了进一步分析,我们接下来尝试在kav的内存中寻找这些动态加载的可执行特征值。由于这个代码是动态加载和链接的,因此假如我们使用“image dump sections”之类的命令来遍历调试器中的内存区域时,它可能不会显示出来:
(lldb) image dump sections
Dumping sections for 301 modules.
Sections for '/Library/Application Support/Kaspersky Lab/KAV/Binaries/kav' (i386):
Load Address Perm Section Name
--------------------------------------- ---- ----------------------------
[0x0000000000000000-0x0000000000001000)* --- kav.__PAGEZERO
[0x000000000008e000-0x000000000039a000) r-x kav.__TEXT
[0x0000000000092500-0x000000000031c620) r-x kav.__TEXT.__text
...
但是,假如我们使用vmmap这样的工具,应该就可以将调试器模块Section列表中未能列出的内存可执行Section显示出来。实际上的确如此,我们发现在0x12824000处有一个11MB大小的内存块:
# vmmap kav
Process: kav [975]
Path: /Library/Application Support/Kaspersky Lab/KAV/Binaries/kav
Load Address: 0x8e000
Identifier: kav
Version: ???
Code Type: X86
OS Version: Mac OS X 10.13 (17A365)
----
Virtual Memory Map of process 975 (kav)
Output report format: 2.4 -- 32-bit process
VM page size: 4096 bytes
==== Non-writable regions for process 975
...
VM_ALLOCATE 0x12824000-0x13379000 [11.3M 7300K 7300K 4304K] r-x/rwx SM=PRV
在调试器中,我们可以通过“memory read”命令来转储这个内存,但在这里需要注意“-binary”标志:
(lldb) memory read --force --binary --outfile /tmp/signatures.bin 0x12824000 0x13379000 11882496 bytes written to '/tmp/signatures.bin'
在反汇编器中,打开转储后的二进制数据,并将其基址设置为0x12824000,就可以显示出与特征值相关的字符串和二进制代码:
至此,我们已经对卡巴斯基的特征值以及它们与反病毒引擎的交互有了一个非常好的理解。至少来说,我们已经掌握了生成用于检测机密文档签名所需的全部知识。
检测机密文档
反病毒引擎用于自动扫描恶意模式的文件(其中包括文档)。既然我们目前已经确定了卡巴斯基未加密签名和检测例程在内存中的位置,那么我们创建一个用于检测机密文档的特征值就不再那么困难。当然,如果一个反病毒软件公司想要这么做(或者被迫这么做),它们完全可以针对特定的客户端(目标用户)部署一个新的特征值,并用来持续检测这些文件。在本文,我们的目的仅仅是从技术角度展现这一点是完全可行的。这个新的“特征值”,会让反病毒引擎自动将包含特征值的加密文档标记出来。
在《Antivirus Hacker’s Handbook》中,Joxean讨论了如何绕过卡巴斯基特征值检测机制,并尝试检测利用CVE-2010-3333漏洞加入恶意代码的文档。由于这一漏洞仅针对微软产品,所以我们可以将其作为一个非常合适的目标。
分析特征值检测例程
通过我们从内存中转储出来的特征值检测例程,我们在地址为0x13071230的位置找到了实现这个特征值逻辑的函数:
正如Joxean所指出的那样,该检测程序首先检查被扫描的文档是以富文本格式(RTF)头部“{rt”开始的,并且大小至少为0x5d00字节。以下伪代码详细展示了初始检查的过程:
//esi is an 'item object'
// +0 points to the start of the document being scanned
// +0xdc14 contains the length of the document
if ((*esi != '{\rt') || (*(esi + 0xdc14) <= 0x5d00))
{
//bail
}
随后,检测代码将从文档中读取数据块,并在这些数据块内扫描各种字符串,例如“dplineco”、“{sp2{sn1 pF”和“ments}”。如果上述字符串都可以在该文档中找到,则函数会返回0x1,这代表着特征值检测例程认为该文档属于恶意文件。
为了展示这一行为,我们需要实际扫描一个利用了CVE-2010-3333漏洞的恶意文件(该文件Hash值为deac10f97dd061780b186160c0be863a1ae00579)。但首先,我们在检测例程开始的地方设置一个断点,其具体地址为0x13071230:
(lldb) b 0x13071230
Breakpoint 1: address = 0x13071230
* thread #131, stop reason = breakpoint 1.1
frame #0: 0x13071230
-> 0x13071230: pushl %ebp
0x13071231: movl %esp, %ebp
0x13071233: subl $0x20, %esp
0x13071236: movl 0x12828164, %eax
Target 0: (kav) stopped.
在扫描文档的过程中,特征值检测程序的断点会被触发。在这里,我们可以转储它所需的参数(在$esp+4中),其参数是一个指向包含正在扫描文档信息的“项目对象”(Item Object)指针。具体来说,我们可以在该对象的开始处看到文档对应的字节“{rtxa{…”,而在偏移量0xdc14的位置是文档的大小(0x00006e1e):
(lldb) x/x $esp+4
0xb11c5f44: 0x79f6041c
(lldb) x/s 0x79f6041c
0x79f6041c: "{\rtxa{\ansi{\shp{
(lldb) x/x 0x79f6041c+0xdc14
0x79f6e030: 0x00006e1e
我们可以步进特征值检测函数,来确认所有需要寻找的字符串都成功被找到,这就意味着该文档将会被标记为CVE-2010-3333的恶意文件。
首先,检查该文档是否以“{\rt”(或者0x74725c7b)开头:
-> 0x13071244: cmpl $0x74725c7b, (%esi)
0x1307124a: pushl %edi
0x1307124b: jne notMalicious
(lldb) x/x $esi
0x79f6041c: 0x74725c7b
随后,检查文档的大小是否不小于0x5d00:
-> 0x13071251: cmpl $0x5d00, 0xdc14(%esi)
0x1307125b: jb notMalicious
(lldb) x/x $esi+0xdc14
0x79f6e030: 0x00006e1e
由于我们所扫描的文件是不小于0x5d00字节的RTF文档,因此将会继续检查文档页脚附近是否存在字符串“dplineco”。这一步是通过调用0x129fcc70的函数来完成的,该函数会扫描字符串中的一个字节块:
我们在0x1307128b的地方,即调用0x129fcc70的位置设置断点,并转储参数,让其显示出我们要查找的字符串(即“dplineco”)和要进行搜索的全部字节(即“necor0dplinecog0dplinecob0))))”):
(lldb) x/4x $esp
0xb11c5f00: 0x79f6041c 0xb11c5f2c 0x00000008 0x79f617fc
(lldb) x/s 0xb11c5f2c
0xb11c5f2c: "dplineco"
(lldb) x/s 0x79f617fc
0x79f617fc: "necor0\dplinecog0\dplinecob0}}}}"
如果找到匹配项,则会继续检查“{sp2{sn1 pF”和“ments}”是否存在,检查过程会再次调用位于0x129fcc70的函数:
* thread #111, stop reason = breakpoint 3.1
-> 0x129fcc70: push ebp
0x129fcc71: mov ebp, esp
0x129fcc73: sub esp, 0x10c
0x129fcc79: mov eax, dword ptr [0x12828164]
Target 0: (kav) stopped.
(lldb) x/5x $esp
0xb11c5efc: 0x13071314 0x79f6041c 0xb11c5f1c 0x0000000d
0xb11c5f0c: 0x79f6181c
(lldb) x/s 0xb11c5f1c
0xb11c5f1c: "{\sp2{\sn1 pF"
(lldb) x/s 0x79f6181c
0x79f6181c: "ture1\levelold0\levelprev1\levelprevspace1\...{\sp2{\sn1 pF}...
* thread #111, stop reason = breakpoint 3.1
-> 0x129fcc70: push ebp
0x129fcc71: mov ebp, esp
0x129fcc73: sub esp, 0x10c
0x129fcc79: mov eax, dword ptr [0x12828164]
(lldb) x/5x $esp
0xb11c5efc: 0x1307132d 0x79f6041c 0xb11c5f2c 0x00000006
0xb11c5f0c: 0x79f6181c
(lldb) x/s 0xb11c5f2c
0xb11c5f2c: "ments}"
(lldb) x/s 0x79f6181c
0x79f6181c: "ture1\levelold0\levelprev1\levelprevspace1\...ments}...
由于我们此次扫描的文档,通过了上述所有的检查,全部特征均与特征库中内容相匹配,因此特征值检测例程将返回0x1,这就表明该文档疑似是恶意文件。
isMalicious:
1307134c mov eax, 0x1
...
13071357 mov esp, ebp
13071359 pop ebp
1307135a ret
在卡巴斯基的UI界面中,我们可以看到该文件确实被标记并隔离:
在全面了解这个特征值检测例程之后,我们就可以利用它来自动检测机密文件。
修改特征值实现检测机密文档
由美国政府分类的文件,通常包含分类标记。例如,包含敏感隔离信息的绝密文件会被标记为TS/SCI。我们将通过修改上文所述的CVE-2010-3333特征值,来让卡巴斯基有能力检测到这些文档。但是,如果反病毒软件公司想要检测这些文件,他们肯定会创建一个新的签名,在本文中,我们采取的是最简单的方式,也就是修改已有的特征值。具体而言,我们要将需要搜索的字符串(例如“ments”)改为文档中的分类标记(例如“TS/SCI”)。
需要强调的一点是,我们希望通过修改特征值来实现对机密文档的检测,而不是通过修改反病毒产品可执行代码的方式,无论是在磁盘上还是在内存中。其原因在于:
1、如果修改任何程序的可执行代码,这就是改变了产品的基本逻辑,而这样的做法并没有意义。并且,如果能够避免修改产品的可执行代码,我们就可以证明代码审计并不能减小我们将反病毒产品用在恶意用途的可能性。
2、在这个特定环境下,我们使用特征值来检测分类特征是否存在的这一过程将会被加上一定的约束条件,具体要看我们所选择原始特征值的可执行代码中包含的约束条件,原因在于卡巴斯基同时支持可执行代码和模式匹配。例如,我们示例中就限制了RTF文档的大小不小于0x5d00字节。在这里,还需要再次强调,一个希望(或者被迫)部署新特征值来检测机密文件的反病毒软件公司不会受到这些因素的限制。
3、在最后,我们成功创建了一个不可执行的检测特征值之后,为了文章的完整性,我们还额外举例讲解了如何创建一个更强大的特征值,该特征值需要对特征值检测的可执行代码进行修改(但不会触及反病毒引擎的核心代码,与1不冲突)。
将卡巴斯基中CVE-2010-3333的特征值修改为检测并隔离已分类文档的特征值,就像修改内存中的匹配模式一样简单。举例来说,我们可以将“ments”修改为“TS/SCI”。相应的修改,可以通过调试器(内存写入0x130a4d80 0x54 0x53 0x2f 0x53 0x43 0x49)来完成,也可以通过负责修改kav守护进程内存的外部进程来完成。在这里,我们采用后者,因为它不需要调试会话(Debugging Session),所以可以以程序的方式来执行,同时还能证明特征值检测例程的地址是动态的。
要修改远程进程的内存,可以调用mach_vm_write() API。正如其名称所暗示的那样,这个函数可以在指定的偏移量处写入特定的字节。
苹果公司提供了一个函数定义的示例,但没有进一步提供更多细节:
kern_return_t mach_vm_write(vm_map_t target_task, mach_vm_address_t address, vm_offset_t data, mach_msg_type_number_t dataCnt);
为了调用这个API,我们必须使用root账户,并且必须具有可以访问目标(远程)进程的任务。通过调用the task_for_pid()方法可以获得上述访问权限。
下面的代码(基于@osxreverser的readmem项目编写)演示了如何利用这些API,将任意字节写入到远程进程的内存之中:
//write some bytes into a remote process
write_memory(pid_t pid, mach_vm_address_t address, vm_offset_t bytes, mach_msg_type_number_t size)
{
//task port
vm_map_t port = 0;
//get task for remote process
task_for_pid(mach_task_self(), pid, &port));
//suspend
task_suspend(port);
//write write write!
// assumes that memory is writable!
mach_vm_write(port, address, bytes, size);
//resume
task_resume(port);
}
通过此代码,我们现在可以修改kav守护进程中的特征匹配模式,例如在内存0x130a4d80处的“ments}”。 要检测包含敏感隔离信息的绝密文档,我们将特征值匹配模式对应的内存值更改为“TS/SCI”。通过调试器或mach_vm_read() API重新读取远程内存,我们能够确认它已经成功被修改:
(lldb) x/s 0x130a4d80
0x130a4d80: "TS/SCI"
现在,卡巴斯基应该就可以自动标记和隔离任何包含此分类标记的文档。
用小熊维尼进行测试
在将特征值添加到卡巴斯基之后,我们进行一下测试。
小熊维尼是我们童年时代的一本经典漫画书,并不属于机密文档。但是,如果我们在其中添加“TS/SCI”分类标记,并将此改动通过保存的方式写入到文件系统(包括自动保存、手动保存或者文档关闭)时,文档将会被扫描,随后卡巴斯基发现该文档符合特征值,触发告警,该文件也随之被标记。
实验视频:
目前,我们已经进行了一次成功的尝试,由此就可以证明,反病毒产品可以轻而易举地被用于检测机密文档。
虽然这个特征值是有效的,但是我们注意到它受到了特征值检测函数可执行代码的轻微“限制”。 比如说,代码首先会检查文档是否大于等于0x5d00字节,较小的机密文档将无法被检测到。
后续改进和优化
我们发现,通过修改特征值检测函数的可执行代码,就可以继续对这个特征值进行改进。 正如我们上文所说的那样,我们可以在不修改任何可执行代码的前提下创建特征值,接下来让我们看看如何修改可执行指令。
由于卡巴斯基会分发包含可执行代码(即自包含特征值检测例程)的特征信息,这些特征在运行时会动态链接到防病毒引擎内核中,因此还可以仅通过修改这些代码来实现。
也就是说,这一过程不会触及到反病毒引擎。
通过修改现有特征值检测例程的可执行代码,来实现对其的扩展,这种方法是非常直接的。针对本文中的例子,我们可以通过这种方法检测到任何大小的文档,不再受到0x5d00字节的限制。首先,在0x13071251(cmp dword [esi + 0xdc14],0x5d00)的位置,修改“检查文件”过程中负责比较的代码。 具体改动如下,修改后即可对全部文件(大小超过0字节)进行检测:
;scan any file over 0 bytes
;cmp file size, now with 0
cmp dword [esi+0xdc14], 0x0
;unlikely to have a negative sized file
;so this jump won't be taken ;)
jb notMalicious
我们只修改了该特征值检测例程的1-2个字节,就可以使防病毒引擎在文件中的任何地方(或在文件开始的位置)搜索分类标记。
当我们拥有这个新的特征值之后,即使是包含分类标志的基本文件,也会被自动标记并隔离。也就是说,该文件会从原始位置“删除”,并移入“隔离”的位置:
机密文档的收集
现在,我们需要考虑怎样去收集这些机密文档。如前文中所述,反病毒软件经常会收集可疑文件和被标记/被隔离的文件,并将它们上传到云端,以便进行更深入的分析。这样的功能,可以让反病毒产品的厂商对某个可疑文件进行更全面、更彻底的分析(与用户计算机相比),同时可以收集威胁情报,并且在整体上提高其产品的检测能力。
卡巴斯基将他们产品的公开收集功能称为“卡巴斯基安全网络(KSN)”他们认为:这样可以让卡巴斯基实验室快速收集新威胁的相关数据,从而开发出针对新威胁的有效防范方案。在KSN文档中,有这样一段内容:“卡巴斯基安全网络服务可能会处理并提交整个文件,如果文件中嵌入的对象包含恶意链接,可能会被攻击者利用,进而对系统或应用的功能产生破坏。因此,卡巴斯基实验室会对其进行额外的检查。”然而我们目前并不清楚,标记的文件是否会自动提交,以供进一步分析。此外,卡巴斯基在博客文章中特别指出,可能会上传检测为恶意的文件,并指出:“如果文件自身被检测出恶意软件,将会提交给卡巴斯基实验室进行分析,该分析由我们的一名分析人员手动进行。”
受研究时间所限,我并没有对卡巴斯基的文件收集功能进行逆向工程和进一步分析。并且,出于一些原因,我不希望与后端系统进行交互,所以我在分析用的虚拟机中禁用了网络连接,以确保新特征值标记的“小熊维尼”文档绝对不会被上传到俄罗斯。
最后,我有充分理由认为,任何具有收集功能的反病毒产品都能够自由地收集(上传)其产品所标记的文件。不过我们要再次强调,这个功能设计的初衷,是为了让产品拥有更强大的能力,而并不是为了窥探用户的隐私。
总结
在这篇文章中,我们展示了如何借助反病毒产品来检测机密文档的特征值。我想重申的是,尽管技术上确实可以,但并不代表着反病毒公司真的会这样做。而对于我们来说,可以将它当作一个有趣的逆向分析尝试。
但是,希望通过本文大家能够理解,任何防病毒产品都可以作为一个完美的网络间谍收集工具。而且由于它们的特征值是加密的,可能会被策略性地部署,会自动安装,包含可执行代码,并且通常与反病毒产品的源代码分离,这就使得用户难以甄别出哪些特征值是可疑的,甚至用户根本都无法查看到这些特征值。
非常有趣的是,在这篇文章发布之前,卡巴斯基刚好发表了一篇博客文章并提到了这种情况。卡巴斯基指出,他们的特征值创建过程很难通过“外部尝试”被篡改(例如被用来检测/收集机密文档):
然而,任何一位反病毒产品所属公司的内部人员,都可能有权限去部署这样的特征值,并且很可能不会被发现。当然,如果该公司被某些组织强迫,或者与一个庞大的集团进行了合作,此时完全能够利用他们的产品,来暗中检测并利用任何感兴趣的文件。
有时候,善恶的分界,不是对立面,而是每个杀软中的一个特征值。
发表评论
您还未登录,请先登录。
登录