微软的Enhanced Mitigation Experience Toolkit v2.0 发布了有一段时间了,这个工具可以有效的减少系统被Exploit的几率,今天看了一篇文章,被激起了兴趣,于是对EMET的若个功能做了些逆向,和大家分享一下
DEP和ASLR这些旧的就不说了,看两个貌似新的feature

Export Address Table Access Filtering (EAF) 
“This mitigation filters accesses to the Export Address Table (EAT), allowing or disallowing the read/write access based on the calling code. With EMET in place, most of today’s shellcode will be blocked when it tries to lookup the APIs needed for its payload.”

    根据它的介绍,我们可以知道EAF主要是基于这样一个事实: 当前绝大部分的Shellcode在运行时,都需要搜索要用到的API地址,而这一行为通常是通过对相应模块导出表的遍历来实现的。而EAF这个Feature通过对ntdll.dll和kernel32.dll导出表的相应位置(其实就是IMAGE_EXPORT_DIRECTORY.AddressOfFunctions字段) 下硬件断点,来监控shellcode 对导出表的搜索行为. 导出表结构如下:
typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   Name;
    DWORD   Base;
    DWORD   NumberOfFunctions;
    DWORD   NumberOfNames;
    DWORD   AddressOfFunctions;     // Set Hardware Breakpoint here
    DWORD   AddressOfNames;         
    DWORD   AddressOfNameOrdinals;  
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

    我们来实际实验一下EAF的效果: 首先安装EMET2.0 (EMET2.0), 随便找个Shellcode, 跑起来,结果crash了,说明确实有效:
 
这次用windbg调试之, 我们看到一个单步异常:
(3ac.154): Single step exception - code 80000004 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
看一下调试寄存器
Dr0= 7c802648, Dr1= 7c90341c, 分别对应了kernel32和ntdll的导出表
    不处理异常, 继续跑之, 经过ntdll!RtlCallVectoredExceptionHandlers进入到emet.dll空间,也就是说, emet.dll通过注册了一个向量化异常处理函数, 来处理硬件断点 
还原一下该函数:
LONG WINAPI
VectoredHandler3(
struct _EXCEPTION_POINTERS *ExceptionInfo
  )
{
  HMODULE hModule     = NULL;
  LONG    dwReturnCode   = EXCEPTION_CONTINUE_SEARCH;

  ClearHardwareBPS(GetCurrentThread());

  //
  // Is our bp hit?
  //
  if (ExceptionInfo->ContextRecord->Dr6 & 0x11)
  {
if (GetModuleHandleExW(  GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
            ExceptionInfo->ContextRecord->Eip,
            &hModule))
    {
      if (hModule)  
        dwReturnCode = EXCEPTION_CONTINUE_EXECUTION;
      else
        Die();
    }
    else
      Die();
  }

  ClearDebugStateRegister();
  SetHardwareBPS(GetCurrentThread());

  return dwReturnCode;
}

非常简单的一个逻辑,只是check一下访问导出表的代码是否在某个Module里面,如果不在,直接报错,终止进程

Heapspray Allocations
“With EMET in place some commonly used pages are pre-allocated. Exploits that rely on controlling these pages (and then jumping into them) will fail.”

这个是用来对付HeapSpary的了,预先把有可能被Spray的常见地址分配掉,我们看两个HeapSpary常用地址 (0c0c0c0c, 0d0d0d0d):
0:000> !address 0c0c0c0c
    0c0c0000 : 0c0c0000 - 00002000
                    Type     00020000 MEM_PRIVATE
                    Protect  00000001 PAGE_NOACCESS
                    State    00001000 MEM_COMMIT
                    Usage    RegionUsageIsVAD
0:000> !address 0d0d0d0d
    0d0d0000 : 0d0d0000 - 00002000
                    Type     00020000 MEM_PRIVATE
                    Protect  00000001 PAGE_NOACCESS
                    State    00001000 MEM_COMMIT
                    Usage    RegionUsageIsVAD

这个就是传说中的占沙发吗?  简单到没什么好说了,不过又确实有效