Example #1
0
        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);
            }
        }
Example #2
0
 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();
 }
Example #3
0
        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);
            }
        }