// get immediate jint as_int(void) const { GUARANTEE(is_immediate(), "check"); GUARANTEE(type() == T_BOOLEAN || type() == T_INT || type() == T_BYTE || type() == T_CHAR || type() == T_SHORT || type() == T_OBJECT || type() == T_ARRAY, "check type"); return _low; }
void NativeMovRegMem::print() { if (is_immediate()) { // offset is a signed 13-bit immediate, so casting it to int will not lose significant bits tty->print_cr(INTPTR_FORMAT ": mov reg, [reg + %d]", p2i(instruction_address()), (int)offset()); } else { tty->print_cr(INTPTR_FORMAT ": mov reg, [reg + reg]", p2i(instruction_address())); } }
void Value::materialize() { GUARANTEE(is_immediate(), "value must be immediate"); GUARANTEE(type() != T_OBJECT || must_be_null(), "object immediate is already materialized"); Value result(type()); result.assign_register(); Compiler::code_generator()->move(result, *this); result.copy(*this); }
void c_func_lsl (ea_t *src, ea_t *dest, int size) { char buf[256]; unsigned int mask; int shift, len; c_fncall (); c_fnbegin (); if (size == BYTE) { mask = 0xff; len = 8; } else if (size == WORD) { mask = 0xffff; len = 16; } else { mask = 0xffffffff; len = 32; } c_readea (dest, buf); cln ("u32 val = (%s)%s;\n", c_usizes[size], buf); if (is_immediate (src)) { shift = src->imm.val; if (shift >= len) { cln ("X = %s;", (shift == len ? "val & 1" : "0")); ifC cln ("C = X;"); cln ("val = 0;"); } else { cln ("val <<= %d;", shift-1); cln ("X = (val & 0x%x);", 1<<(len-1)); ifC cln ("C = X;"); cln ("val <<= 1;"); cln ("val &= 0x%x;", mask); } } else { c_readea (src, buf); cln ("s32 shift = %s & 63;", buf); cln ("if (shift >= %d) {", len); cln (" X = (shift == %d ? val & 1 : 0);", len); ifC cln (" C = X;"); cln (" val = 0;"); cln ("} else if (shift == 0) {"); ifC cln (" C = 0;"); cln ("} else {"); cln (" val <<= shift-1;"); cln (" X = (val & 0x%x);", 1<<(len-1)); ifC cln (" C = X;"); cln (" val <<= 1;"); cln (" val &= 0x%x;", mask); cln ("}"); } ifZ cln ("nZ = ((%s)(val)) != 0;", c_ssizes[size]); ifN cln ("N = ((%s)(val)) < 0;", c_ssizes[size]); ifV cln ("V = 0;"); c_writeea (dest, size, "val"); c_postea (dest); c_postea (src); c_fnend (); }
/* src is the shift */ void c_func_asl (ea_t *src, ea_t *dest, int size) { char buf[256]; unsigned int mask; int shift, len; c_fncall (); c_fnbegin (); if (size == BYTE) { mask = 0xff; len = 8; } else if (size == WORD) { mask = 0xffff; len = 16; } else { mask = 0xffffffff; len = 32; } c_readea (dest, buf); cln ("u32 val = %s;\n", buf); if (is_immediate (src)) { /* mostly for the sake of -O0 compiles... */ shift = src->imm.val; if (shift >= len) { ifV cln ("V = (val != 0);"); cln ("X = %s;", (shift == len ? "val & 1" : "0")); ifC cln ("C = X;"); cln ("val = 0;"); } else { ifV cln ("u32 mask = (0x%x << (%d - %d)) & 0x%x;", mask, len-1, shift, mask); ifV cln ("V = (val & mask) != mask && (val & mask) != 0;"); cln ("val <<= %d;", shift-1); cln ("X = (val & 0x%x);", 1<<(len-1)); ifC cln ("C = (val & 0x%x);", 1<<(len-1)); cln ("val <<= 1;"); } } else { c_readea (src, buf); cln ("s32 src = %s & 63;", buf); cln ("if (src >= %d) {", len); ifV cln (" V = (val != 0);"); cln (" X = (src == %d ? val & 1 : 0);", len); ifC cln ("C = X;"); cln (" val = 0;"); cln ("} else if (src == 0) {"); ifC cln (" C = 0;"); ifV cln (" V = 0;"); cln ("} else {"); ifV cln (" u32 mask = (0x%x << (%d - src)) & 0x%x;", mask, len-1, mask); ifV cln (" V = (val & mask) != mask && (val & mask) != 0;"); cln (" val <<= src-1;"); cln (" X = (val & 0x%x);", 1<<(len-1)); ifC cln (" C = (val & 0x%x);", 1<<(len-1)); cln (" val <<= 1;"); //cln (" val &= 0x%x;", mask); cln ("}"); } ifZ cln ("nZ = ((%s)(val)) != 0;", c_ssizes[size]); ifN cln ("N = ((%s)(val)) < 0;", c_ssizes[size]); c_writeea (dest, size, "val"); c_postea (dest); c_postea (src); c_fnend (); }
void c_func_asr (ea_t *src, ea_t *dest, int size) { char buf[256]; unsigned int mask; int shift, len; c_fncall (); c_fnbegin (); if (size == BYTE) { mask = 0xff; len = 8; } else if (size == WORD) { mask = 0xffff; len = 16; } else { mask = 0xffffffff; len = 32; } c_readea (dest, buf); cln ("u32 val = (%s)%s;\n", c_usizes[size], buf); cln ("u32 sign = (0x%x & val) >> %d;", 1<<(len-1), len-1); if (is_immediate (src)) { shift = src->imm.val; if (shift >= len) { cln ("val = 0x%x & (u32)-sign;", mask); cln ("X = sign;"); ifC cln ("C = X;"); } else { cln ("val >>= %d;", shift-1); cln ("X = val & 1;"); ifC cln ("C = X;"); cln ("val >>= 1;"); cln ("val |= (0x%x << %d) & (u32)-sign;", mask, len - shift); } } else { c_readea (src, buf); cln ("s32 src = %s & 63;", buf); cln ("if (src >= %d) {", len); cln (" val = 0x%x & (u32)-sign;", mask); cln (" X = sign;"); ifC cln (" C = X;"); cln ("} else if (src == 0) {"); ifC cln (" C = 0;"); cln ("} else {"); cln (" val >>= src - 1;"); cln (" X = val & 1;"); ifC cln (" C = X;"); cln (" val >>= 1;"); cln (" val |= (0x%x << (%d - src)) & (u32)-sign;", mask, len); //cln (" val &= 0x%x;", mask); cln ("}"); } ifZ cln ("nZ = ((%s)(val)) != 0;", c_ssizes[size]); ifN cln ("N = ((%s)(val)) < 0;", c_ssizes[size]); ifV cln ("V = 0;"); c_writeea (dest, size, "val"); c_postea (dest); c_postea (src); c_fnend (); }
jint msw_bits() const { GUARANTEE(is_immediate() && type() == T_LONG, "check"); return (MSW_FIRST_FOR_LONG ? _low : _high); }
jlong as_raw_long() const{ GUARANTEE(is_immediate() && type() == T_DOUBLE, "check"); return *(jlong*)&_low; }
jint as_raw_int() const { GUARANTEE(is_immediate() && type() == T_FLOAT, "check"); return _low; }
jdouble as_double() const { GUARANTEE(is_immediate() && type() == T_DOUBLE, "check"); return *(jdouble*)&_low; }
jfloat as_float() const { GUARANTEE(is_immediate() && type() == T_FLOAT, "check"); return *(jfloat*)(&_low); }
jlong as_long(void) const { GUARANTEE(is_immediate() && type() == T_LONG, "check"); return *(jlong*)&_low; }
/** * Process an instruction, and update the register values accordingly. */ static void analyse_instruction(struct analysis_context *ctx, struct tgsi_full_instruction *inst) { struct lp_tgsi_info *info = ctx->info; struct lp_tgsi_channel_info (*regs)[4]; unsigned max_regs; unsigned i; unsigned index; unsigned chan; for (i = 0; i < inst->Instruction.NumDstRegs; ++i) { const struct tgsi_dst_register *dst = &inst->Dst[i].Register; /* * Get the lp_tgsi_channel_info array corresponding to the destination * register file. */ if (dst->File == TGSI_FILE_TEMPORARY) { regs = ctx->temp; max_regs = Elements(ctx->temp); } else if (dst->File == TGSI_FILE_OUTPUT) { regs = info->output; max_regs = Elements(info->output); } else if (dst->File == TGSI_FILE_ADDRESS || dst->File == TGSI_FILE_PREDICATE) { continue; } else { assert(0); continue; } /* * Detect direct TEX instructions */ switch (inst->Instruction.Opcode) { case TGSI_OPCODE_TEX: analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_NONE); break; case TGSI_OPCODE_TXD: analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV); break; case TGSI_OPCODE_TXB: analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_LOD_BIAS); break; case TGSI_OPCODE_TXL: analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_LOD); break; case TGSI_OPCODE_TXP: analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_PROJECTED); break; case TGSI_OPCODE_SAMPLE: analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_NONE, FALSE); break; case TGSI_OPCODE_SAMPLE_C: analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_NONE, TRUE); break; case TGSI_OPCODE_SAMPLE_C_LZ: analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_LOD_ZERO, TRUE); break; case TGSI_OPCODE_SAMPLE_D: analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV, FALSE); break; case TGSI_OPCODE_SAMPLE_B: analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_LOD_BIAS, FALSE); break; case TGSI_OPCODE_SAMPLE_L: analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_LOD, FALSE); break; default: break; } /* * Keep track of assignments and writes */ if (dst->Indirect) { /* * It could be any register index so clear all register indices. */ for (chan = 0; chan < 4; ++chan) { if (dst->WriteMask & (1 << chan)) { for (index = 0; index < max_regs; ++index) { regs[index][chan].file = TGSI_FILE_NULL; } } } } else if (dst->Index < max_regs) { /* * Update this destination register value. */ struct lp_tgsi_channel_info res[4]; memset(res, 0, sizeof res); if (!inst->Instruction.Predicate && !inst->Instruction.Saturate) { for (chan = 0; chan < 4; ++chan) { if (dst->WriteMask & (1 << chan)) { if (inst->Instruction.Opcode == TGSI_OPCODE_MOV) { analyse_src(ctx, &res[chan], &inst->Src[0].Register, chan); } else if (inst->Instruction.Opcode == TGSI_OPCODE_MUL) { /* * Propagate values across 1.0 and 0.0 multiplications. */ struct lp_tgsi_channel_info src0; struct lp_tgsi_channel_info src1; analyse_src(ctx, &src0, &inst->Src[0].Register, chan); analyse_src(ctx, &src1, &inst->Src[1].Register, chan); if (is_immediate(&src0, 0.0f)) { res[chan] = src0; } else if (is_immediate(&src1, 0.0f)) { res[chan] = src1; } else if (is_immediate(&src0, 1.0f)) { res[chan] = src1; } else if (is_immediate(&src1, 1.0f)) { res[chan] = src0; } } } } } for (chan = 0; chan < 4; ++chan) { if (dst->WriteMask & (1 << chan)) { regs[dst->Index][chan] = res[chan]; } } } } /* * Clear all temporaries information in presence of a control flow opcode. */ switch (inst->Instruction.Opcode) { case TGSI_OPCODE_IF: case TGSI_OPCODE_UIF: case TGSI_OPCODE_ELSE: case TGSI_OPCODE_ENDIF: case TGSI_OPCODE_BGNLOOP: case TGSI_OPCODE_BRK: case TGSI_OPCODE_BREAKC: case TGSI_OPCODE_CONT: case TGSI_OPCODE_ENDLOOP: case TGSI_OPCODE_CALLNZ: case TGSI_OPCODE_CAL: case TGSI_OPCODE_BGNSUB: case TGSI_OPCODE_ENDSUB: case TGSI_OPCODE_SWITCH: case TGSI_OPCODE_CASE: case TGSI_OPCODE_DEFAULT: case TGSI_OPCODE_ENDSWITCH: case TGSI_OPCODE_RET: case TGSI_OPCODE_END: /* XXX: Are there more cases? */ memset(&ctx->temp, 0, sizeof ctx->temp); memset(&info->output, 0, sizeof info->output); default: break; } }
/** * Prepares the stack for a 64-bit guest and places the arguments in the correct * register / stack locations. * * Arguments on 64-bit systems: * 1st ARG: %RDI * 2nd ARG: %RSI * 3rd ARG: %RDX * 4th ARG: %RCX * 5th ARG: %R8 * 6th ARG: %R9 * 7th ARG - nth ARG: on stack from right to left * * @param inject The injection structure of the module that is injected. * @param virt_stack A pointer to the virtual address of the memory area * that was reserved for the stack of the module. */ void prepareStack64(struct kvm_vcpu *vcpu, struct injection *inject, u64 *virt_stack) { u64 phys_stack = 0; struct x86_exception error; struct injection_arg *arg = NULL; unsigned int i = 0; int ret = 0; enum kvm_reg reg; // Do we actually have arguments? if (inject->args) { // Move all data to the stack that cannot be directly passed as an argument // such as strings and structures. for (i = 0; i < inject->args->argc; ++i) { arg = get_next_arg(inject, arg); if (!is_immediate(arg)) { // Copy the data to the stack PRINT_DEBUG("Writing data of argument %d with type %d and size %d to 0x%llx\n", i, arg->type, arg->size, *virt_stack - arg->size); // Update address (*virt_stack) -= arg->size; arg->data_on_stack = (void *)(*virt_stack); // Write phys_stack = vcpu->arch.mmu.gva_to_gpa(vcpu, (*virt_stack), 0, &error); ret = kvm_write_guest(vcpu->kvm, phys_stack, get_arg_data(inject, arg), arg->size); if(ret < 0) { PRINT_ERROR("An error (code: %d) occurred while writing the argument %d to memory!\n", ret, i); return; } } } // Place arguments into the correct register / stack locations arg = NULL; for (i = inject->args->argc; i > 0 ; --i) { arg = get_prev_arg(inject, arg); if (i >= 7) { // Arg goes on the stack // ToDo: We just fix this to 8 byte here, but the size of the arg // may actually be shorter (*virt_stack) -= 8; phys_stack = vcpu->arch.mmu.gva_to_gpa(vcpu, (*virt_stack), 0, &error); if (is_immediate(arg)) { PRINT_DEBUG("Writing argument %d with type %d and size %d to the stack 0x%llx\n", i, arg->type, arg->size, *virt_stack); ret = kvm_write_guest(vcpu->kvm, phys_stack, get_arg_data(inject, arg), arg->size); } else { PRINT_DEBUG("Writing pointer 0x%lx to argument %d with type %d and size %d to the stack 0x%llx\n", (unsigned long)arg->data_on_stack, i, arg->type, arg->size, *virt_stack); ret = kvm_write_guest(vcpu->kvm, phys_stack, &arg->data_on_stack, 8); } if(ret < 0) { PRINT_ERROR("An error (code: %d) occurred while writing the argument %d " "to the stack!\n", ret, i); return; } } else { // Arg goes into a register switch (i) { case 1: reg = VCPU_REGS_RDI; break; case 2: reg = VCPU_REGS_RSI; break; case 3: reg = VCPU_REGS_RDX; break; case 4: reg = VCPU_REGS_RCX; break; case 5: reg = VCPU_REGS_R8; break; case 6: reg = VCPU_REGS_R9; break; default: PRINT_ERROR("Argument is not between one and six!\n"); } if (is_immediate(arg)) { PRINT_DEBUG("Writing argument %d with value 0x%lx, type %d, and size %d to register %d\n", i, (unsigned long)arg->data, arg->type, arg->size, reg); kvm_register_write(vcpu, reg, *((unsigned long *)get_arg_data(inject, arg))); } else { PRINT_DEBUG("Writing pointer 0x%lx to argument %d with type %d and size %d to register %d\n", (unsigned long)arg->data_on_stack, i, arg->type, arg->size, reg); kvm_register_write(vcpu, reg, (unsigned long)arg->data_on_stack); } } } } // Add Offset to stack so the shellcode can operate (*virt_stack) -= STACK_AREA_SC ; // Place the original kernel pointer on the stack (*virt_stack) -= 8; // Write address of the original kernel stack on the new stack phys_stack = vcpu->arch.mmu.gva_to_gpa(vcpu, (*virt_stack), 0, &error); ret = kvm_write_guest(vcpu->kvm, phys_stack, &_XTIER_inject.regs.rsp, 8); kvm_register_write(vcpu, VCPU_REGS_RSP, (*virt_stack)); }