mirror of
https://github.com/huiyadanli/RevokeMsgPatcher.git
synced 2025-05-24 22:46:06 +08:00
[+] 优化特征码撤回逻辑
This commit is contained in:
parent
8ffb1ab0d3
commit
520b7db8f9
|
@ -93,7 +93,6 @@ namespace RevokeMsgPatcher
|
|||
ga.RequestPageView($"{enName}/{version}/patch", "点击防撤回");
|
||||
|
||||
EnableAllButton(false);
|
||||
PatchType type = PatchType.Accurate; // 两种打补丁的方式:精准(指定位置替换)、通用(特征码替换)
|
||||
// a.重新初始化编辑器
|
||||
modifier.InitEditors(txtPath.Text);
|
||||
// b.计算SHA1,验证文件完整性,寻找对应的补丁信息(精确版本、通用特征码两种补丁信息)
|
||||
|
@ -103,19 +102,11 @@ namespace RevokeMsgPatcher
|
|||
}
|
||||
catch (BusinessException ex)
|
||||
{
|
||||
if ((ex.ErrorCode == "not_support" || ex.ErrorCode == "maybe_modified") && modifier.EditorsHasCommonModifyInfos())
|
||||
{
|
||||
// 存在特征码修改替换信息的情况下,尝试使用特征码替换
|
||||
type = PatchType.Common;
|
||||
}
|
||||
else
|
||||
{
|
||||
ga.RequestPageView($"{enName}/{version}/patch/sha1/ex/{ex.ErrorCode}", ex.Message);
|
||||
MessageBox.Show(ex.Message);
|
||||
EnableAllButton(true);
|
||||
btnRestore.Enabled = modifier.BackupExists();
|
||||
return;
|
||||
}
|
||||
ga.RequestPageView($"{enName}/{version}/patch/sha1/ex/{ex.ErrorCode}", ex.Message);
|
||||
MessageBox.Show(ex.Message);
|
||||
EnableAllButton(true);
|
||||
btnRestore.Enabled = modifier.BackupExists();
|
||||
return;
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
|
@ -137,7 +128,7 @@ namespace RevokeMsgPatcher
|
|||
// c.打补丁
|
||||
try
|
||||
{
|
||||
modifier.Patch(type);
|
||||
modifier.Patch();
|
||||
ga.RequestPageView($"{enName}/{version}/patch/succ", "防撤回成功");
|
||||
MessageBox.Show("补丁安装成功!");
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ namespace RevokeMsgPatcher.Matcher
|
|||
/// <param name="start">头串匹配位置</param>
|
||||
/// <param name="whole">完整查找串</param>
|
||||
/// <returns></returns>
|
||||
private static bool IsEqual(byte[] content, int start, byte[] whole)
|
||||
public static bool IsEqual(byte[] content, int start, byte[] whole)
|
||||
{
|
||||
int i = 0;
|
||||
for (i = 0; i < whole.Length; i++)
|
||||
|
|
92
RevokeMsgPatcher/Matcher/ModifyFinder.cs
Normal file
92
RevokeMsgPatcher/Matcher/ModifyFinder.cs
Normal file
|
@ -0,0 +1,92 @@
|
|||
using RevokeMsgPatcher.Model;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace RevokeMsgPatcher.Matcher
|
||||
{
|
||||
public class ModifyFinder
|
||||
{
|
||||
public static List<Change> FindChanges(string path, List<ReplacePattern> replacePatterns)
|
||||
{
|
||||
// 读取整个文件(dll)
|
||||
byte[] fileByteArray = File.ReadAllBytes(path);
|
||||
|
||||
List<Change> changes = new List<Change>();
|
||||
|
||||
// 查找所有替换点
|
||||
int matchNum = 0;
|
||||
foreach (ReplacePattern pattern in replacePatterns)
|
||||
{
|
||||
// 所有的匹配点位
|
||||
int[] matchIndexs = FuzzyMatcher.MatchAll(fileByteArray, pattern.Search);
|
||||
if (matchIndexs.Length == 1)
|
||||
{
|
||||
matchNum++;
|
||||
// 与要替换的串不一样才需要替换(当前的特征肯定不一样)
|
||||
if (!FuzzyMatcher.IsEqual(fileByteArray, matchIndexs[0], pattern.Replace))
|
||||
{
|
||||
changes.Add(new Change(matchIndexs[0], pattern.Replace));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 匹配数和期望的匹配数不一致时报错(当前一个特征只会出现一次)
|
||||
if (matchNum != replacePatterns.Count)
|
||||
{
|
||||
if (IsAllReplaced(fileByteArray, replacePatterns))
|
||||
{
|
||||
throw new BusinessException("match_already_replace", "特征比对:当前应用已经安装了防撤回补丁!");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new BusinessException("match_inconformity", $"特征比对:当前特征码匹配数[{matchNum}]和期望的匹配数[{replacePatterns.Count}]不一致,如果当前版本为新版本,特征码可能出现变化,请联系作者处理!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 匹配数和需要替换的数量不一致时,可能时部分/所有特征已经被替换
|
||||
if (matchNum != changes.Count)
|
||||
{
|
||||
// 此逻辑在当前特征配置下不会进入,因为查找串和替换串当前全部都是不相同的
|
||||
if (changes.Count == 0)
|
||||
{
|
||||
throw new BusinessException("match_already_replace", "特征比对:当前应用已经安装了防撤回补丁!");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new BusinessException("match_part_replace", "特征比对:部分特征已经被替换,请确认是否有使用过其他防撤回补丁!");
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// 匹配数和需要替换的数量一致时才是正常状态
|
||||
return changes;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static bool IsAllReplaced(byte[] fileByteArray, List<ReplacePattern> replacePatterns)
|
||||
{
|
||||
int matchNum = 0;
|
||||
foreach (ReplacePattern pattern in replacePatterns)
|
||||
{
|
||||
// 所有的匹配点位
|
||||
int[] matchIndexs = FuzzyMatcher.MatchAll(fileByteArray, pattern.Replace);
|
||||
if (matchIndexs.Length == 1)
|
||||
{
|
||||
matchNum++;
|
||||
}
|
||||
}
|
||||
if (matchNum == replacePatterns.Count)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RevokeMsgPatcher.Model.Enum
|
||||
{
|
||||
/// <summary>
|
||||
/// 两种打补丁的方式
|
||||
/// 精准(指定位置替换)、通用(特征码替换)
|
||||
/// </summary>
|
||||
public enum PatchType
|
||||
{
|
||||
Accurate, // 精准(指定位置替换)
|
||||
Common // 通用(特征码替换)
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using RevokeMsgPatcher.Model;
|
||||
using RevokeMsgPatcher.Matcher;
|
||||
using RevokeMsgPatcher.Model;
|
||||
using RevokeMsgPatcher.Model.Enum;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -168,10 +169,28 @@ namespace RevokeMsgPatcher.Modifier
|
|||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 寻找版本对应的特征码信息
|
||||
/// </summary>
|
||||
/// <param name="editor">文件编辑器</param>
|
||||
private CommonModifyInfo FindCommonModifyInfo(FileHexEditor editor)
|
||||
{
|
||||
foreach (CommonModifyInfo commonModifyInfo in config.FileCommonModifyInfos[editor.FileName])
|
||||
{
|
||||
// editor.FileVersion 在 StartVersion 和 EndVersion 之间
|
||||
if (IsInVersionRange(editor.FileVersion, commonModifyInfo.StartVersion, commonModifyInfo.EndVersion))
|
||||
{
|
||||
return commonModifyInfo;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文件修改器是否已经有对应的特征码修改替换信息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[Obsolete]
|
||||
public bool EditorsHasCommonModifyInfos()
|
||||
{
|
||||
int i = 0;
|
||||
|
@ -238,24 +257,11 @@ namespace RevokeMsgPatcher.Modifier
|
|||
}
|
||||
}
|
||||
|
||||
// 多个版本范围,匹配出对应版本可以使用的特征
|
||||
if (config.FileCommonModifyInfos != null)
|
||||
{
|
||||
foreach (CommonModifyInfo commonModifyInfo in config.FileCommonModifyInfos[editor.FileName])
|
||||
{
|
||||
// editor.FileVersion 在 StartVersion 和 EndVersion 之间
|
||||
if (IsInVersionRange(editor.FileVersion, commonModifyInfo.StartVersion, commonModifyInfo.EndVersion))
|
||||
{
|
||||
editor.FileCommonModifyInfo = commonModifyInfo;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 补丁前SHA1匹配上,肯定是正确的dll
|
||||
if (matchingSHA1Before != null)
|
||||
{
|
||||
editor.FileModifyInfo = matchingSHA1Before;
|
||||
editor.TargetChanges = matchingSHA1Before.Changes;
|
||||
continue;
|
||||
}
|
||||
// 补丁后SHA1匹配上,肯定已经打过补丁
|
||||
|
@ -263,15 +269,36 @@ namespace RevokeMsgPatcher.Modifier
|
|||
{
|
||||
throw new BusinessException("installed", $"你已经安装过此补丁!");
|
||||
}
|
||||
// 全部不匹配,说明不支持
|
||||
if (matchingSHA1Before == null && matchingSHA1After == null && matchingVersion == null)
|
||||
|
||||
// SHA1不匹配说明精准替换肯定不支持
|
||||
if (matchingSHA1Before == null && matchingSHA1After == null)
|
||||
{
|
||||
throw new BusinessException("not_support", $"不支持此版本:{editor.FileVersion}!");
|
||||
}
|
||||
// SHA1不匹配,版本匹配,可能dll已经被其他补丁程序修改过
|
||||
if ((matchingSHA1Before == null && matchingSHA1After == null) && matchingVersion != null)
|
||||
{
|
||||
throw new BusinessException("maybe_modified", $"程序支持此版本:{editor.FileVersion}。但是文件校验不通过,请确认是否使用过其他补丁程序!");
|
||||
// 多个版本范围,匹配出对应版本可以使用的特征
|
||||
if (config.FileCommonModifyInfos != null)
|
||||
{
|
||||
editor.FileCommonModifyInfo = FindCommonModifyInfo(editor);
|
||||
}
|
||||
|
||||
// 存在对应的特征时不报错
|
||||
if (editor.FileCommonModifyInfo != null && editor.FileCommonModifyInfo.ReplacePatterns != null)
|
||||
{
|
||||
// 如果能顺利得到 TargetChanges 不报错则可以使用特征替换方式
|
||||
editor.TargetChanges = ModifyFinder.FindChanges(editor.FilePath, editor.FileCommonModifyInfo.ReplacePatterns);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// SHA1不匹配,连版本也不匹配,说明完全不支持
|
||||
if (matchingVersion == null)
|
||||
{
|
||||
throw new BusinessException("not_support", $"不支持此版本:{editor.FileVersion}!");
|
||||
}
|
||||
// SHA1不匹配,但是版本匹配,可能dll已经被其他补丁程序修改过
|
||||
if (matchingVersion != null)
|
||||
{
|
||||
throw new BusinessException("maybe_modified", $"程序支持此版本:{editor.FileVersion}。但是文件校验不通过,请确认是否使用过其他补丁程序!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -280,21 +307,16 @@ namespace RevokeMsgPatcher.Modifier
|
|||
/// c.根据补丁信息,安装补丁
|
||||
/// 两种打补丁的方式:精准(指定位置替换)、通用(特征码替换)
|
||||
/// </summary>
|
||||
/// <param name="type">两种打补丁的方式:精准(指定位置替换)、通用(特征码替换)</param>
|
||||
/// <returns></returns>
|
||||
public bool Patch(PatchType type = PatchType.Accurate)
|
||||
public bool Patch()
|
||||
{
|
||||
// 首先验证文件修改器是否没问题
|
||||
foreach (FileHexEditor editor in editors)
|
||||
{
|
||||
if (type == PatchType.Accurate && editor.FileModifyInfo == null)
|
||||
if(editor == null)
|
||||
{
|
||||
throw new Exception("补丁安装失败,原因:文件修改器初始化失败!");
|
||||
}
|
||||
if (type == PatchType.Common && editor.FileCommonModifyInfo == null)
|
||||
{
|
||||
throw new Exception("补丁安装失败,原因:特征码修改器初始化失败!");
|
||||
}
|
||||
}
|
||||
// 再备份所有文件
|
||||
foreach (FileHexEditor editor in editors)
|
||||
|
@ -307,7 +329,7 @@ namespace RevokeMsgPatcher.Modifier
|
|||
{
|
||||
foreach (FileHexEditor editor in editors)
|
||||
{
|
||||
bool success = editor.Patch(type);
|
||||
bool success = editor.Patch();
|
||||
if (!success)
|
||||
{
|
||||
editor.Restore();
|
||||
|
@ -366,6 +388,10 @@ namespace RevokeMsgPatcher.Modifier
|
|||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
editor.Restore();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ namespace RevokeMsgPatcher.Modifier
|
|||
{
|
||||
get
|
||||
{
|
||||
return FileUtil.GetFileVersion(FileBakPath);
|
||||
return FileUtil.GetFileVersion(FileBakPath);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,6 +64,11 @@ namespace RevokeMsgPatcher.Modifier
|
|||
/// </summary>
|
||||
public CommonModifyInfo FileCommonModifyInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 将要执行的修改
|
||||
/// </summary>
|
||||
public List<Change> TargetChanges { get; set; }
|
||||
|
||||
public FileHexEditor(string installPath, TargetInfo target)
|
||||
{
|
||||
FileTargetInfo = target.Clone();
|
||||
|
@ -84,91 +89,18 @@ namespace RevokeMsgPatcher.Modifier
|
|||
/// <summary>
|
||||
/// 打补丁
|
||||
/// </summary>
|
||||
/// <param name="type">两种打补丁的方式:精准(指定位置替换)、通用(特征码替换)</param>
|
||||
/// <returns></returns>
|
||||
public bool Patch(PatchType type)
|
||||
public bool Patch()
|
||||
{
|
||||
if (type == PatchType.Accurate)
|
||||
if (TargetChanges == null)
|
||||
{
|
||||
AccuratePatch();
|
||||
throw new BusinessException("change_null", "在安装补丁时,变更的内容为空!");
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
CommonPatch();
|
||||
}
|
||||
FileUtil.EditMultiHex(FilePath, TargetChanges);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 精准(指定位置替换)
|
||||
/// </summary>
|
||||
public void AccuratePatch()
|
||||
{
|
||||
FileUtil.EditMultiHex(FilePath, FileModifyInfo.Changes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通用(特征码替换)
|
||||
/// </summary>
|
||||
public void CommonPatch()
|
||||
{
|
||||
if (FileCommonModifyInfo == null)
|
||||
{
|
||||
throw new Exception("特征码替换:缺失对应特征码信息");
|
||||
}
|
||||
// 1. 拷贝一份临时文件
|
||||
File.Copy(FilePath, fileReplacedPath, true);
|
||||
// 2. 读取整个临时文件
|
||||
byte[] fileByteArray = File.ReadAllBytes(fileReplacedPath);
|
||||
// 3. 循环查找所有未替换的替换点
|
||||
int needReplaceNum = 0;
|
||||
List<Change> changes = new List<Change>();
|
||||
foreach (ReplacePattern pattern in FileCommonModifyInfo.ReplacePatterns)
|
||||
{
|
||||
int[] indexs = FuzzyMatcher.MatchNotReplaced(fileByteArray, pattern.Search, pattern.Replace);
|
||||
if (indexs.Length == 1)
|
||||
{
|
||||
needReplaceNum++;
|
||||
changes.Add(new Change(indexs[0], pattern.Replace));
|
||||
}
|
||||
}
|
||||
// 判断是否可以使用特征码替换的方式
|
||||
if (needReplaceNum == 0)
|
||||
{
|
||||
// 查找所有替换点
|
||||
int matchNum = 0;
|
||||
foreach (ReplacePattern pattern in FileCommonModifyInfo.ReplacePatterns)
|
||||
{
|
||||
int[] indexs = FuzzyMatcher.MatchAll(fileByteArray, pattern.Search);
|
||||
if (indexs.Length == 1)
|
||||
{
|
||||
matchNum++;
|
||||
}
|
||||
}
|
||||
if (matchNum == FileCommonModifyInfo.ReplacePatterns.Count)
|
||||
{
|
||||
throw new BusinessException("already_replace", "特征码替换:当前应用已经防撤回");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new BusinessException("not_found_to_replace", "特征码替换:没有搜索到撤回的相关特征");
|
||||
}
|
||||
}
|
||||
else if (needReplaceNum == FileCommonModifyInfo.ReplacePatterns.Count)
|
||||
{
|
||||
// 正常情况下每个替换点都能找到
|
||||
// 3. 替换所有未替换的替换点
|
||||
FileUtil.EditMultiHex(fileReplacedPath, changes);
|
||||
// 4. 覆盖特征码替换后的文件
|
||||
File.Copy(fileReplacedPath, FilePath, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new BusinessException("found_num_err", "特征码替换:可替换的特征数不正确");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 还原
|
||||
/// </summary>
|
||||
|
|
|
@ -61,7 +61,7 @@ namespace RevokeMsgPatcher.Properties {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 {"Apps":{"Wechat":{"Name":"Wechat","FileTargetInfos":{"WeChatWin.dll":{"Name":"WeChatWin.dll","RelativePath":"WeChatWin.dll","Memo":null}},"FileModifyInfos":{"WeChatWin.dll":[{"Name":"WeChatWin.dll","Version":"2.7.1.88","SHA1Before":"034059bad50dd793140952391bfa7936133e69b4","SHA1After":"dd6d80c30ca9e0ea9f7d2f1add498fc9aa4bc7a0","Changes":[{"Position":2499465,"Content":[235]},{"Position":7952304,"Content":[195]}]},{"Name":"WeChatWin.dll","Version":"2.7.1.85","SHA1Before":"de0df4e138b72460450f66c029e33f4510f [字符串的其余部分被截断]"; 的本地化字符串。
|
||||
/// 查找类似 {"Apps":{"Wechat":{"Name":"Wechat","FileTargetInfos":{"WeChatWin.dll":{"Name":"WeChatWin.dll","RelativePath":"WeChatWin.dll","Memo":null}},"FileModifyInfos":{"WeChatWin.dll":[{"Name":"WeChatWin.dll","Version":"2.8.0.82","SHA1Before":"c359cc1a391441d261753f2844f9156638df8631","SHA1After":"d1b4dee8f7f91e34d68501987fd0675b33fe85da","Changes":[{"Position":2645961,"Content":[235]},{"Position":8263344,"Content":[195]}]},{"Name":"WeChatWin.dll","Version":"2.7.2.78","SHA1Before":"26a5c5503f1e176676da5657c12812da8aa [字符串的其余部分被截断]"; 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string PatchJson {
|
||||
get {
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -59,11 +59,11 @@
|
|||
</Compile>
|
||||
<Compile Include="Matcher\BoyerMooreMatcher.cs" />
|
||||
<Compile Include="Matcher\FuzzyMatcher.cs" />
|
||||
<Compile Include="Matcher\ModifyFinder.cs" />
|
||||
<Compile Include="Model\App.cs" />
|
||||
<Compile Include="Model\Bag.cs" />
|
||||
<Compile Include="Model\Change.cs" />
|
||||
<Compile Include="Model\CommonModifyInfo.cs" />
|
||||
<Compile Include="Model\Enum\PatchType.cs" />
|
||||
<Compile Include="Model\ModifyInfo.cs" />
|
||||
<Compile Include="Model\ReplacePattern.cs" />
|
||||
<Compile Include="Model\TargetInfo.cs" />
|
||||
|
|
Loading…
Reference in New Issue
Block a user