/// <summary> /// Find the first instrucion index that is not affected by the junk insertion in the new block. /// In other words: it Finds the first instruction in the new block which is identical to instruction /// in the original basic block. the identical instruction start an identical sequence of instructions /// untill the end of the two blocks. /// </summary> /// <param name="newBasicBlockBytes">new basic block bytes</param> /// <param name="basicBlock">original basic block</param> /// <param name="disassemblerFactory">diassembler factory</param> /// <returns>the first index of unaffected instruction in the original basic block, or not o value otherwise</returns> private uint?CompareDisassembleToOriginal(byte[] newBasicBlockBytes, IBasicBlock basicBlock, IDisassemblerFactory disassemblerFactory) { //disassemble new bytes after junk have been inserted var newAssemblyInstructions = new List <IAssemblyInstructionForTransformation>(); IDisassembler disasm = disassemblerFactory.Create(newBasicBlockBytes); foreach (var instruction in disasm.Disassemble()) { newAssemblyInstructions.Add(instruction); } //not enought instruction have been decoded right in this block! if (newAssemblyInstructions.Count <= 1) { return(null); } //compare to original basic block instructions //start from index 1 because first instruction is the inserted junk... for (int i = 1; i < newAssemblyInstructions.Count(); i++) { for (int j = 0; j < basicBlock.AssemblyInstructions.Count; j++) { //compare instruction until the end if they are equal if (newAssemblyInstructions[i].BytesEquals(basicBlock.AssemblyInstructions[j])) { if (instructionAreIdenticalUntilTheEnd(newAssemblyInstructions, i + 1, basicBlock.AssemblyInstructions, j + 1)) { return((uint?)j); } } } } return(null); }
public static IEnumerable <Instruction> Disassemble(this IDisassembler disassembler, MethodBase method) { return(disassembler.Disassemble(new MethodBaseAdapter(method))); }
public CodeAnalysis Analyze(IEnumerable <ICodeBlock> codeBlocks, IEnumerable <int> addresses) { var blocks = codeBlocks.ToArray(); var instructions = new Dictionary <int, LocatedInstruction>(); var traces = new Queue <int>(addresses); ICodeBlock GetContainingCodeBlock(int address) { return(blocks.FirstOrDefault(block => { var offset = block.ConvertMappedAddressToRomOffset(address); return offset >= block.Offset && offset < block.Offset + block.Length; })); } int?ReadVector(int address) { var lowByteBlock = GetContainingCodeBlock(address & 0xFFFF); var highByteBlock = GetContainingCodeBlock((address & 0xFF00) | ((address + 1) & 0x00FF)); if (lowByteBlock != null && highByteBlock != null) { return(lowByteBlock.Rom[lowByteBlock.ConvertMappedAddressToRomOffset(address)] | (highByteBlock.Rom[highByteBlock.ConvertMappedAddressToRomOffset(address + 1)] << 8)); } return(null); } while (traces.Count > 0) { var address = traces.Dequeue(); while (!instructions.ContainsKey(address)) { // Find the code block containing the current address. var codeBlock = GetContainingCodeBlock(address); if (codeBlock == null) { break; } // Read the current instruction. var instruction = _disassembler.Disassemble(codeBlock, address); instructions[address] = instruction; // Branches split the path in two. if (instruction.AddressingMode == AddressingMode.Relative) { // Create another trace at the branch location. var branchTarget = address + instruction.Length + (instruction.Operand >= 0x80 ? (instruction.Operand - 0x100) : instruction.Operand); traces.Enqueue(branchTarget); } // Jumps move the address pointer. if (instruction.Opcode == Opcode.Jmp) { if (instruction.AddressingMode == AddressingMode.Indirect) { // If it's indirect, try reading the vector. var vector = ReadVector(instruction.Operand); // If we can't read the vector, end. if (vector == null) { break; } // Get the target address and go there. address = vector.Value; continue; } // Go directly to absolute addresses. address = instruction.Operand; continue; } if (instruction.Opcode == Opcode.Rts || instruction.Opcode == Opcode.Rti) { // Can't do much about returns because we don't have a stack. break; } if (instruction.Opcode == Opcode.Jsr) { // Create a new trace for the subroutine. traces.Enqueue(instruction.Operand); } // Move the pointer forward for the next instruction. address += instruction.Length; } } return(new CodeAnalysis { Instructions = instructions .Select(kv => kv.Value) .OrderBy(i => i.Address) .ToDictionary(i => i.Address, i => i) }); }