[+] 优化特征码撤回逻辑

This commit is contained in:
huiyadanli 2020-01-02 23:52:16 +08:00
parent 8ffb1ab0d3
commit 520b7db8f9
9 changed files with 170 additions and 147 deletions

View File

@ -93,7 +93,6 @@ namespace RevokeMsgPatcher
ga.RequestPageView($"{enName}/{version}/patch", "点击防撤回"); ga.RequestPageView($"{enName}/{version}/patch", "点击防撤回");
EnableAllButton(false); EnableAllButton(false);
PatchType type = PatchType.Accurate; // 两种打补丁的方式:精准(指定位置替换)、通用(特征码替换)
// a.重新初始化编辑器 // a.重新初始化编辑器
modifier.InitEditors(txtPath.Text); modifier.InitEditors(txtPath.Text);
// b.计算SHA1验证文件完整性寻找对应的补丁信息精确版本、通用特征码两种补丁信息 // b.计算SHA1验证文件完整性寻找对应的补丁信息精确版本、通用特征码两种补丁信息
@ -103,19 +102,11 @@ namespace RevokeMsgPatcher
} }
catch (BusinessException ex) catch (BusinessException ex)
{ {
if ((ex.ErrorCode == "not_support" || ex.ErrorCode == "maybe_modified") && modifier.EditorsHasCommonModifyInfos()) ga.RequestPageView($"{enName}/{version}/patch/sha1/ex/{ex.ErrorCode}", ex.Message);
{ MessageBox.Show(ex.Message);
// 存在特征码修改替换信息的情况下,尝试使用特征码替换 EnableAllButton(true);
type = PatchType.Common; btnRestore.Enabled = modifier.BackupExists();
} return;
else
{
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) catch (IOException ex)
{ {
@ -137,7 +128,7 @@ namespace RevokeMsgPatcher
// c.打补丁 // c.打补丁
try try
{ {
modifier.Patch(type); modifier.Patch();
ga.RequestPageView($"{enName}/{version}/patch/succ", "防撤回成功"); ga.RequestPageView($"{enName}/{version}/patch/succ", "防撤回成功");
MessageBox.Show("补丁安装成功!"); MessageBox.Show("补丁安装成功!");
} }

View File

@ -106,7 +106,7 @@ namespace RevokeMsgPatcher.Matcher
/// <param name="start">头串匹配位置</param> /// <param name="start">头串匹配位置</param>
/// <param name="whole">完整查找串</param> /// <param name="whole">完整查找串</param>
/// <returns></returns> /// <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; int i = 0;
for (i = 0; i < whole.Length; i++) for (i = 0; i < whole.Length; i++)

View 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;
}
}
}
}

View File

@ -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 // 通用(特征码替换)
}
}

View File

@ -1,4 +1,5 @@
using RevokeMsgPatcher.Model; using RevokeMsgPatcher.Matcher;
using RevokeMsgPatcher.Model;
using RevokeMsgPatcher.Model.Enum; using RevokeMsgPatcher.Model.Enum;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -168,10 +169,28 @@ namespace RevokeMsgPatcher.Modifier
return false; 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>
/// 文件修改器是否已经有对应的特征码修改替换信息 /// 文件修改器是否已经有对应的特征码修改替换信息
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Obsolete]
public bool EditorsHasCommonModifyInfos() public bool EditorsHasCommonModifyInfos()
{ {
int i = 0; 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 // 补丁前SHA1匹配上肯定是正确的dll
if (matchingSHA1Before != null) if (matchingSHA1Before != null)
{ {
editor.FileModifyInfo = matchingSHA1Before; editor.FileModifyInfo = matchingSHA1Before;
editor.TargetChanges = matchingSHA1Before.Changes;
continue; continue;
} }
// 补丁后SHA1匹配上肯定已经打过补丁 // 补丁后SHA1匹配上肯定已经打过补丁
@ -263,15 +269,36 @@ namespace RevokeMsgPatcher.Modifier
{ {
throw new BusinessException("installed", $"你已经安装过此补丁!"); throw new BusinessException("installed", $"你已经安装过此补丁!");
} }
// 全部不匹配,说明不支持
if (matchingSHA1Before == null && matchingSHA1After == null && matchingVersion == null) // SHA1不匹配说明精准替换肯定不支持
if (matchingSHA1Before == null && matchingSHA1After == null)
{ {
throw new BusinessException("not_support", $"不支持此版本:{editor.FileVersion}"); // 多个版本范围,匹配出对应版本可以使用的特征
} if (config.FileCommonModifyInfos != null)
// SHA1不匹配版本匹配可能dll已经被其他补丁程序修改过 {
if ((matchingSHA1Before == null && matchingSHA1After == null) && matchingVersion != null) editor.FileCommonModifyInfo = FindCommonModifyInfo(editor);
{ }
throw new BusinessException("maybe_modified", $"程序支持此版本:{editor.FileVersion}。但是文件校验不通过,请确认是否使用过其他补丁程序!");
// 存在对应的特征时不报错
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.根据补丁信息,安装补丁 /// c.根据补丁信息,安装补丁
/// 两种打补丁的方式:精准(指定位置替换)、通用(特征码替换) /// 两种打补丁的方式:精准(指定位置替换)、通用(特征码替换)
/// </summary> /// </summary>
/// <param name="type">两种打补丁的方式:精准(指定位置替换)、通用(特征码替换)</param>
/// <returns></returns> /// <returns></returns>
public bool Patch(PatchType type = PatchType.Accurate) public bool Patch()
{ {
// 首先验证文件修改器是否没问题 // 首先验证文件修改器是否没问题
foreach (FileHexEditor editor in editors) foreach (FileHexEditor editor in editors)
{ {
if (type == PatchType.Accurate && editor.FileModifyInfo == null) if(editor == null)
{ {
throw new Exception("补丁安装失败,原因:文件修改器初始化失败!"); throw new Exception("补丁安装失败,原因:文件修改器初始化失败!");
} }
if (type == PatchType.Common && editor.FileCommonModifyInfo == null)
{
throw new Exception("补丁安装失败,原因:特征码修改器初始化失败!");
}
} }
// 再备份所有文件 // 再备份所有文件
foreach (FileHexEditor editor in editors) foreach (FileHexEditor editor in editors)
@ -307,7 +329,7 @@ namespace RevokeMsgPatcher.Modifier
{ {
foreach (FileHexEditor editor in editors) foreach (FileHexEditor editor in editors)
{ {
bool success = editor.Patch(type); bool success = editor.Patch();
if (!success) if (!success)
{ {
editor.Restore(); editor.Restore();
@ -366,6 +388,10 @@ namespace RevokeMsgPatcher.Modifier
return false; return false;
} }
} }
else
{
editor.Restore();
}
} }
return true; return true;
} }

View File

@ -35,7 +35,7 @@ namespace RevokeMsgPatcher.Modifier
{ {
get get
{ {
return FileUtil.GetFileVersion(FileBakPath); return FileUtil.GetFileVersion(FileBakPath);
} }
} }
@ -64,6 +64,11 @@ namespace RevokeMsgPatcher.Modifier
/// </summary> /// </summary>
public CommonModifyInfo FileCommonModifyInfo { get; set; } public CommonModifyInfo FileCommonModifyInfo { get; set; }
/// <summary>
/// 将要执行的修改
/// </summary>
public List<Change> TargetChanges { get; set; }
public FileHexEditor(string installPath, TargetInfo target) public FileHexEditor(string installPath, TargetInfo target)
{ {
FileTargetInfo = target.Clone(); FileTargetInfo = target.Clone();
@ -84,91 +89,18 @@ namespace RevokeMsgPatcher.Modifier
/// <summary> /// <summary>
/// 打补丁 /// 打补丁
/// </summary> /// </summary>
/// <param name="type">两种打补丁的方式:精准(指定位置替换)、通用(特征码替换)</param>
/// <returns></returns> /// <returns></returns>
public bool Patch(PatchType type) public bool Patch()
{ {
if (type == PatchType.Accurate) if (TargetChanges == null)
{ {
AccuratePatch(); throw new BusinessException("change_null", "在安装补丁时,变更的内容为空!");
}
} FileUtil.EditMultiHex(FilePath, TargetChanges);
else
{
CommonPatch();
}
return true; 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>
/// 还原 /// 还原
/// </summary> /// </summary>

View File

@ -61,7 +61,7 @@ namespace RevokeMsgPatcher.Properties {
} }
/// <summary> /// <summary>
/// 查找类似 {&quot;Apps&quot;:{&quot;Wechat&quot;:{&quot;Name&quot;:&quot;Wechat&quot;,&quot;FileTargetInfos&quot;:{&quot;WeChatWin.dll&quot;:{&quot;Name&quot;:&quot;WeChatWin.dll&quot;,&quot;RelativePath&quot;:&quot;WeChatWin.dll&quot;,&quot;Memo&quot;:null}},&quot;FileModifyInfos&quot;:{&quot;WeChatWin.dll&quot;:[{&quot;Name&quot;:&quot;WeChatWin.dll&quot;,&quot;Version&quot;:&quot;2.7.1.88&quot;,&quot;SHA1Before&quot;:&quot;034059bad50dd793140952391bfa7936133e69b4&quot;,&quot;SHA1After&quot;:&quot;dd6d80c30ca9e0ea9f7d2f1add498fc9aa4bc7a0&quot;,&quot;Changes&quot;:[{&quot;Position&quot;:2499465,&quot;Content&quot;:[235]},{&quot;Position&quot;:7952304,&quot;Content&quot;:[195]}]},{&quot;Name&quot;:&quot;WeChatWin.dll&quot;,&quot;Version&quot;:&quot;2.7.1.85&quot;,&quot;SHA1Before&quot;:&quot;de0df4e138b72460450f66c029e33f4510f [字符串的其余部分被截断]&quot;; 的本地化字符串。 /// 查找类似 {&quot;Apps&quot;:{&quot;Wechat&quot;:{&quot;Name&quot;:&quot;Wechat&quot;,&quot;FileTargetInfos&quot;:{&quot;WeChatWin.dll&quot;:{&quot;Name&quot;:&quot;WeChatWin.dll&quot;,&quot;RelativePath&quot;:&quot;WeChatWin.dll&quot;,&quot;Memo&quot;:null}},&quot;FileModifyInfos&quot;:{&quot;WeChatWin.dll&quot;:[{&quot;Name&quot;:&quot;WeChatWin.dll&quot;,&quot;Version&quot;:&quot;2.8.0.82&quot;,&quot;SHA1Before&quot;:&quot;c359cc1a391441d261753f2844f9156638df8631&quot;,&quot;SHA1After&quot;:&quot;d1b4dee8f7f91e34d68501987fd0675b33fe85da&quot;,&quot;Changes&quot;:[{&quot;Position&quot;:2645961,&quot;Content&quot;:[235]},{&quot;Position&quot;:8263344,&quot;Content&quot;:[195]}]},{&quot;Name&quot;:&quot;WeChatWin.dll&quot;,&quot;Version&quot;:&quot;2.7.2.78&quot;,&quot;SHA1Before&quot;:&quot;26a5c5503f1e176676da5657c12812da8aa [字符串的其余部分被截断]&quot;; 的本地化字符串。
/// </summary> /// </summary>
internal static string PatchJson { internal static string PatchJson {
get { get {

File diff suppressed because one or more lines are too long

View File

@ -59,11 +59,11 @@
</Compile> </Compile>
<Compile Include="Matcher\BoyerMooreMatcher.cs" /> <Compile Include="Matcher\BoyerMooreMatcher.cs" />
<Compile Include="Matcher\FuzzyMatcher.cs" /> <Compile Include="Matcher\FuzzyMatcher.cs" />
<Compile Include="Matcher\ModifyFinder.cs" />
<Compile Include="Model\App.cs" /> <Compile Include="Model\App.cs" />
<Compile Include="Model\Bag.cs" /> <Compile Include="Model\Bag.cs" />
<Compile Include="Model\Change.cs" /> <Compile Include="Model\Change.cs" />
<Compile Include="Model\CommonModifyInfo.cs" /> <Compile Include="Model\CommonModifyInfo.cs" />
<Compile Include="Model\Enum\PatchType.cs" />
<Compile Include="Model\ModifyInfo.cs" /> <Compile Include="Model\ModifyInfo.cs" />
<Compile Include="Model\ReplacePattern.cs" /> <Compile Include="Model\ReplacePattern.cs" />
<Compile Include="Model\TargetInfo.cs" /> <Compile Include="Model\TargetInfo.cs" />