public override Arm32Instruction DisassembleInstruction() { // Check to see if we've hit the end of the address space, and return // null if we are. We have to do this because the underlying Capstone // disassembler doesn't distinguish between invalid opcodes and // reaching the end of the image. if (!rdr.IsValid) { return(null); } if (stream.MoveNext()) { // Capstone doesn't actually use the imageReader, but apparently // reko components peek at the reader, so we have to simulate motion. rdr.Offset += stream.Current.Bytes.Length; return(new Arm32Instruction(stream.Current)); } else { // We got an invalid instruction. Create a placeholder and then // advance one opcode (which is 2 bytes for Thumb). var instr = Arm32Instruction.CreateInvalid(rdr.Address); rdr.Offset += 2; this.stream.Dispose(); // Skip over the offending instruction and resume. this.stream = dasm.DisassembleStream( rdr.Bytes, (int)rdr.Offset, (long)rdr.Address.ToLinear() - rdr.Offset) .GetEnumerator(); return(instr); } }
public ThumbDisassembler(ImageReader rdr) { this.rdr = rdr; this.dasm = CapstoneDisassembler.CreateArmDisassembler(DisassembleMode.ArmThumb); dasm.EnableDetails = true; this.stream = dasm.DisassembleStream( rdr.Bytes, (int)rdr.Offset, (long)(rdr.Address.ToLinear())) .GetEnumerator(); }
public static void Analyze(CapstoneDisassembler <Gee.External.Capstone.Arm.ArmInstruction, ArmRegister, ArmInstructionGroup, ArmInstructionDetail> Disassembler, List <Section> Sections, Dictionary <UInt32, ArmInstruction> AnalyzedCode, UInt32 VirtualAddress) { VirtualAddress = VirtualAddress - (VirtualAddress % 2); List <UInt32> AddressesToAnalyze = new List <uint>(); AddressesToAnalyze.Add(VirtualAddress); Section CurrentSection = null; while (AddressesToAnalyze.Count > 0) { UInt32 CurrentAddress = AddressesToAnalyze[0]; if ((CurrentSection == null) || (CurrentAddress < CurrentSection.VirtualAddress) || (CurrentAddress > (CurrentSection.VirtualAddress + CurrentSection.VirtualSize))) { CurrentSection = Sections.Where(s => ((CurrentAddress >= s.VirtualAddress) && (CurrentAddress < (s.VirtualAddress + s.VirtualSize)) && s.IsCode)).FirstOrDefault(); if (CurrentSection == null) { // throw new Exception("Address 0x" + CurrentAddress.ToString("X8") + " is not inside boundaries of code-sections"); // Probably jumped to this address because data was disassembled as if it were code. Ignore this. // return; AddressesToAnalyze.RemoveAt(0); continue; } } if (AnalyzedCode.ContainsKey(CurrentAddress)) { // return; AddressesToAnalyze.RemoveAt(0); continue; } IEnumerable <Instruction <Gee.External.Capstone.Arm.ArmInstruction, ArmRegister, ArmInstructionGroup, ArmInstructionDetail> > NewInstructions = Disassembler.DisassembleStream(CurrentSection.Buffer, (int)CurrentAddress - (int)CurrentSection.VirtualAddress, CurrentAddress); if (NewInstructions.Count() > 0) { UInt32 StartAddress = (UInt32)NewInstructions.First().Address; UInt32 EndAddress = (UInt32)NewInstructions.Last().Address; ArmInstruction PreviousInstruction = null; foreach (Instruction <Gee.External.Capstone.Arm.ArmInstruction, ArmRegister, ArmInstructionGroup, ArmInstructionDetail> DisassemblerInstruction in NewInstructions) { // ArmInstruction Instruction = new ArmInstruction(DisassemblerInstruction); ArmInstruction Instruction = new ArmInstruction() { Address = (UInt32)DisassemblerInstruction.Address, Bytes = DisassemblerInstruction.Bytes, Mnemonic = DisassemblerInstruction.Mnemonic, Operand = DisassemblerInstruction.Operand.Replace("sb", "r9").Replace("sl", "r10").Replace("fp", "r11").Replace("ip", "r12") }; if (AnalyzedCode.ContainsKey((UInt32)Instruction.Address)) { break; } // Merge movw + movt into one command // movw r3, #0x6010 + movt r3, #0x1000 = mov r3, #0x10006010 UInt32 HighPart, LowPart; string HighString, LowString; if ((PreviousInstruction != null) && (PreviousInstruction.Mnemonic == "movt") && (Instruction.Mnemonic == "movw") && (PreviousInstruction.Operand.Split(new char[] { ',' })[0] == Instruction.Operand.Split(new char[] { ',' })[0])) { byte[] Combined = new byte[8]; System.Buffer.BlockCopy(PreviousInstruction.Bytes, 0, Combined, 0, 4); System.Buffer.BlockCopy(Instruction.Bytes, 0, Combined, 4, 4); PreviousInstruction.Bytes = Combined; PreviousInstruction.Mnemonic = "mov"; HighString = PreviousInstruction.Operand.Substring(PreviousInstruction.Operand.IndexOf('#') + 1); if ((HighString.Length >= 2) && (HighString.Substring(0, 2) == "0x")) { HighPart = UInt32.Parse(HighString.Substring(2), System.Globalization.NumberStyles.HexNumber); } else { HighPart = UInt32.Parse(HighString); } LowString = Instruction.Operand.Substring(Instruction.Operand.IndexOf('#') + 1); if ((LowString.Length >= 2) && (LowString.Substring(0, 2) == "0x")) { LowPart = UInt32.Parse(LowString.Substring(2), System.Globalization.NumberStyles.HexNumber); } else { LowPart = UInt32.Parse(LowString); } PreviousInstruction.Operand = PreviousInstruction.Operand.Substring(0, PreviousInstruction.Operand.IndexOf('#') + 1) + "0x" + ((HighPart << 16) + LowPart).ToString("X8"); continue; } if ((PreviousInstruction != null) && (PreviousInstruction.Mnemonic == "movw") && (Instruction.Mnemonic == "movt") && (PreviousInstruction.Operand.Split(new char[] { ',' })[0] == Instruction.Operand.Split(new char[] { ',' })[0])) { byte[] Combined = new byte[8]; System.Buffer.BlockCopy(PreviousInstruction.Bytes, 0, Combined, 0, 4); System.Buffer.BlockCopy(Instruction.Bytes, 0, Combined, 4, 4); PreviousInstruction.Bytes = Combined; PreviousInstruction.Mnemonic = "mov"; HighString = Instruction.Operand.Substring(Instruction.Operand.IndexOf('#') + 1); if ((HighString.Length >= 2) && (HighString.Substring(0, 2) == "0x")) { HighPart = UInt32.Parse(HighString.Substring(2), System.Globalization.NumberStyles.HexNumber); } else { HighPart = UInt32.Parse(HighString); } LowString = PreviousInstruction.Operand.Substring(PreviousInstruction.Operand.IndexOf('#') + 1); if ((LowString.Length >= 2) && (LowString.Substring(0, 2) == "0x")) { LowPart = UInt32.Parse(LowString.Substring(2), System.Globalization.NumberStyles.HexNumber); } else { LowPart = UInt32.Parse(LowString); } PreviousInstruction.Operand = PreviousInstruction.Operand.Substring(0, PreviousInstruction.Operand.IndexOf('#') + 1) + "0x" + ((HighPart << 16) + LowPart).ToString("X8"); continue; } AnalyzedCode.Add((UInt32)Instruction.Address, Instruction); int IndexOfIndirectConstant = Instruction.Operand.IndexOf("[pc, #0x"); if (IndexOfIndirectConstant >= 0) { int IndexOfEnd = Instruction.Operand.IndexOf("]", IndexOfIndirectConstant); string PCOffsetString = Instruction.Operand.Substring(IndexOfIndirectConstant + 8, IndexOfEnd - IndexOfIndirectConstant - 8); UInt32 PCOffset = UInt32.Parse(PCOffsetString, System.Globalization.NumberStyles.HexNumber); UInt32 PC = (UInt32)Instruction.Address + 4; UInt32 PCforIndirect = PC - (PC % 4); UInt32 VirtualAddressOfIndirectConstant = PCforIndirect + PCOffset; // If the address is outside the range of the section, then this is probably data which is compiled as code. // In this case we will ignore this and not do this part of the analysis. if ((VirtualAddressOfIndirectConstant >= CurrentSection.VirtualAddress) && (VirtualAddressOfIndirectConstant < (CurrentSection.VirtualAddress + CurrentSection.VirtualSize))) { UInt32 RawOffsetOfIndirectConstant = VirtualAddressOfIndirectConstant - CurrentSection.VirtualAddress; UInt32 IndirectConstant = BitConverter.ToUInt32(CurrentSection.Buffer, (int)RawOffsetOfIndirectConstant); Instruction.Operand = Instruction.Operand.Substring(0, IndexOfIndirectConstant) + "#0x" + IndirectConstant.ToString("x8") + Instruction.Operand.Substring(IndexOfEnd + 1); } } if (JumpCommands.Contains(Instruction.Mnemonic)) { UInt32 NewAddress = UInt32.Parse(Instruction.Operand.Substring(Instruction.Operand.IndexOf("#0x") + 3), System.Globalization.NumberStyles.HexNumber); NewAddress = NewAddress - (NewAddress % 2); if (((NewAddress < StartAddress) || (NewAddress > EndAddress)) && !AddressesToAnalyze.Any(a => a == NewAddress)) { AddressesToAnalyze.Add(NewAddress); } } PreviousInstruction = Instruction; } } AddressesToAnalyze.RemoveAt(0); } }