2012年10月11日 星期四

Ether System Call Trace and Instruction Trace

Ether Introduction
Ether is proposed in CCS'08, which is the first malware analysis system based on Harware Virtualization Extension.

In traditional analysis , software emulation is widely employed. With the help of binary translation, instrumentation can be achieve easily. However some malware employ technique like anti-debugging, anti-instrumentation, and anti-VM to avoid analysis. Due to software emulation nature, all the instruction must be translate and expose more emulation bugs. Moreover , software emulation locate translator in the same system level with target system which approach is more easier to detect.

Ether has following functions

  1. Instruction Trace
  2. System Call Trace
  3. Memory Write Detection
  4. Unpack Detection
This article will analysis source code of instruction trace and system call trace. Memory write detection and unpack detection will leave in future discussion. 

Instruction Trace

There are two steps to implement instruction trace, setting trap flag and debug trap handler. Setting trap flag is used to enable debug trap in every instruction. Then after each trap , debug trap handler will be triggered and send instruction to user space.Approach here is similar to Hyperdbg, which was presented in ASE'10.

Setting Trap Flag

Ether set trap flag by function vmx_properly_set_trap_flag in "xen/arch/x86/hvm/vmx/vmcs.c".

  1. GUEST_INTERRUPTIBILITY_INFO
    Clear Bit 3 in GUEST_INTERRUPTIBILITY_INFO register to forbiden pending NMI interrupt.
    unsigned long int_state =
      __vmread(GUEST_INTERRUPTIBILITY_INFO);
      if((int_state & 3) )
      {
       int_state &= ~(3);
       __vmwrite(GUEST_INTERRUPTIBILITY_INFO, int_state);
      }
    
  2. EXCEPTION_BITMAP
    unsigned long intercepts = __vmread(EXCEPTION_BITMAP);
      unsigned long mask = (1UL << TRAP_debug);
      /* make sure the exception bitmap says to vmexit on 
       * debug exceptions
       */
      intercepts |= mask;
      __vmwrite(EXCEPTION_BITMAP, intercepts);
    
  3. GUEST_RFLAGS
    unsigned long flags = __vmread(GUEST_RFLAGS);
      unsigned long flags_mask = (X86_EFLAGS_TF);
      __vmwrite(GUEST_RFLAGS, flags);
      vmx_set_pending_exceptions(v);
    
This operation will be taken before VM-ENTER and after each VM-EXIT handler. In vmx_do_resume(), VMM execute  reset_stack_and_jump() and go back to Guest OS. Therefor it is suitable to place vmx_properly_set_trap_flag() before reset_stack_and_jump().

Debug Trap Handler  

Once trap flag is properly set, every instruction will cause a VM-exit trap. Then control will transfer to  VMM. To record every trap, we must modify vmx_vmexit_handler function in "xen/arch/x86/hvm/vmx/vmx.c". In case EXIT_REASON_EXCEPTION_NMI of exit_reason switch, if exception vector is TRAP_debug then we can record this instruction.

System Call Trace

Enforce sysenter to trap

When Ether initialize, Ether will execute ether_initialize() (in xen/arch/x86/hvm/ether.c) and set forced_sysenter_cs, forced_sysenter_eip to 0.
d->arch.hvm_domain.ether_controls.forced_sysenter_cs = 0;
d->arch.hvm_domain.ether_controls.forced_sysenter_eip = 0;
Once we need to record system call, XEN_DOMCTL_ETHER_SET_SYSENTER event will be trigger in arch_do_domctl function(xen/common/domctl.c).
case XEN_DOMCTL_ETHER_SET_SYSENTER:
    if(op->u.ether.sysenter_eip)
    {
 /* operation = set msrs and force their values
  */
        /*Set forced_sysenter_cs to op->u.ether.sysenter_cs*/
 ether_set_sysenter_cs(d, 
  op->u.ether.sysenter_cs);
        /*Set forced_sysenter_eip to op->u.ether.sysenter_eip */
 ether_set_sysenter_eip(d, 
  op->u.ether.sysenter_eip);
        /*Set should_force_sysenter_msr to 1*/
 ether_force_sysenter_msrs(d, 1);       
    }
After those operations, vmx_set_sysenter_msrs() will be called by vmx_properly_set_trap_flag().
inline static void vmx_set_sysenter_msrs(struct domain *d)
{
 u64 new_cs;
 u64 new_eip;
 /* write MSR registers */

 /* default to writing old(imaginary) values to guest */
 new_cs = ether_get_imaginary_sysenter_cs(d);
 new_eip = ether_get_imaginary_sysenter_eip(d);

 if(ether_should_force_sysenter_msr(d))
 {
  /* it seems that we should write user supplied
   * values instead
   */
  u64 forced_cs;
  u64 forced_eip;
  /* writing user supplied forced values to guest */
                /* Get forced_sysenter_cs and forced_sysenter_eip*/
  forced_cs = ether_get_sysenter_cs(d);
  forced_eip = ether_get_sysenter_eip(d);

  if(forced_cs)
   new_cs = forced_cs;

  if(forced_eip)
   new_eip = forced_eip;

 }
        /*Update guest OS MSR*/
 vmx_write_sysenter_msr(GUEST_SYSENTER_CS, new_cs);
 vmx_write_sysenter_msr(GUEST_SYSENTER_EIP, new_eip);
}

