在签名的程序中隐藏和执行恶意软件?

在Blackhat USA 2016上,来自Deep Instinct的安全研究人员呈现了一个名为《Certificate Bypass: Hiding and Executing Malware from a Digitally Signed Executable》的演讲,咋一看还觉得挺惊奇的,听过演讲之后才发现原理十分简单,而且大部分内容都集中在内存加载PE文件上,于是忍不住又是一阵 惊奇:这也可以?在仔细读完作者的Paper之后,发现和传统技术点还是有区别的,不过也有很大的限制。

早期的恶意软件为了躲避检测,使用过一种叫做“傀儡进程注入” 的技术。通俗一点讲,就是先启动并挂起一个合法的可执行文件(进程A),随后通过跨进程内存读写来将自身(或者是第三方PE文件)注入到进程A,同时处理 输入表和重定位表,最后跳转到入口点来执行代码,这样就完成了一次借尸还魂的操作。原始恶意进程在完成这一操作之后会自动退出,而之后恶意代码会一直在傀 儡进程中运行,也就达到了隐藏自身的目的。

自动草稿

那么,Blackhat上的这个演讲有什么不一样的地方呢?有两个关键的地方。

首先,在一个带有合法数字签名的可执行程序中隐藏恶意程序,并且保证原有数字签名的有效性不会被破坏。这可以在一定程度上躲避杀毒软件的检测,因为 某些杀毒软件可能并不会仔细去检查带有合法数字签名的程序。这一过程的实现钻了Windows校验数字签名的一个空子:Windows在校验PE文件的数 据时,有以下三处数据是忽略的:

  1. 可选头中的CheckSum字段,即IMAGE_NT_HEADERS->IMAGE_OPTIONAL_HEADER->CheckSum;
  2. 数据目录表数组的第五个元素,即IMAGE_DIRECTORY_ENTRY_SECURITY(包括VirtualAddress和Size);
  3. 数字签名相关数据,也就是IMAGE_DIRECTORY_ENTRY_SECURITY指向的数据;

通常而言,IMAGE_DIRECTORY_ENTRY_SECURITY指向的数据会放在文件的末尾,所以我们可以在文件末尾附加额外的数据,同 时修改IMAGE_DIRECTORY_ENTRY_SECURITY的Size字段,即可避免数字签名失效。此外,Size是DWORD类型,所以可以 存放大量数据!

其次,恶意程序同时充当了三个角色:是携带恶意代码的载体,也是Loader,还是傀儡进程。相关的实现细节为:

  1. Loader进程启动;
  2. Loader在内存中提取附加的恶意程序的数据;
  3. Loader尝试移动自身的数据到内存空间中的其他位置,这样可以保证恶意程序的数据可以加载到指定的内存地址;在移动的过程中,Loader需要对自身进行重定位操作,但是不需要对附加的恶意程序进行重定位操作;
  4. Loader完成移动操作后,需要跳转到移动后的代码去执行,这样才能继续接管控制权限;
  5. Loader分配内存并加载恶意程序,并处理对应的输入表;
  6. 跳转到恶意程序的入口点执行代码,将控制权限移交给恶意程序;

新的方法不需要跨进程操作内存,且Loader是完全通用的!缺点:

  1. 需要有合法的证书给Loader签名;
  2. 样本可能会被第三方使用,可能复用成本较低(可通过增强校验来避免);
  3. 安全厂商可以通过证书精确打击;

总的来说,这个议题最有新意的地方在于隐藏的实现上,其他内容基本都是很古老的东西了。

[via@Wins0n-煮酒论安全]