Beispiel #1
0
        public static AnalyzedFile Analyze(string FilePath, string AsmPath = null)
        {
            PeFile File = new PeFile(FilePath);

            SortedList <UInt32, ArmInstruction> AnalyzedCode = new SortedList <uint, ArmInstruction>(0x1000000); // Default capacity of 0x100000 was not enough for analyzing ntoskrnl.exe

            if ((AsmPath != null) && System.IO.File.Exists(AsmPath))
            {
                using (StreamReader Reader = new StreamReader(AsmPath))
                {
                    while (Reader.Peek() >= 0)
                    {
                        ArmInstruction Instruction = new ArmInstruction(Reader.ReadLine());
                        AnalyzedCode.Add(Instruction.Address, Instruction);
                    }
                }
            }
            else
            {
                CapstoneDisassembler <Gee.External.Capstone.Arm.ArmInstruction, ArmRegister, ArmInstructionGroup, ArmInstructionDetail> Disassembler = CapstoneDisassembler.CreateArmDisassembler(DisassembleMode.ArmThumb);

                // Initially use a Dictionary and sort it afterwards. For analyzing ntoskrnl.exe this is about 60 times faster than using a SortedList from the start.
                // Default capacity of 0x100000 was not enough for analyzing ntoskrnl.exe
                Dictionary <UInt32, ArmInstruction> TempCode = new Dictionary <uint, ArmInstruction>(0x1000000);

                // Analyze from entrypoint
                Analyze(Disassembler, File.Sections, TempCode, (UInt32)(File.ImageBase + File.EntryPoint));

                // Analyze from exports
                foreach (FunctionDescriptor Function in File.Exports)
                {
                    Analyze(Disassembler, File.Sections, TempCode, (UInt32)(Function.VirtualAddress));
                }

                // Analyze from imports
                foreach (FunctionDescriptor Function in File.Imports)
                {
                    Analyze(Disassembler, File.Sections, TempCode, (UInt32)(Function.VirtualAddress));
                }

                // Analyze from runtime-functions
                foreach (FunctionDescriptor Function in File.RuntimeFunctions)
                {
                    Analyze(Disassembler, File.Sections, TempCode, (UInt32)(Function.VirtualAddress));
                }

                // Sort the instructions.
                // SortedList is used, because it can be indexed by value (not only by key).
                List <UInt32> Keys = TempCode.Keys.ToList();
                Keys.Sort();
                foreach (UInt32 Key in Keys)
                {
                    AnalyzedCode.Add(Key, TempCode[Key]);
                }

                if (AsmPath != null)
                {
                    System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(AsmPath));

                    using (StreamWriter Writer = new StreamWriter(AsmPath, false))
                    {
                        for (int i = 0; i < AnalyzedCode.Count; i++)
                        {
                            Writer.WriteLine(AnalyzedCode.Values[i].ToString());
                        }
                    }
                }
            }

            return(new AnalyzedFile()
            {
                File = File, Code = AnalyzedCode
            });
        }
Beispiel #2
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);
            }
        }