Пример #1
0
addr_t drakvuf_get_current_thread(drakvuf_t drakvuf, uint64_t vcpu_id, x86_registers_t *regs){
    vmi_instance_t vmi = drakvuf->vmi;
    addr_t thread;
    addr_t prcb;
    reg_t fsgs;

    /*
     * fs_base/gs_base in the info->regs structure are not actually filled in
     * by Xen for vm_events, so we need to manually ask for these each time
     */
    if(vmi_get_page_mode(vmi) == VMI_PM_IA32E)  {
        if (!regs->gs_base)
            vmi_get_vcpureg(vmi, &fsgs, GS_BASE, vcpu_id);
        else
            fsgs = regs->gs_base;

        prcb=offsets[KPCR_PRCB];
    } else {
        if (!regs->fs_base)
            vmi_get_vcpureg(vmi, &fsgs, FS_BASE, vcpu_id);
        else
            fsgs = regs->fs_base;

        prcb=offsets[KPCR_PRCBDATA];
    }

    if (VMI_SUCCESS != vmi_read_addr_va(vmi, fsgs + prcb + offsets[KPRCB_CURRENTTHREAD], 0, &thread)){
        return 0;
    }

    return thread;
}
Пример #2
0
void ss_callback(vmi_instance_t vmi, vmi_event_t *event) {
    reg_t rip, cr3;
    vmi_get_vcpureg(vmi, &rip, RIP, event->vcpu_id);
    vmi_get_vcpureg(vmi, &cr3, CR3, event->vcpu_id);
    page_mode_t pm = vmi_get_page_mode(vmi);
    vmi_pid_t pid = vmi_dtb_to_pid(vmi, cr3);
    printf("----- Singlestep: CR3 0x%lx PID %u executing RIP 0x%lx\n", cr3, pid,
            rip);

    if ((PM2BIT(pm) == BIT32 && rip < KERNEL32)
            || (PM2BIT(pm) == BIT64 && rip < KERNEL64)) {
        printf("Good RIP: 0x%lx\n", rip);
        struct injector *injector = event->data;
        injector->ss_enabled = 0;

        injector->target_pid = pid;
        injector->target_rip = vmi_pagetable_lookup(vmi, cr3, rip);

        hijack_thread(injector, vmi, event->vcpu_id, pid);

        vmi_clear_event(vmi, event);
        vmi_clear_event(vmi, &injector->cr3_event);
        injector->mm_count++;

        uint8_t trap = 0xCC;
        vmi_read_8_pa(vmi, injector->target_rip, &injector->backup);
        vmi_write_8_pa(vmi, injector->target_rip, &trap);
    }
}
Пример #3
0
void mm_callback(vmi_instance_t vmi, vmi_event_t *event) {
    struct injector *injector = event->data;
    reg_t rip, cr3, rsp;
    vmi_get_vcpureg(vmi, &rip, RIP, event->vcpu_id);
    vmi_get_vcpureg(vmi, &cr3, CR3, event->vcpu_id);
    vmi_get_vcpureg(vmi, &rsp, RSP, event->vcpu_id);
    vmi_pid_t pid = vmi_dtb_to_pid(vmi, cr3);

    printf("----- Memevent: PID %u executing RIP 0x%lx. Target PID: %u. Target RIP: 0x%lx. My event count: %u\n",
        pid, ((event->mem_event.gfn<<12) + event->mem_event.offset), injector->target_pid, injector->target_rip, injector->mm_count);

    if ((PM2BIT(injector->pm) == BIT32 && rip < KERNEL32)
            || (PM2BIT(injector->pm) == BIT64 && rip < KERNEL64)) {
        injector->target_pid = pid;
        injector->target_rip = (event->mem_event.gfn << 12)
                + event->mem_event.offset;

        hijack_thread(injector, vmi, event->vcpu_id, pid);

        vmi_clear_event(vmi, event);
        vmi_clear_event(vmi, &injector->cr3_event);
        injector->mm_count++;

        uint8_t trap = 0xCC;
        vmi_read_8_pa(vmi, injector->target_rip, &injector->backup);
        vmi_write_8_pa(vmi, injector->target_rip, &trap);

        return;
    }

    vmi_clear_event(vmi, event);
    vmi_step_event(vmi, event, event->vcpu_id, 1, NULL);
}
Пример #4
0
event_response_t mm_callback(vmi_instance_t vmi, vmi_event_t *event) {

    vmi_get_vcpureg(vmi, &cr3, CR3, 0);
    vmi_pid_t current_pid = vmi_dtb_to_pid(vmi, cr3);

    reg_t rip_test;
    vmi_get_vcpureg(vmi, &rip_test, RIP, 0);

    printf("Memevent: {\n\tPID %u. RIP 0x%lx:\n", current_pid, rip_test);

    print_event(event);

    if( current_pid == pid && event->mem_event.gla == rip) {
        printf("\tCought the original RIP executing again!");
        vmi_clear_event(vmi, event, NULL);
        interrupted = 1;
    } else {
        printf("\tEvent on same page, but not the same RIP");
        vmi_clear_event(vmi, event, NULL);

        /* These two calls are equivalent */
        //vmi_step_event(vmi, event, event->vcpu_id, 1, NULL);
        vmi_step_event(vmi, event, event->vcpu_id, 1, step_callback);
    }

    printf("\n}\n");
    return 0;
}
Пример #5
0
void syscall_compat_cb(vmi_instance_t vmi, vmi_event_t *event){
    reg_t rdi, rax;
    vmi_get_vcpureg(vmi, &rax, RAX, event->vcpu_id);
    vmi_get_vcpureg(vmi, &rdi, RDI, event->vcpu_id);

    printf("Syscall happened: RAX(syscall#)=%u RDI(1st argument)=%u\n", (unsigned int)rax, (unsigned int)rdi);

    print_event(*event);

    vmi_clear_event(vmi, &msr_syscall_compat_event);
}
Пример #6
0
addr_t drakvuf_get_kernel_base(drakvuf_t drakvuf) {
    reg_t fsgs;

    if(vmi_get_page_mode(drakvuf->vmi) == VMI_PM_IA32E)  {
        vmi_get_vcpureg(drakvuf->vmi, &fsgs, GS_BASE, 0);
    } else {
        vmi_get_vcpureg(drakvuf->vmi, &fsgs, FS_BASE, 0);
    }

    return fsgs - drakvuf->offsets[KIINITIALPCR];
}
Пример #7
0
event_response_t msr_syscall_sysenter_cb(vmi_instance_t vmi, vmi_event_t *event){
    reg_t rdi, rax;
    vmi_get_vcpureg(vmi, &rax, RAX, event->vcpu_id);
    vmi_get_vcpureg(vmi, &rdi, RDI, event->vcpu_id);

    printf("Syscall happened: RAX(syscall#)=%u RDI(1st argument)=%u\n", (unsigned int)rax, (unsigned int)rdi);

    print_event(*event);

    vmi_clear_event(vmi, &msr_syscall_sysenter_event, NULL);
    return 0;
}
Пример #8
0
//callback function
void mm_callback(vmi_instance_t vmi, vmi_event_t *event) {

    print_event(event);
    vmi_get_vcpureg(vmi,&rax,RAX,0);
    vmi_get_vcpureg(vmi,&rbx,RBX,0);
    vmi_get_vcpureg(vmi,&rcx,RCX,0);
    vmi_get_vcpureg(vmi,&rdx,RDX,0);
    vmi_get_vcpureg(vmi,&rsi,RSI,0);
    vmi_get_vcpureg(vmi,&rdi,RDI,0);
    printf("HYPERCALL is: %s\n RAX value is: %lx\n RBX value is: %lx\n RCX value is: %lx\n RDX value is: %lx\n RSI value is: %lx\n RDI value is: %lx\n",
	event->mem_event.hypercall,rax,rbx,rcx,rdx,rsi,rdi);

    if(event->mem_event.gla == event->mem_event.gla2) {
        printf("\tCought the original hypercall executing again!");
        vmi_clear_event(vmi, event);
        interrupted = 1;
    } else {
        printf("\tEvent on same page, but not the hypercall: %s",event->mem_event.hypercall);
        vmi_clear_event(vmi, event);

        /* These two calls are equivalent */
        //vmi_step_event(vmi, event, event->vcpu_id, 1, NULL);
        vmi_step_event(vmi, event, event->vcpu_id, 1, NULL);
    }

    printf("\n}\n");
}
Пример #9
0
void injector_int3_cb(vmi_instance_t vmi, vmi_event_t *event) {

    struct injector *injector = event->data;
    addr_t pa = (event->interrupt_event.gfn << 12)
            + event->interrupt_event.offset;

    reg_t cr3;
    vmi_get_vcpureg(vmi, &cr3, CR3, event->vcpu_id);
    vmi_pid_t pid = vmi_dtb_to_pid(vmi, cr3);

    printf("INT3 @ 0x%lx. PID %u\n", pa, pid);

    if (pa == injector->userspace_return) {

        event->interrupt_event.reinject = 0;

        if (pid != injector->target_pid) {
            printf("Userspace return trap hit by another PID, not the target (%u)\n",
                    injector->target_pid);
            vmi_write_8_pa(vmi, pa, &injector->userspace_return_backup);
            vmi_step_event(vmi, event, event->vcpu_id, 1, reset_return_trap);
            return;
        }

        injector->target_pid = pid;
        injector->target_rip = pa;
        injector->backup = injector->userspace_return_backup;
        injector->userspace_return = 0;

        hijack_thread(injector, vmi, event->vcpu_id, pid);

/*
                injector->ss_enabled = 1;
                memset(&injector->ss_event, 0, sizeof(vmi_event_t));
                injector->ss_event.type = VMI_EVENT_SINGLESTEP;
                injector->ss_event.callback = ss_callback;
                injector->ss_event.data = injector;
                SET_VCPU_SINGLESTEP(injector->ss_event.ss_event,
                        event->vcpu_id);
                vmi_register_event(vmi, &injector->ss_event);
*/


        vmi_clear_event(vmi, &injector->cr3_event);
        injector->mm_count++;
        return;
    }

    if (pa == injector->target_rip) {

        event->interrupt_event.reinject = 0;

        if (pid != injector->target_pid) {
            printf("Return trap hit by another PID, not the target (%u)\n",
                    injector->target_pid);
            vmi_write_8_pa(vmi, pa, &injector->backup);
            vmi_step_event(vmi, event, event->vcpu_id, 1, reset_return_trap);
            return;
        }

        reg_t rax;
        vmi_get_vcpureg(vmi, &rax, RAX, event->vcpu_id);
        vmi_pid_t pid = vmi_dtb_to_pid(vmi, cr3);

        printf("RAX: 0x%lx\n", rax);

        printf("Restoring RSP to 0x%lx\n", injector->saved_rsp);
        printf("Restoring RAX to 0x%lx\n", injector->saved_rax);
        printf("Restoring RCX to 0x%lx\n", injector->saved_rcx);
        printf("Restoring RDX to 0x%lx\n", injector->saved_rdx);
        printf("Restoring R8 to 0x%lx\n", injector->saved_r8);
        printf("Restoring R9 to 0x%lx\n", injector->saved_r9);

        vmi_set_vcpureg(vmi, injector->saved_rsp, RSP, event->vcpu_id);
        vmi_set_vcpureg(vmi, injector->saved_rax, RAX, event->vcpu_id);
        vmi_set_vcpureg(vmi, injector->saved_rcx, RCX, event->vcpu_id);
        vmi_set_vcpureg(vmi, injector->saved_rdx, RDX, event->vcpu_id);
        vmi_set_vcpureg(vmi, injector->saved_r8, R8, event->vcpu_id);
        vmi_set_vcpureg(vmi, injector->saved_r9, R9, event->vcpu_id);

        if (rax) {
            printf("-- CreateProcessA SUCCESS --\n");

            if (PM2BIT(injector->pm) == BIT32) {
                struct process_information_32 pip;
                vmi_read_va(vmi, injector->process_info, pid, &pip,
                        sizeof(struct process_information_32));
                printf("\tProcess handle: 0x%x. Thread handle: 0x%x\n",
                        pip.hProcess, pip.hThread);
                printf("\tPID: %u. TID: %u\n", pip.dwProcessId, pip.dwThreadId);

                injector->pid = pip.dwProcessId;
                injector->tid = pip.dwThreadId;
                injector->hProc = pip.hProcess;
                injector->hThr = pip.hThread;

            } else {
                struct process_information_64 pip;
                vmi_read_va(vmi, injector->process_info, pid, &pip,
                        sizeof(struct process_information_64));
                printf("\tProcess handle: 0x%lx. Thread handle: 0x%lx\n",
                        pip.hProcess, pip.hThread);
                printf("\tPID: %u. TID: %u\n", pip.dwProcessId, pip.dwThreadId);

                injector->pid = pip.dwProcessId;
                injector->tid = pip.dwThreadId;
                injector->hProc = pip.hProcess;
                injector->hThr = pip.hThread;

            }

            if (injector->pid && injector->tid) {
                injector->ret = rax;

                injector->cr3_event.callback = waitfor_cr3_callback;
                injector->cr3_event.reg_event.equal = vmi_pid_to_dtb(vmi,
                        injector->pid);
                injector->cr3_event.data = injector;
                vmi_register_event(vmi, &injector->cr3_event);
                printf("\tInjected process CR3: 0x%lx\n",
                        injector->cr3_event.reg_event.equal);
            }
        } else {
            injector->clone->interrupted = 1;
        }

        vmi_write_8_pa(vmi, pa, &injector->backup);
        vmi_clear_event(vmi, event);

    } else {
        event->interrupt_event.reinject = 1;
    }
}
Пример #10
0
void cr3_callback(vmi_instance_t vmi, vmi_event_t *event) {

    //printf("CR3 changed to 0x%lx\n", event->reg_event.value);
    struct injector *injector = event->data;

    addr_t thread = 0, kpcrb_offset = 0, trapframe = 0;
    addr_t userspace_return_va = 0, userspace_return_pa = 0;
    reg_t fsgs = 0;

    if (event->reg_event.value == injector->target_cr3) {
        if (!injector->target_rip) {

            /* TODO: Trap frame approach only works on 64-bit */
            if (PM2BIT(injector->pm) == BIT32) {
                if(!injector->mm_enabled) {
                    vmi_pid_t pid = vmi_dtb_to_pid(vmi, event->reg_event.value);
                    addr_t waitfor = sym2va(vmi, pid, "kernel32.dll", "WaitForMultipleObjects");
                    //printf("PID %u waitfor 0x%lx\n", pid, waitfor);

                    if (!waitfor) {
                        //injector->clone->interrupted = 1;
                        printf("Target process doesn't have kernel32.dll mapped!\n");
                        return;
                    }

                    injector->mm_enabled=1;
                    memset(&injector->mm_event, 0, sizeof(vmi_event_t));
                    injector->mm_event.type = VMI_EVENT_MEMORY;
                    injector->mm_event.mem_event.physical_address = vmi_translate_uv2p(vmi, waitfor, pid);
                    injector->mm_event.mem_event.npages = 1;
                    injector->mm_event.mem_event.granularity=VMI_MEMEVENT_PAGE;
                    injector->mm_event.mem_event.in_access = VMI_MEMACCESS_X;
                    injector->mm_event.callback=mm_callback;
                    injector->mm_event.data = injector;
                    vmi_register_event(vmi, &injector->mm_event);
                }
                return;
            }

            /* Read return to userspace RIP out of the stack trap frame. */
            if (PM2BIT(injector->pm) == BIT32) {
                vmi_get_vcpureg(vmi, &fsgs, FS_BASE, event->vcpu_id);
                kpcrb_offset = offsets[KPCR_PRCBDATA];
            } else {
                vmi_get_vcpureg(vmi, &fsgs, GS_BASE, event->vcpu_id);
                kpcrb_offset = offsets[KPCR_PRCB];
            }

            vmi_read_addr_va(vmi,
                fsgs + kpcrb_offset + offsets[KPRCB_CURRENTTHREAD],
                0, &thread);
            vmi_read_addr_va(vmi,
                thread + offsets[KTHREAD_TRAPFRAME],
                0, &trapframe);

            //printf("Trap frame @ 0x%lx\n", trapframe);

            if (PM2BIT(injector->pm) == BIT32) {
                vmi_read_addr_va(vmi,
                    trapframe + offsets[KTRAP_FRAME_EIP],
                    0, &userspace_return_va);
            } else {
                vmi_read_addr_va(vmi,
                    trapframe + offsets[KTRAP_FRAME_RIP],
                    0, &userspace_return_va);
            }

            injector->userspace_return = vmi_pagetable_lookup(vmi, event->reg_event.value, userspace_return_va);
            //printf("Userspace return @ VA 0x%lx -> PA 0x%lx\n", userspace_return_va, injector->userspace_return);

            uint8_t trap = 0xCC;
            vmi_read_8_pa(vmi, injector->userspace_return, &injector->userspace_return_backup);
            vmi_write_8_pa(vmi, injector->userspace_return, &trap);

            /*if (!injector->ss_enabled) {
                printf("My target process is executing, registering singlestep\n");
                injector->ss_enabled = 1;
                memset(&injector->ss_event, 0, sizeof(vmi_event_t));
                injector->ss_event.type = VMI_EVENT_SINGLESTEP;
                injector->ss_event.callback = ss_callback;
                injector->ss_event.data = injector;
                SET_VCPU_SINGLESTEP(injector->ss_event.ss_event,
                        event->vcpu_id);
                vmi_register_event(vmi, &injector->ss_event);
            }*/
        }
    } else {
        //printf("CR3 0x%lx is executing, not my process!\n",
        //        event->reg_event.value);

        if (injector->mm_enabled) {
            injector->mm_enabled = 0;
            vmi_clear_event(vmi, &injector->mm_event);
        }
        if (injector->ss_enabled) {
            //printf("\tDisabling singlestep\n");
            injector->ss_enabled = 0;
            vmi_clear_event(vmi, &injector->ss_event);
        }

        if (injector->userspace_return) {
            vmi_write_8_pa(vmi, injector->userspace_return, &injector->userspace_return_backup);
            injector->userspace_return_backup = 0;
            injector->userspace_return = 0;
        }
    }
}
Пример #11
0
void hijack_thread(struct injector *injector, vmi_instance_t vmi,
        unsigned int vcpu, vmi_pid_t pid) {

    printf("Ready to hijack thread of PID %u on vCPU %u!\n", pid, vcpu);

    addr_t cpa = sym2va(vmi, pid, "kernel32.dll", "CreateProcessA");

    printf("CPA @ 0x%lx\n", cpa);

    reg_t fsgs, rbp, rsp, rip, rcx, rdx, rax, r8, r9;
    addr_t stack_base, stack_limit;

    vmi_get_vcpureg(vmi, &rsp, RSP, vcpu);
    vmi_get_vcpureg(vmi, &rip, RIP, vcpu);
    vmi_get_vcpureg(vmi, &rax, RAX, vcpu);
    vmi_get_vcpureg(vmi, &rcx, RCX, vcpu);
    vmi_get_vcpureg(vmi, &rdx, RDX, vcpu);
    vmi_get_vcpureg(vmi, &r8, R8, vcpu);
    vmi_get_vcpureg(vmi, &r9, R9, vcpu);

    if (injector->pm == VMI_PM_LEGACY || injector->pm == VMI_PM_PAE) {
        vmi_get_vcpureg(vmi, &fsgs, FS_BASE, vcpu);
        vmi_get_vcpureg(vmi, &rbp, RBP, vcpu);
        printf("FS: 0x%lx RBP: 0x%lx", fsgs, rbp);
        vmi_read_addr_va(vmi, fsgs + 0x4, pid, &stack_base);
        vmi_read_addr_va(vmi, fsgs + 0x8, pid, &stack_limit);
    } else {
        vmi_get_vcpureg(vmi, &fsgs, GS_BASE, vcpu);
        printf("GS: 0x%lx ", fsgs);
        vmi_read_addr_va(vmi, fsgs + 0x8, pid, &stack_base);
        vmi_read_addr_va(vmi, fsgs + 0x10, pid, &stack_limit);
    }

    printf("RSP: 0x%lx. RIP: 0x%lx. RCX: 0x%lx\n", rsp, rip, rcx);
    printf("Stack base: 0x%lx. Limit: 0x%lx\n", stack_base, stack_limit);

    //Push input arguments on the stack
    //CreateProcess(NULL, TARGETPROC,
    //                 NULL, NULL, 0, CREATE_SUSPENDED, NULL, NULL, &si, pi))

    uint64_t nul64 = 0;
    uint32_t nul32 = 0;
    uint8_t nul8 = 0;
    size_t len = strlen(injector->target_proc);
    addr_t addr = rsp;
    injector->saved_rsp = rsp;
    injector->saved_rip = rip;
    injector->saved_rax = rax;
    injector->saved_rdx = rdx;
    injector->saved_rcx = rcx;
    injector->saved_r8 = r8;
    injector->saved_r9 = r9;

    if (injector->pm == VMI_PM_LEGACY || injector->pm == VMI_PM_PAE) {

        addr -= 0x4; // the stack has to be alligned to 0x4
                     // and we need a bit of extra buffer before the string for \0
        // we just going to null out that extra space fully
        vmi_write_32_va(vmi, addr, pid, &nul32);

        // this string has to be aligned as well!
        addr -= len + 0x4 - (len % 0x4);
        addr_t str_addr = addr;
        vmi_write_va(vmi, addr, pid, (void*) injector->target_proc, len);
        // add null termination
        vmi_write_8_va(vmi, addr + len, pid, &nul8);
        printf("%s @ 0x%lx.\n", injector->target_proc, str_addr);

        //struct startup_info_32 si = {.wShowWindow = SW_SHOWDEFAULT };
        struct startup_info_32 si;
        memset(&si, 0, sizeof(struct startup_info_32));
        struct process_information_32 pi;
        memset(&pi, 0, sizeof(struct process_information_32));

        addr -= sizeof(struct process_information_32);
        injector->process_info = addr;
        vmi_write_va(vmi, addr, pid, &pi,
                sizeof(struct process_information_32));
        printf("pip @ 0x%lx\n", addr);

        addr -= sizeof(struct startup_info_32);
        addr_t sip = addr;
        vmi_write_va(vmi, addr, pid, &si, sizeof(struct startup_info_32));
        printf("sip @ 0x%lx\n", addr);

        //p10
        addr -= 0x4;
        vmi_write_32_va(vmi, addr, pid, (uint32_t *) &injector->process_info);
        //p9
        addr -= 0x4;
        vmi_write_32_va(vmi, addr, pid, (uint32_t *) &sip);
        //p8
        addr -= 0x4;
        vmi_write_32_va(vmi, addr, pid, &nul32);
        //p7
        addr -= 0x4;
        vmi_write_32_va(vmi, addr, pid, &nul32);
        //p6
        addr -= 0x4;
        vmi_write_32_va(vmi, addr, pid, &nul32);
        //p5
        addr -= 0x4;
        vmi_write_32_va(vmi, addr, pid, &nul32);
        //p4
        addr -= 0x4;
        vmi_write_32_va(vmi, addr, pid, &nul32);
        //p3
        addr -= 0x4;
        vmi_write_32_va(vmi, addr, pid, &nul32);
        //p2
        addr -= 0x4;
        vmi_write_32_va(vmi, addr, pid, (uint32_t *) &str_addr);
        //p1
        addr -= 0x4;
        vmi_write_32_va(vmi, addr, pid, &nul32);

        // save the return address (RIP)
        addr -= 0x4;
        vmi_write_32_va(vmi, addr, pid, (uint32_t *) &rip);

    } else {

        addr -= 0x8; // the stack has to be alligned to 0x8
                     // and we need a bit of extra buffer before the string for \0

        // we just going to null out that extra space fully
        vmi_write_64_va(vmi, addr, pid, &nul64);

        // this string has to be aligned as well!
        addr -= len + 0x8 - (len % 0x8);
        addr_t str_addr = addr;
        vmi_write_va(vmi, addr, pid, (void*) injector->target_proc, len);
        // add null termination
        vmi_write_8_va(vmi, addr + len, pid, &nul8);
        printf("%s @ 0x%lx.\n", injector->target_proc, str_addr);

        struct startup_info_64 si;
        memset(&si, 0, sizeof(struct startup_info_64));
        struct process_information_64 pi;
        memset(&pi, 0, sizeof(struct process_information_64));

        addr -= sizeof(struct process_information_64);
        injector->process_info = addr;
        vmi_write_va(vmi, addr, pid, &pi,
                sizeof(struct process_information_64));
        printf("pip @ 0x%lx\n", addr);

        addr -= sizeof(struct startup_info_64);
        addr_t sip = addr;
        vmi_write_va(vmi, addr, pid, &si, sizeof(struct startup_info_64));
        printf("sip @ 0x%lx\n", addr);

        //http://www.codemachine.com/presentations/GES2010.TRoy.Slides.pdf
        //
        //First 4 parameters to functions are always passed in registers
        //P1=rcx, P2=rdx, P3=r8, P4=r9
        //5th parameter onwards (if any) passed via the stack

        //p10
        addr -= 0x8;
        vmi_write_64_va(vmi, addr, pid, &injector->process_info);
        //p9
        addr -= 0x8;
        vmi_write_64_va(vmi, addr, pid, &sip);
        //p8
        addr -= 0x8;
        vmi_write_64_va(vmi, addr, pid, &nul64);
        //p7
        addr -= 0x8;
        vmi_write_64_va(vmi, addr, pid, &nul64);
        //p6
        addr -= 0x8;
        vmi_write_64_va(vmi, addr, pid, &nul64);
        //p5
        addr -= 0x8;
        vmi_write_64_va(vmi, addr, pid, &nul64);

        // allocate 0x20 "homing space"
        addr -= 0x8;
        vmi_write_64_va(vmi, addr, pid, &nul64);
        addr -= 0x8;
        vmi_write_64_va(vmi, addr, pid, &nul64);
        addr -= 0x8;
        vmi_write_64_va(vmi, addr, pid, &nul64);
        addr -= 0x8;
        vmi_write_64_va(vmi, addr, pid, &nul64);

        //p1
        vmi_set_vcpureg(vmi, 0, RCX, vcpu);
        //p2
        vmi_set_vcpureg(vmi, str_addr, RDX, vcpu);
        //p3
        vmi_set_vcpureg(vmi, 0, R8, vcpu);
        //p4
        vmi_set_vcpureg(vmi, 0, R9, vcpu);

        // save the return address (RIP)
        addr -= 0x8;
        vmi_write_64_va(vmi, addr, pid, &rip);
    }

    printf("Return address @ 0x%lx -> 0x%lx. Setting RSP: 0x%lx.\n", addr, rip,
            addr);

    // Grow the stack and switch execution
    vmi_set_vcpureg(vmi, addr, RSP, vcpu);
    vmi_set_vcpureg(vmi, cpa, RIP, vcpu);

    printf("Done with hijack routine\n");
}
Пример #12
0
int main (int argc, char **argv)
{
    vmi_instance_t vmi = NULL;
    status_t status = VMI_SUCCESS;

    struct sigaction act;

    mm_enabled=0;

    char *name = NULL;

    if(argc < 2){
        fprintf(stderr, "Usage: %s <name of VM>\n", argv[0]);
        exit(1);
    }

    // Arg 1 is the VM name.
    name = argv[1];

    /* for a clean exit */
    act.sa_handler = close_handler;
    act.sa_flags = 0;
    sigemptyset(&act.sa_mask);
    sigaction(SIGHUP,  &act, NULL);
    sigaction(SIGTERM, &act, NULL);
    sigaction(SIGINT,  &act, NULL);
    sigaction(SIGALRM, &act, NULL);

    // Initialize the libvmi library.
    if (vmi_init(&vmi, VMI_XEN | VMI_INIT_COMPLETE | VMI_INIT_EVENTS, name) == VMI_FAILURE){
        printf("Failed to init LibVMI library.\n");
        if (vmi != NULL ) {
            vmi_destroy(vmi);
        }
        return 1;
    }
    else{
        printf("LibVMI init succeeded!\n");
    }

    vmi_pause_vm(vmi);

    SETUP_REG_EVENT(&cr3_event, CR3, VMI_REGACCESS_W, 0, cr3_callback);
    vmi_register_event(vmi, &cr3_event);

    // Setup a mem event for tracking memory at the current instruction's page
    // But don't install it; that will be done by the cr3 handler.

    vmi_get_vcpureg(vmi, &rip, RIP, 0);
    vmi_get_vcpureg(vmi, &cr3, CR3, 0);

    printf("Current value of RIP is 0x%lx\n", rip);
    rip -= 0x1;

    pid = vmi_dtb_to_pid(vmi, cr3);
    if(pid==4) {
        rip_pa = vmi_translate_uv2p(vmi, rip, pid);
    } else {
        rip_pa = vmi_translate_kv2p(vmi, rip);
    }

    printf("Preparing memory event to catch next RIP 0x%lx, PA 0x%lx, page 0x%lx for PID %u\n",
            rip, rip_pa, rip_pa >> 12, pid);
    SETUP_MEM_EVENT(&mm_event, rip_pa, VMI_MEMEVENT_PAGE, VMI_MEMACCESS_X, mm_callback);

    vmi_resume_vm(vmi);

    while(!interrupted){
        status = vmi_events_listen(vmi,500);
        if (status != VMI_SUCCESS) {
            printf("Error waiting for events, quitting...\n");
            interrupted = -1;
        }
    }
    printf("Finished with test.\n");

leave:
    // cleanup any memory associated with the libvmi instance
    vmi_destroy(vmi);

    return 0;
}
Пример #13
0
int main (int argc, char **argv)
{
    vmi_instance_t vmi = NULL;
    status_t status = VMI_SUCCESS;

    struct sigaction act;

    reg_t lstar = 0;
    addr_t phys_lstar = 0;
    reg_t cstar = 0;
    addr_t phys_cstar = 0;
    reg_t sysenter_ip = 0;
    addr_t phys_sysenter_ip = 0;

    addr_t ia32_sysenter_target = 0;
    addr_t phys_ia32_sysenter_target = 0;
    addr_t vsyscall = 0;
    addr_t phys_vsyscall = 0;

    char *name = NULL;
    vmi_pid_t pid = -1;

    if(argc < 2){
        fprintf(stderr, "Usage: events_example <name of VM> <PID of process to track {optional}>\n");
        exit(1);
    }

    // Arg 1 is the VM name.
    name = argv[1];

    // Arg 2 is the pid of the process to track.
    if(argc == 3)
        pid = (int) strtoul(argv[2], NULL, 0);

    /* for a clean exit */
    act.sa_handler = close_handler;
    act.sa_flags = 0;
    sigemptyset(&act.sa_mask);
    sigaction(SIGHUP,  &act, NULL);
    sigaction(SIGTERM, &act, NULL);
    sigaction(SIGINT,  &act, NULL);
    sigaction(SIGALRM, &act, NULL);

    // Initialize the libvmi library.
    if (vmi_init(&vmi, VMI_XEN | VMI_INIT_COMPLETE | VMI_INIT_EVENTS, name) == VMI_FAILURE){
        printf("Failed to init LibVMI library.\n");
        if (vmi != NULL ) {
            vmi_destroy(vmi);
        }
        return 1;
    }
    else{
        printf("LibVMI init succeeded!\n");
    }

    // Get the cr3 for this process.
    if(pid != -1) {
        cr3 = vmi_pid_to_dtb(vmi, pid);
        printf("CR3 for process (%d) == %llx\n", pid, (unsigned long long)cr3);
    }

    // Get the value of lstar and cstar for the system.
    // NOTE: all vCPUs have the same value for these registers
    vmi_get_vcpureg(vmi, &lstar, MSR_LSTAR, 0);
    vmi_get_vcpureg(vmi, &cstar, MSR_CSTAR, 0);
    vmi_get_vcpureg(vmi, &sysenter_ip, SYSENTER_EIP, 0);
    printf("vcpu 0 MSR_LSTAR == %llx\n", (unsigned long long)lstar);
    printf("vcpu 0 MSR_CSTAR == %llx\n", (unsigned long long)cstar);
    printf("vcpu 0 MSR_SYSENTER_IP == %llx\n", (unsigned long long)sysenter_ip);

    ia32_sysenter_target = vmi_translate_ksym2v(vmi, "ia32_sysenter_target");
    printf("ksym ia32_sysenter_target == %llx\n", (unsigned long long)ia32_sysenter_target);

    /* Per Linux ABI, this VA represents the start of the vsyscall page 
     *  If vsyscall support is enabled (deprecated or disabled on many newer 
     *  3.0+ kernels), it is accessible at this address in every process.
     */ 
    vsyscall = 0xffffffffff600000;

    // Translate to a physical address.
    phys_lstar= vmi_translate_kv2p(vmi, lstar);
    printf("Physical LSTAR == %llx\n", (unsigned long long)phys_lstar);

    phys_cstar= vmi_translate_kv2p(vmi, cstar);
    printf("Physical CSTAR == %llx\n", (unsigned long long)phys_cstar);

    phys_sysenter_ip= vmi_translate_kv2p(vmi, sysenter_ip);
    printf("Physical SYSENTER_IP == %llx\n", (unsigned long long)phys_sysenter_ip);

    phys_ia32_sysenter_target = vmi_translate_kv2p(vmi,ia32_sysenter_target);
    printf("Physical ia32_sysenter_target == %llx\n", (unsigned long long)ia32_sysenter_target);
    phys_vsyscall = vmi_translate_kv2p(vmi,vsyscall);
    printf("Physical phys_vsyscall == %llx\n", (unsigned long long)phys_vsyscall);


    // Get only the page that the handler starts.
    printf("LSTAR Physical PFN == %llx\n", (unsigned long long)(phys_lstar >> 12));
    printf("CSTAR Physical PFN == %llx\n", (unsigned long long)(phys_cstar >> 12));
    printf("SYSENTER_IP Physical PFN == %llx\n", (unsigned long long)(phys_sysenter_ip >> 12));
    printf("phys_vsyscall Physical PFN == %llx\n", (unsigned long long)(phys_vsyscall >> 12));
    printf("phys_ia32_sysenter_target Physical PFN == %llx\n", (unsigned long long)(phys_ia32_sysenter_target >> 12));

    /* Configure an event to track when the process is running.
     * (The CR3 register is updated on task context switch, allowing
     *  us to follow as various tasks are scheduled and run upon the CPU)
     */
    memset(&cr3_event, 0, sizeof(vmi_event_t));
    cr3_event.type = VMI_EVENT_REGISTER;
    cr3_event.reg_event.reg = CR3;

    /* Observe only write events to the given register. 
     *   NOTE: read events are unsupported at this time.
     */
    cr3_event.reg_event.in_access = VMI_REGACCESS_W;

    /* Optional (default = 0): Trigger on change 
     *  Causes events to be delivered by the hypervisor to this monitoring
     *   program if and only if the register value differs from that previously 
     *   observed.
     *  Usage: cr3_event.reg_event.onchange = 1;
     *
     * Optional (default = 0): Asynchronous event delivery
     *  Causes events to be delivered by the hypervisor to this monitoring
     *   program if and only if the register value differs from that previously
     *   observed.
     *  Usage: cr3_event.reg_event.async =1;
     */

    if(pid == -1){
        cr3_event.callback = cr3_all_tasks_callback;
        vmi_register_event(vmi, &cr3_event);
    } else {
        cr3_event.callback = cr3_one_task_callback;
        /* This acts as a filter: if the CR3 value at time of event == the CR3
         *  we wish to inspect, then the callback will be invoked. Otherwise,
         *  no action is taken.
         */
        cr3_event.reg_event.equal = cr3;
        vmi_register_event(vmi, &cr3_event);
    }

    // Setup a default event for tracking memory at the syscall handler.
    // But don't install it; that will be done by the cr3 handler.
    memset(&msr_syscall_sysenter_event, 0, sizeof(vmi_event_t));
    msr_syscall_sysenter_event.type = VMI_EVENT_MEMORY;
    msr_syscall_sysenter_event.mem_event.physical_address = phys_sysenter_ip;
    msr_syscall_sysenter_event.mem_event.npages = 1;
    msr_syscall_sysenter_event.mem_event.granularity=VMI_MEMEVENT_PAGE;

    memset(&kernel_sysenter_target_event, 0, sizeof(vmi_event_t));
    kernel_sysenter_target_event.type = VMI_EVENT_MEMORY;
    kernel_sysenter_target_event.mem_event.physical_address = phys_ia32_sysenter_target;
    kernel_sysenter_target_event.mem_event.npages = 1;
    kernel_sysenter_target_event.mem_event.granularity=VMI_MEMEVENT_PAGE;

    memset(&kernel_vsyscall_event, 0, sizeof(vmi_event_t));
    kernel_vsyscall_event.type = VMI_EVENT_MEMORY;
    kernel_vsyscall_event.mem_event.physical_address = phys_vsyscall;
    kernel_vsyscall_event.mem_event.npages = 1;
    kernel_vsyscall_event.mem_event.granularity=VMI_MEMEVENT_PAGE;

    while(!interrupted){
        printf("Waiting for events...\n");
        status = vmi_events_listen(vmi,500);
        if (status != VMI_SUCCESS) {
            printf("Error waiting for events, quitting...\n");
            interrupted = -1;
        }
    }
    printf("Finished with test.\n");

leave:
    // cleanup any memory associated with the libvmi instance
    vmi_destroy(vmi);

    return 0;
}
Пример #14
0
int main (int argc, char **argv)
{
    vmi_instance_t vmi = NULL;
    status_t status = VMI_SUCCESS;

    struct sigaction act;

    reg_t lstar = 0;
    addr_t phys_lstar = 0;
    reg_t cstar = 0;
    addr_t phys_cstar = 0;
    reg_t sysenter_ip = 0;
    addr_t phys_sysenter_ip = 0;

    addr_t ia32_sysenter_target = 0;
    addr_t phys_ia32_sysenter_target = 0;
    addr_t vsyscall = 0;
    addr_t phys_vsyscall = 0;

    char *name = NULL;
    vmi_pid_t pid = -1;

    if(argc < 2){
        fprintf(stderr, "Usage: events_example <name of VM> <PID of process to track {optional}>\n");
        exit(1);
    }

    // Arg 1 is the VM name.
    name = argv[1];

    // Arg 2 is the pid of the process to track.
    if(argc == 3)
        pid = (int) strtoul(argv[2], NULL, 0);

    /* for a clean exit */
    act.sa_handler = close_handler;
    act.sa_flags = 0;
    sigemptyset(&act.sa_mask);
    sigaction(SIGHUP,  &act, NULL);
    sigaction(SIGTERM, &act, NULL);
    sigaction(SIGINT,  &act, NULL);
    sigaction(SIGALRM, &act, NULL);

    // Initialize the libvmi library. //具体哪个虚拟机 由传入的参数决定
    if (vmi_init(&vmi, VMI_XEN | VMI_INIT_COMPLETE | VMI_INIT_EVENTS, name) == VMI_FAILURE){
        printf("Failed to init LibVMI library.\n");
        if (vmi != NULL ) {
            vmi_destroy(vmi);
        }
        return 1;
    }
    else{
        printf("LibVMI init succeeded!\n");
    }

    // Get the cr3 for this process.
    /*
addr_t vmi_pid_to_dtb (vmi_instance_t vmi, vmi_pid_t pid)
Given a pid, this function returns the virtual address of the directory table base for this process' address space. 
This value is effectively what would be in the CR3 register while this process is running.

Parameters

[in] vmi LibVMI instance
[in] pid Desired process id to lookup
Returns

OrderedDict([(u'emphasis', u'pid'), ('#text', u'The directory table base virtual address for')])
    */
    if(pid != -1) {
        cr3 = vmi_pid_to_dtb(vmi, pid);  //虚拟机句柄和进程id  进程基地址
        printf("CR3 for process (%d) == %llx\n", pid, (unsigned long long)cr3);
    }

    // Get the value of lstar and cstar for the system.
    // NOTE: all vCPUs have the same value for these registers
    //status_t vmi_get_vcpureg (vmi_instance_t vmi, reg_t *value, registers_t reg, unsigned long vcpu)
  
  //获取特定寄存器值
    vmi_get_vcpureg(vmi, &lstar, MSR_LSTAR, 0); 
    vmi_get_vcpureg(vmi, &cstar, MSR_CSTAR, 0);
    vmi_get_vcpureg(vmi, &sysenter_ip, SYSENTER_EIP, 0);
  
  //在调用SYSENTER指令前,软件必须通过下面的MSR寄存器,指定0层的代码段和代码指针,0层的堆栈段和堆栈指针:
    printf("vcpu 0 MSR_LSTAR == %llx\n", (unsigned long long)lstar);
    printf("vcpu 0 MSR_CSTAR == %llx\n", (unsigned long long)cstar);
    printf("vcpu 0 MSR_SYSENTER_IP == %llx\n", (unsigned long long)sysenter_ip);

/*
addr_t vmi_translate_ksym2v (vmi_instance_t vmi, const char *symbol)
Performs the translation from a kernel symbol to a virtual address.

Parameters

[in] vmi LibVMI instance
[in] symbol Desired kernel symbol to translate
Returns

Virtual address, or zero on error
*/
    ia32_sysenter_target = vmi_translate_ksym2v(vmi, "ia32_sysenter_target");
    printf("ksym ia32_sysenter_target == %llx\n", (unsigned long long)ia32_sysenter_target);
//??? 返回结果为0 岂不是发生了error


    /* Per Linux ABI, this VA represents the start of the vsyscall page 
     *  If vsyscall support is enabled (deprecated or disabled on many newer 
     *  3.0+ kernels), it is accessible at this address in every process.
     */ 
    vsyscall = 0xffffffffff600000;

    // Translate to a physical address.
    phys_lstar= vmi_translate_kv2p(vmi, lstar);
    printf("Physical LSTAR == %llx0\n", (unsigned long long)phys_lstar);

    phys_cstar= vmi_translate_kv2p(vmi, cstar);
    printf("Physical CSTAR == %llx\n", (unsigned long long)phys_cstar);

    phys_sysenter_ip= vmi_translate_kv2p(vmi, sysenter_ip);
    printf("Physical SYSENTER_IP == %llx\n", (unsigned long long)phys_sysenter_ip);

    phys_ia32_sysenter_target = vmi_translate_kv2p(vmi,ia32_sysenter_target);
    printf("Physical ia32_sysenter_target == %llx\n", (unsigned long long)ia32_sysenter_target);
    /*
http://www.longene.org/forum/viewtopic.php?f=5&t=8851
在x86结构中,较新的CPU都提供了sysenter/sysexit指令,专门用于系统调用的进入和退出,由于去掉了一些不必要的检查,它的速度比以前的int指令要快。
因此在新的Linux系统中,大部分系统调用都采用了sysenter代替原来的int 80。除了一些比较慢的系统调用,如clone、execve等少数几个,因为对于这种系统调用,
进入/退出内核空间所费的时钟周期,相对于其处理时间,几乎可以忽略不计。
考虑到和glibc的对接问题,现在glibc中不直接调用int 80或者sysenter。而是采用vdso方式,在内核中生成一个页面,用于系统调用,
叫做vsyscall,在load_elf_binary时,会将其映射到用户空间,glibc直接调用其中的函数。

关于sysenter的一些资料,可以看这里http://www.cnblogs.com/yangnas/archive/2010/04/28/1723232.html
    */
    phys_vsyscall = vmi_translate_kv2p(vmi,vsyscall);
    printf("Physical phys_vsyscall == %llx\n", (unsigned long long)phys_vsyscall);


    // Get only the page that the handler starts.
    printf("LSTAR Physical PFN == %llx\n", (unsigned long long)(phys_lstar >> 12));
    printf("CSTAR Physical PFN == %llx\n", (unsigned long long)(phys_cstar >> 12));
    printf("SYSENTER_IP Physical PFN == %llx\n", (unsigned long long)(phys_sysenter_ip >> 12));
    printf("phys_vsyscall Physical PFN == %llx\n", (unsigned long long)(phys_vsyscall >> 12));
    printf("phys_ia32_sysenter_target Physical PFN == %llx\n", (unsigned long long)(phys_ia32_sysenter_target >> 12));

    /* Configure an event to track when the process is running.
     * (The CR3 register is updated on task context switch, allowing
     *  us to follow as various tasks are scheduled and run upon the CPU)
     */
    memset(&cr3_event, 0, sizeof(vmi_event_t));
    cr3_event.type = VMI_EVENT_REGISTER;
    cr3_event.reg_event.reg = CR3;

    /* Observe only write events to the given register. 
     *   NOTE: read events are unsupported at this time.
     */
    cr3_event.reg_event.in_access = VMI_REGACCESS_W;

    /* Optional (default = 0): Trigger on change 
     *  Causes events to be delivered by the hypervisor to this monitoring
     *   program if and only if the register value differs from that previously 
     *   observed.
     *  Usage: cr3_event.reg_event.onchange = 1;
     *
     * Optional (default = 0): Asynchronous event delivery
     *  Causes events to be delivered by the hypervisor to this monitoring
     *   program if and only if the register value differs from that previously
     *   observed.
     *  Usage: cr3_event.reg_event.async =1;
     */


//重要 注册事件 回调函数
    if(pid == -1){  //如果没加参数  就为-1
        cr3_event.callback = cr3_all_tasks_callback;
        vmi_register_event(vmi, &cr3_event);
    }
    else {
        cr3_event.callback = cr3_one_task_callback;
        /* This acts as a filter: if the CR3 value at time of event == the CR3
         *  we wish to inspect, then the callback will be invoked. Otherwise,
         *  no action is taken.
         */
         //只有当事件发生时,cr3的值等于我们一开始注册的进程的cr3值,才会调用回调函数
        cr3_event.reg_event.equal = cr3;            //保存原始的cr3的值
        vmi_register_event(vmi, &cr3_event);
    }


//设置内存事件,在cr3的事件处理函数中进行绑定
    // Setup a default event for tracking memory at the syscall handler.
    // But don't install it; that will be done by the cr3 handler.
    memset(&msr_syscall_sysenter_event, 0, sizeof(vmi_event_t));
    msr_syscall_sysenter_event.type = VMI_EVENT_MEMORY; 
    msr_syscall_sysenter_event.mem_event.physical_address = phys_sysenter_ip;
    msr_syscall_sysenter_event.mem_event.npages = 1;
    msr_syscall_sysenter_event.mem_event.granularity=VMI_MEMEVENT_PAGE;

    memset(&kernel_sysenter_target_event, 0, sizeof(vmi_event_t));
    kernel_sysenter_target_event.type = VMI_EVENT_MEMORY;
    kernel_sysenter_target_event.mem_event.physical_address = phys_ia32_sysenter_target;
    kernel_sysenter_target_event.mem_event.npages = 1;
    kernel_sysenter_target_event.mem_event.granularity=VMI_MEMEVENT_PAGE;

    memset(&kernel_vsyscall_event, 0, sizeof(vmi_event_t));
    kernel_vsyscall_event.type = VMI_EVENT_MEMORY;
    kernel_vsyscall_event.mem_event.physical_address = phys_vsyscall;
    kernel_vsyscall_event.mem_event.npages = 1;
    kernel_vsyscall_event.mem_event.granularity=VMI_MEMEVENT_PAGE;

    while(!interrupted){
        printf("Waiting for events...\n");
        status = vmi_events_listen(vmi,500); //监听指定的虚拟机  虚拟机上绑定了特定的监听事件
        if (status != VMI_SUCCESS) {
            printf("Error waiting for events, quitting...\n");
            interrupted = -1;
        }
    }
    printf("Finished with test.\n");

leave:
    // cleanup any memory associated with the libvmi instance
    vmi_destroy(vmi);

    return 0;
}