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))); }
/// <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)); }
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 !); }
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; } }
// 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; } }
/// 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(); }
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)); }
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); }
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."); } }
/// <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; }
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); }
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)); } }
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)); }
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)); } }
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; } }
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); }
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 !); }
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("-", "") ); } }
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; }
public void Warn(string format, params object [] args) { decompilerEventListener.Warn( decompilerEventListener.CreateAddressNavigator(program, addr), string.Format(format, args)); }
public void Warn(Address addr, string message) { eventListener.Warn(eventListener.CreateAddressNavigator(Program, addr), message); }
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, }); }
/// <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); }