Upon vmx_set_sysenter_msrs executes, guest OS will be forced to trap when system call occurs.Then we can get the system call information in VM-Exit handler.

Handle trap due to sysenter

When VM-exit is triggered, vmx_handle_debug_exception() will execute inside vmx_vmexit_handler().(in xen/arch/x86/hvm/vmx/vmx.c)
asmlinkage void vmx_handle_debug_exception(struct vcpu *v, 
  struct cpu_user_regs *regs)
{
 /*
  * things to do
  * 1) grab instruction we trapped at
  *  a) get instruction length (possibly via decode?)
  *  b) grab instruction from memory
  * 2) reset flag for setting trap flag on next instruction
  * 3) call userspace handler for instruction step
  */

 if(ether_get_stepping_type(v->domain) != ETHER_BP_AUTO_STEP)
 {
  ether_handle_instruction(v, regs);
 }
 else
 {
  /* check saved gva == current RIP */
  unsigned long rip = __vmread(GUEST_RIP);
  unsigned long cr3 = hvm_get_guest_ctrl_reg(v, 3);
  unsigned long thread_id = ether_get_windows_tid(__vmread(GUEST_FS_BASE));
  int match_type; 

  match_type = ether_bp_in_list(v, rip, cr3, thread_id);

  if(match_type == ETHER_BP_FULL_MATCH)
  {
   struct ether_bp_list *removed_item;
   /* disable_stepping takes care of changing
    * the stepping type as well
    */
   ether_disable_stepping(v->domain);
   removed_item = ether_bp_get_and_remove(v, rip, cr3, 
     thread_id);

   if(removed_item != NULL)
   {
    ether_handle_syscall_return(v, removed_item->call_number, regs);
    xfree(removed_item);
   }

   
  }
  else if(match_type == ETHER_BP_GFN_MATCH)
  {
   unsigned char two_byte[2];
   two_byte[0] = two_byte[1] = 0;

   hvm_copy_from_guest_virt(&two_byte, rip, 2);
   /* about to hit an INT instruction */
   if(two_byte[0] == 0xCD)
   {
    unsigned long bp_location = 0;

    bp_location = 
     ether_read_idt_entry(two_byte[1]);

    if(bp_location != 0)
    {
     /* ignore ESP and call# in breakpoint
      */
     if(0 < ether_bp_create(v, bp_location, cr3, 0, 0, 1))
     {
      /*printk("ETHER_BP: set bp for INT handler: 0x%lx\n",*/
        /*bp_location);*/
     }
    }
    else
    {
     printk("ETHER: could not read IDT entry\n");
    }
    
   }
   ether_disable_stepping(v->domain);
   ether_bp_mark_np(v, ether_bp_get_known_gva(v),
    1, 1);

  }
  else if(match_type == ETHER_BP_NO_MATCH)
  {
   ether_disable_stepping(v->domain);
   /* mark page NP again */
   ether_bp_mark_np(v, ether_bp_get_known_gva(v),
    1, 1);
  }
 }
 
}

Reference

XEN internal
http://www.docin.com/p-334444719.html
http://wiki.xen.org/wiki/Mini-OS-DevNotes

ETHER webpage
http://ether.gtisc.gatech.edu/source.html#patching_xen
http://www.offensivecomputing.net/?q=node/1575
https://groups.google.com/forum/?fromgroups=#!topic/ether-devel/Us47vyfwnZE
http://mether.googlecode.com/svn/trunk/ether/vmx.c

XEN VMEXIT HANDLER
http://www.cnblogs.com/superymk/archive/2010/02/02/1661686.html
http://old-list-archives.xen.org/archives/html/xen-devel/2010-07/msg01675.html
http://lkml.indiana.edu/hypermail/linux/kernel/1205.0/02778.html

XEN Single Step Trap
http://comments.gmane.org/gmane.comp.emulators.xen.devel/113088

XEN Debugger
http://www.xen.org/files/xensummit_intel09/xen-debugging.pdf

Research Paper
XenLR: Xen-based Logging for Deterministic Replay*
http://grid.hust.edu.cn/hkliu/index_files/XenLR%20Xen-based%20Logging%20for%20Deterministic%20Replay.pdf
Deterministic Replay for Xen
http://www.cs.ubc.ca/~sara88/538wslides.pdf

Improving VMM based IPS for real-time
snapshot and nullification of buffer overflow
exploitation
http://homepage2.nifty.com/way_to_hack/pdfs/jwis06RuoAndo.pdf