//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; }
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 }
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 }
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; }
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++; } }
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; }
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; }
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; }
/* * 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); } } } }
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)); } }
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); }
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); }
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)); }
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); }
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); } } }
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)); }
/** * 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); //} } } }
//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; }
/** * 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); } } } }
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; } }