翻译:myswsun
预估稿费:200RMB
投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿
0x00 前言
本文的主题是基础的shellcode概念、汇编级编码器/解码器的设计和一些绕过反利用解决方案(如微软的EMET)的方法。为了理解本文的内容,读者至少需要有较好的x86汇编知识,并熟悉COFF及PE的文件格式,还可以阅读(Art of Anti Detection 1 – Introduction to AV & Detection Techniques 和Art of Anti Detection 2 – PE Backdoor Manufacturing)帮助你理解AV产品使用的基本的检测技术的内部细节和本文中的术语。
0x01 术语
进程环境块(PEB):PEB是Windows NT操作系统家族中的一个数据结构。它是由操作系统内部使用的一个不透明的数据结构,它的大部分字段不适用与操作系统之外。[1]微软MSDN文档(其中只包含了部分字段)说明这个结构可能随着操作系统版本不同而变化。[2]PEB包含全局上下文、启动参数、程序映像加载器的数据结构、映像基址和进程内提供互斥的同步对象。
导入地址表(IAT):当应用程序在不同模块中调用一个函数时,地址表被用来作为一个查询表。它包括两种导入形式(序号和名字)。因为一个编译好的程序无法知道依赖库的内存位置,当调用API时需要间接跳转。因为动态链接器加载模块并将它们连接在一起,它将真实的地址写入IAT, 因此它们指向相应库函数的内存位置。
数据执行保护(DEP):DEP是用来校验内存来帮助阻止恶意代码执行的一组硬件和软件的技术。在微软Windows XP SP2和Windows XP Tablet PC Edition 2005版本中,DEP通过硬件和软件实现。DEP的好处是阻止代码从数据页执行。典型的,代码不能在默认堆和栈中执行。硬件增强的DEP检测这些位置的代码运行,当执行发生时抛出异常。软件增强的DEP帮助阻止恶意代码利用Windows的异常处理机制。
地址空间布局随机化(ASLR):它是一种避免缓冲区溢出攻击的保护措施。为了阻止攻击者固定的跳转,例如,一个特别的内存漏洞利用,ASLR能随机分配进程内关键区域的地址,包括可执行文件的基地址和栈、堆、动态库的位置。
stdcall调用约定:stdcall调用约定由pascal约定演变而来,被调用者负责清理栈,但是参数从右向左的顺序压栈(和_cdecl调用约定一样)。寄存器EAX,ECX,EDX在函数中使用。返回结果保存在EAX中。stdcall是微软win32 API和open Watcom C 的标准调用约定。
0x02 介绍
shellcode在安全领域扮演了很重要的角色,他们在很多恶意软件和利用中都有使用。
因此,什么是shellcode?shellcode以一系列字节为基础,其组成CPU指令,编写shellcode的主要目的是利用漏洞(如溢出漏洞)来允许在系统中执行任意代码。因为shellcode能直接在内存中运行,导致大量恶意软件使用它。命名为shellcode的原因是通常运行shellcode后都会返回一个命令行shell,但是随着时间推移意义也改变了。在今天几乎所有的编译器生成的程序都能转化为shellcode。因为编写shellcode涉及到深入理解目标架构和操作系统的汇编语言,本文假设读者可以在Windows和Linux环境中使用汇编编写程序。在网络上有很多开源的shellcode,但是对于新利用和不同的漏洞,每个安全研究员应该都能编写他自己的shellcode,同时编写你自己的shellcode能很大程度上帮助你理解操作系统的关键东西。本文的目标是介绍基本的shellcode概念,降低shellcode被检测的概率,和绕过一些反利用缓解措施。
0x03 基本的shellcode编程
为不同的操作系统编写shellcode需要不同的方法,不像Windows,基于Unix的操作系统提供了一种通过int 0x80接口与内核通信的方式,基于Unix的操作系统的所有的系统调用都有一个唯一的调用号,通过80中断来调用(int 0x80),内核通过被提供的调用号和参数执行系统调用,但是这里有个问题,Windows没有一个直接调用内核的接口,意味着不得不有精准的函数指针(内存地址)以便调用它们。不幸的是,硬编码函数地址不能完全解决问题,Windows中的每个函数地址在每个版本中都会改变,使用硬编码的shellcode高度依赖版本,在Windows上编写不依赖版本的shellcode是可能的,只要解决地址问题,这个能通过在运行时动态获取地址解决。
0x04 解决地址问题
随着时间的推移,shellcode编写者找到了聪明的方法能在运行时找到Windows API函数的地址,在本文中我们主要关注一种称为解析PEB的方法,这个方法使用PEB数据结构来定位加载的动态库的地址,并解析导出地址表得到函数地址。在metasploit框架中,几乎所有的不依赖版本的shellcode都是用这个技术得到Windows API函数地址。使用这个方法充分利用了FS段寄存器,在Windows中这个寄存器指向线程环境块(TEB)地址,TEB包含了很多有用的数据,包括我们寻找的PEB结构,当shellcode在内存中执行时,我们需要从TEB块向前偏移48字节,
12 | 1.xor eax, eax 2.mov edx, [fs:eax 48] |
现在我们得到了PEB结构,
在得到PEB结构指针后,我们在PEB块中向前移12字节,以便得到ldr数据结构的地址。
1 |
|
ldr结构包含了进程加载模块的信息,在ldr结构向前偏移20字节,我们得到InMemoryOrderModuleList中的第一个模块,
1 |
|