Пример #1
0
//FIXME: this function may potentially overflow "buf" --Heng
static inline int readustr_with_cr3(uint32_t addr, uint32_t cr3, void *buf,
    CPUState *_env) {
  uint32_t unicode_data[2];
  int i, j, unicode_len = 0;
  uint8_t unicode_str[MAX_UNICODE_LENGTH] = { '\0' };
  char *store = (char *) buf;

  if (DECAF_read_mem(_env, addr, sizeof(unicode_data), unicode_data) < 0) {
    store[0] = '\0';
    goto done;
  }

  unicode_len = (int) (unicode_data[0] & 0xFFFF);
  if (unicode_len > MAX_UNICODE_LENGTH)
    unicode_len = MAX_UNICODE_LENGTH;

  if (DECAF_read_mem(_env, unicode_data[1], unicode_len, (void *) unicode_str) < 0) {
    store[0] = '\0';
    goto done;
  }

  for (i = 0, j = 0; i < unicode_len; i += 2, j++) {
    store[j] = tolower(unicode_str[i]);
  }
  store[j] = '\0';

done:
  return j;
}
Пример #2
0
static void ExInterlockedPushEntryList_call(void *opaque)
{
    taintcheck_taint_virtmem(NULL, DECAF_cpu_regs[R_ESP]+4, 12, 0, NULL);
    uint32_t vaddr;
    DECAF_read_mem(NULL, DECAF_cpu_regs[R_ESP] + 4, 4, &vaddr); // first argument
    taintcheck_taint_virtmem(NULL, vaddr, 8, 0, NULL); //clean it
    DECAF_read_mem(NULL, DECAF_cpu_regs[R_ESP] + 8, 4, &vaddr); // second argument
    taintcheck_taint_virtmem(NULL, vaddr, 8, 0, NULL); //clean it
}
Пример #3
0
static void InterlockedPushEntrySList_call(void *opaque)
{
    //fastcall
    taintcheck_reg_clean(R_ECX, 0, 4);
    taintcheck_reg_clean(R_EDX, 0, 4);
    uint32_t vaddr;
    DECAF_read_mem(NULL, DECAF_cpu_regs[R_ECX], 4, &vaddr); // first argument
    taintcheck_taint_virtmem(NULL, vaddr, 8, 0, NULL); //clean it
    DECAF_read_mem(NULL, DECAF_cpu_regs[R_EDX], 4, &vaddr); // second argument
    taintcheck_taint_virtmem(NULL, vaddr, 8, 0, NULL); //clean it
}
Пример #4
0
gva_t DECAF_get_first_mmap(CPUState* env, gva_t addr)
{
  gva_t mmaddr = 0;
  gva_t mmap = 0;
  DECAF_read_mem(env, addr + task_struct_mm_offset, &mmaddr, sizeof(mmaddr));

  if (0 != mmaddr)
  {
    DECAF_read_mem(env, mmaddr, &mmap, sizeof(mmap));
  }

  return mmap;
}
Пример #5
0
void check_call(DECAF_Callback_Params *param) {
  uint32_t eip, cr3, insn_buf;
  CPUState *env = NULL;

  //If we've gotten this far, params is not null
  if(calls<MAXCALLS) {
    env = param->be.env;
    if(env!=NULL) {
      eip=DECAF_getPC(env);
      cr3=DECAF_getPGD(env);
    } else {
      eip=0x0;
      cr3=0x0;
    }

    DECAF_printf("sysenter_eip: (0x%x)\n", env->sysenter_eip);
    fprintf(tracefile, "sysenter_eip: (0x%x)\n", env->sysenter_eip);
    fprintf(tracefile, "sysenter_esp: (0x%x)\n", env->sysenter_esp);
    fprintf(tracefile, "current esp: (0x%x)\n", env->regs[R_ESP]-env->sysenter_eip);
    //fprintf(tracefile, "idt base: (0x%x) \n", env->idt.base); 

    //Read 32bits worth of code... will be used to identify this later
    DECAF_read_mem(env,param->be.cur_pc,sizeof(uint32_t),&insn_buf);
    DECAF_printf("call: (0x%x@0x%x) 0x%x\n", eip-env->sysenter_eip, cr3, insn_buf);
    fprintf(tracefile, "call: (0x%x@0x%x) 0x%x\n", eip-env->sysenter_eip, cr3,
            insn_buf);
    fprintf(tracefile, "call (-esp): (0x%x@0x%x) 0x%x\n", eip-env->sysenter_esp, 
            cr3, insn_buf);
    calls++;
  }
}
Пример #6
0
gpa_t DECAF_get_pgd(CPUState* env, gva_t addr)
{
  gva_t mmaddr;
  gpa_t pgd;
  DECAF_read_mem(env, addr + task_struct_mm_offset, &mmaddr, sizeof(mmaddr));
  if (0 == mmaddr)
    DECAF_read_mem(env, addr + task_struct_mm_offset + sizeof(mmaddr),
                &mmaddr, sizeof(mmaddr));

  if (0 != mmaddr)
    DECAF_read_mem(env, mmaddr + mm_struct_pgd_offset, &pgd, sizeof(pgd));
  else
    memset(&pgd, 0, sizeof(pgd));

  return pgd;
}
Пример #7
0
gva_t prev_task_struct(CPUState* env, gva_t addr)
{
  gva_t retval;

  if (addr == 0) //LOK: Added here to give the init_task
  {
    return (taskaddr);
  }
  else
  {
    gva_t next;

    if (DECAF_read_mem(env, addr + task_struct_tasks_offset + sizeof(gva_t), &next, sizeof(gva_t)) != 0)
    {
      return (0);
    }

    if (next == 0)
    {
      return (0);
    }
    retval = next - task_struct_tasks_offset;
  }

  return retval;
}
Пример #8
0
gva_t DECAF_get_next_task_struct(CPUState* env, gva_t addr)
{
  gva_t retval;
  if (addr == 0) //LOK: Added here to give the init_task
  {
    return (taskaddr);
  }
  else
  {
    // default is kernel 2.6
    gva_t next;
    if (DECAF_read_mem(env, addr + task_struct_tasks_offset, &next, sizeof(gva_t)) != 0)
    {
      return (0);
    }

    if (next == 0)
    {
      return (0);
    }
    retval = next - task_struct_tasks_offset;
  }

  return retval;
}
Пример #9
0
/*
 *

NTSTATUS NtCreateFile(
  __out     PHANDLE FileHandle,
  __in      ACCESS_MASK DesiredAccess,
  __in      POBJECT_ATTRIBUTES ObjectAttributes,
  __out     PIO_STATUS_BLOCK IoStatusBlock,
  __in_opt  PLARGE_INTEGER AllocationSize,
  __in      ULONG FileAttributes,
  __in      ULONG ShareAccess,
  __in      ULONG CreateDisposition,
  __in      ULONG CreateOptions,
  __in      PVOID EaBuffer,
  __in      ULONG EaLength
);
 *
 */
