// TODO: taskswitch handling static void save_state_to_tss32(CPUState *cpu, struct x86_tss_segment32 *tss) { X86CPU *x86_cpu = X86_CPU(cpu); CPUX86State *env = &x86_cpu->env; /* CR3 and ldt selector are not saved intentionally */ tss->eip = EIP(env); tss->eflags = EFLAGS(env); tss->eax = EAX(env); tss->ecx = ECX(env); tss->edx = EDX(env); tss->ebx = EBX(env); tss->esp = ESP(env); tss->ebp = EBP(env); tss->esi = ESI(env); tss->edi = EDI(env); tss->es = vmx_read_segment_selector(cpu, R_ES).sel; tss->cs = vmx_read_segment_selector(cpu, R_CS).sel; tss->ss = vmx_read_segment_selector(cpu, R_SS).sel; tss->ds = vmx_read_segment_selector(cpu, R_DS).sel; tss->fs = vmx_read_segment_selector(cpu, R_FS).sel; tss->gs = vmx_read_segment_selector(cpu, R_GS).sel; }
static int _mmap_data(int pid, size_t len, void *base_address, int protections, int flags, void **out) { int ret = 0; unsigned char *shellcode = NULL; FILE *f = fopen(MMAP_ASM, "rb"); CHECK(f, "Error opening " MMAP_ASM); CHECK(fseek(f, 0, SEEK_END) == 0, "fseek error"); long shellcode_len = ftell(f); CHECK(shellcode_len > 0, "ftell error"); // align shellcode size to 32/64-bit boundary long shellcode_len_aligned = shellcode_len + (sizeof(void*) - (shellcode_len % sizeof(void*))); CHECK(fseek(f, 0, SEEK_SET) == 0, "fseek error"); shellcode = malloc(shellcode_len_aligned); memset(shellcode, 0x90, shellcode_len_aligned); // fill with NOPs CHECK(shellcode, "malloc error"); size_t r = fread(shellcode, 1, shellcode_len, f); CHECK(r == (size_t)shellcode_len, "fread error: %ld %ld", r, shellcode_len); fclose(f); // get current registers struct user_regs_struct orig_regs, regs = {0}; CHECK(ptrace_getregs(pid, ®s), "Failed to get registers of target process"); orig_regs = regs; // put our arguments in the proper registers (see mmap{64,32}.asm) #ifdef __i386__ regs.ebx = (long)base_address; regs.ecx = (long)len; regs.edx = (long)((protections) ? protections : MMAP_PROTS); regs.esi = (long)((flags) ? flags : MMAP_FLAGS); #elif defined(__x86_64__) regs.rdi = (unsigned long long)base_address; regs.rsi = (unsigned long long)len; regs.rdx = (unsigned long long)((protections) ? protections : MMAP_PROTS); regs.r10 = (unsigned long long)((flags) ? flags : MMAP_FLAGS); #endif CHECK(ptrace_setregs(pid, ®s), "Failed to set registers of target process"); dprintf("Wrote our shellcode parameters into process registers"); // write mmap code to target process EIP CHECK(ptrace_writemem(pid, (void*)EIP(®s), shellcode, shellcode_len_aligned), "Failed to write mmap code to target process"); dprintf("Wrote mmap code to EIP %p", (void*)EIP(®s)); // run mmap code and check return value CHECK(ptrace_continue(pid, 0), "Failed to execute mmap code"); CHECK(_wait_trap(pid), "Error waiting for interrupt"); dprintf("Mmap() finished execution"); // get return value from mmap() CHECK(ptrace_getregs(pid, ®s), "Failed to get registers of target process"); *out = (void*)EAX(®s); dprintf("Mmap() returned %p", *out); CHECK(*out != MAP_FAILED, "Mmap() returned error"); // restore registers CHECK(ptrace_setregs(pid, &orig_regs), "Failed to restore registers of target process"); dprintf("Restored registers of target process"); ret = 1; error: if (shellcode) free(shellcode); return ret; }
static int _launch_payload(int pid, void *code_cave, size_t code_cave_size, void *stack_address, size_t stack_size, void *payload_address, size_t payload_len, void *payload_param, int flags) { int ret = 0; unsigned char *shellcode = NULL; FILE *f = fopen(CLONE_ASM, "rb"); CHECK(f, "Error opening " CLONE_ASM); CHECK(fseek(f, 0, SEEK_END) == 0, "fseek error"); long shellcode_len = ftell(f); CHECK(shellcode_len > 0, "ftell error"); CHECK(shellcode_len <= code_cave_size, "Shellcode is too big (%ld) for allocated code cave", shellcode_len); CHECK(fseek(f, 0, SEEK_SET) == 0, "fseek error"); shellcode = malloc(code_cave_size); CHECK(shellcode, "malloc error"); memset(shellcode, 0x90, code_cave_size); // fill with NOPs size_t r = fread(shellcode, 1, shellcode_len, f); CHECK(r == (size_t)shellcode_len, "fread error: %ld %ld", r, shellcode_len); fclose(f); // get current registers struct user_regs_struct regs = {0}; CHECK(ptrace_getregs(pid, ®s), "Failed to get registers of target process"); // put our arguments in the proper registers (see clone{64,32}.asm) #ifdef __i386__ regs.eax = (long)code_cave_size; regs.ebx = (long)((flags) ? flags : CLONE_FLAGS); regs.ecx = (long)stack_address; regs.edx = (long)stack_size; regs.esi = (long)payload_address; regs.edi = (long)payload_len; regs.ebp = (long)payload_param; #elif defined(__x86_64__) regs.rax = (unsigned long long)code_cave_size; regs.rdi = (unsigned long long)((flags) ? flags : CLONE_FLAGS); regs.rsi = (unsigned long long)stack_address; regs.rdx = (unsigned long long)stack_size; regs.rcx = (unsigned long long)payload_address; regs.r8 = (unsigned long long)payload_len; regs.r9 = (unsigned long long)payload_param; #endif // move EIP to our code cave EIP(®s) = ADDR2INT(code_cave); CHECK(ptrace_setregs(pid, ®s), "Failed to set registers of target process"); dprintf("Wrote our shellcode parameters into process registers. EIP: %p", code_cave); // write shellcode to target process code cave CHECK(ptrace_writemem(pid, code_cave, shellcode, code_cave_size), "Failed to write clone trampoline code to target process"); dprintf("Wrote clone trampoline code to address %p", code_cave); // run shellcode and check return value CHECK(ptrace_continue(pid, code_cave), "Failed to execute clone trampoline code"); CHECK(_wait_trap(pid), "Error waiting for interrupt"); dprintf("Clone() finished execution"); CHECK(ptrace_getregs(pid, ®s), "Failed to get registers of target process"); dprintf("New thread ID: %lld", EAX(®s)); CHECK((int)EAX(®s) != -1, "Clone() returned error"); // no need to restore registers, as we're about to call _restore_state() dprintf("Successfully launched payload"); ret = 1; error: if (ret == 0) dprintf("Failed to launch payload"); if (shellcode) free(shellcode); return ret; }