Ejemplo n.º 1
0
        public static ImageSegment?LoadSegment(MemorySegment_v1 segment, IPlatform platform, DecompilerEventListener listener)
        {
            if (segment.Name is null)
            {
                listener.Warn("Memory map segments must have names.");
                return(null);
            }

            if (!platform.TryParseAddress(segment.Address, out var addr))
            {
                listener.Warn(
                    "Unable to parse address '{0}' in memory map segment {1}.",
                    segment.Address !,
                    segment.Name !);
                return(null);
            }
            if (!uint.TryParse(segment.Size, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var size))
            {
                listener.Warn(
                    "Unable to parse hexadecimal size '{0}' in memory map segment {1}.",
                    segment.Size !,
                    segment.Name !);
                return(null);
            }

            var mem = new ByteMemoryArea(addr, new byte[size]);

            return(new ImageSegment(segment.Name, mem, ConvertAccess(segment.Attributes)));
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Rewrites a machine word constant depending on its data type.
        /// </summary>
        /// <param name="c"></param>
        /// <param name="dereferenced"></param>
        /// <returns></returns>
        public Expression Rewrite(Constant c, Expression?basePtr, bool dereferenced)
        {
            this.c       = c;
            this.basePtr = basePtr;
            DataType dtInferred = c.DataType;

            if (dtInferred == null)
            {
                eventListener.Warn(new NullCodeLocation(""),
                                   $"The equivalence class {c.TypeVariable!.Name} has a null data type");
                dtInferred = c.TypeVariable.DataType;
            }
            else
            {
                this.pOrig = (c.DataType as PrimitiveType) !;
                if (c.TypeVariable != null)
                {
                    dtInferred = c.TypeVariable.DataType;
                    this.pOrig = (c.TypeVariable.OriginalDataType as PrimitiveType) !;
                }
            }
            var dt = dtInferred.ResolveAs <DataType>() !;

            this.dereferenced = dereferenced;
            return(dt.Accept(this));
        }
Ejemplo n.º 3
0
 public Expression Transform()
 {
     if (this.pt != null)
     {
         ctx.RemoveIdentifierUse(idDst !);
         var cNew = src !.CloneExpression();
         cNew.DataType = dt !;
         return(cNew);
     }
     if (this.ptr != null)
     {
         if (src is Constant cSrc)
         {
             ctx.RemoveIdentifierUse(idDst !);
             var addr = Address.Create(ptr, cSrc.ToUInt64());
             addr.DataType = ptr;
             return(addr);
         }
         if (src is Address)
         {
             ctx.RemoveIdentifierUse(idDst !);
             var addr = src.CloneExpression();
             addr.DataType = ptr;
             return(addr);
         }
     }
     listener.Warn(
         new NullCodeLocation(""),
         "Constant propagation failed. Resulting type is {0}, which isn't supported yet.",
         dt !);
     return(idDst !);
 }
Ejemplo n.º 4
0
        public override void ApplyRelocation(Address baseOfImage, uint page, EndianImageReader rdr, RelocationDictionary relocations)
        {
            ushort  fixup  = rdr.ReadLeUInt16();
            Address offset = baseOfImage + page + (fixup & 0x0FFFu);
            var     arch   = program.Architecture;
            var     imgR   = program.CreateImageReader(arch, offset);
            var     imgW   = program.CreateImageWriter(arch, offset);

            switch (fixup >> 12)
            {
            case RelocationAbsolute:
                // Used for padding to 4-byte boundary, ignore.
                break;

            case RelocationHighLow:
            {
                uint n = (uint)(imgR.ReadUInt32() + (baseOfImage - program.ImageMap.BaseAddress));
                imgW.WriteUInt32(n);
                relocations.AddPointerReference(offset.ToLinear(), n);
                break;
            }

            case 0xA:
                break;

            default:
                dcSvc.Warn(
                    dcSvc.CreateAddressNavigator(program, offset),
                    string.Format(
                        "Unsupported i386 PE fixup type: {0:X}",
                        fixup >> 12));
                break;
            }
        }
Ejemplo n.º 5
0
        // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
        public override void ApplyRelocation(Address baseOfImage, uint page, EndianImageReader rdr, RelocationDictionary relocations)
        {
            ushort  fixup  = rdr.ReadLeUInt16();
            var     rt     = (Arm64Rt)(fixup >> 12);
            Address offset = baseOfImage + page + (fixup & 0x0FFFu);

            DebugEx.Verbose(PeImageLoader.trace, "  {0:X4} {1}", fixup, rt);
            var imgR = program.CreateImageReader(program.Architecture, offset);
            var imgW = program.CreateImageWriter(program.Architecture, offset);

            switch (rt)
            {
            case Arm64Rt.IMAGE_REL_ARM64_ABSOLUTE:
                break;

            case Arm64Rt.IMAGE_REL_ARM64_SECREL_HIGH12A:
                var uInstr = imgR.ReadLeUInt32();
                break;

            default:
                eventListener.Warn(
                    eventListener.CreateAddressNavigator(program, offset),
                    string.Format(
                        "Unsupported AArch64 PE fixup type: {0:X}",
                        fixup >> 12));
                break;
            }
        }
Ejemplo n.º 6
0
        /// Plan of attack:
        /// In each unscanned "hole", look for signatures of procedure entries.
        /// These are procedure entry candidates.
        /// Scan each of the procedure entry candidates heuristically.
        ///
        /// Next scan all executable code segments for:
        ///  - calls that reach those candidates
        ///  - jmps to those candidates
        ///  - pointers to those candidates.
        /// Each time we find a call, we increase the score of the candidate.
        /// At the end we have a list of scored candidates.
        public void ScanImageHeuristically()
        {
            var sw = new Stopwatch();

            sw.Start();
            var list     = new List <HeuristicBlock>();
            var ranges   = FindUnscannedRanges();
            var fnRanges = FindPossibleFunctions(ranges).ToList();
            int n        = 0;

            foreach (var range in fnRanges)
            {
                var hproc = DisassembleProcedure(range.Item1, range.Item2);
                var hps   = new HeuristicProcedureScanner(program, hproc, host);
                hps.BlockConflictResolution();
                DumpBlocks(hproc.Cfg.Nodes);
                hps.GapResolution();
                // TODO: add all guessed code to image map -- clearly labelled.
                AddBlocks(hproc);
                list.AddRange(hproc.Cfg.Nodes);
                eventListener.ShowProgress("Estimating procedures", n, fnRanges.Count);
                ++n;
            }
            eventListener.Warn(
                new Reko.Core.Services.NullCodeLocation("Heuristics"),
                string.Format("Scanned image in {0} seconds, finding {1} blocks.",
                              sw.Elapsed.TotalSeconds, list.Count));
            list.ToString();
        }
Ejemplo n.º 7
0
        public ExternalProcedure ResolveProcedure(string moduleName, int ordinal, IPlatform platform)
        {
            foreach (var program in project.Programs)
            {
                if (!program.EnvironmentMetadata.Modules.TryGetValue(moduleName, out var mod))
                {
                    continue;
                }

                if (mod.ServicesByOrdinal.TryGetValue(ordinal, out var svc))
                {
                    EnsureSignature(program, svc);
                    if (svc.Signature != null)
                    {
                        return(new ExternalProcedure(svc.Name, svc.Signature, svc.Characteristics));
                    }
                    else
                    {
                        // We have a name for the external procedure, but can't find a proper signature for it.
                        // So we make a "dumb" one. It's better than nothing.
                        eventListener.Warn(
                            new NullCodeLocation(moduleName),
                            "Unable to resolve signature for {0}", svc.Name);
                        return(new ExternalProcedure(svc.Name, new FunctionType()));
                    }
                }
            }
            return(platform.LookupProcedureByOrdinal(moduleName, ordinal));
        }
Ejemplo n.º 8
0
        public void Transform()
        {
            var ppr = new PtrPrimitiveReplacer(factory, store, program, eventListener);

            ppr.ReplaceAll();
            var cpa = new ConstantPointerAnalysis(factory, store, program);

            cpa.FollowConstantPointers();
            int iteration = 0;

            do
            {
                if (eventListener.IsCanceled())
                {
                    return;
                }
                ++iteration;
                if (iteration > 50)
                {
                    eventListener.Warn(
                        string.Format("Type transformer has looped {0} times, quitting prematurely.", iteration));
                    return;
                }
                Changed = false;
                visitedTypes.Clear();
                foreach (TypeVariable tv in store.TypeVariables)
                {
                    if (eventListener.IsCanceled())
                    {
                        return;
                    }
                    EquivalenceClass eq = tv.Class;
                    if (eq.DataType != null)
                    {
                        DateTime start = DateTime.Now;
                        eq.DataType = eq.DataType.Accept(this);
                        DateTime end = DateTime.Now;
                        if (eq.DataType is UnionType ut)
                        {
                            //trace.Verbose("= TT: took {2,4} msec to simplify {0} ({1})", tv.DataType, eq.DataType, (end - start).Milliseconds);
                        }
                    }
                    if (tv.DataType != null)
                    {
                        tv.DataType = tv.DataType.Accept(this);
                    }
                    // Debug.Print("Transformed {0}:{1}", tv, tv.Class.DataType);
                }
                if (ppr.ReplaceAll())
                {
                    Changed = true;
                }
                if (NestedComplexTypeExtractor.ReplaceAll(factory, store))
                {
                    Changed = true;
                }
            } while (Changed);
        }
Ejemplo n.º 9
0
 public void VisitPhiAssignment(PhiAssignment phi)
 {
     if (!seenPhi)
     {
         seenPhi = true;
         eventListener.Warn(
             eventListener.CreateBlockNavigator(this.program, stmCur.Block),
             "Phi functions will be ignored by type analysis. " +
             "This may be caused by a failure in a previous stage of the decompilation.");
     }
 }
Ejemplo n.º 10
0
        /// <summary>
        /// Executes the core of the analysis
        /// </summary>
        /// <remarks>
        /// The algorithm visits nodes in post-order in each iteration. This
        /// means that all descendants of a node will be visited (and
        /// hence had the chance to be reduced) before the node itself.
        /// The algorithm’s behavior when visiting node _n_
        /// depends on hether the region at _n_
        /// is acyclic (has no loop) or not. For an acyclic region, the 
        /// algorithm tries to match the subgraph
        /// at _n_to an acyclic schemas (3.2). If there is no match,
        /// and the region is a switch candidate, then it attempts to
        /// refine the region at _n_ into a switch region.
        ///             
        /// If _n_ is cyclic, the algorithm 
        /// compares the region at _n_ to the cyclic schemata.
        /// If this fails, it refines _n_ into a loop (3.6).
        /// 
        /// If both matching and refinement do not make progress, the
        /// current node _n_ is then skipped for the current iteration of
        /// the algorithm.  If there is an iteration in which all
        /// nodes are skipped, i.e., the algorithm makes no progress, then
        /// the algorithm employs a last resort refinement (3.7) to
        /// ensure that progress can be made in the next iteration.
        /// </remarks>
        public Region Execute()
        {
            var result = BuildRegionGraph(proc);
            this.regionGraph = result.Item1;
            this.entry = result.Item2;
            int iterations = 0;
            int oldCount;
            int newCount;
            do
            {
                if (eventListener.IsCanceled())
                    break;
                ++iterations;
                if (iterations > 1000)
                {
                    eventListener.Warn(
                        eventListener.CreateProcedureNavigator(program, proc),
                        "Structure analysis stopped making progress, quitting. Please report this issue at https://github.com/uxmal/reko");
                    DumpGraph();
                    break;
                }

                oldCount = regionGraph.Nodes.Count;
                this.doms = new DominatorGraph<Region>(this.regionGraph, result.Item2);
                this.unresolvedCycles = new Queue<Tuple<Region, ISet<Region>>>();
                this.unresolvedNoncycles = new Queue<Tuple<Region, ISet<Region>>>();
                var postOrder = new DfsIterator<Region>(regionGraph).PostOrder(entry).ToList();

                bool didReduce = false;
                foreach (var n in postOrder)
                {
                    Probe();
                    didReduce = false;
                    do
                    {
                        if (eventListener.IsCanceled())
                            break;
                        didReduce = ReduceAcyclic(n);
                        if (!didReduce && IsCyclic(n))
                        {
                            didReduce = ReduceCyclic(n);
                        }
                    } while (didReduce);
                }
                newCount = regionGraph.Nodes.Count;
                if (newCount == oldCount && newCount > 1)
                {
                    // Didn't make any progress this round,
                    // try refining unstructured regions
                    ProcessUnresolvedRegions();
                }
            } while (regionGraph.Nodes.Count > 1);
            return entry;
        }
Ejemplo n.º 11
0
        public void Transform()
        {
            var ppr = new PtrPrimitiveReplacer(factory, store, program);

            ppr.ReplaceAll(eventListener);
            var cpa = new ConstantPointerAnalysis(factory, store, program);

            cpa.FollowConstantPointers();
            int iteration = 0;

            do
            {
                if (eventListener.IsCanceled())
                {
                    return;
                }
                ++iteration;
                if (iteration > 50)
                {
                    eventListener.Warn(new NullCodeLocation(""),
                                       string.Format("Type transformer has looped {0} times, quitting prematurely.", iteration));
                    return;
                }
                Changed           = false;
                this.visitedTypes = new HashSet <DataType>();
                foreach (TypeVariable tv in store.TypeVariables)
                {
                    if (eventListener.IsCanceled())
                    {
                        return;
                    }
                    tvCur = tv;
                    EquivalenceClass eq = tv.Class;
                    if (eq.DataType != null)
                    {
                        eq.DataType = eq.DataType.Accept(this);
                    }
                    if (tv.DataType != null)
                    {
                        tv.DataType = tv.DataType.Accept(this);
                    }
                    // Debug.Print("Transformed {0}:{1}", tv, tv.Class.DataType);
                }
                if (ppr.ReplaceAll(eventListener))
                {
                    Changed = true;
                }
                if (NestedComplexTypeExtractor.ReplaceAll(factory, store))
                {
                    Changed = true;
                }
            } while (Changed);
        }
Ejemplo n.º 12
0
        public Expression Rewrite(Address addr, Expression?basePtr, bool dereferenced)
        {
            if (addr.Selector.HasValue)
            {
                if (!mpSelectorToSegId.TryGetValue(addr.Selector.Value, out Identifier segId))
                {
                    eventListener.Warn(
                        "Selector {0:X4} has no known segment.",
                        addr.Selector.Value);
                    return(addr);
                }
                var ptrSeg = segId.TypeVariable !.DataType.ResolveAs <Pointer>();
                if (ptrSeg == null)
                {
                    //$TODO: what should the warning be?
                    //$BUG: create a fake field for now.
                    var        field = new StructureField((int)addr.Offset, new UnknownType());
                    Expression x     = new FieldAccess(new UnknownType(), new Dereference(segId.DataType, segId), field);
                    if (!dereferenced)
                    {
                        x = new UnaryExpression(Operator.AddrOf, addr.DataType, x);
                    }
                    return(x);
                }
                var baseType = ptrSeg.Pointee.ResolveAs <StructureType>() !;
                var dt       = addr.TypeVariable !.DataType.ResolveAs <Pointer>() !;
                this.c = Constant.Create(
                    PrimitiveType.CreateWord(addr.DataType.BitSize - ptrSeg.BitSize),
                    addr.Offset);

                var        f  = EnsureFieldAtOffset(baseType, dt.Pointee, c.ToInt32());
                Expression ex = new FieldAccess(f.DataType, new Dereference(ptrSeg, segId), f);
                if (dereferenced || dt.Pointee is ArrayType)
                {
                    return(ex);
                }
                else
                {
                    var un = new UnaryExpression(Operator.AddrOf, dt, ex);
                    return(un);
                }
            }
            else
            {
                this.c = addr.ToConstant();
                this.c.TypeVariable = addr.TypeVariable;
                var dtInferred = addr.TypeVariable !.DataType.ResolveAs <DataType>() !;
                this.pOrig        = addr.TypeVariable.OriginalDataType as PrimitiveType;
                this.dereferenced = dereferenced;
                return(dtInferred.Accept(this));
            }
        }
Ejemplo n.º 13
0
 private KeyValuePair <Address, Procedure_v1> LoadUserProcedure_v1(
     Program program,
     Procedure_v1 sup)
 {
     program.Architecture.TryParseAddress(sup.Address, out Address addr);
     if (!sup.Decompile && sup.Signature == null && string.IsNullOrEmpty(sup.CSignature))
     {
         listener.Warn(
             listener.CreateAddressNavigator(program, addr),
             "User procedure '{0}' has been marked 'no decompile' but its signature " +
             "has not been specified.",
             sup.Name);
     }
     return(new KeyValuePair <Address, Procedure_v1>(addr, sup));
 }
Ejemplo n.º 14
0
        public Expression Rewrite(Address addr, bool dereferenced)
        {
            if (addr.Selector.HasValue)
            {
                Identifier segId;
                if (!mpSelectorToSegId.TryGetValue(addr.Selector.Value, out segId))
                {
                    eventListener.Warn(
                        new NullCodeLocation(""),
                        "Selector {0:X4} has no known segment.",
                        addr.Selector.Value);
                    return(addr);
                }
                var ptrSeg = segId.TypeVariable.DataType.ResolveAs <Pointer>();
                if (ptrSeg == null)
                {
                    //$TODO: what should the warning be?
                    return(addr);
                }
                var baseType = ptrSeg.Pointee.ResolveAs <StructureType>();
                var dt       = addr.TypeVariable.DataType.ResolveAs <Pointer>();
                this.c = Constant.Create(
                    PrimitiveType.CreateWord(addr.DataType.Size - ptrSeg.Size),
                    addr.Offset);

                var        f  = EnsureFieldAtOffset(baseType, dt.Pointee, c.ToInt32());
                Expression ex = new FieldAccess(dt, new Dereference(ptrSeg, segId), f);
                if (dereferenced || dt.Pointee is ArrayType)
                {
                    return(ex);
                }
                else
                {
                    var un = new UnaryExpression(Operator.AddrOf, dt, ex);
                    return(un);
                }
            }
            else
            {
                this.c = Constant.UInt32(addr.ToUInt32());  //$BUG: won't work for x86.
                var dtInferred = addr.TypeVariable.DataType.ResolveAs <DataType>();
                this.pOrig        = addr.TypeVariable.OriginalDataType as PrimitiveType;
                this.dereferenced = dereferenced;
                return(dtInferred.Accept(this));
            }
        }
Ejemplo n.º 15
0
        public const short IMAGE_REL_MIPS_PAIR      = 0x0025; // This relocation is only valid when it immediately follows a REFHI or SECRELHI relocation. Its SymbolTableIndex contains a displacement and not an index into the symbol table.

        public override void ApplyRelocation(Address baseOfImage, uint page, EndianImageReader rdr, RelocationDictionary relocations)
        {
            ushort  fixup  = rdr.ReadUInt16();
            Address offset = baseOfImage + page + (fixup & 0x0FFFu);
            var     arch   = program.Architecture;
            var     imgR   = program.CreateImageReader(arch, offset);
            var     imgW   = program.CreateImageWriter(arch, offset);
            uint    w      = imgR.ReadUInt32();
            int     s;

            switch (fixup >> 12)
            {
            case IMAGE_REL_MIPS_ABSOLUTE:
                // Used for padding to 4-byte boundary, ignore.
                break;

            case IMAGE_REL_MIPS_REFWORD:
                break;

            case IMAGE_REL_MIPS_JMPADDR:
                break;

            case IMAGE_REL_MIPS_REFHI:
                w = imgR.ReadUInt32();
                //w += (fixup & 0x0FFFu);
                //imgW.WriteUInt32(w);
                s = rdr.ReadInt16();
                w = (uint)(w + s);
                // w points to something.
                break;

            case IMAGE_REL_MIPS_REFLO:
                // w points to something.
                break;

            default:
                dcSvc.Warn(
                    dcSvc.CreateAddressNavigator(program, offset),
                    string.Format(
                        "Unsupported MIPS PE fixup type: {0:X}",
                        fixup >> 12));
                break;
            }
        }
Ejemplo n.º 16
0
        public override DataType VisitStructure(StructureType str)
        {
            ++recursionGuard;
            DataType dt;

            if (recursionGuard > 100)
            {
                eventListener.Warn(new NullCodeLocation(""), "Recursion too deep in PtrPrimitiveReplacer");
                dt = str;
            }
            else
            {
                //if (visitedTypes.Contains(str))
                //   return str;
                //visitedTypes.Add(str);
                dt = base.VisitStructure(str);
            }
            --recursionGuard;
            return(dt);
        }
Ejemplo n.º 17
0
 public Expression Transform()
 {
     if (this.pt != null)
     {
         ctx.RemoveIdentifierUse(idDst !);
         var pt   = idDst !.DataType.ResolveAs <PrimitiveType>();
         var cNew = src !.CloneExpression();
         if (src.DataType.IsWord &&
             src is Constant cSrc &&
             pt != null &&
             pt.Domain == Domain.Real)
         {
             // Raw bitvector assigned to an real-valued register. We need to interpret the bitvector
             // as a floating-point constant.
             cNew = Constant.RealFromBitpattern(pt, cSrc.ToInt64());
         }
         cNew.DataType = dt !;
         return(cNew);
     }
     if (this.ptr != null)
     {
         if (src is Constant cSrc)
         {
             ctx.RemoveIdentifierUse(idDst !);
             var addr = Address.Create(ptr, cSrc.ToUInt64());
             addr.DataType = ptr;
             return(addr);
         }
         if (src is Address)
         {
             ctx.RemoveIdentifierUse(idDst !);
             var addr = src.CloneExpression();
             addr.DataType = ptr;
             return(addr);
         }
     }
     listener.Warn(
         "Constant propagation failed. Resulting type is {0}, which isn't supported yet.",
         dt !);
     return(idDst !);
 }
Ejemplo n.º 18
0
        private void LoadHeaders()
        {
            ImageData imageData = xexData;

            xexData.header = rdr.ReadStruct <XexHeader>();

            XexHeader header = xexData.header;

            switch (header.magic)
            {
            case XEX2_MAGIC:
            case XEX1_MAGIC:
                break;

            default:
                throw new BadImageFormatException("Invalid XEX Magic");
            }

            for (uint i = 0; i < header.header_count; i++)
            {
                bool add = true;
                XexOptionalHeader st_optionalHeader = rdr.ReadStruct <XexOptionalHeader>();
                OptionalHeader    optionalHeader    = new OptionalHeader(st_optionalHeader);

                switch ((byte)optionalHeader.key)
                {
                // just the data
                case 0x00:
                case 0x01:
                    optionalHeader.value  = optionalHeader.offset;
                    optionalHeader.offset = 0;
                    break;

                case 0xFF:
                    optionalHeader.length = rdr.ReadAt <UInt32>(optionalHeader.offset, (r) =>
                    {
                        return(r.ReadUInt32());
                    });
                    optionalHeader.offset += 4;

                    if (optionalHeader.length + optionalHeader.offset > rdr.Bytes.Length)
                    {
                        decompilerEventListener.Warn(
                            new NullCodeLocation(""),
                            $"Optional header {i} (0x{optionalHeader.key:X}) crosses file boundary. Will not be read"
                            );
                        add = false;
                    }
                    break;

                default:
                    optionalHeader.length = ((uint)(byte)optionalHeader.key) * 4;

                    if (optionalHeader.length + optionalHeader.offset > rdr.Bytes.Length)
                    {
                        decompilerEventListener.Warn(
                            new NullCodeLocation(""),
                            $"Optional header {i} (0x{optionalHeader.key:X}) crosses file boundary. Will not be read"
                            );
                        add = false;
                    }
                    break;
                }

                if (add)
                {
                    optional_headers.Add(optionalHeader);
                }
            }

            for (int i = 0; i < optional_headers.Count; i++)
            {
                OptionalHeader opt = optional_headers[i];

                // go to the header offset
                if (opt.length > 0 && opt.offset != 0)
                {
                    rdr.Offset = opt.offset;
                }

                // process the optional headers
                switch (opt.key)
                {
                case XEXHeaderKeys.XEX_HEADER_SYSTEM_FLAGS:
                    imageData.system_flags = (XEXSystemFlags)opt.value;
                    break;

                case XEXHeaderKeys.XEX_HEADER_RESOURCE_INFO:
                    uint count = (opt.length - 4) / 16;
                    xexData.resources = new List <XexResourceInfo>((int)count);

                    for (uint n = 0; n < count; n++)
                    {
                        xexData.resources.Insert(i, rdr.ReadStruct <XexResourceInfo>());
                    }
                    break;

                case XEXHeaderKeys.XEX_HEADER_EXECUTION_INFO:
                    imageData.execution_info = rdr.ReadStruct <XexExecutionInfo>();
                    break;

                case XEXHeaderKeys.XEX_HEADER_GAME_RATINGS:
                    break;

                case XEXHeaderKeys.XEX_HEADER_TLS_INFO:
                    imageData.tls_info = rdr.ReadStruct <XexTlsInfo>();
                    break;

                case XEXHeaderKeys.XEX_HEADER_IMAGE_BASE_ADDRESS:
                    imageData.exe_address = opt.value;
                    break;

                case XEXHeaderKeys.XEX_HEADER_ENTRY_POINT:
                    imageData.exe_entry_point = opt.value;
                    break;

                case XEXHeaderKeys.XEX_HEADER_DEFAULT_STACK_SIZE:
                    imageData.exe_stack_size = opt.value;
                    break;

                case XEXHeaderKeys.XEX_HEADER_DEFAULT_HEAP_SIZE:
                    imageData.exe_heap_size = opt.value;
                    break;

                case XEXHeaderKeys.XEX_HEADER_FILE_FORMAT_INFO:
                    XexEncryptionHeader encHeader = rdr.ReadStruct <XexEncryptionHeader>();

                    imageData.file_format_info.encryption_type  = encHeader.encryption_type;
                    imageData.file_format_info.compression_type = encHeader.compression_type;

                    switch (encHeader.compression_type)
                    {
                    case XEXCompressionType.XEX_COMPRESSION_NONE:
                        break;

                    case XEXCompressionType.XEX_COMPRESSION_DELTA:
                        throw new NotImplementedException("XEX: image::Binary is using unsupported delta compression");

                    case XEXCompressionType.XEX_COMPRESSION_BASIC:
                        uint block_count = (opt.length - 8) / 8;
                        imageData.file_format_info.basic_blocks = new List <XexFileBasicCompressionBlock>((int)block_count);

                        for (int ib = 0; ib < block_count; ib++)
                        {
                            imageData.file_format_info.basic_blocks.Insert(ib, rdr.ReadStruct <XexFileBasicCompressionBlock>());
                        }
                        break;

                    case XEXCompressionType.XEX_COMPRESSION_NORMAL:
                        imageData.file_format_info.normal = rdr.ReadStruct <XexFileNormalCompressionInfo>();
                        break;
                    }

                    if (encHeader.encryption_type != XEXEncryptionType.XEX_ENCRYPTION_NONE)
                    {
                        //
                    }
                    break;

                case XEXHeaderKeys.XEX_HEADER_IMPORT_LIBRARIES:
                    XexImportLibraryBlockHeader blockHeader = rdr.ReadStruct <XexImportLibraryBlockHeader>();

                    long string_table = rdr.Offset;
                    for (int j = 0; j < blockHeader.count; j++)
                    {
                        string name = rdr.ReadCString(PrimitiveType.Char, Encoding.ASCII).ToString();
                        imageData.libNames.Add(name);
                    }
                    rdr.Offset = string_table + blockHeader.string_table_size;

                    for (int m = 0; m < blockHeader.count; m++)
                    {
                        XexImportLibaryHeader imp_header = rdr.ReadStruct <XexImportLibaryHeader>();

                        string name       = null;
                        int    name_index = (byte)imp_header.name_index;
                        if (name_index < blockHeader.count)
                        {
                            name = imageData.libNames[name_index];
                        }

                        for (uint ri = 0; ri < imp_header.record_count; ++ri)
                        {
                            UInt32 recordEntry = rdr.ReadUInt32();
                            xexData.import_records.Add(recordEntry);
                        }
                    }
                    break;
                }
            }

            // load the loader info
            {
                rdr.Offset = header.security_offset;

                switch (header.magic)
                {
                case XEX1_MAGIC:
                    Xex1LoaderInfo info1 = rdr.ReadStruct <Xex1LoaderInfo>();
                    xexData.loader_info.aes_key = info1.aes_key;
                    break;

                case XEX2_MAGIC:
                    Xex2LoaderInfo info2 = rdr.ReadStruct <Xex2LoaderInfo>();
                    xexData.loader_info.aes_key = info2.aes_key;
                    break;
                }
            }

            // load the sections
            {
                rdr.Offset = header.security_offset + 0x180;

                UInt32 sectionCount = rdr.ReadUInt32();
                xexData.sections = new List <XexSection>((int)sectionCount);

                for (int si = 0; si < sectionCount; si++)
                {
                    xexData.sections.Insert(0, rdr.ReadStruct <XexSection>());
                }
            }

            // decrypt the XEX key
            {
                byte[] keyToUse = xe_xex2_devkit_key;
                if (header.magic != XEX1_MAGIC && xexData.execution_info.title_id != 0)
                {
                    keyToUse = xe_xex2_retail_key;
                }

                Rijndael aes = new RijndaelManaged()
                {
                    BlockSize = 128,
                    KeySize   = 128,
                    Mode      = CipherMode.ECB,
                    Key       = keyToUse,
                    Padding   = PaddingMode.None
                };

                xexData.session_key = aes
                                      .CreateDecryptor()
                                      .TransformFinalBlock(xexData.loader_info.aes_key, 0, 16);
                decompilerEventListener.Info(
                    new NullCodeLocation(""),
                    "XEX Session key: " + BitConverter.ToString(xexData.session_key).Replace("-", "")
                    );
            }
        }
Ejemplo n.º 19
0
 public void LoadUserData(UserData_v4 sUser, Program program, UserData user, string projectFilePath)
 {
     if (sUser == null)
         return;
     user.OnLoadedScript = sUser.OnLoadedScript;
     if (sUser.Processor != null)
     {
         user.Processor = sUser.Processor.Name;
         if (program.Architecture == null && !string.IsNullOrEmpty(user.Processor))
         {
             program.Architecture = Services.RequireService<IConfigurationService>().GetArchitecture(user.Processor!)!;
         }
         //$BUG: what if architecture isn't supported? fail the whole thing?
         program.Architecture!.LoadUserOptions(XmlOptions.LoadIntoDictionary(sUser.Processor.Options, StringComparer.OrdinalIgnoreCase));
     }
     if (sUser.PlatformOptions != null)
     {
         user.Environment = sUser.PlatformOptions.Name;
         program.Platform.LoadUserOptions(XmlOptions.LoadIntoDictionary(sUser.PlatformOptions.Options, StringComparer.OrdinalIgnoreCase));
     }
     if (sUser.Procedures != null)
     {
         user.Procedures = sUser.Procedures
             .Select(sup => LoadUserProcedure_v1(program, sup))
             .Where(kv => !(kv.Key is null))
             .ToSortedList(kv => kv.Key, kv => kv.Value);
         user.ProcedureSourceFiles = user.Procedures
             .Where(kv => !string.IsNullOrEmpty(kv.Value.OutputFile))
             .ToDictionary(kv => kv.Key!, kv => ConvertToAbsolutePath(projectFilePath, kv.Value.OutputFile)!);
     }
     if (sUser.GlobalData != null)
     {
         user.Globals = sUser.GlobalData
             .Select(sud =>
             {
                 program.Architecture.TryParseAddress(sud.Address, out Address addr);
                 return new KeyValuePair<Address, GlobalDataItem_v2>(
                     addr,
                     sud);
             })
             .Where(kv => !(kv.Key is null))
            .ToSortedList(kv => kv.Key, kv => kv.Value);
     }
   
     if (sUser.Annotations != null)
     {
         user.Annotations = new AnnotationList(sUser.Annotations
             .Select(LoadAnnotation)
             .Where(a => !(a.Address is null))
             .ToList());
     }
     if (sUser.Heuristics != null)
     {
         user.Heuristics.UnionWith(sUser.Heuristics
             .Where(h => !(h.Name is null))
             .Select(h => h.Name!));
     }
     if (sUser.TextEncoding != null)
     {
         Encoding enc = null;
         try
         {
             enc = Encoding.GetEncoding(sUser.TextEncoding);
         }
         catch
         {
             listener.Warn(
                 "Unknown text encoding '{0}'. Defaulting to platform text encoding.", 
                 sUser.TextEncoding);
         }
         user.TextEncoding = enc;
     }
     program.EnvironmentMetadata = project.LoadedMetadata;
     if (sUser.Calls != null)
     {
         program.User.Calls = sUser.Calls
             .Select(c => LoadUserCall(c, program))
             .Where(c => c != null && !(c.Address is null))
             .ToSortedList(k => k!.Address!, v => v!);
     }
     if (sUser.RegisterValues != null)
     {
         program.User.RegisterValues = LoadRegisterValues(sUser.RegisterValues);
     }
     if (sUser.JumpTables != null)
     {
         program.User.JumpTables = sUser.JumpTables.Select(LoadJumpTable_v4)
             .Where(t => t != null && t.Address != null)
             .ToSortedList(k => k!.Address, v => v);
     }
     if (sUser.IndirectJumps != null)
     {
         program.User.IndirectJumps = sUser.IndirectJumps
             .Select(ij => LoadIndirectJump_v4(ij, program))
             .Where(ij => ij.Item1 != null)
             .ToSortedList(k => k!.Item1, v => v!.Item2);
     }
     if (sUser.Segments != null)
     {
         program.User.Segments = sUser.Segments
             .Select(s => LoadUserSegment_v4(s))
             .Where(s => s != null)
             .ToList();
     }
     program.User.ShowAddressesInDisassembly = sUser.ShowAddressesInDisassembly;
     program.User.ShowBytesInDisassembly = sUser.ShowBytesInDisassembly;
     program.User.ExtractResources = sUser.ExtractResources;
     // Backwards compatibility: older versions used single file policy.
     program.User.OutputFilePolicy = sUser.OutputFilePolicy ?? Program.SingleFilePolicy;
     program.User.AggressiveBranchRemoval = sUser.AggressiveBranchRemoval;
 }
Ejemplo n.º 20
0
 public void Warn(string format, params object [] args)
 {
     decompilerEventListener.Warn(
         decompilerEventListener.CreateAddressNavigator(program, addr),
         string.Format(format, args));
 }
Ejemplo n.º 21
0
 public void Warn(Address addr, string message)
 {
     eventListener.Warn(eventListener.CreateAddressNavigator(Program, addr), message);
 }
Ejemplo n.º 22
0
        public TableExtent DiscoverTableExtent(Address addrSwitch, RtlTransfer xfer, DecompilerEventListener listener)
        {
            if (!Start(rtlBlock, host.BlockInstructionCount(rtlBlock) - 1, xfer.Target))
            {
                // No registers were found, so we can't trace back.
                return(null);
            }
            while (Step())
            {
                ;
            }

            var jumpExpr = this.JumpTableFormat;
            var interval = this.JumpTableIndexInterval;
            var index    = this.JumpTableIndexToUse;
            var ctx      = new Dictionary <Expression, ValueSet>(new ExpressionValueComparer());

            if (index == null)
            {
                // Weren't able to find the index register,
                // try finding it by blind pattern matching.
                index = this.FindIndexWithPatternMatch(this.JumpTableFormat);
                if (index == null)
                {
                    // This is likely an indirect call like a C++
                    // vtable dispatch. Since these are common, we don't
                    // spam the user with warnings.
                    return(null);
                }

                // We have a jump table, and we've guessed the index expression.
                // At this point we've given up on knowing the exact size
                // of the table, but we do know that it must be at least
                // more than one entry. The safest assumption is that it
                // has two entries.
                listener.Warn(
                    listener.CreateAddressNavigator(host.Program, addrSwitch),
                    "Unable to determine size of call or jump table; there may be more than 2 entries.");
                ctx.Add(index, new IntervalValueSet(index.DataType, StridedInterval.Create(1, 0, 1)));
            }
            else if (interval.IsEmpty)
            {
                return(null);
            }
            else if (interval.High == Int64.MaxValue)
            {
                // We have no reasonable upper bound. We make the arbitrary
                // assumption that the jump table has 2 items; it wouldn't
                // make sense to be indexing otherwise.
                listener.Warn(
                    listener.CreateAddressNavigator(host.Program, addrSwitch),
                    "Unable to determine the upper bound of an indirect call or jump; there may be more than 2 entries.");
                var vs = new IntervalValueSet(
                    this.JumpTableIndex.DataType,
                    StridedInterval.Create(1, interval.Low, interval.Low + 1));
                ctx.Add(this.JumpTableIndexToUse, vs);
            }
            else
            {
                ctx.Add(this.JumpTableIndex, new IntervalValueSet(this.JumpTableIndex.DataType, interval));
            }
            var vse = new ValueSetEvaluator(host.Architecture, host.SegmentMap, ctx, this.processorState);

            var(values, accesses) = vse.Evaluate(jumpExpr);
            var vector = values.Values
                         .TakeWhile(c => c != Constant.Invalid)
                         .Take(2000)    // Arbitrary limit
                         .Select(ForceToAddress)
                         .TakeWhile(a => a != null)
                         .ToList();

            if (vector.Count == 0)
            {
                return(null);
            }
            return(new TableExtent
            {
                Targets = vector,
                Accesses = accesses,
                Index = index,
            });
        }
Ejemplo n.º 23
0
        /// <summary>
        /// Apply relocations to a segment.
        /// </summary>
        private bool ApplyRelocations(EndianImageReader rdr, int cRelocations, NeSegment seg)
        {
            Address           address = null;
            NeRelocationEntry rep;

            Debug.Print("== Relocating segment {0}", seg.Address);
            for (int i = 0; i < cRelocations; i++)
            {
                rep = new NeRelocationEntry
                {
                    address_type    = (NE_RADDR)rdr.ReadByte(),
                    relocation_type = (NE_RELTYPE)rdr.ReadByte(),
                    offset          = rdr.ReadLeUInt16(),
                    target1         = rdr.ReadLeUInt16(),
                    target2         = rdr.ReadLeUInt16(),
                };
                Debug.Print("  {0}", WriteRelocationEntry(rep));

                // Get the target address corresponding to this entry.

                // If additive, there is no target chain list. Instead, add source
                //  and target.
                bool additive = (rep.relocation_type & NE_RELTYPE.ADDITIVE) != 0;
                Tuple <Address, ImportReference> impRef;
                uint   lp;
                string module = "";
                switch (rep.relocation_type & (NE_RELTYPE)3)
                {
                case NE_RELTYPE.ORDINAL:
                    module = moduleNames[rep.target1 - 1];
                    // Synthesize an import
                    lp = ((uint)rep.target1 << 16) | rep.target2;
                    if (importStubs.TryGetValue(lp, out impRef))
                    {
                        address = impRef.Item1;
                    }
                    else
                    {
                        address = addrImportStubs;
                        importStubs.Add(lp, new Tuple <Address, ImportReference>(
                                            address,
                                            new OrdinalImportReference(address, module, rep.target2, SymbolType.ExternalProcedure)));
                        addrImportStubs += 8;
                    }
                    break;

                case NE_RELTYPE.NAME:
                    module = moduleNames[rep.target1 - 1];
                    uint offName      = lfaNew + this.offImportedNamesTable + rep.target2;
                    var  nameRdr      = new LeImageReader(RawImage, offName);
                    byte fnNameLength = nameRdr.ReadByte();
                    var  abFnName     = nameRdr.ReadBytes(fnNameLength);
                    // Synthesize the import.
                    lp = ((uint)rep.target1 << 16) | rep.target2;
                    if (importStubs.TryGetValue(lp, out impRef))
                    {
                        address = impRef.Item1;
                    }
                    else
                    {
                        address = addrImportStubs;
                        string fnName = Encoding.ASCII.GetString(abFnName);
                        importStubs.Add(lp, new Tuple <Address, ImportReference>(
                                            address,
                                            new NamedImportReference(address, module, fnName, SymbolType.ExternalProcedure)));
                        addrImportStubs += 8;
                    }
                    break;

                case NE_RELTYPE.INTERNAL:
                    if ((rep.target1 & 0xff) == 0xff)
                    {
                        address = this.entryPoints[rep.target2 - 1].Address;
                    }
                    else
                    {
                        address = segments[rep.target1 - 1].Address + rep.target2;
                    }
                    Debug.Print("    {0}: {1:X4}:{2:X4} {3}",
                                i + 1,
                                address.Selector.Value,
                                address.Offset,
                                "");
                    break;

                case NE_RELTYPE.OSFIXUP:
                    /* Relocation type 7:
                     *
                     *    These appear to be used as fixups for the Windows
                     * floating point emulator.  Let's just ignore them and
                     * try to use the hardware floating point.  Linux should
                     * successfully emulate the coprocessor if it doesn't
                     * exist.
                     */
                    /*
                     * TRACE("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
                     *   i + 1, rep->relocation_type, rep->offset,
                     *   rep->target1, rep->target2,
                     *   NE_GetRelocAddrName( rep->address_type, additive ) );
                     */
                    continue;
                }
                ushort offset = rep.offset;

                // Apparently, high bit of address_type is sometimes set;
                // we ignore it for now.
                if (rep.address_type > NE_RADDR.OFFSET32)
                {
                    listener.Error(
                        string.Format(
                            "Module {0}: unknown relocation address type {1:X2}. Please report",
                            module, rep.address_type));
                    return(false);
                }

                if (additive)
                {
                    var sp = seg.Address + offset;
                    Debug.Print("    {0} (contains: {1:X4})", sp, mem.ReadLeUInt16(sp));
                    byte   b;
                    ushort w;
                    switch (rep.address_type & (NE_RADDR)0x7f)
                    {
                    case NE_RADDR.LOWBYTE:
                        b = mem.ReadByte(sp);
                        mem.WriteByte(sp, (byte)(b + address.Offset));
                        break;

                    case NE_RADDR.OFFSET16:
                        w = mem.ReadLeUInt16(sp);
                        mem.WriteLeUInt16(sp, (ushort)(w + address.Offset));
                        break;

                    case NE_RADDR.POINTER32:
                        w = mem.ReadLeUInt16(sp);
                        mem.WriteLeUInt16(sp, (ushort)(w + address.Offset));
                        mem.WriteLeUInt16(sp + 2, address.Selector.Value);
                        break;

                    case NE_RADDR.SELECTOR:
                        // Borland creates additive records with offset zero. Strange, but OK.
                        w = mem.ReadLeUInt16(sp);
                        if (w != 0)
                        {
                            listener.Error(string.Format("Additive selector to {0:X4}. Please report.", w));
                        }
                        else
                        {
                            mem.WriteLeUInt16(sp, address.Selector.Value);
                        }
                        break;

                    default:
                        goto unknown;
                    }
                }
                else
                {
                    // Non-additive fixup.
                    do
                    {
                        var    sp          = seg.Address + offset;
                        ushort next_offset = mem.ReadLeUInt16(sp);
                        Debug.Print("    {0} (contains: {1:X4})", sp, next_offset);
                        switch (rep.address_type & (NE_RADDR)0x7f)
                        {
                        case NE_RADDR.LOWBYTE:
                            mem.WriteByte(sp, (byte)address.Offset);
                            break;

                        case NE_RADDR.OFFSET16:
                            mem.WriteLeUInt16(sp, (ushort)address.Offset);
                            break;

                        case NE_RADDR.POINTER32:
                            mem.WriteLeUInt16(sp, (ushort)address.Offset);
                            mem.WriteLeUInt16(sp + 2, address.Selector.Value);
                            break;

                        case NE_RADDR.SELECTOR:
                            mem.WriteLeUInt16(sp, address.Selector.Value);
                            break;

                        default:
                            goto unknown;
                        }
                        if (next_offset == offset)
                        {
                            break;                         // avoid infinite loop
                        }
                        if (next_offset >= seg.Alloc)
                        {
                            break;
                        }
                        offset = next_offset;
                    } while (offset != 0xffff);
                }
            }
            return(true);

unknown:
            listener.Warn("{0}: unknown ADDR TYPE {1},  " +
                          "TYPE {2},  OFFSET {3:X4},  TARGET {4:X4} {5:X4}",
                          seg.Address.Selector, rep.address_type, rep.relocation_type,
                          rep.offset, rep.target1, rep.target2);
            return(false);
        }