void schedule(struct cpuRegs_s *regs) { if (allocatedVMs > 0) { saveVMState(regs); currentVMID++; if (currentVMID >= allocatedVMs) currentVMID = 0; switchToVM(virtualMachines[currentVMID], regs); } }
/** * Inject the given code into the VM. * * @param inject A pointer to the XTIER_inject structure used for injection. * It contains a pointer to the code and the length of the code. */ void XTIER_inject_code(struct kvm_vcpu *vcpu, struct injection *inject) { u64 virt_code = 0; u64 virt_stack = 0; u64 phys_code = 0; u64 phys_stack = 0; struct x86_exception error; int ret = 0; u32 state = 0; PRINT_DEBUG("Injecting code...\n"); // Get Time XTIER_inject_begin_time_measurement(&_starttime); if(_XTIER_inject.new_module) { // This is the first injection, reset the timer XTIER_inject_init_performance_struct(); // Reset _XTIER_inject.new_module = 0; } // Reduce auto injection if enabled if(inject->auto_inject > 0) inject->auto_inject--; // Disable hooks to avoid exceptions during injection if(inject->event_based) XTIER_inject_disable_hook(vcpu); // Reset the fault variable _XTIER_inject.injection_fault = 0; // Save VM state saveVMState(vcpu); // Get a mapping // We currently can only reserve space for a little less than 4MB. if(inject->code_len > (512 * 4096)) { /* virt_code = XTIER_memory_establish_mapping(vcpu, XTIER_INJECTION_PID, _XTIER_inject.sregs.cr3, 512 * 4096); XTIER_memory_establish_mapping(vcpu, XTIER_INJECTION_PID, _XTIER_inject.sregs.cr3, inject->code_len - (512 * 4096)); */ PRINT_ERROR("The module that should be injected is to large!\n"); return; } // Code virt_code = XTIER_memory_establish_mapping(vcpu, XTIER_INJECTION_PID, _XTIER_inject.sregs.cr3, inject->code_len); // Stack // Do NOT modify the stack pointer in case of event based injection if(!inject->event_based) { // Reserve space for the args and the stack itself virt_stack = XTIER_memory_establish_mapping(vcpu, XTIER_INJECTION_PID, _XTIER_inject.sregs.cr3, inject->args_size + 4096); if (virt_stack) { // Currently virt_stack points to the end of the stack // Fix that virt_stack += inject->args_size + 4000; // We leave 96 bytes free // Prepare Stack switch(_XTIER.os) { case XTIER_OS_UBUNTU_64: prepareStack64(vcpu, inject, &virt_stack); break; case XTIER_OS_WINDOWS_7_32: /* Fall through*/ case XTIER_OS_UBUNTU_32: virt_stack -= 4; // 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, 4); kvm_register_write(vcpu, VCPU_REGS_RSP, virt_stack); if(inject->args_size > 0) PRINT_WARNING("Module arguments for 32-bit OSs are currently not supported!\n"); break; default: PRINT_ERROR("OS type is unknown! Cannot inject module!\n"); XTIER_memory_remove_mappings_pid(vcpu, XTIER_INJECTION_PID); return; } } } else { // Event based injection // Set the stack to the original stack - The SC offset virt_stack = _XTIER_inject.regs.rsp - STACK_AREA_SC; // Prepare Stack switch(_XTIER.os) { case XTIER_OS_UBUNTU_64: // 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); break; case XTIER_OS_WINDOWS_7_32: /* Fall through*/ case XTIER_OS_UBUNTU_32: virt_stack -= 4; // 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, 4); kvm_register_write(vcpu, VCPU_REGS_RSP, virt_stack); break; default: PRINT_ERROR("OS type is unknown! Cannot inject module!\n"); XTIER_memory_remove_mappings_pid(vcpu, XTIER_INJECTION_PID); return; } if(inject->args_size > 0) PRINT_WARNING("Module arguments are not supported in the case of event-based injection!\n"); } // Verify that the memory was reserved if(virt_code == 0 || virt_stack == 0) { PRINT_ERROR("Could not establish the mappings for code injection. Aborting.\n"); return; } // Get Physical address phys_code = vcpu->arch.mmu.gva_to_gpa(vcpu, virt_code, 0, &error); // Write Data ret = kvm_write_guest(vcpu->kvm, phys_code, inject->code, inject->code_len); if(ret < 0) { PRINT_ERROR("An error (code: %d) occurred while writing the binary to memory!\n", ret); // Remove Mappings XTIER_memory_remove_mappings_pid(vcpu, XTIER_INJECTION_PID); // Reenable hook if(inject->event_based) XTIER_inject_enable_hook(vcpu, inject); return; } // Set params _XTIER_inject.event_based = inject->event_based; _XTIER_inject.exit_after_injection = inject->exit_after_injection; // Increase injections _XTIER_performance.injections++; PRINT_INFO("Running shellcode @ 0x%llx (ESP: 0x%llx, KERNEL ESP: 0x%llx, SEIP: 0x%llx, CR3: 0x%llx)\n", virt_code, virt_stack, _XTIER_inject.regs.rsp, _XTIER_inject.regs.rip, _XTIER_inject.sregs.cr3); // Set Mode _XTIER.mode |= XTIER_CODE_INJECTION; // Set HALT Exiting XTIER_enable_hlt_exiting(); // Set Exception Exiting XTIER_enable_interrupt_exiting(vcpu); // Set EIP kvm_rip_write(vcpu, virt_code); // Flush TLB //kvm_x86_ops->tlb_flush(vcpu); // Get Time XTIER_inject_end_time_measurement(&_starttime, &_XTIER_performance.total_module_load_time); // Take Time for execution just before we enter the VM XTIER_take_time_on_entry(&_starttime); // Make sure the VM is not halted XTIER_read_vmcs(GUEST_ACTIVITY_STATE, &state); if(state == GUEST_ACTIVITY_HLT) XTIER_write_vmcs(GUEST_ACTIVITY_STATE, GUEST_ACTIVITY_ACTIVE); }