public virtual string FormatInstruction(Instruction instruction) { if (instruction == null) throw new ArgumentNullException("instruction"); StringBuilder sb = new StringBuilder(); // Format group 1 (LOCK/REPZ/REPNZ) prefix. if ((instruction.Prefix & Prefixes.Group1) != 0) { sb.Append((instruction.Prefix & Prefixes.Group1).ToString().ToLowerInvariant()); sb.Append(' '); } // Format mnemonic. sb.Append(FormatMnemonic(instruction.Operation)); // Format operands. for (int i = 0; i < instruction.Operands.Length; i++) { if (i > 0) { sb.Append(','); } sb.Append(' '); sb.Append(FormatOperand(instruction.Operands[i])); } return sb.ToString(); }
/// <summary> /// Decodes an instruction. /// </summary> /// <param name="code">X86 binary code.</param> /// <param name="startIndex">Index of the first byte to start /// decoding.</param> /// <param name="context">Decoding context.</param> /// <returns>The decoded instruction.</returns> /// <exception cref="InvalidInstructionException">If decoding failed. /// </exception> public Instruction Decode( byte[] code, int startIndex, int count, DecoderContext context) { Instruction instruction = new Instruction(); // Create an instruction reader. InstructionReader reader = new InstructionReader(code, startIndex, count); // Reset the context. context.AddressSize = CpuSize.Use16Bit; context.OperandSize = CpuSize.Use16Bit; context.SegmentOverride = Register.None; // Decode prefixes. Prefixes prefix = DecodeLegacyPrefixes(reader); if ((prefix & Prefixes.OperandSizeOverride) != 0) { context.OperandSize = CpuSize.Use32Bit; } if ((prefix & Prefixes.AddressSizeOverride) != 0) { context.AddressSize = CpuSize.Use32Bit; } if ((prefix & Prefixes.Group2) != 0) { Register seg = Register.None; switch (prefix & Prefixes.Group2) { case Prefixes.ES: seg = Register.ES; break; case Prefixes.CS: seg = Register.CS; break; case Prefixes.SS: seg = Register.SS; break; case Prefixes.DS: seg = Register.DS; break; case Prefixes.FS: seg = Register.FS; break; case Prefixes.GS: seg = Register.GS; break; } context.SegmentOverride = seg; } instruction.Prefix = prefix; // Decode the opcode to retrieve opcode specification. Op spec = DecodeOpcode(reader); instruction.Operation = spec.Operation; // Decode operands. instruction.Operands = new Operand[spec.Operands.Length]; for (int i = 0; i < spec.Operands.Length; i++) { instruction.Operands[i] = DecodeOperand(spec.Operands[i], reader, context); } // Update the encoded length of the instruction. instruction.EncodedLength = reader.Position; //instruction.Location = location; return instruction; }
public void Add(Address address, Instruction instruction) { if (!image.IsAddressValid(address)) throw new ArgumentOutOfRangeException("address"); if (instruction == null) throw new ArgumentNullException("instruction"); this.instructions.Add(address, instruction); }
public override string FormatInstruction(Instruction instruction) { string s = base.FormatInstruction(instruction); // Make "interesting" instructions bold. switch (instruction.Operation) { //case Operation.CALL: //case Operation.CALLF: // return string.Format("<b>{0}</b>", s); default: return s; } }
private static string FormatSymbolicOperand( X86Codec.Instruction instruction, X86Codec.Operand operand, FixupDefinition fixup, ObjectModule module) { if (fixup.Target.Method == FixupTargetMethod.ExternalPlusDisplacement || fixup.Target.Method == FixupTargetMethod.ExternalWithoutDisplacement) { var extIndex = fixup.Target.IndexOrFrame; var extName = module.ExternalNames[extIndex - 1]; var disp = fixup.Target.Displacement; //System.Diagnostics.Debug.WriteLine(string.Format( // "{0} : operand {4} refers to {1}+{2} : {3}", // instruction, extName, disp, fixup.Location, operand)); return(extName.Name); } return(null); }
public static CodeFeatures GetFeatures(Instruction instruction) { CodeFeatures features = CodeFeatures.None; switch (instruction.Operation) { case Operation.INT: case Operation.INTO: features |= CodeFeatures.HasInterrupt; break; case Operation.RET: features |= CodeFeatures.HasRETN; break; case Operation.RETF: features |= CodeFeatures.HasRETF; break; case Operation.IRET: features |= CodeFeatures.HasIRET; break; case Operation.FCLEX: features |= CodeFeatures.HasFpu; break; } return features; }
private static void ComputeMore( HashAlgorithm hasher, byte[] code, int startIndex, Instruction instruction) { if (instruction == null) throw new ArgumentNullException("instruction"); // Find the opcode part. // TODO: in X86Codec, since a fixable location always comes after // prefix+opcode+modrm+sib, we should put the fixable location as // a property of the instruction instead of the operand. int opcodeLength = instruction.EncodedLength; foreach (Operand operand in instruction.Operands) { if (operand.FixableLocation.Length > 0) opcodeLength = Math.Min(opcodeLength, operand.FixableLocation.StartOffset); } // Since the opcode uniquely determines the displacement and // immediate format, we only need to hash the opcode part and // don't need to hash dummy zeros for the remaining part of the // instruction. hasher.TransformBlock(code, startIndex, opcodeLength, code, startIndex); }
protected virtual XRef CreateFlowXRef( XRefType xrefType, Address source, Instruction instruction) { switch (xrefType) { case XRefType.ConditionalJump: case XRefType.FarJump: case XRefType.NearJump: case XRefType.FarCall: case XRefType.NearCall: return CreateBranchJumpCallXRef(xrefType, source, instruction); case XRefType.NearIndexedJump: throw new NotImplementedException(); default: return null; } }
protected virtual XRef CreateBranchJumpCallXRef( XRefType type, Address source, Instruction instruction) { Address target = ResolveFlowInstructionTarget(instruction.Operands[0]); if (target == Address.Invalid) { AddError(source, ErrorCode.DynamicTarget, "Cannot determine the target of {0} instruction.", instruction.Operation); } return new XRef( type: type, source: source, target: target ); }
/// <summary> /// Replaces any RelativeOperand with SourceAwareRelativeOperand. /// </summary> /// <param name="instruction"></param> // TODO: make SourceAwareRelativeOperand.Target a dummy // SymbolicTarget, so that we can handle them consistently. protected static void MakeRelativeOperandSourceAware( Instruction instruction, Address instructionStart) { for (int i = 0; i < instruction.Operands.Length; i++) { if (instruction.Operands[i] is RelativeOperand && instruction.Operands[i].Tag == null) { instruction.Operands[i] = new SourceAwareRelativeOperand( (RelativeOperand)instruction.Operands[i], instructionStart + instruction.EncodedLength); } } }
/// <summary> /// Analyzes an instruction and returns a xref if the instruction is /// one of the branch/call/jump instructions. Note that the 'no-jump' /// branch of a conditional jump instruction is not returned. The /// caller must manually create such a xref if needed. /// </summary> /// <param name="instruction">The instruction to analyze.</param> /// <returns>XRef if the instruction is a b/c/j instruction; /// null otherwise.</returns> /// TBD: address wrapping if IP is above 0xFFFF is not handled. It should be. private XRef AnalyzeFlowInstruction(Pointer start, Instruction instruction) { Operation op = instruction.Operation; // Find the type of branch/call/jump instruction being processed. // // Note: If the instruction is a conditional jump, we assume that // the condition may be true or false, so that both "jump" and // "no jump" is a reachable branch. If the code is malformed such // that either branch will never be executed, the analysis may not // work correctly. // // Note: If the instruction is a function call, we assume that the // subroutine being called will return. If the subroutine never // returns the analysis may not work correctly. XRefType bcjType; switch (op) { case Operation.JO: case Operation.JNO: case Operation.JB: case Operation.JAE: case Operation.JE: case Operation.JNE: case Operation.JBE: case Operation.JA: case Operation.JS: case Operation.JNS: case Operation.JP: case Operation.JNP: case Operation.JL: case Operation.JGE: case Operation.JLE: case Operation.JG: case Operation.JCXZ: case Operation.LOOP: case Operation.LOOPZ: case Operation.LOOPNZ: bcjType = XRefType.ConditionalJump; break; case Operation.JMP: bcjType = XRefType.NearJump; break; case Operation.JMPF: bcjType = XRefType.FarJump; break; case Operation.CALL: bcjType = XRefType.NearCall; break; case Operation.CALLF: bcjType = XRefType.FarCall; break; default: // Not a b/c/j instruction; do nothing. return null; } // Create a cross-reference depending on the type of operand. if (instruction.Operands[0] is RelativeOperand) // near jump/call to relative address { RelativeOperand opr = (RelativeOperand)instruction.Operands[0]; return new XRef( type: bcjType, source: start, target: start.IncrementWithWrapping(instruction.EncodedLength + opr.Offset.Value) ); } if (instruction.Operands[0] is PointerOperand) // far jump/call to absolute address { PointerOperand opr = (PointerOperand)instruction.Operands[0]; return new XRef( type: bcjType, source: start, target: new Pointer(opr.Segment.Value, (UInt16)opr.Offset.Value) ); } if (instruction.Operands[0] is MemoryOperand) // indirect jump/call { MemoryOperand opr = (MemoryOperand)instruction.Operands[0]; // Handle static near jump table. We recognize a jump table // heuristically if the instruction looks like the following: // // jmpn word ptr cs:[bx+3782h] // // That is, it meets the requirements that // - the instruction is JMPN // - the jump target is a word-ptr memory location // - the memory location has CS prefix // - a base register (e.g. bx) specifies the entry index // // Note that a malformed executable may create a jump table // not conforming to the above rules, or create a non-jump // table that conforms to the above rules. We do not deal with // these cases for the moment. if (op == Operation.JMP && opr.Size == CpuSize.Use16Bit && opr.Segment == Register.CS && opr.Base != Register.None && opr.Index == Register.None) { return new XRef( type: XRefType.NearIndexedJump, source: start, target: Pointer.Invalid, dataLocation: new Pointer(start.Segment, (UInt16)opr.Displacement.Value) ); } } // Other jump/call targets that we cannot recognize. AddError(start, ErrorCategory.Message, "Cannot determine target of {0} instruction.", op); return new XRef( type: bcjType, source: start, target: Pointer.Invalid ); }