Example #1
0
 public static string MatchDetails(Patch p) {
     StringBuilder result = new StringBuilder();
     byte[] beforeBytes = new byte[p.patchOffset];
     byte[] origBytes = new byte[p.patchBytes.Length];
     byte[] afterBytes = new byte[p.matchBytes.Length - p.patchBytes.Length - p.patchOffset];
     Array.ConstrainedCopy(p.matchBytes, 0, beforeBytes, 0, beforeBytes.Length);
     Array.ConstrainedCopy(p.matchBytes, p.patchOffset, origBytes, 0, origBytes.Length);
     Array.ConstrainedCopy(p.matchBytes, p.patchOffset + p.patchBytes.Length, afterBytes, 0, afterBytes.Length);
     result.AppendFormat("{0}{{{1}}}{2}", BytesAsString(beforeBytes), BytesAsString(origBytes), BytesAsString(afterBytes));
     return result.ToString();
 }
Example #2
0
 public static string PatchDetails(Patch p) {
     StringBuilder result = new StringBuilder();
     result.AppendFormat("[{0}] => [{1}]", MatchDetails(p), BytesAsString(p.patchBytes));
     return result.ToString();
 }
Example #3
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);
        }
Example #4
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);
        }