📄 lrmi.c
字号:
cx = CONTEXT_REGS.REG(ecx) & 0xffff; while (cx--) em_outs(size, seg); CONTEXT_REGS.REG(ecx) &= 0xffff0000;}static voidem_inbl(unsigned char literal){ asm volatile ("inb %w1, %b0" : "=a" (CONTEXT_REGS.REG(eax)) : "d" (literal), "0" (CONTEXT_REGS.REG(eax)));}static voidem_inb(void){ asm volatile ("inb %w1, %b0" : "=a" (CONTEXT_REGS.REG(eax)) : "d" (CONTEXT_REGS.REG(edx)), "0" (CONTEXT_REGS.REG(eax)));}static voidem_inw(void){ asm volatile ("inw %w1, %w0" : "=a" (CONTEXT_REGS.REG(eax)) : "d" (CONTEXT_REGS.REG(edx)), "0" (CONTEXT_REGS.REG(eax)));}static voidem_inl(void){ asm volatile ("inl %w1, %0" : "=a" (CONTEXT_REGS.REG(eax)) : "d" (CONTEXT_REGS.REG(edx)));}static voidem_outbl(unsigned char literal){ asm volatile ("outb %b0, %w1" : : "a" (CONTEXT_REGS.REG(eax)), "d" (literal));}static voidem_outb(void){ asm volatile ("outb %b0, %w1" : : "a" (CONTEXT_REGS.REG(eax)), "d" (CONTEXT_REGS.REG(edx)));}static voidem_outw(void){ asm volatile ("outw %w0, %w1" : : "a" (CONTEXT_REGS.REG(eax)), "d" (CONTEXT_REGS.REG(edx)));}static voidem_outl(void){ asm volatile ("outl %0, %w1" : : "a" (CONTEXT_REGS.REG(eax)), "d" (CONTEXT_REGS.REG(edx)));}static intemulate(void){ unsigned char *insn; struct { unsigned char seg; unsigned int size : 1; unsigned int rep : 1; } prefix = { DSEG, 0, 0 }; int i = 0; insn = (unsigned char *)((unsigned int)CONTEXT_REGS.REG(cs) << 4); insn += CONTEXT_REGS.REG(eip); while (1) { if (insn[i] == 0x66) { prefix.size = 1 - prefix.size; i++; } else if (insn[i] == 0xf3) { prefix.rep = 1; i++; } else if (insn[i] == CSEG || insn[i] == SSEG || insn[i] == DSEG || insn[i] == ESEG || insn[i] == FSEG || insn[i] == GSEG) { prefix.seg = insn[i]; i++; } else if (insn[i] == 0xf0 || insn[i] == 0xf2 || insn[i] == 0x67) { /* these prefixes are just ignored */ i++; } else if (insn[i] == 0x6c) { if (prefix.rep) em_rep_ins(1); else em_ins(1); i++; break; } else if (insn[i] == 0x6d) { if (prefix.rep) { if (prefix.size) em_rep_ins(4); else em_rep_ins(2); } else { if (prefix.size) em_ins(4); else em_ins(2); } i++; break; } else if (insn[i] == 0x6e) { if (prefix.rep) em_rep_outs(1, prefix.seg); else em_outs(1, prefix.seg); i++; break; } else if (insn[i] == 0x6f) { if (prefix.rep) { if (prefix.size) em_rep_outs(4, prefix.seg); else em_rep_outs(2, prefix.seg); } else { if (prefix.size) em_outs(4, prefix.seg); else em_outs(2, prefix.seg); } i++; break; } else if (insn[i] == 0xe4) { em_inbl(insn[i + 1]); i += 2; break; } else if (insn[i] == 0xec) { em_inb(); i++; break; } else if (insn[i] == 0xed) { if (prefix.size) em_inl(); else em_inw(); i++; break; } else if (insn[i] == 0xe6) { em_outbl(insn[i + 1]); i += 2; break; } else if (insn[i] == 0xee) { em_outb(); i++; break; } else if (insn[i] == 0xef) { if (prefix.size) em_outl(); else em_outw(); i++; break; } else return 0; } CONTEXT_REGS.REG(eip) += i; return 1;}#if defined(__linux__)/* I don't know how to make sure I get the right vm86() from libc. The one I want is syscall # 113 (vm86old() in libc 5, vm86() in glibc) which should be declared as "int vm86(struct vm86_struct *);" in <sys/vm86.h>. This just does syscall 113 with inline asm, which should work for both libc's (I hope).*/#if !defined(USE_LIBC_VM86)static intlrmi_vm86(struct vm86_struct *vm){ int r;#ifdef __PIC__ asm volatile ( "pushl %%ebx\n\t" "movl %2, %%ebx\n\t" "int $0x80\n\t" "popl %%ebx" : "=a" (r) : "0" (113), "r" (vm));#else asm volatile ( "int $0x80" : "=a" (r) : "0" (113), "b" (vm));#endif return r;}#else#define lrmi_vm86 vm86#endif#endif /* __linux__ */static voiddebug_info(int vret){#ifdef LRMI_DEBUG int i; unsigned char *p; fputs("vm86() failed\n", stderr); fprintf(stderr, "return = 0x%x\n", vret); fprintf(stderr, "eax = 0x%08x\n", CONTEXT_REGS.REG(eax)); fprintf(stderr, "ebx = 0x%08x\n", CONTEXT_REGS.REG(ebx)); fprintf(stderr, "ecx = 0x%08x\n", CONTEXT_REGS.REG(ecx)); fprintf(stderr, "edx = 0x%08x\n", CONTEXT_REGS.REG(edx)); fprintf(stderr, "esi = 0x%08x\n", CONTEXT_REGS.REG(esi)); fprintf(stderr, "edi = 0x%08x\n", CONTEXT_REGS.REG(edi)); fprintf(stderr, "ebp = 0x%08x\n", CONTEXT_REGS.REG(ebp)); fprintf(stderr, "eip = 0x%08x\n", CONTEXT_REGS.REG(eip)); fprintf(stderr, "cs = 0x%04x\n", CONTEXT_REGS.REG(cs)); fprintf(stderr, "esp = 0x%08x\n", CONTEXT_REGS.REG(esp)); fprintf(stderr, "ss = 0x%04x\n", CONTEXT_REGS.REG(ss)); fprintf(stderr, "ds = 0x%04x\n", CONTEXT_REGS.REG(ds)); fprintf(stderr, "es = 0x%04x\n", CONTEXT_REGS.REG(es)); fprintf(stderr, "fs = 0x%04x\n", CONTEXT_REGS.REG(fs)); fprintf(stderr, "gs = 0x%04x\n", CONTEXT_REGS.REG(gs)); fprintf(stderr, "eflags = 0x%08x\n", CONTEXT_REGS.REG(eflags)); fputs("cs:ip = [ ", stderr); p = (unsigned char *)((CONTEXT_REGS.REG(cs) << 4) + (CONTEXT_REGS.REG(eip) & 0xffff)); for (i = 0; i < 16; ++i) fprintf(stderr, "%02x ", (unsigned int)p[i]); fputs("]\n", stderr);#endif}#if defined(__linux__)static intrun_vm86(void){ unsigned int vret; sigset_t all_sigs, old_sigs; unsigned long old_gs, old_fs; while (1) { // FIXME: may apply this to BSD equivalents? sigfillset(&all_sigs); sigprocmask(SIG_SETMASK, &all_sigs, &old_sigs); asm volatile ("mov %%gs, %0" : "=rm" (old_gs)); asm volatile ("mov %%fs, %0" : "=rm" (old_fs)); vret = lrmi_vm86(&context.vm); asm volatile ("mov %0, %%gs" :: "rm" (old_gs)); asm volatile ("mov %0, %%fs" :: "rm" (old_fs)); sigprocmask(SIG_SETMASK, &old_sigs, NULL); if (VM86_TYPE(vret) == VM86_INTx) { unsigned int v = VM86_ARG(vret); if (v == RETURN_TO_32_INT) return 1; pushw(CONTEXT_REGS.REG(eflags)); pushw(CONTEXT_REGS.REG(cs)); pushw(CONTEXT_REGS.REG(eip)); CONTEXT_REGS.REG(cs) = get_int_seg(v); CONTEXT_REGS.REG(eip) = get_int_off(v); CONTEXT_REGS.REG(eflags) &= ~(VIF_MASK | TF_MASK); continue; } if (VM86_TYPE(vret) != VM86_UNKNOWN) break; if (!emulate()) break; } debug_info(vret); return 0;}#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)#if defined(__NetBSD__) || defined(__OpenBSD__)static voidvm86_callback(int sig, int code, struct sigcontext *sc){ /* Sync our context with what the kernel develivered to us. */ memcpy(&CONTEXT_REGS, sc, sizeof(*sc)); switch (VM86_TYPE(code)) { case VM86_INTx: { unsigned int v = VM86_ARG(code); if (v == RETURN_TO_32_INT) { context.success = 1; longjmp(context.env, 1); } pushw(CONTEXT_REGS.REG(eflags)); pushw(CONTEXT_REGS.REG(cs)); pushw(CONTEXT_REGS.REG(eip)); CONTEXT_REGS.REG(cs) = get_int_seg(v); CONTEXT_REGS.REG(eip) = get_int_off(v); CONTEXT_REGS.REG(eflags) &= ~(VIF_MASK | TF_MASK); break; } case VM86_UNKNOWN: if (emulate() == 0) { context.success = 0; context.vret = code; longjmp(context.env, 1); } break; default: context.success = 0; context.vret = code; longjmp(context.env, 1); return; } /* ...and sync our context back to the kernel. */ memcpy(sc, &CONTEXT_REGS, sizeof(*sc));}#elif defined(__FreeBSD__)static voidvm86_callback(int sig, int code, struct sigcontext *sc){ unsigned char *addr; /* Sync our context with what the kernel develivered to us. */ memcpy(&CONTEXT_REGS, sc, sizeof(*sc)); if (code) { /* XXX probably need to call original signal handler here */ context.success = 0; context.vret = code; longjmp(context.env, 1); } addr = (unsigned char *)((CONTEXT_REGS.REG(cs) << 4) + CONTEXT_REGS.REG(eip)); if (addr[0] == 0xcd) { /* int opcode */ if (addr[1] == RETURN_TO_32_INT) { context.success = 1; longjmp(context.env, 1); } pushw(CONTEXT_REGS.REG(eflags)); pushw(CONTEXT_REGS.REG(cs)); pushw(CONTEXT_REGS.REG(eip)); CONTEXT_REGS.REG(cs) = get_int_seg(addr[1]); CONTEXT_REGS.REG(eip) = get_int_off(addr[1]); CONTEXT_REGS.REG(eflags) &= ~(VIF_MASK | TF_MASK); } else { if (emulate() == 0) { context.success = 0; longjmp(context.env, 1); } } /* ...and sync our context back to the kernel. */ memcpy(sc, &CONTEXT_REGS, sizeof(*sc));}#endif /* __FreeBSD__ */static intrun_vm86(void){ if (context.old_sighandler) {#ifdef LRMI_DEBUG fprintf(stderr, "run_vm86: callback already installed\n");#endif return (0); }#if defined(__NetBSD__) || defined(__OpenBSD__) context.old_sighandler = signal(SIGURG, (void (*)(int))vm86_callback);#elif defined(__FreeBSD__) context.old_sighandler = signal(SIGBUS, (void (*)(int))vm86_callback);#endif if (context.old_sighandler == (void *)-1) { context.old_sighandler = NULL;#ifdef LRMI_DEBUG fprintf(stderr, "run_vm86: cannot install callback\n");#endif return (0); } if (setjmp(context.env)) {#if defined(__NetBSD__) || defined(__OpenBSD__) (void) signal(SIGURG, context.old_sighandler);#elif defined(__FreeBSD__) (void) signal(SIGBUS, context.old_sighandler);#endif context.old_sighandler = NULL; if (context.success) return (1); debug_info(context.vret); return (0); }#if defined(__NetBSD__) || defined(__OpenBSD__) if (i386_vm86(&context.vm) == -1) return (0);#elif defined(__FreeBSD__) if (i386_vm86(VM86_INIT, &context.vm.init)) return 0; CONTEXT_REGS.REG(eflags) |= PSL_VM | PSL_VIF; sigreturn(&context.vm.uc);#endif /* __FreeBSD__ */ /* NOTREACHED */ return (0);}#endif /* __NetBSD__ || __FreeBSD__ || __OpenBSD__ */intLRMI_call(struct LRMI_regs *r){ unsigned int vret; memset(&CONTEXT_REGS, 0, sizeof(CONTEXT_REGS)); set_regs(r); CONTEXT_REGS.REG(cs) = r->cs; CONTEXT_REGS.REG(eip) = r->ip; if (r->ss == 0 && r->sp == 0) { CONTEXT_REGS.REG(ss) = context.stack_seg; CONTEXT_REGS.REG(esp) = context.stack_off; } else { CONTEXT_REGS.REG(ss) = r->ss; CONTEXT_REGS.REG(esp) = r->sp; } pushw(context.ret_seg); pushw(context.ret_off); vret = run_vm86(); get_regs(r); return vret;}intLRMI_int(int i, struct LRMI_regs *r){ unsigned int vret; unsigned int seg, off; seg = get_int_seg(i); off = get_int_off(i); /* If the interrupt is in regular memory, it's probably still pointing at a dos TSR (which is now gone). */ if (seg < 0xa000 || (seg << 4) + off >= 0x100000) {#ifdef LRMI_DEBUG fprintf(stderr, "Int 0x%x is not in rom (%04x:%04x)\n", i, seg, off);#endif return 0; } memset(&CONTEXT_REGS, 0, sizeof(CONTEXT_REGS)); set_regs(r); CONTEXT_REGS.REG(cs) = seg; CONTEXT_REGS.REG(eip) = off; if (r->ss == 0 && r->sp == 0) { CONTEXT_REGS.REG(ss) = context.stack_seg; CONTEXT_REGS.REG(esp) = context.stack_off; } else { CONTEXT_REGS.REG(ss) = r->ss; CONTEXT_REGS.REG(esp) = r->sp; } pushw(DEFAULT_VM86_FLAGS); pushw(context.ret_seg); pushw(context.ret_off); vret = run_vm86(); get_regs(r); return vret;}#else /* (__linux__ || __NetBSD__ || __FreeBSD__ || __OpenBSD__) && __i386__ */#warning "LRMI is not supported on your system!"#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -