static public bool IsCorrectUnpacker(ExeImageLoader exe, byte[] rawImg) { int offset = ExePackHeaderOffset(exe); return(MemoryArea.CompareArrays(rawImg, offset, signature, signature.Length) || MemoryArea.CompareArrays(rawImg, offset, signature2, signature2.Length)); }
/// <summary> /// Peeks at the beginning of the image to determine if it's an XML file. /// </summary> /// <remarks> /// We do not attempt to handle UTF-8 encoded Unicode BOM characters. /// </remarks> /// <param name="image"></param> /// <returns></returns> private static bool IsXmlFile(byte[] image) { if (MemoryArea.CompareArrays(image, 0, new byte[] { 0x3C, 0x3F, 0x78, 0x6D, 0x6C }, 5)) // <?xml { return(true); } return(false); }
static public bool IsCorrectUnpacker(ExeImageLoader exe, byte [] rawImg) { if (exe.e_ovno != 0) { return(false); } return(MemoryArea.CompareArrays(rawImg, (int)signatureOffset, signature, signature.Length)); }
// EXE header test (is it LZEXE file?) static public bool IsCorrectUnpacker(ExeImageLoader exe, byte [] rawImg) { if (exe.e_ovno != 0 || exe.e_lfaRelocations != 0x1C) return false; int lzHdrOffset = ((int) exe.e_cparHeader + (int) exe.e_cs) << 4; int entry = lzHdrOffset + exe.e_ip; return (MemoryArea.CompareArrays(rawImg, entry, s_sig91, s_sig91.Length) || MemoryArea.CompareArrays(rawImg, entry, s_sig90, s_sig90.Length)); }
public ExePackLoader(IServiceProvider services, string filename, byte[] imgRaw) : base(services, filename, imgRaw) { var cfgSvc = services.RequireService <IConfigurationService>(); arch = cfgSvc.GetArchitecture("x86-real-16"); platform = cfgSvc.GetEnvironment("ms-dos") .Load(Services, arch); var exe = new ExeImageLoader(services, filename, imgRaw); this.exeHdrSize = (uint)(exe.e_cparHeader * 0x10U); this.hdrOffset = (uint)(exe.e_cparHeader + exe.e_cs) * 0x10U; EndianImageReader rdr = new LeImageReader(RawImage, hdrOffset); this.ip = rdr.ReadLeUInt16(); this.cs = rdr.ReadLeUInt16(); rdr.ReadLeUInt16(); this.cbExepackHeader = rdr.ReadLeUInt16(); this.sp = rdr.ReadLeUInt16(); this.ss = rdr.ReadLeUInt16(); this.cpUncompressed = rdr.ReadLeUInt16(); int offset = ExePackHeaderOffset(exe); if (MemoryArea.CompareArrays(imgRaw, offset, signature, signature.Length)) { relocationsOffset = 0x012D; } else if (MemoryArea.CompareArrays(imgRaw, offset, signature2, signature2.Length)) { relocationsOffset = 0x0125; } else { throw new ApplicationException("Not a recognized EXEPACK image."); } }
/// <summary> /// Given a <paramref name="program" /> returns a list of locations /// where patches need to be applied. /// </summary> /// <remarks> /// Scans through all loaded segments, looking for a LCALL instruction /// to the Keil sparse switch subroutine. /// </remarks> /// <param name="program"></param> /// <returns></returns> private IEnumerable <CodePatch> MakeSparseSwitchPatches(Program program) { const byte LCall_Opcode = 0x12; foreach (var seg in program.SegmentMap.Segments.Values) { var rdr = seg.MemoryArea.CreateBeReader(0); while (rdr.TryReadByte(out byte b)) { if (b != LCall_Opcode) { continue; } var addrCall = rdr.Address - 1; if (!rdr.TryReadBeUInt16(out ushort uAddrSwitchSubroutine)) { break; } var addrSwitchSubroutine = Address.Ptr16(uAddrSwitchSubroutine); if (!program.SegmentMap.TryFindSegment(addrSwitchSubroutine, out var segment)) { continue; } var mem = segment.MemoryArea; var offset = (int)(addrSwitchSubroutine - mem.BaseAddress); if (!MemoryArea.CompareArrays(mem.Bytes, offset, sparseSwitchSubroutine, sparseSwitchSubroutine.Length)) { continue; } // We found the sparse switch subroutine. Now we parse the sparse switch // data. var cluster = MakeCluster(addrCall, rdr); yield return(new CodePatch(cluster)); } } }
private void Validate(ExeImageLoader exe) { this.lzHdrOffset = (exe.e_cparHeader + exe.e_cs) << 4; // Locate the LzExe header and verify signature. byte[] abC = RawImage; int entry = lzHdrOffset + exe.e_ip; if (MemoryArea.CompareArrays(abC, entry, s_sig90, s_sig90.Length)) { // Untested binary version isLz91 = false; throw new NotImplementedException("Untested"); } else if (MemoryArea.CompareArrays(abC, entry, s_sig91, s_sig91.Length)) { isLz91 = true; } else { throw new ApplicationException("Image is not an LzExe-compressed binary"); } }
/// <summary> /// Tries to identify the main program of various MS-DOS compilers, and if /// successful, sets the DS register to the appropriate value. /// </summary> /// <returns></returns> public ImageSymbol FindMainAddress() { var diagSvc = services.RequireService <IDiagnosticsService>(); Address addrEntry; /* This function checks the startup code for various compilers' way of * loading DS. If found, it sets DS. This may not be needed in the future if * pushing and popping of registers is implemented. * Also sets prog.offMain and prog.segMain if possible */ uint startoff; uint init; uint i; ushort rel, para; char chModel = 'x'; char chVendor = 'x'; char chVersion = 'x'; char[] temp = new char[4]; ImageSegment segment; prog.SegmentMap.TryFindSegment(start, out segment); var image = segment.MemoryArea; var startOff = (uint)(start - image.BaseAddress); // Offset into the Image of the initial CS:IP // Check the Turbo Pascal signatures first, since they involve only the // first 3 bytes, and false positives may be found with the others later if (locatePattern(image.Bytes, startOff, startOff + 5, pattBorl4on, out i)) { // The first 5 bytes are a far call. Follow that call and // determine the version from that */ var addrNew = ReadSegPtr(image, startOff + 1); init = (uint)(addrNew - image.BaseAddress); if (locatePattern(image.Bytes, init, init + 26, pattBorl4Init, out i)) { setState("ds", image.ReadLeUInt16(i + 1)); Debug.Print("Borland Pascal v4 detected\n"); chVendor = 't'; /* Turbo */ chModel = 'p'; /* Pascal */ chVersion = '4'; /* Version 4 */ addrEntry = start; /* Code starts immediately */ /* At the 5 byte jump */ goto gotVendor; /* Already have vendor */ } else if (locatePattern(image.Bytes, init, init + 26, pattBorl5Init, out i)) { setState("ds", image.ReadLeUInt16(i + 1)); Debug.Print("Borland Pascal v5.0 detected"); chVendor = 't'; /* Turbo */ chModel = 'p'; /* Pascal */ chVersion = '5'; /* Version 5 */ addrEntry = start; /* Code starts immediately */ goto gotVendor; /* Already have vendor */ } else if (locatePattern(image.Bytes, init, init + 26, pattBorl7Init, out i)) { setState("ds", image.ReadLeUInt16(i + 1)); Debug.Print("Borland Pascal v7 detected"); chVendor = 't'; /* Turbo */ chModel = 'p'; /* Pascal */ chVersion = '7'; /* Version 7 */ addrEntry = start; /* Code starts immediately */ goto gotVendor; /* Already have vendor */ } } /* Search for the call to main pattern. This is compiler independant, * but decides the model required. Note: must do the far data models * (large and compact) before the others, since they are the same pattern * as near data, just more pushes at the start. */ if (image.Length > startOff + 0x180 + pattMainLarge.Length) { if (locatePattern(image.Bytes, startOff, startOff + 0x180, pattMainLarge, out i)) { addrEntry = ReadSegPtr(image, i + OFFMAINLARGE); chModel = 'l'; /* Large model */ } else if (locatePattern(image.Bytes, startOff, startOff + 0x180, pattMainCompact, out i)) { short srel = image.ReadLeInt16(i + OFFMAINCOMPACT); /* This is the rel addr of main */ addrEntry = image.BaseAddress + i + OFFMAINCOMPACT + 2 + srel; /* Save absolute image offset */ chModel = 'c'; /* Compact model */ } else if (locatePattern(image.Bytes, startOff, startOff + 0x180, pattMainMedium, out i)) { addrEntry = ReadSegPtr(image, i + OFFMAINMEDIUM); /* This is abs off of main */ chModel = 'm'; /* Medium model */ } else if (locatePattern(image.Bytes, startOff, startOff + 0x180, pattMainSmall, out i)) { var srel = image.ReadLeInt16(i + OFFMAINSMALL); /* This is rel addr of main */ addrEntry = image.BaseAddress + i + OFFMAINSMALL + 2 + srel; /* Save absolute image offset */ chModel = 's'; /* Small model */ } else if (MemoryArea.CompareArrays(image.Bytes, (int)startOff, pattTPasStart, pattTPasStart.Length)) { var srel = image.ReadLeInt16(startOff + 1); /* Get the jump offset */ addrEntry = start + srel + 3; /* Save absolute image offset */ addrEntry += 0x20; /* These first 32 bytes are setting up */ chVendor = 't'; /* Turbo.. */ chModel = 'p'; /* ...Pascal... (only 1 model) */ chVersion = '3'; /* 3.0 */ Debug.Print("Turbo Pascal 3.0 detected"); Debug.Print("Main at {0}", addrEntry); goto gotVendor; /* Already have vendor */ } else { Debug.Print("Main could not be located!"); addrEntry = null; } } else { Debug.Print("Main could not be located!"); addrEntry = null; } Debug.Print("Model: {0}", chModel); //prog.addressingMode = chModel; /* Now decide the compiler vendor and version number */ if (MemoryArea.CompareArrays(image.Bytes, (int)startOff, pattMsC5Start, pattMsC5Start.Length)) { /* Yes, this is Microsoft startup code. The DS is sitting right here * in the next 2 bytes */ setState("ds", image.ReadLeUInt16((uint)(startOff + pattMsC5Start.Length))); chVendor = 'm'; /* Microsoft compiler */ chVersion = '5'; /* Version 5 */ Debug.Print("MSC 5 detected"); } /* The C8 startup pattern is different from C5's */ else if (MemoryArea.CompareArrays(image.Bytes, (int)startOff, pattMsC8Start, pattMsC8Start.Length)) { setState("ds", image.ReadLeUInt16((uint)(startOff + pattMsC8Start.Length))); chVendor = 'm'; /* Microsoft compiler */ chVersion = '8'; /* Version 8 */ Debug.Print("MSC 8 detected"); } /* The C8 .com startup pattern is different again! */ else if (MemoryArea.CompareArrays( image.Bytes, (int)startOff, pattMsC8ComStart, pattMsC8ComStart.Length)) { Debug.Print("MSC 8 .com detected"); chVendor = 'm'; /* Microsoft compiler */ chVersion = '8'; /* Version 8 */ } else if (locatePattern(image.Bytes, startOff, startOff + 0x30, pattBorl2Start, out i)) { /* Borland startup. DS is at the second uint8_t (offset 1) */ setState("ds", image.ReadLeUInt16(i + 1)); Debug.Print("Borland v2 detected\n"); chVendor = 'b'; /* Borland compiler */ chVersion = '2'; /* Version 2 */ } else if (locatePattern(image.Bytes, startOff, startOff + 0x30, pattBorl3Start, out i)) { /* Borland startup. DS is at the second uint8_t (offset 1) */ setState("ds", image.ReadLeUInt16(i + 1)); diagSvc.Inform("Borland C v3 runtime detected"); chVendor = 'b'; /* Borland compiler */ chVersion = '3'; /* Version 3 */ } else if (locatePattern(image.Bytes, startOff, startOff + 0x30, pattLogiStart, out i)) { /* Logitech modula startup. DS is 0, despite appearances */ Debug.Print("Logitech modula detected"); chVendor = 'l'; /* Logitech compiler */ chVersion = '1'; /* Version 1 */ } /* Other startup idioms would go here */ else { Debug.Print("Warning - compiler not recognised"); return(null); } gotVendor: ; //sSigName = string.Format("dcc{0}{1}{2}.sig", // chVendor, /* Add vendor */ // chVersion, /* Add version */ // chModel); /* Add model */ //Debug.Print("Signature file: {0}", sSigName); return(new ImageSymbol(addrEntry) { Name = "main", ProcessorState = this.state, Type = SymbolType.Procedure, }); }
/// <summary> /// Check this function to see if it is a library function. Return true if /// it is, and copy its name to pProc.Name /// </summary> public bool LibCheck(IServiceProvider services, Program program, Procedure proc, Address addr) { var diagSvc = services.RequireService<IDiagnosticsService>(); long fileOffset; int h; // i, j, arg; uint Idx; if (false) // && program.bSigs == false) { /* No signatures... can't rely on hash parameters to be initialised so always return false */ return false; } ImageSegment segment; if (!program.SegmentMap.TryFindSegment(addr, out segment)) return false; fileOffset = addr - segment.MemoryArea.BaseAddress; /* Offset into the image */ //if (fileOffset == program.offMain) //{ // /* Easy - this function is called main! */ // pProc.Name = "main"; // return false; //} byte[] pat = new byte[PATLEN]; if (!segment.MemoryArea.TryReadBytes(fileOffset, PATLEN, pat)) return false; fixWildCards(pat); /* Fix wild cards in the copy */ h = g_pattern_hasher.hash(pat); /* Hash the found proc */ /* We always have to compare keys, because the hash function will always return a valid index */ if (MemoryArea.CompareArrays(ht[h].htPat, 0, pat, PATLEN)) { #if NOT_YET /* We have a match. Save the name, if not already set */ if (string.IsNullOrEmpty(pProc.Name)) /* Don't overwrite existing name */ { /* Give proc the new name */ pProc.Name = ht[h].htSym; } /* But is it a real library function? */ i = NIL; if ((numFunc == 0) || (i = searchPList(ht[h].htSym)) != NIL) { pProc.flg |= PROC_ISLIB; /* It's a lib function */ pProc.callingConv(CConv::C); if (i != NIL) { /* Allocate space for the arg struct, and copy the hlType to the appropriate field */ arg = pFunc[i].firstArg; pProc.args.numArgs = pFunc[i].numArg; pProc.args.resize(pFunc[i].numArg); for (j = 0; j < pFunc[i].numArg; j++) { pProc.args[j].type = pArg[arg++]; } if (pFunc[i].typ != hlType.TYPE_UNKNOWN) { pProc.retVal.type = pFunc[i].typ; pProc.flg |= PROC_IS_FUNC; switch (pProc.retVal.type) { case hlType.TYPE_LONG_SIGN: case hlType.TYPE_LONG_UNSIGN: pProc.liveOut.setReg(rDX).addReg(rAX); break; case hlType.TYPE_WORD_SIGN: case hlType.TYPE_WORD_UNSIGN: pProc.liveOut.setReg(rAX); break; case hlType.TYPE_BYTE_SIGN: case hlType.TYPE_BYTE_UNSIGN: pProc.liveOut.setReg(rAL); break; case hlType.TYPE_STR: case hlType.TYPE_PTR: fprintf(stderr, "Warning assuming Large memory model\n"); pProc.liveOut.setReg(rAX).addReg(rDS); break; default: diagSvc.Warn(string.Format("Unknown retval type {0} for {1} in LibCheck.", pProc.retVal.type, pProc.Name); break; /*** other types are not considered yet ***/ } } pProc.getFunctionType()->m_vararg = pFunc[i].bVararg; } } else if (i == NIL) { /* Have a symbol for it, but does not appear in a header file. Treat it as if it is not a library function */ pProc.flg |= PROC_RUNTIME; /* => is a runtime routine */ } #endif } if (locatePattern(segment.MemoryArea.Bytes, (uint) fileOffset, (uint) (fileOffset + pattMsChkstk.Length), pattMsChkstk, out Idx)) { /* Found _chkstk */ //pProc.Name = "chkstk"; //pProc.flg |= PROC_ISLIB; /* We'll say its a lib function */ //pProc.args.numArgs = 0; /* With no args */ } return true; // ((pProc.flg & PROC_ISLIB) != 0); }
bool DFS(int parentE, int v) { int e, w; // Depth first search of the graph, starting at vertex v, looking for // cycles. parent and v are origin 1. Note parent is an EDGE, // not a vertex visited[v] = true; // For each e incident with v .. for (e = graphFirst[v]; e != 0; e = graphNext[NumEntry + e]) { byte[] key1; if (deleted[Math.Abs(e)]) { /* A deleted key. Just ignore it */ continue; } key1 = m_collector.getKey(Math.Abs(e) - 1); w = graphNode[NumEntry + e]; if (visited[w]) { /* Did we just come through this edge? If so, ignore it. */ if (Math.Abs(e) != Math.Abs(parentE)) { /* There is a cycle in the graph. There is some subtle code here * to work around the distinct possibility that there may be * duplicate keys. Duplicate keys will always cause unit * cycles, since f1 and f2 (used to select v and w) will be the * same for both. The edges (representing an index into the * array of keys) are distinct, but the key values are not. * The logic is as follows: for the candidate edge e, check to * see if it terminates in the parent vertex. If so, we test * the keys associated with e and the parent, and if they are * the same, we can safely ignore e for the purposes of cycle * detection, since edge e adds nothing to the cycle. Cycles * involving v, w, and e0 will still be found. The parent * edge was not similarly eliminated because at the time when * it was a candidate, v was not yet visited. * We still have to remove the key from further consideration, * since each edge is visited twice, but with a different * parent edge each time. */ /* We save some stack space by calculating the parent vertex * for these relatively few cases where it is needed */ int parentV = graphNode[NumEntry - parentE]; if (w == parentV) { byte[] key2; key2 = m_collector.getKey(Math.Abs(parentE) - 1); if (MemoryArea.CompareArrays(key1, 0, key2, EntryLen)) { Debug.Print("Duplicate keys with edges {0} and {1} (", e, parentE); m_collector.dispKey(Math.Abs(e) - 1); Debug.Print(" & "); m_collector.dispKey(Math.Abs(parentE) - 1); Debug.Print(")\n"); deleted[Math.Abs(e)] = true; /* Wipe the key */ } else { /* A genuine (unit) cycle. */ Debug.Print("There is a unit cycle involving vertex %d and edge %d\n", v, e); return(true); } } else { // We have reached a previously visited vertex not the // parent. Therefore, we have uncovered a genuine cycle Debug.Print("There is a cycle involving vertex {0} and edge {1}", v, e); return(true); } } } else // Not yet seen. Traverse it { if (DFS(e, w)) { // Cycle found deeper down. Exit return(true); } } } return(false); }