mirror of
https://github.com/huiyadanli/RevokeMsgPatcher.git
synced 2025-05-23 05:46:07 +08:00
[+] 完成基于特征码的防撤回查找替换功能
This commit is contained in:
parent
604f84b0f6
commit
88f6ae7417
|
@ -93,7 +93,7 @@ namespace RevokeMsgPatcher.Assistant
|
|||
|
||||
if (changeOffsets.Count == 0)
|
||||
{
|
||||
throw new Exception("查询串与替换串完全相同!请联系作者确认远端补丁信息的正确性。");
|
||||
throw new Exception("查询串与替换串完全相同!请确认补丁信息的正确性。");
|
||||
}
|
||||
|
||||
List<Change> changes = new List<Change>();
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using RevokeMsgPatcher.Model;
|
||||
using RevokeMsgPatcher.Model.Enum;
|
||||
using RevokeMsgPatcher.Modifier;
|
||||
using RevokeMsgPatcher.Utils;
|
||||
using System;
|
||||
|
@ -95,18 +96,38 @@ namespace RevokeMsgPatcher
|
|||
ga.RequestPageView($"{enName}/{version}/patch", "点击防撤回");
|
||||
|
||||
EnableAllButton(false);
|
||||
PatchType type = PatchType.Accurate; // 两种打补丁的方式:精准(指定位置替换)、通用(特征码替换)
|
||||
// a.重新初始化编辑器
|
||||
modifier.InitEditors(txtPath.Text);
|
||||
// b.计算SHA1,验证文件完整性,寻找对应的补丁信息
|
||||
// b.计算SHA1,验证文件完整性,寻找对应的补丁信息(精确版本、通用特征码两种补丁信息)
|
||||
try
|
||||
{
|
||||
modifier.ValidateAndFindModifyInfo();
|
||||
}
|
||||
catch (BusinessException ex)
|
||||
{
|
||||
ga.RequestPageView($"{enName}/{version}/patch/sha1/ex/{ex.ErrorCode}", ex.Message);
|
||||
MessageBox.Show(ex.Message);
|
||||
return;
|
||||
if ((ex.ErrorCode == "not_support" || ex.ErrorCode == "maybe_modified") && modifier.EditorsHasCommonModifyInfos())
|
||||
{
|
||||
// 存在特征码修改替换信息的情况下,发起一次询问
|
||||
DialogResult useCommonPatch =
|
||||
MessageBox.Show("尝试使用精准匹配补丁程序时发生错误:【" +
|
||||
ex.Message + "】,不过该版本支持使用特征码替换补丁程序,当前建议继续尝试防撤回!是否继续尝试防撤回?",
|
||||
"是否使用特征码补丁", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
|
||||
if (useCommonPatch == DialogResult.OK)
|
||||
{
|
||||
type = PatchType.Common;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ga.RequestPageView($"{enName}/{version}/patch/sha1/ex/{ex.ErrorCode}", ex.Message);
|
||||
MessageBox.Show(ex.Message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
|
@ -128,7 +149,7 @@ namespace RevokeMsgPatcher
|
|||
// c.打补丁
|
||||
try
|
||||
{
|
||||
modifier.Patch();
|
||||
modifier.Patch(type);
|
||||
ga.RequestPageView($"{enName}/{version}/patch/succ", "防撤回成功");
|
||||
MessageBox.Show("补丁安装成功!");
|
||||
}
|
||||
|
|
|
@ -12,6 +12,17 @@ namespace RevokeMsgPatcher.Model
|
|||
|
||||
public byte[] Content { get; set; }
|
||||
|
||||
public Change()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public Change(long position, byte[] content)
|
||||
{
|
||||
Position = position;
|
||||
Content = content;
|
||||
}
|
||||
|
||||
public Change Clone()
|
||||
{
|
||||
Change o = new Change();
|
||||
|
|
18
RevokeMsgPatcher/Model/Enum/PatchType.cs
Normal file
18
RevokeMsgPatcher/Model/Enum/PatchType.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
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.Model.Enum;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
|
@ -166,6 +167,30 @@ namespace RevokeMsgPatcher.Modifier
|
|||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文件修改器是否已经有对应的特征码修改替换信息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool EditorsHasCommonModifyInfos()
|
||||
{
|
||||
int i = 0;
|
||||
for (i = 0; i < editors.Count; i++) // 多种文件
|
||||
{
|
||||
if (editors[i].FileCommonModifyInfo == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == editors.Count)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// a.初始化修改器
|
||||
/// </summary>
|
||||
|
@ -235,34 +260,40 @@ namespace RevokeMsgPatcher.Modifier
|
|||
// 补丁后SHA1匹配上,肯定已经打过补丁
|
||||
if (matchingSHA1After != null)
|
||||
{
|
||||
throw new BusinessException("installed", $"你已经安装过此补丁,文件路径:{editor.FilePath}");
|
||||
throw new BusinessException("installed", $"你已经安装过此补丁!");
|
||||
}
|
||||
// 全部不匹配,说明不支持
|
||||
if (matchingSHA1Before == null && matchingSHA1After == null && matchingVersion == null)
|
||||
{
|
||||
throw new BusinessException("not_support", $"不支持此版本:{editor.FileVersion},文件路径:{editor.FilePath}");
|
||||
throw new BusinessException("not_support", $"不支持此版本:{editor.FileVersion}!");
|
||||
}
|
||||
// SHA1不匹配,版本匹配,可能dll已经被其他补丁程序修改过
|
||||
if ((matchingSHA1Before == null && matchingSHA1After == null) && matchingVersion != null)
|
||||
{
|
||||
throw new BusinessException("maybe_modified", $"程序支持此版本:{editor.FileVersion}。但是文件校验不通过,请确认是否使用过其他补丁程序。文件路径:{editor.FilePath}");
|
||||
throw new BusinessException("maybe_modified", $"程序支持此版本:{editor.FileVersion}。但是文件校验不通过,请确认是否使用过其他补丁程序!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// c.根据补丁信息,安装补丁
|
||||
/// 两种打补丁的方式:精准(指定位置替换)、通用(特征码替换)
|
||||
/// </summary>
|
||||
/// <param name="type">两种打补丁的方式:精准(指定位置替换)、通用(特征码替换)</param>
|
||||
/// <returns></returns>
|
||||
public bool Patch()
|
||||
public bool Patch(PatchType type = PatchType.Accurate)
|
||||
{
|
||||
// 首先验证文件修改器是否没问题
|
||||
foreach (FileHexEditor editor in editors)
|
||||
{
|
||||
if (editor.FileModifyInfo == null)
|
||||
if (type == PatchType.Accurate && editor.FileModifyInfo == null)
|
||||
{
|
||||
throw new Exception("补丁安装失败,原因:文件修改器初始化失败!");
|
||||
}
|
||||
if (type == PatchType.Common && editor.FileCommonModifyInfo == null)
|
||||
{
|
||||
throw new Exception("补丁安装失败,原因:特征码修改器初始化失败!");
|
||||
}
|
||||
}
|
||||
// 再备份所有文件
|
||||
foreach (FileHexEditor editor in editors)
|
||||
|
@ -275,12 +306,15 @@ namespace RevokeMsgPatcher.Modifier
|
|||
{
|
||||
foreach (FileHexEditor editor in editors)
|
||||
{
|
||||
bool success = editor.Patch();
|
||||
bool success = editor.Patch(type);
|
||||
if (!success)
|
||||
{
|
||||
editor.Restore();
|
||||
}
|
||||
done.Add(editor);
|
||||
else
|
||||
{
|
||||
done.Add(editor);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using RevokeMsgPatcher.Model;
|
||||
using RevokeMsgPatcher.Matcher;
|
||||
using RevokeMsgPatcher.Model;
|
||||
using RevokeMsgPatcher.Model.Enum;
|
||||
using RevokeMsgPatcher.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -53,7 +55,7 @@ namespace RevokeMsgPatcher.Modifier
|
|||
public ModifyInfo FileModifyInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 通过比对版本范围得到的通用查找替换的修改信息
|
||||
/// 通过比对版本范围得到的通用查找替换的修改信息(特征码替换信息)
|
||||
/// </summary>
|
||||
public CommonModifyInfo FileCommonModifyInfo { get; set; }
|
||||
|
||||
|
@ -76,14 +78,90 @@ namespace RevokeMsgPatcher.Modifier
|
|||
|
||||
/// <summary>
|
||||
/// 打补丁
|
||||
/// 优先使用特定的补丁信息(存在对应SHA1信息)
|
||||
/// 不存在补丁信息,使用通用版本替换方法
|
||||
/// </summary>
|
||||
/// <param name="type">两种打补丁的方式:精准(指定位置替换)、通用(特征码替换)</param>
|
||||
/// <returns></returns>
|
||||
public bool Patch()
|
||||
public bool Patch(PatchType type)
|
||||
{
|
||||
if (type == PatchType.Accurate)
|
||||
{
|
||||
AccuratePatch();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
CommonPatch();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 精准(指定位置替换)
|
||||
/// </summary>
|
||||
public void AccuratePatch()
|
||||
{
|
||||
FileUtil.EditMultiHex(FilePath, FileModifyInfo.Changes);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <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 Exception("特征码替换:当前应用已经防撤回");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("特征码替换:没有搜索到撤回的相关特征");
|
||||
}
|
||||
}
|
||||
else if (needReplaceNum == FileCommonModifyInfo.ReplacePatterns.Count)
|
||||
{
|
||||
// 正常情况下每个替换点都能找到
|
||||
// 3. 替换所有未替换的替换点
|
||||
FileUtil.EditMultiHex(fileReplacedPath, changes);
|
||||
// 4. 覆盖特征码替换后的文件
|
||||
File.Copy(fileReplacedPath, FilePath, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("特征码替换:可替换的特征数不正确");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
<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