void NtCreateFile_ret_handler(void *opaque)
{
	monitor_printf(default_mon, "NtCreateFile_ret\n");
	uint32_t esp, offset;
	uint32_t i,j;
	CPUState *cpu;
	cpu = cpu_single_env;

	UNICODE_STRING ObjectName;
	char *Buffer = NULL;
	ULONG Length=0;
	uint8_t unicode_str[1024];

	POBJECT_ATTRIBUTES po = NULL;


	/* Populate out arguments */
	esp = cpu->regs[R_ESP];
	//offset = esp;
	uint32_t stack_data[11];
	DECAF_read_mem(cpu,esp,4*11,(void *)stack_data);
	uint64_t data_temp=(uint64_t)stack_data[2];
	po = malloc(sizeof(OBJECT_ATTRIBUTES)); ;
	DECAF_read_mem(cpu,stack_data[2],sizeof(OBJECT_ATTRIBUTES),(void *)po);

		if(po->ObjectName){
			DECAF_read_mem(cpu,(uint32_t)po->ObjectName, sizeof(UNICODE_STRING), (void *)&ObjectName);

			monitor_printf(default_mon, "\t\tObjectName.Length: %d\n", ObjectName.Length);
			monitor_printf(default_mon, "\t\tObjectName.MaximumLength: %d\n", ObjectName.MaximumLength);
			monitor_printf(default_mon, "\t\tObjectName.Buffer: 0x%p\n", ObjectName.Buffer);
			if(ObjectName.Buffer && ObjectName.Length){
				Buffer = (char *) malloc (sizeof(char) * ObjectName.Length);
				if(Buffer != '\0') {
					cpu_memory_rw_debug(cpu_single_env, (target_ulong)ObjectName.Buffer, (uint8_t *)&unicode_str, ObjectName.Length, 0);
					for (i = 0, j = 0; i < ObjectName.Length; i+=2, j++)
						Buffer[j] = unicode_str[i];
					Buffer[j] = '\0';
					DECAF_printf("%s\n",Buffer);
					monitor_printf(default_mon, "\t\t\tBuffer: %s \n", Buffer);
					free(Buffer);
				}
			}
		}


}
Пример #10
0
static void alloca_probe_call(void *opaque)
{
    uint32_t ret_eip;
    DECAF_read_mem(NULL, DECAF_cpu_regs[R_ESP], 4, &ret_eip);
    uint32_t *hook_handle = malloc(sizeof(uint32_t));
    if(hook_handle) {
        *hook_handle = hookapi_hook_return(ret_eip, alloca_probe_ret,
                                           hook_handle, sizeof(uint32_t));
    }
}
Пример #11
0
gva_t DECAF_getReturnAddr(CPUState* env)
{
  gva_t temp;

  if (env == NULL)
  {
    return (INV_ADDR);
  }

  DECAF_read_mem(env, env->regs[R_ESP], &temp, sizeof(temp));
  return (temp);
}
Пример #12
0
static void NtCreateFile_ret(void *param)
{
	NtCreateFile_hook_context_t *ctx = (NtCreateFile_hook_context_t *)param;
	DECAF_printf("NtCreateFile exit:");

	hookapi_remove_hook(ctx->hook_handle);
	uint32_t out_handle;

	DECAF_read_mem(NULL, ctx->call_stack[1], 4, &out_handle);
	DECAF_printf("out_handle=%08x\n", out_handle);
	free(ctx);
}
Пример #13
0
static void VirtualAlloc_call(void *opaque)
{
	DECAF_printf("VirtualAlloc entry\n");
	NtCreateFile_hook_context_t *ctx = (NtCreateFile_hook_context_t*)
			malloc(sizeof(NtCreateFile_hook_context_t));
	if(!ctx) //run out of memory
		return;

	DECAF_read_mem(NULL, cpu_single_env->regs[R_ESP], 12*4, ctx->call_stack);
	ctx->hook_handle = hookapi_hook_return(ctx->call_stack[0],
			VirtualAlloc_ret, ctx, sizeof(*ctx));
}
Пример #14
0
gva_t DECAF_get_current_task_struct(CPUState* env)
{
  gva_t threadinfo = 0;
  gva_t curtask = 0;
  if (env == NULL)
  {
    return (0);
  }

  threadinfo = DECAF_getESP(env) & ~8191;
  DECAF_read_mem(env, threadinfo + thread_info_task_offset, &curtask, 4);
  return (curtask);
}
Пример #15
0
int DECAF_get_arg_name(CPUState* env, gva_t addr, char* buf, int size)
{
  gva_t mmaddr = 0;
  gva_t argstart = 0;
  gpa_t pgd = 0;
  DECAF_read_mem(env, addr + task_struct_mm_offset, &mmaddr, sizeof(mmaddr));
  if (mmaddr == 0)
  {
    return (-1);
  }
  else
  {
    DECAF_read_mem(env, mmaddr + mm_struct_pgd_offset, &pgd, sizeof(pgd));
    DECAF_read_mem(env, mmaddr + mm_struct_mm_arg_start_offset, &argstart, sizeof(argstart));
    if (argstart != 0 && pgd != 0)
    {
      return (DECAF_read_mem_with_pgd(env, pgd & ~0xC0000000, argstart, buf, size));
    }
    else
    {
      return (-1);
    }
  }
}
Пример #16
0
int DECAF_get_name(CPUState* env, gva_t addr, char *buf, int size)
{
  return (DECAF_read_mem(env, addr + task_struct_comm_offset,
                buf, (size < size_of_task_struct_comm) ? size : size_of_task_struct_comm));
}
Пример #17
0
/**
 * Instruction Begin callback.
 */
void nd_instruction_begin_callback(DECAF_Callback_Params* params){
	DEFENSIVE_CHECK0(params == NULL);
	DEFENSIVE_CHECK0(getCurrentPID() != ND_GLOBAL_TRACING_PID);

	CPUState* env = params->ib.env;
	gva_t cur_pc = params->ib.cur_pc;
	//since for thumb instruction, the last bit is '1'	
	gva_t cur_pc_even = cur_pc & 0xfffffffe;


	if(!nd_in_blacklist(cur_pc_even)){
		return;
	}

	//ARM Instruction
	union _tmpARMInsn{
		target_ulong insn;
		char chars[4];
	} tmpARMInsn;
	//Thumb Instruction
	union _tmpThumbInsn{
		unsigned short insn;
		char chars[2];
	} tmpThumbInsn;
	//Thumb2 Instruction
	union _tmpThumb2Insn{
		target_ulong insn;
		char chars[4];
	} tmpThumb2Insn;

	//undefined instruction
	if(cur_pc == -1){
		return;
	}

	//the first instruction of target native method
	SourcePolicy* sourcePolicy = findSourcePolicy(cur_pc_even);
	if(sourcePolicy != NULL){
		DECAF_printf("Step into Native\n");
		sourcePolicy->handler(sourcePolicy, env);
	}

	//DECAF_printf("%x  %x\n", cur_pc_even, lastCallSysLibAddrRet);

	//return from JNI API calls/system library calls
	if(cur_pc_even == lastCallJNIAddrRet){
		if(lastJniHandler != NULL){
			lastJniHandler(env, 0);
			lastJniHandler = NULL;
			lastCallJNIAddrRet = -1;
		}
	}
	
	if(cur_pc_even == lastCallSysLibAddrRet){
		if(lastSysLibHandler != NULL){
			lastSysLibHandler(env, 0);
			lastSysLibHandler = NULL;
			lastCallSysLibAddrRet = -1;
		}
	}
	
	//Thumb instruction
	if(env->thumb == 1){
		if(DECAF_read_mem(env, cur_pc_even, tmpThumbInsn.chars, 2) != -1){
			darm_t d;
			//darm_str_t str;
    	// magic table constructed based on section A6.1 of the ARM manual
    	static uint8_t is_thumb2[0x20] = {
        [0x01d] = 1,
        [0x01e] = 1,
        [0x01f] = 1,
    	};

			if(is_thumb2[tmpThumbInsn.insn >> 11]){
				//Thumb2 instruction
				if(DECAF_read_mem(env, cur_pc_even, tmpThumb2Insn.chars, 4) != -1){
					if(darm_thumb2_disasm(&d, tmpThumb2Insn.insn & 0x0000ffff, 
								tmpThumb2Insn.insn >> 16, env) == 0){
						//if(darm_str(&d, &str, env) == 0){
							//DECAF_printf("T2  %x: %s\n", cur_pc, str.total);
						//}
					}
				}
			}else{
				//Thumb instruction
				if(darm_thumb_disasm(&d, tmpThumbInsn.insn, env) == 0){
					//if(darm_str(&d, &str, env) == 0){
						//DECAF_printf("T   %x: %s\n", cur_pc, str.total);
					//}
				}
			}
		}
Пример #18
0
//LOK: My tests have shown that do_fork -> then update on a PGD write is a perfect choice. Should change the logic to do that.
// it seems to cover many more cases than do_fork and schedule()
//TODO: have to fix the potential problem where this is called twice before the return is processed
// in which case the process name will not be updated properly
void contextBBCallback(DECAF_Callback_Params* params)
{
  static gva_t taskAddr = INV_ADDR;
  static int updateMask = 0;
  gpid_t pid = -1;
  TranslationBlock* tb = NULL;
  CPUState* env = NULL;

  DEFENSIVE_CHECK0(params == NULL);

  env = params->bb.env;
  tb = params->bb.tb;
  
  if (NULL == tb)
  {
    return;
  }

  if ( (tb->pc == SET_TASK_COMM_ADDR) || (tb->pc == DO_PRCTL_ADDR) )//set_task_comm
  {
    //In this case, we just update the name when the function returns
    //TODO: Fix i386 support 
    //TODO: Make sure this taskAddr is NOT the thread's task 
#ifdef TARGET_ARM
    taskAddr = env->regs[0];
    Context_retAddr = env->regs[14];
#elif TARGET_I386
    taskAddr = env->regs[R_EAX];
    DECAF_read_mem(env, env->regs[R_ESP], &Context_retAddr, sizeof(Context_retAddr));
#endif
  }
  else if ( (tb->pc == DO_EXECVE_ADDR) || (tb->pc == DO_CLONE_ADDR) )//do_execve
  {
    //we OR the update mask since its possible for the system call
    // to call another test - e.g. do_fork - and without declaring
    // the updateMask as static and using |= the flags will be
    // overwritten
    //TODO: Implement a STACK for the return addresses!!!
    //in this case we update the process, threads and module lists
    updateMask |= UPDATE_PROCESSES | UPDATE_THREADS | UPDATE_MODULES;
#ifdef TARGET_ARM
    Context_retAddr = env->regs[14];
#endif
  }
  else if (tb->pc == DO_FORK_ADDR) //do_fork
  {
    //In this case we just update the process and threads lists 
    updateMask |= UPDATE_PROCESSES | UPDATE_THREADS;
#ifdef TARGET_ARM
    Context_retAddr = env->regs[14];
#endif
  }

  if (tb->pc == Context_retAddr)
  {
    if (taskAddr != INV_ADDR)
    //if we need to update the names only
    {
      pid = DECAF_get_pid(env, taskAddr);
      if (pid != -1)
      {
        //if we found the PID then just read the names and update
        updateProcessListByTask(env, taskAddr, UPDATE_PROCESSES | UPDATE_THREADS | UPDATE_MODULES, 0);
      }
      taskAddr = INV_ADDR;
    } 
    else
    {
      updateProcessList(env, getCurrentPGD(), updateMask);
    }

    //since we updated the list already - lets skip the next PGD
    //write update
    bSkipNextPGDUpdate = 1;
    Context_retAddr = 0;
    DECAF_flushTranslationBlock_env(env, Context_retAddr);
  }

  if (Context_retAddr != 0)
  {
    //instead of registering for a new callback - we will just update our
    //conditions list and flush the entry for retAddr
   DECAF_flushTranslationBlock_env(env, Context_retAddr);
  }

  return;
}
Пример #19
0
/**
 * Instruction Begin callback.
 */
void nd_instruction_begin_callback(DECAF_Callback_Params* params){
	DEFENSIVE_CHECK0(params == NULL);
	DEFENSIVE_CHECK0(getCurrentPID() != ND_GLOBAL_TRACING_PID);

	CPUState* env = params->ib.env;
	gva_t cur_pc = params->ib.cur_pc;
	//since for thumb instruction, the last bit is '1'	
	gva_t cur_pc_even = cur_pc & 0xfffffffe;

	//ARM Instruction
	union _tmpARMInsn{
		target_ulong insn;
		char chars[4];
	} tmpARMInsn;
	//Thumb Instruction
	union _tmpThumbInsn{
		unsigned short insn;
		char chars[2];
	} tmpThumbInsn;
	//Thumb2 Instruction
	union _tmpThumb2Insn{
		target_ulong insn;
		char chars[4];
	} tmpThumb2Insn;

	//undefined instruction
	if(cur_pc == -1){
		return;
	}

	//the first instruction of target native method
	SourcePolicy* sourcePolicy = findSourcePolicy(cur_pc_even);
	if(sourcePolicy != NULL){
		sourcePolicy->handler(sourcePolicy, env);
	}
	
	//Thumb instruction
	if(env->thumb == 1){
		if(DECAF_read_mem(env, cur_pc_even, tmpThumbInsn.chars, 2) != -1){
			darm_t d;
			darm_str_t str;
    	// magic table constructed based on section A6.1 of the ARM manual
    	static uint8_t is_thumb2[0x20] = {
        [0x01d] = 1,
        [0x01e] = 1,
        [0x01f] = 1,
    	};

			if(is_thumb2[tmpThumbInsn.insn >> 11]){
				//Thumb2 instruction
				if(DECAF_read_mem(env, cur_pc_even, tmpThumb2Insn.chars, 4) != -1){
					if(darm_thumb2_disasm(&d, tmpThumb2Insn.insn >> 16, tmpThumb2Insn.insn & 0x0000ffff) == 0){
						if(darm_str(&d, &str) == 0){
							//DECAF_printf("T2  %x: %s\n", cur_pc, str.total);
						}
					}
				}
			}else{
				//Thumb instruction
				if(darm_thumb_disasm(&d, tmpThumbInsn.insn) == 0){
					if(darm_str(&d, &str) == 0){
						//DECAF_printf("T   %x: %s\n", cur_pc, str.total);
					}
				}
			}
		}
Пример #20
0
void decode_address(uint32_t address, EntryHeader *eh)//, int ignore_taint)
{
  unsigned char insn_buf[MAX_INSN_BYTES];
  unsigned int is_stackpush = 0, is_stackpop = 0;
  unsigned int stackpushpop_acc = 0;
  int ignore_taint = 0;
  if (xed2chris_regmapping[XED_REG_EAX][0] == 0) {
    init_xed2chris();
    assert(xed2chris_regmapping[XED_REG_EAX][0] != 0);
  }

  /* Read memory from DECAF */
  DECAF_read_mem(cpu_single_env,address, MAX_INSN_BYTES, insn_buf);


  /* Disassemble instruction buffer */
  xed_decoded_inst_zero_set_mode(&xedd, &dstate);
  xed_error_enum_t xed_error =
    xed_decode(&xedd, XED_STATIC_CAST(const xed_uint8_t*,insn_buf), MAX_INSN_BYTES);
  xed_bool_t okay = (xed_error == XED_ERROR_NONE);
  if (!okay) return;

  // Increase counters
  tstats.insn_counter_decoded++;

  int i;

  /* Clear out Entry header */
  memset(eh, 0, sizeof(EntryHeader));

  /* Copy the address and instruction size */
  eh->address = address;
  eh->inst_size = xed_decoded_inst_get_length(&xedd);
  if (eh->inst_size > MAX_INSN_BYTES) eh->inst_size = MAX_INSN_BYTES;

  /* Copy instruction rawbytes */
  memcpy(eh->rawbytes, insn_buf, eh->inst_size);

  /* Get the number of XED operands */
  const xed_inst_t* xi = xed_decoded_inst_inst(&xedd);
  int xed_ops = xed_inst_noperands(xi);
  int op_idx = -1;

  /* Get the category of the instruction */
  xed_category_enum_t category = xed_decoded_inst_get_category(&xedd);

  /* Iterate over the XED operands */
  for(i = 0; i < xed_ops; i++) {
  	if(op_idx >= MAX_NUM_OPERANDS)
  	  break;
    //assert(op_idx < MAX_NUM_OPERANDS);

    /* Get operand */
    const xed_operand_t* op = xed_inst_operand(xi,i);
    xed_operand_enum_t op_name = xed_operand_name(op);

    switch(op_name) {
      /* Register */
      case XED_OPERAND_REG0:
      case XED_OPERAND_REG1:
      case XED_OPERAND_REG2:
      case XED_OPERAND_REG3:
      case XED_OPERAND_REG4:
      case XED_OPERAND_REG5:
      case XED_OPERAND_REG6:
      case XED_OPERAND_REG7:
      case XED_OPERAND_REG8:
      case XED_OPERAND_REG9:
      case XED_OPERAND_REG10:
      case XED_OPERAND_REG11:
      case XED_OPERAND_REG12:
      case XED_OPERAND_REG13:
      case XED_OPERAND_REG14:
      case XED_OPERAND_REG15: {
        xed_reg_enum_t reg_id = xed_decoded_inst_get_reg(&xedd, op_name);
        int regnum = xed2chris_regmapping[reg_id][1];

        // Special handling for Push
        if (reg_id == XED_REG_STACKPUSH) is_stackpush = 1;
        else if (reg_id == XED_REG_STACKPOP) is_stackpop = 1;

        if (-1 == regnum)
          break;
        else {
	  op_idx++;
          eh->num_operands++;
          eh->operand[op_idx].type = TRegister;
          eh->operand[op_idx].addr = xed2chris_regmapping[reg_id][0];
	  eh->operand[op_idx].length =
	    (uint8_t) xed_decoded_inst_operand_length (&xedd, i);
	  eh->operand[op_idx].access = (uint8_t) xed_operand_rw (op);
          eh->operand[op_idx].value = cpu_single_env->regs[regnum];
          switch (eh->operand[op_idx].addr) {
            case ax_reg:
            case bx_reg:
            case cx_reg:
            case dx_reg:
            case bp_reg:
            case sp_reg:
            case si_reg:
            case di_reg:
              eh->operand[op_idx].value &= 0xFFFF;
              break;
            case al_reg:
            case bl_reg:
            case cl_reg:
            case dl_reg:
              eh->operand[op_idx].value &= 0xFF;
              break;
            case ah_reg:
            case bh_reg:
            case ch_reg:
            case dh_reg:
              eh->operand[op_idx].value = (eh->operand[i].value & 0xFF00) >> 8;
              break;
            default:
              break;
          }
        }
        if (ignore_taint == 0) set_operand_data(&(eh->operand[op_idx]),1);
        break;
      }

      /* Immediate */
      case XED_OPERAND_IMM0: {
        op_idx++;
        eh->num_operands++;
        eh->operand[op_idx].type = TImmediate;
	eh->operand[op_idx].length =
	  (uint8_t) xed_decoded_inst_operand_length (&xedd, i);
	eh->operand[op_idx].access = (uint8_t) xed_operand_rw (op);
        //xed_uint_t width = xed_decoded_inst_get_immediate_width(&xedd);
        if (xed_decoded_inst_get_immediate_is_signed(&xedd)) {
          xed_int32_t signed_imm_val =
	    xed_decoded_inst_get_signed_immediate(&xedd);
          eh->operand[op_idx].value = (uint32_t) signed_imm_val;
        }
        else {
          xed_uint64_t unsigned_imm_val =
            xed_decoded_inst_get_unsigned_immediate(&xedd);
          eh->operand[op_idx].value = (uint32_t) unsigned_imm_val;
        }
        break;
      break;
      }
      /* Special immediate only used in ENTER instruction */
      case XED_OPERAND_IMM1: {
        op_idx++;
        eh->num_operands++;
        eh->operand[op_idx].type = TImmediate;
	eh->operand[op_idx].length =
	  (uint8_t) xed_decoded_inst_operand_length (&xedd, i);
	eh->operand[op_idx].access = (uint8_t) xed_operand_rw (op);
        xed_uint8_t unsigned_imm_val =
	  xed_decoded_inst_get_second_immediate(&xedd);
        eh->operand[op_idx].value = (uint32_t) unsigned_imm_val;
        break;
      }


      /* Memory */
      case XED_OPERAND_AGEN:
      case XED_OPERAND_MEM0:
      case XED_OPERAND_MEM1: {
	unsigned long base = 0;
	unsigned long index = 0;
	unsigned long scale = 1;
	unsigned long segbase = 0;
	unsigned short segsel = 0;
	unsigned long displacement = 0;
	unsigned int j;
	size_t remaining = 0;

	/* Set memory index */
        int mem_idx = 0;
        if (op_name == XED_OPERAND_MEM1) mem_idx = 1;

	unsigned int memlen = xed_decoded_inst_operand_length (&xedd, i);

	for (j = 0; j < memlen; j+=4) {
	  /* Initialization */
	  base = 0;
	  index = 0;
	  scale = 1;
	  segbase = 0;
	  segsel = 0;
	  displacement = 0;
	  remaining = memlen - j;

	  op_idx++;
	  if(op_idx >= MAX_NUM_OPERANDS)
	    break;
	  //assert(op_idx < MAX_NUM_OPERANDS);
	  eh->num_operands++;
	  eh->operand[op_idx].type = TMemLoc;
	  eh->operand[op_idx].access = (uint8_t) xed_operand_rw (op);
	  eh->operand[op_idx].length =
	    remaining > 4 ? 4 : (uint8_t) remaining;

	  // Get Segment register
	  xed_reg_enum_t seg_regid =
	    xed_decoded_inst_get_seg_reg(&xedd,mem_idx);

	  if (seg_regid != XED_REG_INVALID) {
	    const xed_operand_values_t *xopv =
	      xed_decoded_inst_operands_const(&xedd);
	    xed_bool_t default_segment =
	      xed_operand_values_using_default_segment (xopv,mem_idx);

	    if (!default_segment) {
	      eh->num_operands++;
	      int segmentreg = xed2chris_regmapping[seg_regid][0] - 100;

	      segbase = cpu_single_env->segs[segmentreg].base;
	      segsel = cpu_single_env->segs[segmentreg].selector;

	      eh->memregs[op_idx][0].type = TRegister;
	      eh->memregs[op_idx][0].length = 2;
	      eh->memregs[op_idx][0].addr = xed2chris_regmapping[seg_regid][0];
	      eh->memregs[op_idx][0].access = (uint8_t) XED_OPERAND_ACTION_R;
	      eh->memregs[op_idx][0].value = segsel;
	      eh->memregs[op_idx][0].usage = memsegment;
	      if (ignore_taint == 0)
		set_operand_data(&(eh->memregs[op_idx][0]),1);

	      int dt;
	      if (segsel & 0x4)       // ldt
		dt = cpu_single_env->ldt.base;
	      else                    //gdt
		dt = cpu_single_env->gdt.base;
	      segsel = segsel >> 3;

	      unsigned long segent = dt + 8 * segsel;
	      unsigned char segdes[8];
	      DECAF_read_mem(cpu_single_env,segent, 8, segdes);

#if 0
	      // debugging code to double check segbase value
	      unsigned long segbasenew = segdes[2] + segdes[3] * 256 +
	      segdes[4] * 256 * 256 + segdes[7] * 256 * 256 * 256;
	      if (segbase != segbasenew) {
		monitor_printf("segbase unexpected: 0x%08lX v.s 0x%08lX\n",
			segbase, segbasenew);
	      }
#endif
	      /* Segment descriptor is stored as a memory operand */
	      eh->num_operands+=2;
	      eh->memregs[op_idx][3].type = TMemLoc;
	      eh->memregs[op_idx][3].length = 4;
	      eh->memregs[op_idx][3].addr = segent;
	      eh->memregs[op_idx][3].access =
		(uint8_t) XED_OPERAND_ACTION_INVALID;
	      eh->memregs[op_idx][3].value = *((uint32_t *) segdes);
	      eh->memregs[op_idx][3].tainted_begin = 0;
	      eh->memregs[op_idx][3].usage = memsegent0;

	      eh->memregs[op_idx][4].type = TMemLoc;
	      eh->memregs[op_idx][4].length = 4;
	      eh->memregs[op_idx][4].addr = segent + 4;
	      eh->memregs[op_idx][4].access =
		(uint8_t) XED_OPERAND_ACTION_INVALID;
	      eh->memregs[op_idx][4].value = *(uint32_t *) (segdes + 4);
	      eh->memregs[op_idx][4].tainted_begin = 0;
	      eh->memregs[op_idx][4].usage = memsegent1;
	    }
	  }

	  // Get Base register
	  xed_reg_enum_t base_regid =
	    xed_decoded_inst_get_base_reg(&xedd,mem_idx);
	  if (base_regid != XED_REG_INVALID) {
	    eh->num_operands++;
	    int basereg = xed2chris_regmapping[base_regid][1];
	    base = cpu_single_env->regs[basereg];
	    eh->memregs[op_idx][1].type = TRegister;
	    eh->memregs[op_idx][1].addr = xed2chris_regmapping[base_regid][0];
	    eh->memregs[op_idx][1].length = 4;
	    eh->memregs[op_idx][1].access = (uint8_t) XED_OPERAND_ACTION_R;
	    eh->memregs[op_idx][1].value = base;
	    eh->memregs[op_idx][1].usage = membase;
	    if (ignore_taint == 0) set_operand_data(&(eh->memregs[op_idx][1]),1);
	  }
	  // Get Index register and Scale
	  xed_reg_enum_t index_regid =
	    xed_decoded_inst_get_index_reg(&xedd,mem_idx);
	  if (mem_idx == 0 && index_regid != XED_REG_INVALID) {
	    eh->num_operands++;
	    int indexreg = xed2chris_regmapping[index_regid][1];
	    index = cpu_single_env->regs[indexreg];
	    eh->memregs[op_idx][2].type = TRegister;
	    eh->memregs[op_idx][2].addr = xed2chris_regmapping[index_regid][0];
	    eh->memregs[op_idx][2].length = 4;
	    eh->memregs[op_idx][2].access = (uint8_t) XED_OPERAND_ACTION_R;
	    eh->memregs[op_idx][2].value = index;
	    eh->memregs[op_idx][2].usage = memindex;
	    if (ignore_taint == 0) set_operand_data(&(eh->memregs[op_idx][2]),1);

	    // Get Scale (AKA width) (only have a scale if the index exists)
	    if (xed_decoded_inst_get_scale(&xedd,i) != 0) {
	      scale = (unsigned long) xed_decoded_inst_get_scale(&xedd,mem_idx);
	    }
	  }
	  // Get displacement (AKA offset)
	  displacement =
	    (unsigned long) xed_decoded_inst_get_memory_displacement
	    (&xedd,mem_idx);

	  // Fix displacement for:
	  //   1) Any instruction that pushes into the stack, since ESP is
	  //        decremented before memory operand is written using ESP.
	  //        Affects: ENTER,PUSH,PUSHA,PUSHF,CALL
	  if (is_stackpush) {
            stackpushpop_acc += eh->operand[op_idx].length;
            displacement = displacement - stackpushpop_acc -j;
	  }
	  //   2) Pop instructions where the
	  //      destination operand is a memory location that uses ESP
	  //        as base or index register.
	  //      The pop operations increments ESP and the written memory
	  //        location address needs to be adjusted.
	  //      Affects: pop (%esp)
	  else if ((category == XED_CATEGORY_POP) && (!is_stackpop)) {
	    if ((eh->memregs[op_idx][1].addr == esp_reg) ||
		(eh->memregs[op_idx][2].addr == esp_reg))
	    {
	      displacement = displacement + eh->operand[op_idx].length;
	    }
	  }

	  // Calculate memory address accessed
	  eh->operand[op_idx].addr =
	    j + segbase + base + index * scale + displacement;

	  // Special handling for LEA instructions
	  if (op_name == XED_OPERAND_AGEN) {
	    eh->operand[op_idx].type = TMemAddress;
	    eh->operand[op_idx].length = 4;
	    has_page_fault = 0; // LEA won't trigger page fault
	  }
	  else {
	    has_page_fault = DECAF_read_mem(cpu_single_env,eh->operand[op_idx].addr,
	      (int)(eh->operand[op_idx].length),
	      (uint8_t *)&(eh->operand[op_idx].value));
	  }

	  // Check if instruction accesses user memory
	  // kernel_mem_start defined in shared/read_linux.c
	  if ((eh->operand[op_idx].addr < VMI_guest_kernel_base) &&
	    (op_name != XED_OPERAND_AGEN))
	  {
	    access_user_mem = 1;
	  }
	  if (ignore_taint == 0) set_operand_data(&(eh->operand[op_idx]),1);
	}
	break;
      }

      /* Jumps */
      case XED_OPERAND_PTR:  // pointer (always in conjunction with a IMM0)
      case XED_OPERAND_RELBR: { // branch displacements
          xed_uint_t disp = xed_decoded_inst_get_branch_displacement(&xedd);
	  /* Displacement is from instruction end */
	  /* Adjust displacement with instruction size */
	  disp = disp + eh->inst_size;
	  op_idx++;
	  eh->num_operands++;
	  eh->operand[op_idx].type = TJump;
	  eh->operand[op_idx].length = 4;
	  eh->operand[op_idx].access = (uint8_t) xed_operand_rw (op);
	  eh->operand[op_idx].value = disp;
          break;
      }

      /* Floating point registers */
      case XED_REG_X87CONTROL:
      case XED_REG_X87STATUS:
      case XED_REG_X87TOP:
      case XED_REG_X87TAG:
      case XED_REG_X87PUSH:
      case XED_REG_X87POP:
      case XED_REG_X87POP2:
          op_idx++;
          eh->num_operands++;
          eh->operand[op_idx].type = TFloatRegister;
          eh->operand[op_idx].length = 4;
	  eh->operand[op_idx].access = (uint8_t) xed_operand_rw (op);
      default:
        break;
     }
  }