📄 vm86.c
字号:
addr = operand(prefix, regs, modrm); if (prefix & DATA32) { data = read32(addr); push32(regs, data); } else { data = read16(addr); push16(regs, data); } TRACE((regs, (regs->eip - n) + 1, "push *0x%x", addr));}enum { OPC_INVALID, OPC_EMULATED };#define rdmsr(msr,val1,val2) \ __asm__ __volatile__( \ "rdmsr" \ : "=a" (val1), "=d" (val2) \ : "c" (msr))#define wrmsr(msr,val1,val2) \ __asm__ __volatile__( \ "wrmsr" \ : /* no outputs */ \ : "c" (msr), "a" (val1), "d" (val2))/* * Emulate a single instruction, including all its prefixes. We only implement * a small subset of the opcodes, and not all opcodes are implemented for each * of the four modes we can operate in. */static intopcode(struct regs *regs){ unsigned eip = regs->eip; unsigned opc, modrm, disp; unsigned prefix = 0; if (mode == VM86_PROTECTED_TO_REAL && oldctx.cs_arbytes.fields.default_ops_size) { prefix |= DATA32; prefix |= ADDR32; } for (;;) { switch ((opc = fetch8(regs))) { case 0x00: /* addr32 add r8, r/m8 */ case 0x01: /* addr32 add r16, r/m16 */ case 0x03: /* addr32 add r/m16, r16 */ if (mode != VM86_REAL && mode != VM86_REAL_TO_PROTECTED) goto invalid; if ((prefix & ADDR32) == 0) goto invalid; if (!add(regs, prefix, opc)) goto invalid; return OPC_EMULATED; case 0x07: /* pop %es */ regs->ves = (prefix & DATA32) ? pop32(regs) : pop16(regs); TRACE((regs, regs->eip - eip, "pop %%es")); if (mode == VM86_REAL_TO_PROTECTED) { saved_rm_regs.ves = 0; oldctx.es_sel = regs->ves; } return OPC_EMULATED; case 0x0F: /* two byte opcode */ if (mode == VM86_PROTECTED) goto invalid; switch ((opc = fetch8(regs))) { case 0x01: switch (((modrm = fetch8(regs)) >> 3) & 7) { case 0: /* sgdt */ case 1: /* sidt */ goto invalid; case 2: /* lgdt */ if (!lgdt(regs, prefix, modrm)) goto invalid; return OPC_EMULATED; case 3: /* lidt */ if (!lidt(regs, prefix, modrm)) goto invalid; return OPC_EMULATED; case 4: /* smsw */ goto invalid; case 5: goto invalid; case 6: /* lmsw */ if (!lmsw(regs, prefix, modrm)) goto invalid; return OPC_EMULATED; case 7: /* invlpg */ goto invalid; } break; case 0x06: /* clts */ oldctx.cr0 &= ~CR0_TS; return OPC_EMULATED; case 0x09: /* wbinvd */ return OPC_EMULATED; case 0x20: /* mov Rd, Cd (1h) */ case 0x22: if (!movcr(regs, prefix, opc)) goto invalid; return OPC_EMULATED; case 0x30: /* WRMSR */ wrmsr(regs->ecx, regs->eax, regs->edx); return OPC_EMULATED; case 0x32: /* RDMSR */ rdmsr(regs->ecx, regs->eax, regs->edx); return OPC_EMULATED; default: goto invalid; } goto invalid; case 0x1F: /* pop %ds */ regs->vds = (prefix & DATA32) ? pop32(regs) : pop16(regs); TRACE((regs, regs->eip - eip, "pop %%ds")); if (mode == VM86_REAL_TO_PROTECTED) { saved_rm_regs.vds = 0; oldctx.ds_sel = regs->vds; } return OPC_EMULATED; case 0x26: TRACE((regs, regs->eip - eip, "%%es:")); prefix |= SEG_ES; continue; case 0x2E: TRACE((regs, regs->eip - eip, "%%cs:")); prefix |= SEG_CS; continue; case 0x36: TRACE((regs, regs->eip - eip, "%%ss:")); prefix |= SEG_SS; continue; case 0x39: /* addr32 cmp r16, r/m16 */ case 0x3B: /* addr32 cmp r/m16, r16 */ if (mode == VM86_PROTECTED_TO_REAL || !(prefix & ADDR32)) goto invalid; if (!cmp(regs, prefix, opc)) goto invalid; return OPC_EMULATED; case 0x3E: TRACE((regs, regs->eip - eip, "%%ds:")); prefix |= SEG_DS; continue; case 0x64: TRACE((regs, regs->eip - eip, "%%fs:")); prefix |= SEG_FS; continue; case 0x65: TRACE((regs, regs->eip - eip, "%%gs:")); prefix |= SEG_GS; continue; case 0x66: if (mode == VM86_PROTECTED_TO_REAL && oldctx.cs_arbytes.fields.default_ops_size) { TRACE((regs, regs->eip - eip, "data16")); prefix &= ~DATA32; } else { TRACE((regs, regs->eip - eip, "data32")); prefix |= DATA32; } continue; case 0x67: if (mode == VM86_PROTECTED_TO_REAL && oldctx.cs_arbytes.fields.default_ops_size) { TRACE((regs, regs->eip - eip, "addr16")); prefix &= ~ADDR32; } else { TRACE((regs, regs->eip - eip, "addr32")); prefix |= ADDR32; } continue; case 0x88: /* addr32 mov r8, r/m8 */ case 0x8A: /* addr32 mov r/m8, r8 */ if (mode == VM86_PROTECTED_TO_REAL || !(prefix & ADDR32)) goto invalid; if (!movr(regs, prefix, opc)) goto invalid; return OPC_EMULATED; case 0x89: /* mov r16, r/m16 */ case 0x8B: /* mov r/m16, r16 */ if (mode != VM86_PROTECTED_TO_REAL && !(prefix & ADDR32)) goto invalid; if (!movr(regs, prefix, opc)) goto invalid; return OPC_EMULATED; case 0x8E: /* mov r16, sreg */ if (!mov_to_seg(regs, prefix, opc)) goto invalid; return OPC_EMULATED; case 0x8F: /* addr32 pop r/m16 */ if (!(prefix & ADDR32)) goto invalid; if (!pop(regs, prefix, opc)) goto invalid; return OPC_EMULATED; case 0x90: /* nop */ TRACE((regs, regs->eip - eip, "nop")); return OPC_EMULATED; case 0x9C: /* pushf */ TRACE((regs, regs->eip - eip, "pushf")); if (prefix & DATA32) push32(regs, regs->eflags & ~EFLAGS_VM); else push16(regs, regs->eflags & ~EFLAGS_VM); return OPC_EMULATED; case 0x9D: /* popf */ TRACE((regs, regs->eip - eip, "popf")); if (prefix & DATA32) regs->eflags = pop32(regs); else regs->eflags = (regs->eflags & 0xFFFF0000L) | pop16(regs); regs->eflags |= EFLAGS_VM; return OPC_EMULATED; case 0xA1: /* mov ax, r/m16 */ { int addr, data; int seg = segment(prefix, regs, regs->vds); int offset = prefix & ADDR32 ? fetch32(regs) : fetch16(regs); if (prefix & DATA32) { addr = address(regs, seg, offset); data = read32(addr); setreg32(regs, 0, data); } else { addr = address(regs, seg, offset); data = read16(addr); setreg16(regs, 0, data); } TRACE((regs, regs->eip - eip, "mov *0x%x, %%ax", addr)); return OPC_EMULATED; } case 0xA4: /* movsb */ case 0xA5: /* movsw */ if ((prefix & ADDR32) == 0) goto invalid; if (!movs(regs, prefix, opc)) goto invalid; return OPC_EMULATED; case 0xAD: /* lodsw */ if ((prefix & ADDR32) == 0) goto invalid; if (!lods(regs, prefix, opc)) goto invalid; return OPC_EMULATED; case 0xBB: /* mov bx, imm16 */ { int data; if (prefix & DATA32) { data = fetch32(regs); setreg32(regs, 3, data); } else { data = fetch16(regs); setreg16(regs, 3, data); } TRACE((regs, regs->eip - eip, "mov $0x%x, %%bx", data)); return OPC_EMULATED; } case 0xC6: /* addr32 movb $imm, r/m8 */ if (!(prefix & ADDR32)) goto invalid; if (!movr(regs, prefix, opc)) goto invalid; return OPC_EMULATED; case 0xCB: /* retl */ if (mode == VM86_REAL_TO_PROTECTED || mode == VM86_PROTECTED_TO_REAL) { retl(regs, prefix); return OPC_INVALID; } goto invalid; case 0xCD: /* int $n */ TRACE((regs, regs->eip - eip, "int")); interrupt(regs, fetch8(regs)); return OPC_EMULATED; case 0xCF: /* iret */ if (prefix & DATA32) { TRACE((regs, regs->eip - eip, "data32 iretd")); regs->eip = pop32(regs); regs->cs = pop32(regs); regs->eflags = pop32(regs); } else { TRACE((regs, regs->eip - eip, "iret")); regs->eip = pop16(regs); regs->cs = pop16(regs); regs->eflags = (regs->eflags & 0xFFFF0000L) | pop16(regs); } return OPC_EMULATED; case 0xE4: /* inb al, port */ if (!inbyte(regs, prefix, opc)) goto invalid; return OPC_EMULATED; case 0xE6: /* outb port, al */ if (!outbyte(regs, prefix, opc)) goto invalid; return OPC_EMULATED; case 0xEA: /* jmpl */ if (mode == VM86_REAL_TO_PROTECTED || mode == VM86_PROTECTED_TO_REAL) { jmpl(regs, prefix); return OPC_INVALID; } goto invalid; case 0xFF: { unsigned modrm = fetch8(regs); switch((modrm >> 3) & 7) { case 5: /* jmpl (indirect) */ if (mode == VM86_REAL_TO_PROTECTED || mode == VM86_PROTECTED_TO_REAL) { jmpl_indirect(regs, prefix, modrm); return OPC_INVALID; } goto invalid; case 6: /* push r/m16 */ pushrm(regs, prefix, modrm); return OPC_EMULATED; default: goto invalid; } } case 0xEB: /* short jump */ if (mode == VM86_REAL_TO_PROTECTED || mode == VM86_PROTECTED_TO_REAL) { disp = (char) fetch8(regs); TRACE((regs, 2, "jmp 0x%x", regs->eip + disp)); regs->eip += disp; return OPC_EMULATED; } goto invalid; case 0xEC: /* inb al, (%dx) */ if (!inbyte(regs, prefix, opc)) goto invalid; return OPC_EMULATED; case 0xEE: /* outb (%dx), al */ if (!outbyte(regs, prefix, opc)) goto invalid; return OPC_EMULATED; case 0xF0: /* lock */ TRACE((regs, regs->eip - eip, "lock")); continue; case 0xF4: /* hlt */ TRACE((regs, regs->eip - eip, "hlt")); /* Do something power-saving here! */ return OPC_EMULATED; case 0xF3: /* rep/repe/repz */ TRACE((regs, regs->eip - eip, "rep")); prefix |= REP; continue; case 0xF6: /* addr32 testb $imm, r/m8 */ if (!(prefix & ADDR32)) goto invalid; if (!test(regs, prefix, opc)) goto invalid; return OPC_EMULATED; case 0xFA: /* cli */ TRACE((regs, regs->eip - eip, "cli")); regs->eflags &= ~EFLAGS_IF; return OPC_EMULATED; case 0xFB: /* sti */ TRACE((regs, regs->eip - eip, "sti")); regs->eflags |= EFLAGS_IF; return OPC_EMULATED; default: goto invalid; } }invalid: regs->eip = eip; TRACE((regs, regs->eip - eip, "opc 0x%x", opc)); return OPC_INVALID;}voidemulate(struct regs *regs){ unsigned flteip; int nemul = 0; unsigned ip; /* emulate as many instructions as possible */ while (opcode(regs) != OPC_INVALID) nemul++; /* detect the case where we are not making progress */ if (nemul == 0 && prev_eip == regs->eip) { flteip = address(regs, MASK16(regs->cs), regs->eip); printf("Undecoded sequence: \n"); for (ip=flteip; ip < flteip+16; ip++) printf("0x%02x ", read8(ip)); printf("\n"); panic("Unknown opcode at %04x:%04x=0x%x", MASK16(regs->cs), regs->eip, flteip); } else prev_eip = regs->eip;}voidtrap(int trapno, int errno, struct regs *regs){ /* emulate device interrupts */ if (trapno >= NR_EXCEPTION_HANDLER) { int irq = trapno - NR_EXCEPTION_HANDLER; if (irq < 8) interrupt(regs, irq + 8); else interrupt(regs, 0x70 + (irq - 8)); return; } switch (trapno) { case 1: /* Debug */ if (regs->eflags & EFLAGS_VM) { /* emulate any 8086 instructions */ if (mode == VM86_REAL) return; if (mode != VM86_REAL_TO_PROTECTED) panic("not in real-to-protected mode"); emulate(regs); return; } goto invalid; case 13: /* GPF */ if (regs->eflags & EFLAGS_VM) { /* emulate any 8086 instructions */ if (mode == VM86_PROTECTED) panic("unexpected protected mode"); emulate(regs); return; } goto invalid; default: invalid: printf("Trap (0x%x) while in %s mode\n", trapno, regs->eflags & EFLAGS_VM ? "real" : "protected"); if (trapno == 14) printf("Page fault address 0x%x\n", get_cr2()); dump_regs(regs); halt(); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -