📄 test-i386.c
字号:
{ r->esp = (r->esp & ~0xffff) | ((r->esp - 2) & 0xffff); *(uint16_t *)seg_to_linear(r->ss, r->esp) = val;}#undef __syscall_return#define __syscall_return(type, res) \do { \ return (type) (res); \} while (0)_syscall2(int, vm86, int, func, struct vm86plus_struct *, v86)extern char vm86_code_start;extern char vm86_code_end;#define VM86_CODE_CS 0x100#define VM86_CODE_IP 0x100void test_vm86(void){ struct vm86plus_struct ctx; struct vm86_regs *r; uint8_t *vm86_mem; int seg, ret; vm86_mem = mmap((void *)0x00000000, 0x110000, PROT_WRITE | PROT_READ | PROT_EXEC, MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0); if (vm86_mem == MAP_FAILED) { printf("ERROR: could not map vm86 memory"); return; } memset(&ctx, 0, sizeof(ctx)); /* init basic registers */ r = &ctx.regs; r->eip = VM86_CODE_IP; r->esp = 0xfffe; seg = VM86_CODE_CS; r->cs = seg; r->ss = seg; r->ds = seg; r->es = seg; r->fs = seg; r->gs = seg; r->eflags = VIF_MASK; /* move code to proper address. We use the same layout as a .com dos program. */ memcpy(vm86_mem + (VM86_CODE_CS << 4) + VM86_CODE_IP, &vm86_code_start, &vm86_code_end - &vm86_code_start); /* mark int 0x21 as being emulated */ set_bit((uint8_t *)&ctx.int_revectored, 0x21); for(;;) { ret = vm86(VM86_ENTER, &ctx); switch(VM86_TYPE(ret)) { case VM86_INTx: { int int_num, ah, v; int_num = VM86_ARG(ret); if (int_num != 0x21) goto unknown_int; ah = (r->eax >> 8) & 0xff; switch(ah) { case 0x00: /* exit */ goto the_end; case 0x02: /* write char */ { uint8_t c = r->edx; putchar(c); } break; case 0x09: /* write string */ { uint8_t c, *ptr; ptr = seg_to_linear(r->ds, r->edx); for(;;) { c = *ptr++; if (c == '$') break; putchar(c); } r->eax = (r->eax & ~0xff) | '$'; } break; case 0xff: /* extension: write eflags number in edx */ v = (int)r->edx;#ifndef LINUX_VM86_IOPL_FIX v &= ~0x3000;#endif printf("%08x\n", v); break; default: unknown_int: printf("unsupported int 0x%02x\n", int_num); goto the_end; } } break; case VM86_SIGNAL: /* a signal came, we just ignore that */ break; case VM86_STI: break; default: printf("ERROR: unhandled vm86 return code (0x%x)\n", ret); goto the_end; } } the_end: printf("VM86 end\n"); munmap(vm86_mem, 0x110000);}#endif/* exception tests */#if defined(__i386__) && !defined(REG_EAX)#define REG_EAX EAX#define REG_EBX EBX#define REG_ECX ECX#define REG_EDX EDX#define REG_ESI ESI#define REG_EDI EDI#define REG_EBP EBP#define REG_ESP ESP#define REG_EIP EIP#define REG_EFL EFL#define REG_TRAPNO TRAPNO#define REG_ERR ERR#endif#if defined(__x86_64__)#define REG_EIP REG_RIP#endifjmp_buf jmp_env;int v1;int tab[2];void sig_handler(int sig, siginfo_t *info, void *puc){ struct ucontext *uc = puc; printf("si_signo=%d si_errno=%d si_code=%d", info->si_signo, info->si_errno, info->si_code); printf(" si_addr=0x%08lx", (unsigned long)info->si_addr); printf("\n"); printf("trapno=" FMTLX " err=" FMTLX, (long)uc->uc_mcontext.gregs[REG_TRAPNO], (long)uc->uc_mcontext.gregs[REG_ERR]); printf(" EIP=" FMTLX, (long)uc->uc_mcontext.gregs[REG_EIP]); printf("\n"); longjmp(jmp_env, 1);}void test_exceptions(void){ struct sigaction act; volatile int val; act.sa_sigaction = sig_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO | SA_NODEFER; sigaction(SIGFPE, &act, NULL); sigaction(SIGILL, &act, NULL); sigaction(SIGSEGV, &act, NULL); sigaction(SIGBUS, &act, NULL); sigaction(SIGTRAP, &act, NULL); /* test division by zero reporting */ printf("DIVZ exception:\n"); if (setjmp(jmp_env) == 0) { /* now divide by zero */ v1 = 0; v1 = 2 / v1; }#if !defined(__x86_64__) printf("BOUND exception:\n"); if (setjmp(jmp_env) == 0) { /* bound exception */ tab[0] = 1; tab[1] = 10; asm volatile ("bound %0, %1" : : "r" (11), "m" (tab[0])); }#endif#ifdef TEST_SEGS printf("segment exceptions:\n"); if (setjmp(jmp_env) == 0) { /* load an invalid segment */ asm volatile ("movl %0, %%fs" : : "r" ((0x1234 << 3) | 1)); } if (setjmp(jmp_env) == 0) { /* null data segment is valid */ asm volatile ("movl %0, %%fs" : : "r" (3)); /* null stack segment */ asm volatile ("movl %0, %%ss" : : "r" (3)); } { struct modify_ldt_ldt_s ldt; ldt.entry_number = 1; ldt.base_addr = (unsigned long)&seg_data1; ldt.limit = (sizeof(seg_data1) + 0xfff) >> 12; ldt.seg_32bit = 1; ldt.contents = MODIFY_LDT_CONTENTS_DATA; ldt.read_exec_only = 0; ldt.limit_in_pages = 1; ldt.seg_not_present = 1; ldt.useable = 1; modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ if (setjmp(jmp_env) == 0) { /* segment not present */ asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1))); } }#endif /* test SEGV reporting */ printf("PF exception:\n"); if (setjmp(jmp_env) == 0) { val = 1; /* we add a nop to test a weird PC retrieval case */ asm volatile ("nop"); /* now store in an invalid address */ *(char *)0x1234 = 1; } /* test SEGV reporting */ printf("PF exception:\n"); if (setjmp(jmp_env) == 0) { val = 1; /* read from an invalid address */ v1 = *(char *)0x1234; } /* test illegal instruction reporting */ printf("UD2 exception:\n"); if (setjmp(jmp_env) == 0) { /* now execute an invalid instruction */ asm volatile("ud2"); } printf("lock nop exception:\n"); if (setjmp(jmp_env) == 0) { /* now execute an invalid instruction */ asm volatile("lock nop"); } printf("INT exception:\n"); if (setjmp(jmp_env) == 0) { asm volatile ("int $0xfd"); } if (setjmp(jmp_env) == 0) { asm volatile ("int $0x01"); } if (setjmp(jmp_env) == 0) { asm volatile (".byte 0xcd, 0x03"); } if (setjmp(jmp_env) == 0) { asm volatile ("int $0x04"); } if (setjmp(jmp_env) == 0) { asm volatile ("int $0x05"); } printf("INT3 exception:\n"); if (setjmp(jmp_env) == 0) { asm volatile ("int3"); } printf("CLI exception:\n"); if (setjmp(jmp_env) == 0) { asm volatile ("cli"); } printf("STI exception:\n"); if (setjmp(jmp_env) == 0) { asm volatile ("cli"); }#if !defined(__x86_64__) printf("INTO exception:\n"); if (setjmp(jmp_env) == 0) { /* overflow exception */ asm volatile ("addl $1, %0 ; into" : : "r" (0x7fffffff)); }#endif printf("OUTB exception:\n"); if (setjmp(jmp_env) == 0) { asm volatile ("outb %%al, %%dx" : : "d" (0x4321), "a" (0)); } printf("INB exception:\n"); if (setjmp(jmp_env) == 0) { asm volatile ("inb %%dx, %%al" : "=a" (val) : "d" (0x4321)); } printf("REP OUTSB exception:\n"); if (setjmp(jmp_env) == 0) { asm volatile ("rep outsb" : : "d" (0x4321), "S" (tab), "c" (1)); } printf("REP INSB exception:\n"); if (setjmp(jmp_env) == 0) { asm volatile ("rep insb" : : "d" (0x4321), "D" (tab), "c" (1)); } printf("HLT exception:\n"); if (setjmp(jmp_env) == 0) { asm volatile ("hlt"); } printf("single step exception:\n"); val = 0; if (setjmp(jmp_env) == 0) { asm volatile ("pushf\n" "orl $0x00100, (%%esp)\n" "popf\n" "movl $0xabcd, %0\n" "movl $0x0, %0\n" : "=m" (val) : : "cc", "memory"); } printf("val=0x%x\n", val);}#if !defined(__x86_64__)/* specific precise single step test */void sig_trap_handler(int sig, siginfo_t *info, void *puc){ struct ucontext *uc = puc; printf("EIP=" FMTLX "\n", (long)uc->uc_mcontext.gregs[REG_EIP]);}const uint8_t sstep_buf1[4] = { 1, 2, 3, 4};uint8_t sstep_buf2[4];void test_single_step(void){ struct sigaction act; volatile int val; int i; val = 0; act.sa_sigaction = sig_trap_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; sigaction(SIGTRAP, &act, NULL); asm volatile ("pushf\n" "orl $0x00100, (%%esp)\n" "popf\n" "movl $0xabcd, %0\n" /* jmp test */ "movl $3, %%ecx\n" "1:\n" "addl $1, %0\n" "decl %%ecx\n" "jnz 1b\n" /* movsb: the single step should stop at each movsb iteration */ "movl $sstep_buf1, %%esi\n" "movl $sstep_buf2, %%edi\n" "movl $0, %%ecx\n" "rep movsb\n" "movl $3, %%ecx\n" "rep movsb\n" "movl $1, %%ecx\n" "rep movsb\n" /* cmpsb: the single step should stop at each cmpsb iteration */ "movl $sstep_buf1, %%esi\n" "movl $sstep_buf2, %%edi\n" "movl $0, %%ecx\n" "rep cmpsb\n" "movl $4, %%ecx\n" "rep cmpsb\n" /* getpid() syscall: single step should skip one instruction */ "movl $20, %%eax\n" "int $0x80\n" "movl $0, %%eax\n" /* when modifying SS, trace is not done on the next instruction */ "movl %%ss, %%ecx\n" "movl %%ecx, %%ss\n" "addl $1, %0\n" "movl $1, %%eax\n" "movl %%ecx, %%ss\n" "jmp 1f\n" "addl $1, %0\n" "1:\n" "movl $1, %%eax\n" "pushl %%ecx\n" "popl %%ss\n" "addl $1, %0\n" "movl $1, %%eax\n" "pushf\n" "andl $~0x00100, (%%esp)\n" "popf\n" : "=m" (val) : : "cc", "memory", "eax", "ecx", "esi", "edi"); printf("val=%d\n", val); for(i = 0; i < 4; i++) printf("sstep_buf2[%d] = %d\n", i, sstep_buf2[i]);}/* self modifying code test */uint8_t code[] = { 0xb8, 0x1, 0x00, 0x00, 0x00, /* movl $1, %eax */ 0xc3, /* ret */};asm("smc_code2:\n" "movl 4(%esp), %eax\n" "movl %eax, smc_patch_addr2 + 1\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "smc_patch_addr2:\n" "movl $1, %eax\n" "ret\n");typedef int FuncType(void);extern int smc_code2(int);void test_self_modifying_code(void){ int i; printf("self modifying code:\n"); printf("func1 = 0x%x\n", ((FuncType *)code)()); for(i = 2; i <= 4; i++) { code[1] = i; printf("func%d = 0x%x\n", i, ((FuncType *)code)()); } /* more difficult test : the modified code is just after the modifying instruction. It is forbidden in Intel specs, but it is used by old DOS programs */ for(i = 2; i <= 4; i++) { printf("smc_code2(%d) = %d\n", i, smc_code2(i)); }}#endiflong enter_stack[4096];#if defined(__x86_64__)#define RSP "%%rsp"#define RBP "%%rbp"#else#define RSP "%%esp"#define RBP "%%ebp"#endif#define TEST_ENTER(size, stack_type, level)\{\ long esp_save, esp_val, ebp_val, ebp_save, i;\ stack_type *ptr, *stack_end, *stack_ptr;\ memset(enter_stack, 0, sizeof(enter_stack));\ stack_end = stack_ptr = (stack_type *)(enter_stack + 4096);\ ebp_val = (long)stack_ptr;\ for(i=1;i<=32;i++)\ *--stack_ptr = i;\ esp_val = (long)stack_ptr;\ asm("mov " RSP ", %[esp_save]\n"\ "mov " RBP ", %[ebp_save]\n"\ "mov %[esp_val], " RSP "\n"\ "mov %[ebp_val], " RBP "\n"\ "enter" size " $8, $" #level "\n"\ "mov " RSP ", %[esp_val]\n"\ "mov " RBP ", %[ebp_val]\n"\ "mov %[esp_save], " RSP "\n"\ "mov %[ebp_save], " RBP "\n"\ : [esp_save] "=r" (esp_save),\ [ebp_save] "=r" (ebp_save),\ [esp_val] "=r" (esp_val),\ [ebp_val] "=r" (ebp_val)\ : "[esp_val]" (esp_val),\ "[ebp_val]" (ebp_val));\ printf("level=%d:\n", level);\
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -