public override line GetNextLine(ByteProvider bp) { byte[] l = new byte[4]; l[0] = bp.GetNextByte(); l[1] = bp.GetNextByte(); l[2] = bp.GetNextByte(); l[3] = bp.GetNextByte(); uint l2 = BitConverter.ToUInt32(l, 0); arm_line ret = new arm_line(); ret.opcode = l2; ret.opcodes = l; try { InterpretOpcode(l2, ret); } catch (NotImplementedException) { } ret.bp = bp; return(ret); }
public override line GetNextLine(ByteProvider bp) { x86_64_line l = new x86_64_line(); List <byte> os = new List <byte>(); l.offset_start = bp.Offset; byte rex = 0x0; bool has_prefix_66 = false; bool has_prefix_f2 = false; bool has_prefix_f3 = false; byte b = bp.GetNextByte(); os.Add(b); // read any prefixes bool reading_prefixes = true; List <ulong> prefixes = new List <ulong>(); while (reading_prefixes) { switch (b) { case 0xf2: case 0x66: case 0xf3: if (b == 0xf2) { has_prefix_f2 = true; } if (b == 0xf3) { has_prefix_f3 = true; } if (b == 0x66) { has_prefix_66 = true; } b = bp.GetNextByte(); os.Add(b); break; case 0xf0: case 0x2e: case 0x36: case 0x3e: case 0x26: case 0x64: case 0x65: case 0x67: prefixes.Add(b); b = bp.GetNextByte(); os.Add(b); break; default: reading_prefixes = false; break; } } l.prefixes = prefixes.ToArray(); // read any rex prefix if ((b >= 0x40) && (b <= 0x4f)) { prefixes.Add(b); l.prefixes = prefixes.ToArray(); rex = b; b = bp.GetNextByte(); os.Add(b); } // read the opcode if (b == 0x0f) { // two byte opcode /* read any rex prefix (in multi-byte opcodes, the rex * prefix comes after the 0x0f byte) */ byte b2 = bp.GetNextByte(); os.Add(b2); if ((b2 >= 0x40) && (b2 <= 0x4f)) { prefixes.Add(b2); l.prefixes = prefixes.ToArray(); rex = b; b2 = bp.GetNextByte(); os.Add(b2); } if ((b2 == 0x38) || (b2 == 0x3a)) { byte b3 = bp.GetNextByte(); os.Add(b3); l.opcode = (ulong)((b << 16) + (b2 << 8) + b3); } else if (has_prefix_f2) { l.opcode = (ulong)((0xf2 << 16) + (b << 8) + b2); } else if (has_prefix_f3) { l.opcode = (ulong)((0xf3 << 16) + (b << 8) + b2); } else if (has_prefix_66) { l.opcode = (ulong)((0x66 << 16) + (b << 8) + b2); } else { l.opcode = (ulong)((b << 8) + b2); } } else { if (has_prefix_f2) { prefixes.Add(0xf2); } if (has_prefix_f3) { prefixes.Add(0xf3); } if (has_prefix_66) { prefixes.Add(0x66); } l.opcode = (ulong)b; } opcode o = null; if (opcodes.ContainsKey(l.opcode)) { o = opcodes[l.opcode]; } if (o == null) { l.offset_end = bp.Offset; return(l); } else { byte modrm; byte sib = 0; long disp = 0; ulong imm = 0; if (o.has_rm) { // read the rm byte modrm = bp.GetNextByte(); os.Add(modrm); byte mod = (byte)(modrm >> 6); byte rm = (byte)(modrm & 7); byte reg = (byte)((modrm >> 3) & 7); if (o.reinterpret_after_r) { l.opcode = (((ulong)reg) << 24) + l.opcode + 0x10000000; if (opcodes.ContainsKey(l.opcode)) { o = opcodes[l.opcode]; } else { l.offset_end = bp.Offset; return(l); } } // decide if we need an sib byte if ((mod != 3) && (rm == 4)) { sib = bp.GetNextByte(); os.Add(sib); } // decide if we need a displacement if (((mod == 0) && (rm == 5)) || (mod == 2)) { // 4 byte displacement byte d1 = bp.GetNextByte(); os.Add(d1); byte d2 = bp.GetNextByte(); os.Add(d2); byte d3 = bp.GetNextByte(); os.Add(d3); byte d4 = bp.GetNextByte(); os.Add(d4); byte[] dval = new byte[] { d1, d2, d3, d4 }; disp = BitConverter.ToInt32(dval, 0); //disp = (ulong)d1 + (((ulong)d2) << 8) + (((ulong)d3) << 16) + (((ulong)d4) << 24); } else if (mod == 1) { // 1 byte displacement byte d1 = bp.GetNextByte(); os.Add(d1); byte extend = 0; if ((d1 & 0x80) == 0x80) { extend = 0xff; } byte[] dval = new byte[] { d1, extend, extend, extend }; disp = BitConverter.ToInt32(dval, 0); } // load a immediate value if necessary int imm_length = o.immediate_length; if ((imm_length == 4) && (o.immediate_extends_on_rexw) && ((rex & 0x08) == 0x08)) { imm_length = 8; } for (int i = 0; i < imm_length; i++) { byte cur_b = bp.GetNextByte(); os.Add(cur_b); imm += ((ulong)cur_b) << (i * 8); } // work out the opcodes List <location> args = new List <location>(); foreach (opcode.operand_source osrc in o.operand_sources) { switch (osrc.type) { case opcode.operand_source.src_type.Fixed: if (osrc.Fixed_Location.type == location.location_type.Register) { ulong reg_no = osrc.Fixed_Location.reg_no; reg_no = reg_no % 8; if (osrc.extends_on_rexb && ((rex & 0x01) == 0x01)) { reg_no += reg_nos["r8"]; } else if ((rex & 0x08) == 0x08) { reg_no += reg_nos["rax"]; } else { reg_no = osrc.Fixed_Location.reg_no; } args.Add(new location { type = location.location_type.Register, reg_no = reg_no }); } else { args.Add(osrc.Fixed_Location); } break; case opcode.operand_source.src_type.Imm: args.Add(new location { type = location.location_type.Immediate, immediate = imm, is_pc_relative = osrc.is_pc_relative }); break; case opcode.operand_source.src_type.ModRM_Reg: { ulong base_reg = 0; switch (osrc.length) { case opcode.operand_source.reg_length.r8: base_reg = reg_nos["al"]; break; case opcode.operand_source.reg_length.r16: base_reg = reg_nos["ax"]; break; case opcode.operand_source.reg_length.r32: base_reg = reg_nos["eax"]; if (has_prefix_66) { base_reg = reg_nos["ax"]; } else { if (((rex & rex_w) == rex_w) && osrc.extends_on_rexw) { base_reg = reg_nos["rax"]; } if ((rex & 0x4) == 0x4) { base_reg = reg_nos["r8"]; } } break; case opcode.operand_source.reg_length.r64: base_reg = reg_nos["rax"]; if ((rex & 0x4) == 0x4) { base_reg = reg_nos["r8"]; } break; case opcode.operand_source.reg_length.mm: base_reg = reg_nos["mm0"]; break; case opcode.operand_source.reg_length.xmm: base_reg = reg_nos["xmm0"]; if ((rex & 0x4) == 0x4) { base_reg = reg_nos["xmm8"]; } break; case opcode.operand_source.reg_length.cr: base_reg = reg_nos["cr0"]; break; } args.Add(new location { type = location.location_type.Register, reg_no = base_reg + (ulong)reg }); } break; case opcode.operand_source.src_type.ModRM_RM: { if (mod == 3) { ulong base_reg = 0; switch (osrc.length) { case opcode.operand_source.reg_length.r8: base_reg = reg_nos["al"]; break; case opcode.operand_source.reg_length.r16: base_reg = reg_nos["ax"]; break; case opcode.operand_source.reg_length.r32: base_reg = reg_nos["eax"]; if (has_prefix_66) { base_reg = reg_nos["ax"]; } else { if (((rex & rex_w) == rex_w) && osrc.extends_on_rexw) { base_reg = reg_nos["rax"]; } if ((rex & 0x1) == 0x1) { base_reg = reg_nos["r8"]; } } break; case opcode.operand_source.reg_length.r64: base_reg = reg_nos["rax"]; if ((rex & 0x1) == 0x1) { base_reg = reg_nos["r8"]; } break; case opcode.operand_source.reg_length.mm: base_reg = reg_nos["mm0"]; break; case opcode.operand_source.reg_length.xmm: base_reg = reg_nos["xmm0"]; if ((rex & 0x1) == 0x1) { base_reg = reg_nos["xmm8"]; } break; case opcode.operand_source.reg_length.cr: base_reg = reg_nos["cr0"]; break; } args.Add(new location { type = location.location_type.Register, reg_no = base_reg + (ulong)rm }); } else { ulong base_reg = reg_nos["rax"]; switch (rm) { case 0: base_reg = reg_nos["rax"]; break; case 1: base_reg = reg_nos["rcx"]; break; case 2: base_reg = reg_nos["rdx"]; break; case 3: base_reg = reg_nos["rbx"]; break; case 4: { // interpret sib byte byte s_scale = (byte)(sib >> 6); byte s_base = (byte)(sib & 7); byte s_index = (byte)((sib >> 3) & 7); List <location> sib_args = new List <location>(); bool need_plus = false; // the special combination of base = 5, mod = 0, rex_b = 0 means no base if (!((s_base == 5) && (mod == 0) && ((rex & rex_b) == rex_b))) { // otherwise we have a base ulong s_base_base_reg = reg_nos["rax"]; if ((rex & rex_b) == rex_b) { s_base_base_reg = reg_nos["r8"]; } need_plus = true; sib_args.Add(new location { type = location.location_type.Register, reg_no = s_base_base_reg + s_base }); } // if s_index != 4, then we have a index register if (!((s_index == 4) && ((rex & rex_x) != rex_x))) { location.scale_func scale = location.scale_func.None; if (need_plus) { scale = location.scale_func.Plus; } ulong s_index_base_reg = reg_nos["rax"]; if ((rex & rex_x) == rex_x) { s_index_base_reg = reg_nos["r8"]; } need_plus = true; sib_args.Add(new location { type = location.location_type.Register, reg_no = s_index_base_reg + s_index, scale = scale }); if (s_scale == 1) { sib_args.Add(new location { type = location.location_type.Const, immediate = 2, scale = location.scale_func.Multiply }); } else if (s_scale == 2) { sib_args.Add(new location { type = location.location_type.Const, immediate = 4, scale = location.scale_func.Multiply }); } else if (s_scale == 3) { sib_args.Add(new location { type = location.location_type.Const, immediate = 8, scale = location.scale_func.Multiply }); } } if ((mod == 1) || (mod == 2) || ((mod == 0) && (s_base == 5) && ((rex & rex_b) == rex_b))) { // add displacement location.scale_func scale = location.scale_func.None; if (need_plus) { scale = ((disp >= 0) ? location.scale_func.Plus : location.scale_func.Minus); } sib_args.Add(new location { type = location.location_type.Immediate, immediate = ((disp >= 0) ? (ulong)disp : (ulong)(-disp)), scale = scale }); } args.Add(new location { type = location.location_type.ContentsOf, args = sib_args.ToArray() }); continue; } case 5: { if (mod == 0) { args.Add(new location { type = location.location_type.ContentsOf, args = new location[] { new location { type = location.location_type.Register, reg_no = reg_nos["rip"] }, new location { type = location.location_type.Immediate, scale = ((disp >= 0) ? location.scale_func.Plus : location.scale_func.Minus), immediate = ((disp >= 0) ? (ulong)disp : (ulong)(-disp)) } } }); continue; } else { base_reg = reg_nos["rbp"]; } } break; case 6: base_reg = reg_nos["rsi"]; break; case 7: base_reg = reg_nos["rdi"]; break; } if ((rex & 0x1) == 0x1) { base_reg = base_reg - reg_nos["rax"] + reg_nos["r8"]; } location loc = new location { type = location.location_type.ContentsOf, args = new location[] { new location { type = location.location_type.Register, reg_no = base_reg } } }; if ((mod == 1) || (mod == 2)) { loc.args = new location[] { loc.args[0], new location { type = location.location_type.Immediate, scale = ((disp >= 0) ? location.scale_func.Plus : location.scale_func.Minus), immediate = ((disp >= 0) ? (ulong)disp : (ulong)(-disp)) } } } ; args.Add(loc); } } break; } } l.arguments = args.ToArray(); } else { // no mod_rm // load a immediate value if necessary int imm_length = o.immediate_length; if ((imm_length == 4) && (o.immediate_extends_on_rexw) && ((rex & 0x08) == 0x08)) { imm_length = 8; } for (int i = 0; i < imm_length; i++) { byte cur_b = bp.GetNextByte(); os.Add(cur_b); imm += ((ulong)cur_b) << (i * 8); } List <location> args = new List <location>(); foreach (opcode.operand_source osrc in o.operand_sources) { switch (osrc.type) { case opcode.operand_source.src_type.Fixed: if (osrc.Fixed_Location.type == location.location_type.Register) { ulong reg_no = osrc.Fixed_Location.reg_no; reg_no = reg_no % 8; if (osrc.extends_on_rexb && ((rex & 0x01) == 0x01)) { reg_no += reg_nos["r8"]; } else if ((rex & 0x08) == 0x08) { reg_no += reg_nos["rax"]; } else { reg_no = osrc.Fixed_Location.reg_no; } args.Add(new location { type = location.location_type.Register, reg_no = reg_no }); } else { args.Add(osrc.Fixed_Location); } break; case opcode.operand_source.src_type.Imm: args.Add(new location { type = location.location_type.Immediate, immediate = imm, is_pc_relative = osrc.is_pc_relative }); break; } } l.arguments = args.ToArray(); } } l.o = o; l.opcodes = os.ToArray(); l.bp = bp; l.offset_end = bp.Offset; return(l); }