protected Address ReadSegmentedCodeAddress(int byteSize, EndianImageReader rdr, ProcessorState state) { if (byteSize == PrimitiveType.Word16.Size) { return(CreateSegmentedAddress(state.GetRegister(Registers.cs).ToUInt16(), rdr.ReadLeUInt16())); } else { ushort off = rdr.ReadLeUInt16(); ushort seg = rdr.ReadLeUInt16(); return(CreateSegmentedAddress(seg, off)); } }
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; } }
public override bool MatchJump(EndianImageReader rdr, uint opcode, out uint target) { target = 0; ushort sopcode = (ushort)opcode; var offset = rdr.Offset; if (((sopcode & 0xFF00) == 0xEF00) // GOTO n && rdr.IsValidOffset(rdr.Offset + 2u)) { ushort word2 = rdr.ReadLeUInt16(); if ((word2 & 0xF000U) == 0xF000U) { target = (uint)(sopcode.Extract(0, 8) | (word2.Extract(0, 12) << 8)); return(true); } } if ((sopcode & 0xF800) == 0xD000) // BRA n { var off = (int)sopcode.ExtractSignExtend(0, 11); target = (uint)((long)rdr.Address.ToLinear() + 2 + (off * 2)); return(true); } if ((sopcode & 0xF800) == 0xE000) // Bcond n { var off = (sbyte)(sopcode.ExtractSignExtend(0, 8)); target = (uint)((long)rdr.Address.ToLinear() + 2 + (off * 2)); return(true); } rdr.Offset = offset; return(false); }
// 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; } }
// Read a section of the file, considering endian issues void readFileSection(ushort[] p, int len, EndianImageReader rdr) { int pp = 0; for (int i = 0; i < len; i += 2) { p[pp++] = rdr.ReadLeUInt16(); } }
public short ReadCoffHeader(EndianImageReader rdr) { this.machine = rdr.ReadLeUInt16(); short expectedMagic = GetExpectedMagic(machine); arch = CreateArchitecture(machine); platform = CreatePlatform(machine, Services, arch); innerLoader = CreateInnerLoader(machine); sections = rdr.ReadLeInt16(); rdr.ReadLeUInt32(); // timestamp. rdr.ReadLeUInt32(); // COFF symbol table. rdr.ReadLeUInt32(); // #of symbols. optionalHeaderSize = rdr.ReadLeInt16(); this.fileFlags = rdr.ReadLeUInt16(); rvaSectionTable = (uint)((int)rdr.Offset + optionalHeaderSize); return(expectedMagic); }
// 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 = (ArmRt)(fixup >> 12); DebugEx.Verbose(PeImageLoader.trace, " {0:X4} {1}", fixup, rt); switch (fixup) { } }
/// <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); }
public void ReadOptionalHeader(EndianImageReader rdr, short expectedMagic) { if (optionalHeaderSize <= 0) { throw new BadImageFormatException("Optional header size should be larger than 0 in a PE executable image file."); } short magic = rdr.ReadLeInt16(); if (magic != expectedMagic) { throw new BadImageFormatException("Not a valid PE Header."); } rdr.ReadByte(); // Linker major version rdr.ReadByte(); // Linker minor version rdr.ReadLeUInt32(); // code size (== .text section size) rdr.ReadLeUInt32(); // size of initialized data rdr.ReadLeUInt32(); // size of uninitialized data rvaStartAddress = rdr.ReadLeUInt32(); uint rvaBaseOfCode = rdr.ReadLeUInt32(); preferredBaseOfImage = innerLoader.ReadPreferredImageBase(rdr); rdr.ReadLeUInt32(); // section alignment rdr.ReadLeUInt32(); // file alignment rdr.ReadLeUInt16(); // OS major version rdr.ReadLeUInt16(); // OS minor version rdr.ReadLeUInt16(); // Image major version rdr.ReadLeUInt16(); // Image minor version rdr.ReadLeUInt16(); // Subsystem major version rdr.ReadLeUInt16(); // Subsystem minor version rdr.ReadLeUInt32(); // reserved uint sizeOfImage = rdr.ReadLeUInt32(); uint sizeOfHeaders = rdr.ReadLeUInt32(); uint checksum = rdr.ReadLeUInt32(); ushort subsystem = rdr.ReadLeUInt16(); ushort dllFlags = rdr.ReadLeUInt16(); var stackReserve = innerLoader.ReadWord(rdr); var stackCommit = innerLoader.ReadWord(rdr); var heapReserve = innerLoader.ReadWord(rdr); var heapCommit = innerLoader.ReadWord(rdr); rdr.ReadLeUInt32(); // loader flags uint dictionaryCount = rdr.ReadLeUInt32(); if (dictionaryCount == 0) { return; } this.rvaExportTable = rdr.ReadLeUInt32(); this.sizeExportTable = rdr.ReadLeUInt32(); if (--dictionaryCount == 0) { return; } this.rvaImportTable = rdr.ReadLeUInt32(); uint importTableSize = rdr.ReadLeUInt32(); if (--dictionaryCount == 0) { return; } this.rvaResources = rdr.ReadLeUInt32(); // resource address rdr.ReadLeUInt32(); // resource size if (--dictionaryCount == 0) { return; } this.rvaExceptionTable = rdr.ReadLeUInt32(); // exception address this.sizeExceptionTable = rdr.ReadLeUInt32(); // exception size if (--dictionaryCount == 0) { return; } rdr.ReadLeUInt32(); // certificate address rdr.ReadLeUInt32(); // certificate size if (--dictionaryCount == 0) { return; } this.rvaBaseRelocationTable = rdr.ReadLeUInt32(); this.sizeBaseRelocationTable = rdr.ReadLeUInt32(); if (--dictionaryCount == 0) { return; } uint rvaDebug = rdr.ReadLeUInt32(); uint cbDebug = rdr.ReadLeUInt32(); if (--dictionaryCount == 0) { return; } uint rvaArchitecture = rdr.ReadLeUInt32(); uint cbArchitecture = rdr.ReadLeUInt32(); if (--dictionaryCount == 0) { return; } uint rvaGlobalPointer = rdr.ReadLeUInt32(); uint cbGlobalPointer = rdr.ReadLeUInt32(); if (--dictionaryCount == 0) { return; } uint rvaTls = rdr.ReadLeUInt32(); uint cbTls = rdr.ReadLeUInt32(); if (--dictionaryCount == 0) { return; } uint rvaLoadConfig = rdr.ReadLeUInt32(); uint cbLoadConfig = rdr.ReadLeUInt32(); if (--dictionaryCount == 0) { return; } uint rvaBoundImport = rdr.ReadLeUInt32(); uint cbBoundImport = rdr.ReadLeUInt32(); if (--dictionaryCount == 0) { return; } uint rvaIat = rdr.ReadLeUInt32(); uint cbIat = rdr.ReadLeUInt32(); if (--dictionaryCount == 0) { return; } this.rvaDelayImportDescriptor = rdr.ReadLeUInt32(); uint cbDelayImportDescriptor = rdr.ReadLeUInt32(); }
public override Address ReadCodeAddress(int size, EndianImageReader rdr, ProcessorState state) { ushort uAddr = rdr.ReadLeUInt16(); return(Address.Ptr16(uAddr)); }