万用特征码替换补丁工具C#源代码
本帖最后由 yujunqiang 于 2022-5-27 10:51 编辑运行环境: WINDOWS、.NET 4.0
涉及工具: VS2017
编程语言: C#
以下为主题内容:万用特征码替换补丁工具C#源代码(主体)
using System;
using System.IO;
using System.Text;
using System.Windows.Forms;
namespace 十六进制搜索替换
{
public partial class Form1 : Form
{
string TargetFileName;//定义目标可执行EXE或DLL文件
OpenFileDialog OpenFileDialog1 = new OpenFileDialog(); //定义打开对话框
string[] SourceHex;//原码十六进制
string[] PatchHex;//补丁十六进制
bool ConfBool;//是否载入配置文件
public Form1()
{
InitializeComponent();//初始化
}
private void Form1_Load(object sender, EventArgs e)
{
string ConfFileName = Application.StartupPath + @"\config.prg";//完整配置文件名
OpenConfigFile(ConfFileName);//默认打开配置文件
}
private void Form1_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)//鼠标左键
{
if (!ConfBool) { return; }//没有载入配置文件则返回退出过程
OpenFileDialog1.Filter = "可执行文件(*.exe)|*.exe|库文件(*.dll)|*.dll|所有文件(*.*)|*.*";
OpenFileDialog1.FilterIndex = 1;
OpenFileDialog1.Title = "打开目标文件";
OpenFileDialog1.FileName = TargetFileName;//目标文件名
OpenFileDialog1.InitialDirectory = Application.StartupPath; //首选当前目录
if (OpenFileDialog1.ShowDialog() == DialogResult.OK)
{
try
{
string TargetFilePathName;//目标文件名
TargetFilePathName = OpenFileDialog1.FileName; //完整目标文件名
int Pos = TargetFilePathName.LastIndexOf(".");//最后的.位置
string BakFilePathName = TargetFilePathName.Substring(0, Pos) + "-Bak" + TargetFilePathName.Substring(Pos);//完整备份文件名
byte[] FSData = File.ReadAllBytes(TargetFilePathName);//读入文件到字节数组
File.Move(TargetFilePathName, BakFilePathName);//备份文件
int PatchNum = SourceHex.Length - 1;//补丁个数
byte[] SourceByte = null;//原始特征码字节数组
byte[] PatchByte = null; //补丁特征码字节数组
for (int i = 1; i <= PatchNum; i++)
{
string[] SourceHexStr = SourceHex.Split(' '); //将原码十六进制特征码按空格拆分为字符串数组
string[] PatchHexStr = PatchHex.Split(' '); //将补丁十六进制特征码按空格拆分为字符串数组
int HexNum = SourceHexStr.Length - 1; //字符串数组个数
Array.Resize(ref SourceByte, HexNum + 1);//为原码字节数组定义个数
Array.Resize(ref PatchByte, HexNum + 1);//为补丁字节数组定义个数
for (int j = 0; j <= HexNum; j++)
{
SourceByte = Convert.ToByte(SourceHexStr,16); //原始特征码转换为字节数组
PatchByte = Convert.ToByte(PatchHexStr, 16);//补丁特征码转换为字节数组
}
do
{
int Index = IndexOf(FSData, SourceByte); //检索原始特征码在程序中的索引位置
if (Index != -1) //特征码匹配
{
int P = 0;
int Indexs = Index + PatchByte.Length - 1;
for (int m = Index; m <= Indexs; m++)
{
FSData = PatchByte; //逐字节替换特征码
P += 1;
}
}
else if (Index == -1)
{
break;//无补丁退出DO
}
} while (true);
}
File.WriteAllBytes(TargetFilePathName, FSData);//写补丁文件
MessageBox.Show("完成程序补丁!原文件已备份", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
MessageBox.Show("配置文件中错误:\r\n1、原始特征码和补丁特征码不匹配,不符合设定!\r\n2、特征码十六进制空格或位数不符合设定!\r\n\r\n" + ex.StackTrace, "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
else if (e.Button == MouseButtons.Middle)//鼠标中键
{
AboutBox aboutBox = new AboutBox();
aboutBox.Show();//显示关于
}
else if (e.Button == MouseButtons.Right)//鼠标右键
{
OpenFileDialog1.Filter = "目标配置文件(*.prg)|*.prg";
OpenFileDialog1.FilterIndex = 1;
OpenFileDialog1.Title = "更改目标配置文件";
OpenFileDialog1.InitialDirectory = Application.StartupPath; //首选当前目录
if (OpenFileDialog1.ShowDialog() == DialogResult.OK)
{
string ConfFileName = OpenFileDialog1.FileName;//完整配置文件名
OpenConfigFile(ConfFileName);
}
}
}
/// <summary>打开或更改配置文件</summary>
/// <param name="ConfigFilePathName">配置文件含完整目录全称</param>
private void OpenConfigFile(string ConfigFilePathName)
{
if (!File.Exists(ConfigFilePathName))//无默认配置文件
{
Text = "万用特征码补丁器 [无配置文件 Config.prg]";
ConfBool = false;//没有默认配置文件
}
else
{
try
{
StreamReader ReaderConfig = new StreamReader(ConfigFilePathName, Encoding.UTF8);//读入配置文件流
int i = 0;
SourceHex = null;
PatchHex = null;
while (ReaderConfig.Peek() > 0)
{
Array.Resize(ref SourceHex, i + 1);// 为原码字符数组定义个数
Array.Resize(ref PatchHex, i + 1);// 为补丁字符数组定义个数
SourceHex = ReaderConfig.ReadLine();//读原码行数据
PatchHex = ReaderConfig.ReadLine(); //读补丁行数据
ConfBool = true;
i++;
}
ReaderConfig.Dispose();//释放文件流
TargetFileName = SourceHex;
string TargetFileVer = PatchHex;
Text = "万用特征码补丁器 [" + TargetFileName + " " + TargetFileVer + "]";
}
catch (Exception ex)
{
ConfBool = false;
MessageBox.Show("配置文件错误:\r\n配置文件非法或不符合设定!\r\n\r\n" + ex.StackTrace, "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
/// <summary>
/// 报告指定的 System.Byte[] 在此实例中的第一个匹配项的索引。
/// </summary>
/// <param name="srcBytes">被执行查找的 System.Byte[]。</param>
/// <param name="searchBytes">要查找的 System.Byte[]。</param>
/// <returns>如果找到该字节数组,则为 searchBytes 的索引位置;如果未找到该字节数组,则为 -1。如果 searchBytes 为 null 或者长度为0,则返回值为 -1。</returns>
internal int IndexOf(byte[] srcBytes, byte[] searchBytes)
{
if (srcBytes == null) { return -1; }
if (searchBytes == null) { return -1; }
if (srcBytes.Length == 0) { return -1; }
if (searchBytes.Length == 0) { return -1; }
if (srcBytes.Length < searchBytes.Length) { return -1; }
for (int i = 0; i < srcBytes.Length - searchBytes.Length; i++)
{
if (srcBytes == searchBytes) //先比较首字节
{
if (searchBytes.Length == 1) { return i; }//搜索字节只一位
bool flag = true;
for (int j = 1; j < searchBytes.Length; j++)//比较首字节后面的其它字节
{
if (srcBytes != searchBytes)
{
flag = false;
break;//只要其中有一个字节不匹配则退出循环
}
}
if (flag) { return i; }//搜索到匹配的字节,返回字节位置索引
}
}
return -1;//无匹配返回-1
}
}
}
C#完整源码压缩包,含完整工程、项目、资源:
特征码补丁文件示例:BarTender 2019 R10、BarTender 2021 R1、BarTender 2021 R8、BarTender 2022 R1、RibbonCreator 2021 X64 V1.1.01
谢谢分享 谢谢分享 谢谢分享 感谢楼主 感谢楼主 感谢楼主 谢谢分享 Thanks~ 向楼主致敬! 楼主好强啊!学习了!