예제 #1
0
        static void patchFile(string origPath, string patchedPath, string diffFile)
        {
            List <Patch> patches;

            using (StreamReader sr = new StreamReader(diffFile)) {
                XmlSerializer xs = new XmlSerializer(typeof(List <Patch>));
                patches = (List <Patch>)xs.Deserialize(sr);
            }

            byte[] orig = File.ReadAllBytes(origPath);
            byte[] mod  = new byte[orig.Length];
            Array.Copy(orig, mod, orig.Length);
            int cApplied = 0, cTodo = 0;

            int patchNum = 0;

            foreach (Patch p in patches)
            {
                Console.WriteLine();
                patchNum++;
                int manualLoc = 0;
                if (g_overrides.ContainsKey(patchNum))
                {
                    manualLoc = g_overrides[patchNum];
                }
                List <int> matchLoc = new List <int>();
                byte[]     match    = p.matchBytes;
                for (int i = 0; i < orig.Length - match.Length; ++i)
                {
                    bool mismatch = false;
                    for (int j = 0; j < match.Length; ++j)
                    {
                        if (orig[i + j] != match[j])
                        {
                            mismatch = true;
                            break;
                        }
                    }
                    if (mismatch)
                    {
                        continue;
                    }
                    matchLoc.Add(i);
                }

                int applyAtOffset = -1;

                int cMatches = matchLoc.Count;
                if (cMatches == 1)
                {
                    applyAtOffset = matchLoc[0] + p.patchOffset;
                    Console.WriteLine("<<<{0}>>> 100% MATCH: {1} bytes at 0x{2:X8}\n{3}", patchNum, p.patchBytes.Length, matchLoc[0] + p.patchOffset,
                                      Useful.PatchDetails(p));
                }
                else if (cMatches > 1)
                {
                    Console.WriteLine("<<<{0}>>> MULTIPLE MATCHES:\n{1} matches q={2:p0}\n{3}", patchNum, cMatches, p.quality,
                                      Useful.PatchDetails(p));
                    const int NFirst = 5;
                    Console.WriteLine("FIRST {0} MATCHES", Math.Min(NFirst, cMatches));
                    for (int i = 0; i < Math.Min(cMatches, NFirst); ++i)
                    {
                        Console.WriteLine("#{0} at 0x{1:X8}", i + 1, matchLoc[i] + p.patchOffset);
                    }
                    if (manualLoc != 0)
                    {
                        if (manualLoc > 0)
                        {
                            applyAtOffset = manualLoc;
                        }
                        else
                        {
                            applyAtOffset = matchLoc[-1 - manualLoc] + p.patchOffset;
                        }
                    }
                }
                else
                {
                    Console.WriteLine("<<<{0}>>> NO EXACT MATCHES FOUND\n{1}", patchNum,
                                      Useful.PatchDetails(p));
                    // weighted matching: score every half-byte matching; patch bytes weigh more than surroundings. Find top scores, print top5 and their relative and absolute weights.
                    Dictionary <int, double> scores = new Dictionary <int, double>(orig.Length - match.Length);
                    double[] matchWeight            = new double[match.Length];
                    double   matchWeightNormalizer  = 0.0;
                    for (int i = 0; i < match.Length; ++i)
                    {
                        double weight;
                        if (i < p.patchOffset)
                        {
                            weight = 1.0 / Math.Sqrt(p.patchOffset - i + 1);
                        }
                        else if (i < p.patchOffset + p.patchBytes.Length)
                        {
                            weight = 1.0;
                        }
                        else
                        {
                            weight = 1.0 / Math.Sqrt(i + 2 - (p.patchOffset + p.patchBytes.Length));
                        }

                        matchWeight[i]         = weight;
                        matchWeightNormalizer += weight;
                    }
                    for (int i = 0; i < match.Length; ++i)
                    {
                        matchWeight[i] /= matchWeightNormalizer;
                    }

                    for (int i = 0; i < orig.Length - match.Length; ++i)
                    {
                        double score = 0.0;
                        for (int j = 0; j < match.Length; ++j)
                        {
                            byte   o = orig[i + j];
                            byte   m = match[j];
                            double factor;
                            int    x = o ^ m;
                            if (x == 0)
                            {
                                factor = 1.0;
                            }
                            else if (x == 0xF0 || x == 0x0F)
                            {
                                factor = .3;
                            }
                            else
                            {
                                continue;
                            }
                            score += factor * matchWeight[j];
                        }
                        scores.Add(i, score);
                    }
                    const int NTop          = 5;
                    var       topN          = scores.OrderByDescending(x => x.Value).Take(NTop).ToArray();
                    byte[]    topMatchBytes = orig.Skip(topN[0].Key).Take(p.matchBytes.Length).ToArray();
                    Patch     tmp           = new Patch(topMatchBytes, p.patchBytes, p.patchOffset, 0);
                    bool      fApplyBestBet = manualLoc == 0 && topN[0].Value * 100 >= g_confidence;
                    Console.WriteLine("TOP {0} MATCHES: TOP 1 is {1:P0}\n{2}", NTop, topN[0].Value, Useful.PatchDetails(tmp));
                    for (int i = 0; i < NTop; ++i)
                    {
                        var x = topN[i];
                        Console.WriteLine("#{0}: {1:P0} at 0x{2:X8})", i + 1, x.Value, x.Key + p.patchOffset);
                    }
                    if (fApplyBestBet)
                    {
                        applyAtOffset = topN[0].Key + p.patchOffset;
                    }
                    else if (manualLoc != 0)
                    {
                        if (manualLoc > 0)
                        {
                            applyAtOffset = manualLoc;
                        }
                        else
                        {
                            applyAtOffset = topN[-1 - manualLoc].Key + p.patchOffset;
                        }
                    }
                }

                if (applyAtOffset > 0)
                {
                    Console.WriteLine(
                        "------------------------------\n" +
                        "++APPLIED at 0x{0:X8}", applyAtOffset);
                    Array.Copy(p.patchBytes, 0, mod, applyAtOffset, p.patchBytes.Length);
                    cApplied++;
                }
                else
                {
                    Console.WriteLine(
                        "------------------------------\n" +
                        "!!! TODO #{0} !!!", ++cTodo);
                }
            }

            File.WriteAllBytes(patchedPath, mod);

            Console.WriteLine(
                "\n=============================================\n" +
                "Applied {0} of {1} patches ({2:P0})", cApplied, patches.Count, ((double)cApplied) / patches.Count);
        }
