/// <summary> /// Load a Basic PRG. /// </summary> /// <param name="imageBytes"></param> /// <returns></returns> private Program LoadPrg(byte[] imageBytes) { var stm = new MemoryStream(); ushort preferredAddress = LoadedImage.ReadLeUInt16(imageBytes, 0); ushort alignedAddress = (ushort)(preferredAddress & ~0xF); int pad = preferredAddress - alignedAddress; while (pad-- > 0) { stm.WriteByte(0); } stm.Write(imageBytes, 2, imageBytes.Length - 2); var loadedBytes = stm.ToArray(); var image = new LoadedImage( Address.Ptr16(alignedAddress), loadedBytes); var rdr = new C64BasicReader(image, 0x0801); var prog = rdr.ToSortedList(line => (ushort)line.Address.ToLinear(), line => line); var arch = new C64Basic(prog); image = new LoadedImage( Address.Ptr16(prog.Keys[0]), new byte[0xFFFF]); var program = new Program( image, image.CreateImageMap(), arch, new C64Platform(Services, null)); program.EntryPoints.Add(new EntryPoint(image.BaseAddress, arch.CreateProcessorState())); return(program); }
public PkLiteUnpacker(IServiceProvider services, string filename, byte [] rawImg) : base(services, filename, rawImg) { var exe = new ExeImageLoader(services, filename, rawImg); arch = new IntelArchitecture(ProcessorMode.Real); platform = services.RequireService <IConfigurationService>() .GetEnvironment("ms-dos") .Load(services, arch); uint pkLiteHdrOffset = (uint)(exe.e_cparHeader * 0x10); if (RawImage[pkLiteHdrOffset] != 0xB8) { throw new ApplicationException(string.Format("Expected MOV AX,XXXX at offset 0x{0:X4}.", pkLiteHdrOffset)); } uint cparUncompressed = LoadedImage.ReadLeUInt16(RawImage, pkLiteHdrOffset + 1); abU = new byte[cparUncompressed * 0x10U]; if (RawImage[pkLiteHdrOffset + 0x04C] != 0x83) { throw new ApplicationException(string.Format("Expected ADD BX,+XX at offset 0x{0:X4}.", pkLiteHdrOffset + 0x04C)); } uint offCompressedData = pkLiteHdrOffset + RawImage[pkLiteHdrOffset + 0x04E] * 0x10u - PspSize; bitStm = new BitStream(RawImage, (int)offCompressedData); }
// Unpacks the relocation entries in a LzExe 0.91 binary private ImageMap Relocate91(byte [] abUncompressed, ushort segReloc, LoadedImage pgmImgNew, RelocationDictionary relocations) { const int CompressedRelocationTableAddress = 0x0158; int ifile = lzHdrOffset + CompressedRelocationTableAddress; int rel_off = 0; for (;;) { ushort span = abUncompressed[ifile++]; if (span == 0) { span = abUncompressed[ifile++]; span |= (ushort)(abUncompressed[ifile++] << 8); if (span == 0) { rel_off += 0x0FFF0; continue; } else if (span == 1) { break; } } rel_off += span; ushort seg = (ushort)(pgmImgNew.ReadLeUInt16((uint)rel_off) + segReloc); pgmImgNew.WriteLeUInt16((uint)rel_off, seg); relocations.AddSegmentReference((uint)rel_off, seg); imageMap.AddSegment(Address.SegPtr(seg, 0), seg.ToString("X4"), AccessMode.ReadWriteExecute); } return(imageMap); }
public override RelocationResults Relocate(Address addrLoad) { ImageMap imageMap = imgLoadedMap; ImageReader rdr = new LeImageReader(exe.RawImage, (uint)exe.e_lfaRelocations); var relocations = new RelocationDictionary(); int i = exe.e_cRelocations; while (i != 0) { uint offset = rdr.ReadLeUInt16(); ushort segOffset = rdr.ReadLeUInt16(); offset += segOffset * 0x0010u; ushort seg = (ushort)(imgLoaded.ReadLeUInt16(offset) + addrLoad.Selector); imgLoaded.WriteLeUInt16(offset, seg); relocations.AddSegmentReference(offset, seg); imageMap.AddSegment(Address.SegPtr(seg, 0), seg.ToString("X4"), AccessMode.ReadWriteExecute); --i; } // Found the start address. Address addrStart = Address.SegPtr((ushort)(exe.e_cs + addrLoad.Selector), exe.e_ip); imageMap.AddSegment(Address.SegPtr(addrStart.Selector, 0), addrStart.Selector.ToString("X4"), AccessMode.ReadWriteExecute); return(new RelocationResults( new List <EntryPoint> { new EntryPoint(addrStart, arch.CreateProcessorState()) }, relocations)); }
public override RelocationResults Relocate(Program program, Address addrLoad) { var relocations = new RelocationDictionary(); ushort segCode = (ushort)(addrLoad.Selector.Value + (PspSize >> 4)); for (;;) { int relocs = (ushort)bitStm.GetByte(); if (relocs == 0) { break; } uint relocBase = PspSize + bitStm.GetWord() * 0x10u; do { ushort relocOff = bitStm.GetWord(); ushort seg = imgU.ReadLeUInt16(relocBase + relocOff); seg = (ushort)(seg + segCode); imgU.WriteLeUInt16(relocBase + relocOff, seg); relocations.AddSegmentReference(relocBase + relocOff, seg); imageMap.AddSegment(Address.SegPtr(seg, 0), seg.ToString("X4"), AccessMode.ReadWriteExecute, 0); } while (--relocs != 0); } ushort pklSs = (ushort)(bitStm.GetWord() + segCode); ushort pklSp = (ushort)bitStm.GetWord(); pklCs = (ushort)(bitStm.GetWord() + segCode); pklIp = bitStm.GetWord(); var state = arch.CreateProcessorState(); state.SetRegister(Registers.ds, Constant.Word16(addrLoad.Selector.Value)); state.SetRegister(Registers.es, Constant.Word16(addrLoad.Selector.Value)); state.SetRegister(Registers.cs, Constant.Word16(pklCs)); state.SetRegister(Registers.ax, Constant.Word16(0)); state.SetRegister(Registers.bx, Constant.Word16(0)); state.SetRegister(Registers.cx, Constant.Word16(0)); state.SetRegister(Registers.dx, Constant.Word16(0)); state.SetRegister(Registers.bp, Constant.Word16(0)); state.SetRegister(Registers.sp, Constant.Word16(pklSp)); state.SetRegister(Registers.si, Constant.Word16(0)); state.SetRegister(Registers.di, Constant.Word16(0)); return(new RelocationResults( new List <EntryPoint> { new EntryPoint(Address.SegPtr(pklCs, pklIp), state) }, relocations, new List <Address>())); }
public override Program Load(Address addr) { byte[] abC = RawImage; byte[] abU = new byte[cpUncompressed * 0x10U + ExeImageLoader.CbPsp]; Array.Copy(abC, exeHdrSize, abU, ExeImageLoader.CbPsp, abC.Length - exeHdrSize); imgU = new LoadedImage(addr, abU); uint SI = hdrOffset - 1; while (abC[SI] == 0xFF) { --SI; } int DI = abU.Length - 1; byte op; do { op = abC[SI]; int cx = LoadedImage.ReadLeUInt16(abC, SI - 2); SI -= 3; if ((op & 0xFE) == 0xB0) { byte b = abC[SI--]; while (cx != 0) { abU[DI--] = b; --cx; } } else { if ((op & 0xFE) != 0xB2) { throw new ApplicationException("Packed file is corrupt."); } while (cx != 0) { abU[DI--] = abC[SI--]; --cx; } } } while ((op & 1) == 0); imageMap = imgU.CreateImageMap(); return(new Program(imgU, imageMap, new X86ArchitectureReal(), platform)); }
// Apply relocations to a segment. bool ApplyRelocations(ImageReader rdr, int cRelocations, NeSegment seg) { string module = ""; Address address = null; NeRelocationEntry rep = null; for (int i = 0; i < cRelocations; i++) { rep = new NeRelocationEntry { address_type = rdr.ReadByte(), relocation_type = rdr.ReadByte(), offset = rdr.ReadLeUInt16(), target1 = rdr.ReadLeUInt16(), target2 = rdr.ReadLeUInt16(), }; // 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_RELFLAG_ADDITIVE) != 0; Tuple <Address, ImportReference> impRef; uint lp; switch (rep.relocation_type & 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))); 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); 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))); } break; case NE_RELTYPE_INTERNAL: if ((rep.target1 & 0xff) == 0xff) { throw new NotImplementedException(); } else { address = segments[rep.target1 - 1].Address + rep.target2; } Debug.Print("{0}: {1:X4}:{2:X4} {3}", i + 1, address.Selector.Value, address.Selector.Value, ""); 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) { diags.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:X4}:{0:X4}", offset, offset); byte b; ushort w; switch (rep.address_type & 0x7f) { case NE_RADDR_LOWBYTE: b = image.ReadByte(sp); image.WriteByte(sp, (byte)(b + address.Offset)); break; case NE_RADDR_OFFSET16: w = image.ReadLeUInt16(sp); image.WriteLeUInt16(sp, (ushort)(w + address.Offset)); break; case NE_RADDR_POINTER32: w = image.ReadLeUInt16(sp); image.WriteLeUInt16(sp, (ushort)(w + address.Offset)); image.WriteLeUInt16(sp + 2, address.Selector.Value); break; case NE_RADDR_SELECTOR: // Borland creates additive records with offset zero. Strange, but OK. w = image.ReadLeUInt16(sp); if (w != 0) { diags.Error(string.Format("Additive selector to {0:X4}. Please report.", w)); } else { image.WriteLeUInt16(sp, address.Selector.Value); } break; default: goto unknown; } } else { // Non-additive fixup. do { var sp = seg.Address + offset; ushort next_offset = image.ReadLeUInt16(sp); Debug.Print(" {0:X4}:{0:X4}", offset, next_offset); switch (rep.address_type & 0x7f) { case NE_RADDR_LOWBYTE: image.WriteByte(sp, (byte)address.Offset); break; case NE_RADDR_OFFSET16: image.WriteLeUInt16(sp, (ushort)address.Offset); break; case NE_RADDR_POINTER32: image.WriteLeUInt16(sp, (ushort)address.Offset); image.WriteLeUInt16(sp + 2, address.Selector.Value); break; case NE_RADDR_SELECTOR: image.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: var svc = Services.RequireService <IDiagnosticsService>(); svc.Warn(string.Format("{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); }