예제 #2
0
        static void diffFiles(string origPath, string modPath, string diffFile)
        {
            byte[]       orig              = File.ReadAllBytes(origPath);
            byte[]       mod               = File.ReadAllBytes(modPath);
            int          commonSize        = Math.Min(orig.Length, mod.Length);
            int          chunkStart        = -1;
            int          chunkEnd          = -1;
            bool         inChunk           = false;
            bool         previouslyInChunk = false;
            List <Patch> patches           = new List <Patch>();

            for (int i = 0; i < commonSize; ++i)
            {
                inChunk = orig[i] != mod[i];
                if (previouslyInChunk != inChunk)
                {
                    previouslyInChunk = inChunk;
                    if (inChunk)
                    {
                        chunkStart = i;
                    }
                    else
                    {
                        chunkEnd = i;
                        patches.Add(processChunk(orig, mod, chunkStart, chunkEnd));
                    }
                }
            }
            Debug.Assert(!inChunk);
            Console.WriteLine("{0} patches located", patches.Count);
            foreach (Patch p in patches)
            {
                Console.WriteLine("{0} bytes, {1:P0} quality:\t{2}", p.matchBytes.Length, p.quality, Useful.MatchDetails(p));
            }
            using (StreamWriter sw = new StreamWriter(diffFile)) {
                XmlSerializer xs = new XmlSerializer(typeof(List <Patch>));
                xs.Serialize(sw, patches);
                sw.Flush();
            }
        }