Merge pull request #1 from huiyadanli/master

同步更新0.6
This commit is contained in:
2019-12-11 20:17:58 +08:00 committed by GitHub
commit ebae5ec00e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
87 changed files with 3817 additions and 427 deletions

BIN
Images/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

BIN
Images/screenshot.v0.4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

BIN
Images/screenshot.v0.5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

BIN
Images/wiki/qq/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
Images/wiki/qq/10.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

BIN
Images/wiki/qq/11.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

BIN
Images/wiki/qq/12.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

BIN
Images/wiki/qq/13.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

BIN
Images/wiki/qq/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
Images/wiki/qq/3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

BIN
Images/wiki/qq/4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

BIN
Images/wiki/qq/5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

BIN
Images/wiki/qq/6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

BIN
Images/wiki/qq/7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

BIN
Images/wiki/qq/8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

BIN
Images/wiki/qq/9.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

View File

@ -1,13 +1,13 @@
<p align="center">
<a><img width="380px" src="https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/master/Images/logo.jpg"/></a>
<a><img width="100px" src="https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/master/Images/logo.png"/></a>
</p>
<p align="center">
<a href="https://www.microsoft.com/download/details.aspx?id=30653">
<img src="https://img.shields.io/badge/platform-windows-lightgrey.svg?style=flat-square"/>
</a>
<a href="https://github.com/huiyadanli/RevokeMsgPatcher/releases">
<img src="https://img.shields.io/github/downloads/huiyadanli/RevokeMsgPatcher/total.svg?style=flat-squares"/>
<img src="https://img.shields.io/github/downloads/huiyadanli/RevokeMsgPatcher/total.svg?style=flat-square"/>
</a>
<a href="http://hits.dwyl.io/huiyadanli/RevokeMsgPatcher">
<img src="http://hits.dwyl.io/huiyadanli/RevokeMsgPatcher.svg"/>
@ -17,43 +17,49 @@
</a>
</p>
# :eyes:微信防撤回补丁
适用于 Windows 下PC版微信的防撤回补丁。
# 👀微信/QQ/TIM防撤回补丁
适用于 Windows 下 PC 版微信/QQ/TIM的防撤回补丁。
<img width="180px" src="https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/master/Images/revoke.jpg"/>
支持最新测试版本2.7.0.70
支持最新稳定版本2.6.8.68
支持历史版本2.6.6.28、2.6.7.32、2.6.7.40、2.6.7.57、2.6.8.37、2.6.8.51、2.6.8.52、2.6.8.65、2.7.0.65
下载地址:
[:zap:点我下载最新版本](https://github.com/huiyadanli/RevokeMsgPatcher/releases/download/0.4/RevokeMsgPatcher.v0.4.zip)
**[⚡️点我下载最新版本](https://github.com/huiyadanli/RevokeMsgPatcher/releases/download/0.6/RevokeMsgPatcher.v0.6.zip)** |
[☁备用下载-蓝奏云](https://www.lanzous.com/i75gffi) |
[☁备用下载-百度云](https://pan.baidu.com/s/1M8rNYrhS85pFjpAASZqKlw) 提取码coco
## :camera:截图
相关文档:
**[✔支持哪些版本](https://github.com/huiyadanli/RevokeMsgPatcher/wiki/%E7%89%88%E6%9C%AC%E6%94%AF%E6%8C%81)** |
[❓常见问题](https://github.com/huiyadanli/RevokeMsgPatcher/wiki#%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98) |
[📖查看完整文档](https://github.com/huiyadanli/RevokeMsgPatcher/wiki)
原理与方法:
[📗微信](https://github.com/huiyadanli/RevokeMsgPatcher/wiki/%E5%BE%AE%E4%BF%A1%E9%98%B2%E6%92%A4%E5%9B%9E%E4%B8%8E%E5%A4%9A%E5%BC%80%E6%95%99%E7%A8%8B) |
[📕QQ](https://github.com/huiyadanli/RevokeMsgPatcher/wiki/QQ%E6%88%96TIM%E9%98%B2%E6%92%A4%E5%9B%9E%E6%95%99%E7%A8%8B) |
[📘TIM](https://github.com/huiyadanli/RevokeMsgPatcher/wiki/QQ%E6%88%96TIM%E9%98%B2%E6%92%A4%E5%9B%9E%E6%95%99%E7%A8%8B)
## 📷截图
![Screenshot](https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/master/Images/screenshot.png)
## 🔨使用方法
**请以管理员身份运行本程序,由于修改了微信的 `WeChatWin.dll` 文件,杀毒软件可能会弹出警告,放行即可。**
1. 首先,你的系统需要满足以下条件:
启动时会自动从注册表中获取微信的安装路径,如果没找到,需要手动选择微信路径。
* Windows 7 或更高版本,**不支持XP**。
* [.NET Framework 4.5](https://www.microsoft.com/zh-cn/download/details.aspx?id=30653) 或更高版本。**低于此版本在打开程序时可能无反应,或者直接报错**。
环境要求:
2. 使用本程序前,先关闭微信/QQ/TIM。
* Windows 7 或更高版本。
* [.NET Framework 4.5](https://www.microsoft.com/zh-cn/download/details.aspx?id=30653) 或更高版本。
3. **以管理员身份运行本程序**,等待右下角获取最新的补丁信息。
4. 选择微信/QQ/TIM的安装路径。如果你用的安装版的微信/QQ/TIM正常情况下本程序会自动从注册表中获取安装路径绿色版需要手动选择路径。
5. 点击防撤回。界面可能会出现一段时间的无响应,请耐心等待。**由于修改了微信的 WeChatWin.dll 文件、QQ/TIM的 IM.dll 文件,杀毒软件可能会弹出警告,放行即可。**
如果你想得到本软件最新版本的推送,请点击 Watch -> Release only
![Screenshot](https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/master/Images/watch_release.png)
## ❤Thanks
## :heart:Thanks
[wechat_anti_revoke](https://github.com/36huo/wechat_anti_revoke)
## 📃License
## 📄License
GPLv3
![](https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/master/Images/give_a_star.png)

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,61 @@
namespace RevokeMsgPatcher.Assistant
{
partial class FormAssisant
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows
/// <summary>
/// 设计器支持所需的方法 - 不要修改
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.txtInfo = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// txtInfo
//
this.txtInfo.Location = new System.Drawing.Point(12, 12);
this.txtInfo.Multiline = true;
this.txtInfo.Name = "txtInfo";
this.txtInfo.Size = new System.Drawing.Size(484, 238);
this.txtInfo.TabIndex = 0;
//
// FormAssisant
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(508, 262);
this.Controls.Add(this.txtInfo);
this.Name = "FormAssisant";
this.Text = "冷血无情的助手界面";
this.Load += new System.EventHandler(this.FormMain_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox txtInfo;
}
}

View File

@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace RevokeMsgPatcher.Assistant
{
public partial class FormAssisant : Form
{
public FormAssisant()
{
InitializeComponent();
}
private void FormMain_Load(object sender, EventArgs e)
{
JsonData obj = new JsonData();
string json = obj.BagJson();
Console.WriteLine(json);
DirectoryInfo directory = new DirectoryInfo("../../Data/" + obj.Bag().LatestVersion);
if (!directory.Exists)
{
directory.Create();
}
string path = Path.Combine(directory.FullName, "patch.json");
File.WriteAllText(path, json);
txtInfo.AppendText("生成完毕!位置:" + path);
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,539 @@
using RevokeMsgPatcher.Model;
using System.Collections.Generic;
using System.Web.Script.Serialization;
namespace RevokeMsgPatcher
{
/// <summary>
/// 补丁信息
/// </summary>
public class JsonData
{
public Bag Bag()
{
return new Bag
{
Apps = AppConfig(),
LatestVersion = "0.6",
Notice = ""
};
}
public string BagJson()
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Serialize(Bag());
}
public Dictionary<string, App> AppConfig()
{
return new Dictionary<string, App>
{
{ "Wechat" , Wechat() },
{ "QQ" , QQ() },
{ "TIM" , TIM() },
{ "QQLite" , QQLite() }
};
}
public string AppConfigJson()
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Serialize(AppConfig());
}
public App Wechat()
{
return new App
{
Name = "Wechat",
FileTargetInfos = new Dictionary<string, TargetInfo>
{
{
"WeChatWin.dll",
new TargetInfo
{
Name = "WeChatWin.dll",
RelativePath = "WeChatWin.dll"
}
}
},
FileModifyInfos = new Dictionary<string, List<ModifyInfo>>
{
{
"WeChatWin.dll",
new List<ModifyInfo>
{
new ModifyInfo {
Name="WeChatWin.dll",
Version="2.7.1.88",
SHA1Before="034059bad50dd793140952391bfa7936133e69b4",
SHA1After="dd6d80c30ca9e0ea9f7d2f1add498fc9aa4bc7a0",
Changes = new List<Change>
{
new Change
{
Position =0x00262389,
Content =new byte[] { 0xEB }
},
new Change
{
Position =0x007957B0,
Content =new byte[] { 0xC3 }
}
}
},
new ModifyInfo {
Name="WeChatWin.dll",
Version="2.7.1.85",
SHA1Before="de0df4e138b72460450f66c029e33f4510f5e2df",
SHA1After="fbd35720aaff3cdcfd3ff18ea503dc06450e5c99",
Changes = new List<Change>
{
new Change
{
Position =0x00262389,
Content =new byte[] { 0xEB }
},
new Change
{
Position =0x00795680,
Content =new byte[] { 0xC3 }
}
}
},
new ModifyInfo {
Name="WeChatWin.dll",
Version="2.7.1.82",
SHA1Before="20e111a18872bf6c7148a897c11da26c1ec95520",
SHA1After="1e0741d325ca6b1cd2402b829a3d13a2524af617",
Changes = new List<Change>
{
new Change
{
Position =0x00262389,
Content =new byte[] { 0xEB }
},
new Change
{
Position =0x00795650,
Content =new byte[] { 0xC3 }
}
}
},
new ModifyInfo {
Name="WeChatWin.dll",
Version="2.7.1.74",
SHA1Before="b1eaf7edc074a88be5d0f89230436cc2084d24d2",
SHA1After="eb3d74ccd87a09059a005f4972861898fc3de463",
Changes = new List<Change>
{
new Change
{
Position =0x00262389,
Content =new byte[] { 0xEB }
},
new Change
{
Position =0x00795550,
Content =new byte[] { 0xC3 }
}
}
},
new ModifyInfo {
Name="WeChatWin.dll",
Version="2.7.1.65",
SHA1Before="8346b97d264725da924d240c6eb77df3e693385e",
SHA1After="42bab2c9c79ef4f2088c00ea6d817973e14a5e6e",
Changes = new List<Change>
{
new Change
{
Position =2495545,
Content =new byte[] { 235}
}
}
},
new ModifyInfo {Name="WeChatWin.dll",Version="2.7.1.59",SHA1Before="df954d403edaca89cd5394927a325a0023e93281",SHA1After="6aa22460c91bb5c5e2f0ec1af99b8a5f6d4318c0",Changes = new List<Change> { new Change {Position=2496073,Content=new byte[] { 235} } } },new ModifyInfo {Name="WeChatWin.dll",Version="2.7.1.43",SHA1Before="39cd9e09e1a3eac09e6808749bff525c9e3216ce",SHA1After="7b829f1ff0217e346a80f9510fdd7634ddd49445",Changes = new List<Change> { new Change {Position=2494169,Content=new byte[] { 235} } } },new ModifyInfo {Name="WeChatWin.dll",Version="2.7.0.70",SHA1Before="3b0601864aff3c1d792f812ad1ca05f02aa761e3",SHA1After="1e8734d32b0a8c12758e30f99c77f729991fb071",Changes = new List<Change> { new Change {Position=2475657,Content=new byte[] { 235} } } },new ModifyInfo {Name="WeChatWin.dll",Version="2.7.0.65",SHA1Before="063c2e05a0df1bdb8987c2d978d93499bd2052ba",SHA1After="5ed4c09a4f18643b967f063a824d7e65d0567f8a",Changes = new List<Change> { new Change {Position=2475449,Content=new byte[] { 117} } } },new ModifyInfo {Name="WeChatWin.dll",Version="2.6.8.68",SHA1Before="2e9417f4276b12fe32ca7b4fee49272a4a2af334",SHA1After="699602ee3cbb9ae5714f6e6ebc658c875a6c66e6",Changes = new List<Change> { new Change {Position=2454006,Content=new byte[] { 116} } } },new ModifyInfo {Name="WeChatWin.dll",Version="2.6.8.65",SHA1Before="e01f6855a96c12c30808960903ed199a33e4952c",SHA1After="d9120569cfd0433aebea107d7b90805cbbac7518",Changes = new List<Change> { new Change {Position=2454265,Content=new byte[] { 117} } } },new ModifyInfo {Name="WeChatWin.dll",Version="2.6.8.52",SHA1Before="88131302f664df6a657c9ca49d152da536fe5729",SHA1After="8d1454b73831644181e962c1fa0ea4e2da4124a3",Changes = new List<Change> { new Change {Position=2453049,Content=new byte[] { 117} } } },new ModifyInfo {Name="WeChatWin.dll",Version="2.6.8.51",SHA1Before="d0a5517b1292a751501b00b4b1f0702db2d9fc30",SHA1After="53e7b1525d49bf2c3250a8131ff0ba2510779b78",Changes = new List<Change> { new Change {Position=2452614,Content=new byte[] { 116} } } },new ModifyInfo {Name="WeChatWin.dll",Version="2.6.8.37",SHA1Before="7e01f8b04a158a4a50bc5a6e67c2fb8b02233170",SHA1After="a1895004415fe9bcd7e690bd6e482b833b515599",Changes = new List<Change> { new Change {Position=2452614,Content=new byte[] { 116} } } },new ModifyInfo {Name="WeChatWin.dll",Version="2.6.7.57",SHA1Before="80a91aaf941bcb1c24a7d672838ac73e9ebb2e40",SHA1After="a0d3f9a45a835f97aef7fe0872387d8cfb5c25a4",Changes = new List<Change> { new Change {Position=2433413,Content=new byte[] { 116} } } },new ModifyInfo {Name="WeChatWin.dll",Version="2.6.7.40",SHA1Before="04bd0cb28df6630b518f42a3f9c2caa4a9359fbc",SHA1After="13c91cf1d4609959771fd137b9a86a5ca365e1b6",Changes = new List<Change> { new Change {Position=2432934,Content=new byte[] { 116} } } },new ModifyInfo {Name="WeChatWin.dll",Version="2.6.7.32",SHA1Before="a02519c1007ee6723947c262c720d63c619f633e",SHA1After="f3007471ca8734c29783c25f0bb49949a783a44",Changes = new List<Change> { new Change {Position=2432806,Content=new byte[] { 116} } } },new ModifyInfo {Name="WeChatWin.dll",Version="2.6.6.28",SHA1Before="0b19cb17a62c3ea0efce0fb675a1d3b17845cba3",SHA1After="260948656725446b818ea668273ceff02ddfb44d",Changes = new List<Change> { new Change {Position=2401678,Content=new byte[] { 116} } } }
}
}
}
};
}
public App QQ()
{
return new App
{
Name = "QQ",
FileTargetInfos = new Dictionary<string, TargetInfo>
{
{
"IM.dll",
new TargetInfo
{
Name = "IM.dll",
RelativePath = @"Bin\IM.dll"
}
}
},
FileModifyInfos = new Dictionary<string, List<ModifyInfo>>
{
{
"IM.dll",
new List<ModifyInfo>
{
new ModifyInfo
{
Name = "IM.dll",
Version = "9.2.2.26569",
SHA1Before = "434254e76c520789558e075af677821258536311",
SHA1After = "237c9e489a97858a175f0f7c72ade4ebcbac7a69",
Changes = new List<Change>
{
new Change
{
Position = 0x0005A9CA,
Content = new byte[] { 0xEB, 0x09, 0x90, 0x90, 0x90 }
},
new Change
{
Position = 0x0005ABE7,
Content = new byte[] { 0xEB, 0x09, 0x90, 0x90, 0x90 }
},
new Change
{
Position = 0x0005AD95,
Content = new byte[] { 0xEB, 0x08, 0x90, 0x90, 0x90, 0x90 }
}
}
},
new ModifyInfo
{
Name = "IM.dll",
Version = "9.2.1.26546",
SHA1Before = "8d8ea2c2cbf43f5acf8d684b153e90035352d5f5",
SHA1After = "7d194dd5be03982b533d7375c93d9a72587fe28d",
Changes = new List<Change>
{
new Change
{
Position = 0x0005A389,
Content = new byte[] { 0xEB, 0x09, 0x90, 0x90, 0x90 }
},
new Change
{
Position = 0x0005A5A6,
Content = new byte[] { 0xEB, 0x09, 0x90, 0x90, 0x90 }
},
new Change
{
Position = 0x0005A754,
Content = new byte[] { 0xEB, 0x08, 0x90, 0x90, 0x90, 0x90 }
}
}
},
new ModifyInfo
{
Name = "IM.dll",
Version = "9.2.0.26453",
SHA1Before = "c1935ca6347b0c2a7e6108a7f8ee0643d39deb66",
SHA1After = "42811188a7e7b346a6a3c1066936b98c747acaf6",
Changes = new List<Change>
{
new Change
{
Position = 0x00056602,
Content = new byte[] { 0xEB, 0x09, 0x90, 0x90, 0x90 }
},
new Change
{
Position = 0x0005681F,
Content = new byte[] { 0xEB, 0x09, 0x90, 0x90, 0x90 }
},
new Change
{
Position = 0x000569CF,
Content = new byte[] { 0xEB, 0x08, 0x90, 0x90, 0x90, 0x90 }
}
}
},
new ModifyInfo
{
Name = "IM.dll",
Version = "9.2.0.26389",
SHA1Before = "6f8855fb80acfa456f8f69989fe949308fe4d154",
SHA1After = "f6b8e05a178b9b10ba17c597fa0a44b7a2a966a8",
Changes = new List<Change>
{
new Change
{
Position = 0x000571C8,
Content = new byte[] { 0xEB, 0x09, 0x90, 0x90, 0x90 }
},
new Change
{
Position = 0x000573E5,
Content = new byte[] { 0xEB, 0x09, 0x90, 0x90, 0x90 }
},
new Change
{
Position = 0x00057595,
Content = new byte[] { 0xEB, 0x08, 0x90, 0x90, 0x90, 0x90 }
}
}
},
new ModifyInfo
{
Name = "IM.dll",
Version = "9.1.9.26361",
SHA1Before = "022d3433d13d07a354c38816f61cb0b7ac60d3fd",
SHA1After = "873a57c1fb51cdd099c8cb7108b5ab5cb4459557",
Changes = new List<Change>
{
new Change
{
Position = 0x000567DE,
Content = new byte[] { 0xEB, 0x09, 0x90, 0x90, 0x90 }
},
new Change
{
Position = 0x000569FB,
Content = new byte[] { 0xEB, 0x09, 0x90, 0x90, 0x90 }
},
new Change
{
Position = 0x00056BAB,
Content = new byte[] { 0xEB, 0x08, 0x90, 0x90, 0x90, 0x90 }
}
}
},
new ModifyInfo
{
Name = "IM.dll",
Version = "9.1.9.26346",
SHA1Before = "895eb70f707b8222e6460c91492b1281e525059b",
SHA1After = "0bb83990e2b5b5f23b7b43249941ff638201af54",
Changes = new List<Change>
{
new Change
{
Position = 0x000567DE,
Content = new byte[] { 0xEB, 0x09, 0x90, 0x90, 0x90 }
},
new Change
{
Position = 0x000569FB,
Content = new byte[] { 0xEB, 0x09, 0x90, 0x90, 0x90 }
},
new Change
{
Position = 0x00056BAB,
Content = new byte[] { 0xEB, 0x08, 0x90, 0x90, 0x90, 0x90 }
}
}
},
new ModifyInfo
{
Name = "IM.dll",
Version = "9.1.8.26211",
SHA1Before = "a950d3cf5e8925f7775624271105ef78d9c5cb57",
SHA1After = "dffc1cb87b91e6467e13c935611f2f7fd76b9a8d",
Changes = new List<Change>
{
new Change
{
Position = 0x000524EF,
Content = new byte[] { 0xEB, 0x09, 0x90, 0x90, 0x90 }
},
new Change
{
Position = 0x0005270C,
Content = new byte[] { 0xEB, 0x09, 0x90, 0x90, 0x90 }
},
new Change
{
Position = 0x000528BC,
Content = new byte[] { 0xEB, 0x08, 0x90, 0x90, 0x90, 0x90 }
}
}
},
new ModifyInfo
{
Name = "IM.dll",
Version = "9.1.7.25980",
SHA1Before = "c6632339fbe675312a70ae4620e70699c258cd36",
SHA1After = "e9ddc5cc681950796fc8fe4c55f580428c890b51",
Changes = new List<Change>
{
new Change
{
Position = 0x0005009F,
Content = new byte[] { 0xEB, 0x09, 0x90, 0x90, 0x90 }
},
new Change
{
Position = 0x000502BC,
Content = new byte[] { 0xEB, 0x09, 0x90, 0x90, 0x90 }
},
new Change
{
Position = 0x0005046C,
Content = new byte[] { 0xEB, 0x08, 0x90, 0x90, 0x90, 0x90 }
}
}
},
new ModifyInfo
{
Name = "IM.dll",
Version = "9.0.4.23786",
SHA1Before = "69a714f4eadb09f1453f6f022d4adbcd801cfab8",
SHA1After = "b48e77a924076b3ebdffc4af514c868c551d2bca",
Changes = new List<Change>
{
new Change
{
Position = 0x0004DB71,
Content = new byte[] { 0xEB, 0x07, 0x90, 0x90, 0x90 }
},
new Change
{
Position = 0x0004DD8E,
Content = new byte[] { 0xEB, 0x07, 0x90, 0x90, 0x90 }
},
new Change
{
Position = 0x0004DF93,
Content = new byte[] { 0xEB, 0x07, 0x90, 0x90, 0x90 }
}
}
}
}
}
}
};
}
public App TIM()
{
return new App
{
Name = "TIM",
FileTargetInfos = new Dictionary<string, TargetInfo>
{
{
"IM.dll",
new TargetInfo
{
Name = "IM.dll",
RelativePath = @"Bin\IM.dll"
}
}
},
FileModifyInfos = new Dictionary<string, List<ModifyInfo>>
{
{
"IM.dll",
new List<ModifyInfo>
{
new ModifyInfo
{
Name = "IM.dll",
Version = "2.3.2.21173",
SHA1Before = "ecf3e69f3fb100ffe2fee095ffded591b9781024",
SHA1After = "0514d1304e7ac46b4d33386ec3313888f5ae7171",
Changes = new List<Change>
{
new Change
{
Position = 0x0004D78A,
Content = new byte[] { 0xEB, 0x09, 0x90, 0x90, 0x90 }
},
new Change
{
Position = 0x0004D9A7,
Content = new byte[] { 0xEB, 0x09, 0x90, 0x90, 0x90 }
},
new Change
{
Position = 0x0004DB57,
Content = new byte[] { 0xEB, 0x08, 0x90, 0x90, 0x90, 0x90 }
}
}
}
}
}
}
};
}
public App QQLite()
{
return new App
{
Name = "QQLite",
FileTargetInfos = new Dictionary<string, TargetInfo>
{
{
"IM.dll",
new TargetInfo
{
Name = "IM.dll",
RelativePath = @"Bin\IM.dll"
}
}
},
FileModifyInfos = new Dictionary<string, List<ModifyInfo>>
{
{
"IM.dll",
new List<ModifyInfo>
{
new ModifyInfo
{
Name = "IM.dll",
Version = "7.9.14314.0",
SHA1Before = "2e97d7671963fa148a1beeda6ce4964314310593",
SHA1After = "723c008fb53435ead20fa6f2e951c9a4a8ff46da",
Changes = new List<Change>
{
new Change
{
Position = 0x00024505,
Content = new byte[] { 0xEB, 0x02, 0x90, 0x90 }
},
new Change
{
Position = 0x000248B9,
Content = new byte[] { 0xEB, 0x02, 0x90, 0x90 }
}
}
},
new ModifyInfo
{
Name = "IM.dll",
Version = "7.9.14308.0",
SHA1Before = "b8a7a873178706b97be11c25f13bcf09e9e578a2",
SHA1After = "c5bf533c7af6996b42d1fb2a0fb3f26dfd52f8bf",
Changes = new List<Change>
{
new Change
{
Position = 0x00024505,
Content = new byte[] { 0xEB, 0x02, 0x90, 0x90 }
},
new Change
{
Position = 0x000248B9,
Content = new byte[] { 0xEB, 0x02, 0x90, 0x90 }
}
}
}
}
}
}
};
}
}
}

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace RevokeMsgPatcher.Assistant
{
static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new FormAssisant());
}
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("RevokeMsgPatcher.Assistant")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("RevokeMsgPatcher.Assistant")]
[assembly: AssemblyCopyright("Copyright © 2019")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("6992004f-17e6-45bf-8d72-180a31e9c23c")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
// 方法是按如下所示使用“*”: :
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,71 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本: 4.0.30319.42000
//
// 对此文件的更改可能导致不正确的行为,如果
// 重新生成代码,则所做更改将丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace RevokeMsgPatcher.Assistant.Properties
{
/// <summary>
/// 强类型资源类,用于查找本地化字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或删除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// 返回此类使用的缓存 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RevokeMsgPatcher.Assistant.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 覆盖当前线程的 CurrentUICulture 属性
/// 使用此强类型的资源类的资源查找。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}

View File

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace RevokeMsgPatcher.Assistant.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}

View File

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{6992004F-17E6-45BF-8D72-180A31E9C23C}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>RevokeMsgPatcher.Assistant</RootNamespace>
<AssemblyName>RevokeMsgPatcher.Assistant</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="FormAssisant.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="FormAssisant.Designer.cs">
<DependentUpon>FormAssisant.cs</DependentUpon>
</Compile>
<Compile Include="JsonData.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="FormAssisant.resx">
<DependentUpon>FormAssisant.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<None Include="Data\0.6\patch.json" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\RevokeMsgPatcher\RevokeMsgPatcher.csproj">
<Project>{977bf781-ced8-4389-9404-0fa08fdf21df}</Project>
<Name>RevokeMsgPatcher</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>

View File

@ -0,0 +1,186 @@
namespace RevokeMsgPatcher.MultiInstance
{
partial class FormMultiInstance
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows
/// <summary>
/// 设计器支持所需的方法 - 不要修改
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.txtPath = new System.Windows.Forms.TextBox();
this.lblPathTag = new System.Windows.Forms.Label();
this.btnChoosePath = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.startNum = new System.Windows.Forms.NumericUpDown();
this.btnStart = new System.Windows.Forms.Button();
this.linkLabel1 = new System.Windows.Forms.LinkLabel();
this.label3 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
((System.ComponentModel.ISupportInitialize)(this.startNum)).BeginInit();
this.SuspendLayout();
//
// txtPath
//
this.txtPath.Location = new System.Drawing.Point(86, 60);
this.txtPath.Name = "txtPath";
this.txtPath.Size = new System.Drawing.Size(332, 21);
this.txtPath.TabIndex = 7;
//
// lblPathTag
//
this.lblPathTag.AutoSize = true;
this.lblPathTag.Location = new System.Drawing.Point(15, 63);
this.lblPathTag.Name = "lblPathTag";
this.lblPathTag.Size = new System.Drawing.Size(65, 12);
this.lblPathTag.TabIndex = 6;
this.lblPathTag.Text = "微信路径:";
//
// btnChoosePath
//
this.btnChoosePath.Location = new System.Drawing.Point(424, 59);
this.btnChoosePath.Name = "btnChoosePath";
this.btnChoosePath.Size = new System.Drawing.Size(36, 23);
this.btnChoosePath.TabIndex = 8;
this.btnChoosePath.Text = "...";
this.btnChoosePath.UseVisualStyleBackColor = true;
this.btnChoosePath.Click += new System.EventHandler(this.btnChoosePath_Click);
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(84, 151);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(293, 24);
this.label1.TabIndex = 9;
this.label1.Text = "只要我打开微信的速度足够快,我就多开无限个微信。\r\n我为什么能手动双开微信别问问就是手速快。";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(15, 95);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(65, 12);
this.label2.TabIndex = 11;
this.label2.Text = "多开个数:";
//
// startNum
//
this.startNum.Location = new System.Drawing.Point(86, 91);
this.startNum.Maximum = new decimal(new int[] {
1000,
0,
0,
0});
this.startNum.Minimum = new decimal(new int[] {
2,
0,
0,
0});
this.startNum.Name = "startNum";
this.startNum.Size = new System.Drawing.Size(55, 21);
this.startNum.TabIndex = 12;
this.startNum.Value = new decimal(new int[] {
2,
0,
0,
0});
//
// btnStart
//
this.btnStart.Location = new System.Drawing.Point(369, 91);
this.btnStart.Name = "btnStart";
this.btnStart.Size = new System.Drawing.Size(91, 23);
this.btnStart.TabIndex = 13;
this.btnStart.Text = "点击启动!";
this.btnStart.UseVisualStyleBackColor = true;
this.btnStart.Click += new System.EventHandler(this.btnStart_Click);
//
// linkLabel1
//
this.linkLabel1.AutoSize = true;
this.linkLabel1.Location = new System.Drawing.Point(284, 95);
this.linkLabel1.Name = "linkLabel1";
this.linkLabel1.Size = new System.Drawing.Size(41, 12);
this.linkLabel1.TabIndex = 15;
this.linkLabel1.TabStop = true;
this.linkLabel1.Text = "GitHub";
this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel1_LinkClicked);
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(177, 95);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(101, 12);
this.label3.TabIndex = 14;
this.label3.Text = "软件主页(开源)";
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(12, 9);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(323, 36);
this.label4.TabIndex = 16;
this.label4.Text = "注意:\r\n1. 使用本程序多开前不能存在正在运行的微信进程。\r\n2. 多开的成功率取决于你的机器性能,不保证每次都能成功";
//
// FormMultiInstance
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(472, 133);
this.Controls.Add(this.label4);
this.Controls.Add(this.linkLabel1);
this.Controls.Add(this.label3);
this.Controls.Add(this.btnStart);
this.Controls.Add(this.startNum);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Controls.Add(this.txtPath);
this.Controls.Add(this.lblPathTag);
this.Controls.Add(this.btnChoosePath);
this.Name = "FormMultiInstance";
this.Text = "微信多开小工具";
((System.ComponentModel.ISupportInitialize)(this.startNum)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox txtPath;
private System.Windows.Forms.Label lblPathTag;
private System.Windows.Forms.Button btnChoosePath;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.NumericUpDown startNum;
private System.Windows.Forms.Button btnStart;
private System.Windows.Forms.LinkLabel linkLabel1;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label4;
}
}

View File

@ -0,0 +1,111 @@
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace RevokeMsgPatcher.MultiInstance
{
public partial class FormMultiInstance : Form
{
public FormMultiInstance()
{
InitializeComponent();
string installFolder = FindInstallPathFromRegistry("Wechat");
if (!string.IsNullOrEmpty(installFolder))
{
string wechatPath = Path.Combine(installFolder, "WeChat.exe");
if (File.Exists(wechatPath))
{
txtPath.Text = wechatPath;
}
}
}
private void btnChoosePath_Click(object sender, EventArgs e)
{
OpenFileDialog dialog = new OpenFileDialog
{
Multiselect = false,
Title = "请选择微信启动主程序",
Filter = "微信主程序|WeChat.exe"
};
if (dialog.ShowDialog() == DialogResult.OK)
{
txtPath.Text = dialog.FileName;
}
}
private void btnStart_Click(object sender, EventArgs e)
{
if (File.Exists(txtPath.Text))
{
// 检测微信进程是否存在
Process[] ps = Process.GetProcessesByName("WeChat");
if (ps.Length > 0)
{
DialogResult result = MessageBox.Show("当前存在运行中的微信进程,请先关闭当前微信才能使用该功能。点击【确定】强制关闭当前所有微信进程并进行多开,点击【取消】不做任何处理。", "当前存在运行中的微信进程", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
if (result == DialogResult.OK)
{
foreach (Process p in ps)
p.Kill();
}
else
{
return;
}
}
// 启动多个实例
for (int i = 0; i < startNum.Value; i++)
{
Process.Start(txtPath.Text);
}
}
}
private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
Process.Start("https://github.com/huiyadanli/RevokeMsgPatcher");
}
/// <summary>
/// 从注册表中寻找安装路径
/// </summary>
/// <param name="uninstallKeyName">
/// 安装信息的注册表键名
/// 微信WeChat
/// QQ{052CFB79-9D62-42E3-8A15-DE66C2C97C3E}
/// TIMTIM
/// </param>
/// <returns>安装路径</returns>
public static string FindInstallPathFromRegistry(string uninstallKeyName)
{
try
{
RegistryKey key = Registry.LocalMachine.OpenSubKey($@"Software\Microsoft\Windows\CurrentVersion\Uninstall\{uninstallKeyName}");
if (key == null)
{
return null;
}
object installLocation = key.GetValue("InstallLocation");
key.Close();
if (installLocation != null && !string.IsNullOrEmpty(installLocation.ToString()))
{
return installLocation.ToString();
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return null;
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace RevokeMsgPatcher.MultiInstance
{
static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new FormMultiInstance());
}
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("RevokeMsgPatcher.MultiInstance")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("RevokeMsgPatcher.MultiInstance")]
[assembly: AssemblyCopyright("Copyright © 2019")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("73043ca8-af54-4591-9174-40fb6e0a3d36")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
// 方法是按如下所示使用“*”: :
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,71 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本: 4.0.30319.42000
//
// 对此文件的更改可能导致不正确的行为,如果
// 重新生成代码,则所做更改将丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace RevokeMsgPatcher.MultiInstance.Properties
{
/// <summary>
/// 强类型资源类,用于查找本地化字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或删除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// 返回此类使用的缓存 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RevokeMsgPatcher.MultiInstance.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 覆盖当前线程的 CurrentUICulture 属性
/// 使用此强类型的资源类的资源查找。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}

View File

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace RevokeMsgPatcher.MultiInstance.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}

View File

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{73043CA8-AF54-4591-9174-40FB6E0A3D36}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>RevokeMsgPatcher.MultiInstance</RootNamespace>
<AssemblyName>RevokeMsgPatcher.MultiInstance</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="FormMultiInstance.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="FormMultiInstance.Designer.cs">
<DependentUpon>FormMultiInstance.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="FormMultiInstance.resx">
<DependentUpon>FormMultiInstance.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -5,6 +5,10 @@ VisualStudioVersion = 15.0.28010.2016
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RevokeMsgPatcher", "RevokeMsgPatcher\RevokeMsgPatcher.csproj", "{977BF781-CED8-4389-9404-0FA08FDF21DF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RevokeMsgPatcher.Assistant", "RevokeMsgPatcher.Assistant\RevokeMsgPatcher.Assistant.csproj", "{6992004F-17E6-45BF-8D72-180A31E9C23C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RevokeMsgPatcher.MultiInstance", "RevokeMsgPatcher.MultiInstance\RevokeMsgPatcher.MultiInstance.csproj", "{73043CA8-AF54-4591-9174-40FB6E0A3D36}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -15,6 +19,14 @@ Global
{977BF781-CED8-4389-9404-0FA08FDF21DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{977BF781-CED8-4389-9404-0FA08FDF21DF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{977BF781-CED8-4389-9404-0FA08FDF21DF}.Release|Any CPU.Build.0 = Release|Any CPU
{6992004F-17E6-45BF-8D72-180A31E9C23C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6992004F-17E6-45BF-8D72-180A31E9C23C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6992004F-17E6-45BF-8D72-180A31E9C23C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6992004F-17E6-45BF-8D72-180A31E9C23C}.Release|Any CPU.Build.0 = Release|Any CPU
{73043CA8-AF54-4591-9174-40FB6E0A3D36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{73043CA8-AF54-4591-9174-40FB6E0A3D36}.Debug|Any CPU.Build.0 = Debug|Any CPU
{73043CA8-AF54-4591-9174-40FB6E0A3D36}.Release|Any CPU.ActiveCfg = Release|Any CPU
{73043CA8-AF54-4591-9174-40FB6E0A3D36}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -0,0 +1,14 @@
using System;
namespace RevokeMsgPatcher
{
class BusinessException : ApplicationException
{
public string ErrorCode { get; protected set; }
public BusinessException(string errcode, string message) : base(message)
{
ErrorCode = errcode;
}
}
}

View File

@ -29,7 +29,7 @@
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormMain));
this.label2 = new System.Windows.Forms.Label();
this.lblPathTag = new System.Windows.Forms.Label();
this.btnPatch = new System.Windows.Forms.Button();
this.txtPath = new System.Windows.Forms.TextBox();
this.btnChoosePath = new System.Windows.Forms.Button();
@ -37,21 +37,29 @@
this.linkLabel1 = new System.Windows.Forms.LinkLabel();
this.btnRestore = new System.Windows.Forms.Button();
this.lblUpdatePachJson = new System.Windows.Forms.Label();
this.lblVersion = new System.Windows.Forms.Label();
this.lblVersionTag = new System.Windows.Forms.Label();
this.rbtWechat = new System.Windows.Forms.RadioButton();
this.rbtQQ = new System.Windows.Forms.RadioButton();
this.rbtTIM = new System.Windows.Forms.RadioButton();
this.label5 = new System.Windows.Forms.Label();
this.panelMask = new System.Windows.Forms.Panel();
this.rbtQQLite = new System.Windows.Forms.RadioButton();
this.SuspendLayout();
//
// label2
// lblPathTag
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(17, 15);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(65, 12);
this.label2.TabIndex = 1;
this.label2.Text = "微信路径:";
this.lblPathTag.AutoSize = true;
this.lblPathTag.Location = new System.Drawing.Point(12, 34);
this.lblPathTag.Name = "lblPathTag";
this.lblPathTag.Size = new System.Drawing.Size(65, 12);
this.lblPathTag.TabIndex = 1;
this.lblPathTag.Text = "应用路径:";
//
// btnPatch
//
this.btnPatch.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnPatch.Location = new System.Drawing.Point(409, 10);
this.btnPatch.Location = new System.Drawing.Point(372, 56);
this.btnPatch.Name = "btnPatch";
this.btnPatch.Size = new System.Drawing.Size(102, 23);
this.btnPatch.TabIndex = 3;
@ -63,15 +71,16 @@
//
this.txtPath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.txtPath.Location = new System.Drawing.Point(88, 12);
this.txtPath.Location = new System.Drawing.Point(82, 29);
this.txtPath.Name = "txtPath";
this.txtPath.Size = new System.Drawing.Size(275, 21);
this.txtPath.Size = new System.Drawing.Size(352, 21);
this.txtPath.TabIndex = 4;
this.txtPath.TextChanged += new System.EventHandler(this.txtPath_TextChanged);
//
// btnChoosePath
//
this.btnChoosePath.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnChoosePath.Location = new System.Drawing.Point(369, 10);
this.btnChoosePath.Location = new System.Drawing.Point(440, 27);
this.btnChoosePath.Name = "btnChoosePath";
this.btnChoosePath.Size = new System.Drawing.Size(34, 23);
this.btnChoosePath.TabIndex = 5;
@ -82,7 +91,7 @@
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(17, 44);
this.label1.Location = new System.Drawing.Point(12, 87);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(101, 12);
this.label1.TabIndex = 6;
@ -91,7 +100,7 @@
// linkLabel1
//
this.linkLabel1.AutoSize = true;
this.linkLabel1.Location = new System.Drawing.Point(112, 44);
this.linkLabel1.Location = new System.Drawing.Point(119, 87);
this.linkLabel1.Name = "linkLabel1";
this.linkLabel1.Size = new System.Drawing.Size(41, 12);
this.linkLabel1.TabIndex = 7;
@ -102,7 +111,7 @@
// btnRestore
//
this.btnRestore.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnRestore.Location = new System.Drawing.Point(409, 39);
this.btnRestore.Location = new System.Drawing.Point(264, 56);
this.btnRestore.Name = "btnRestore";
this.btnRestore.Size = new System.Drawing.Size(102, 23);
this.btnRestore.TabIndex = 8;
@ -112,32 +121,122 @@
//
// lblUpdatePachJson
//
this.lblUpdatePachJson.AutoSize = true;
this.lblUpdatePachJson.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.lblUpdatePachJson.Cursor = System.Windows.Forms.Cursors.Hand;
this.lblUpdatePachJson.Location = new System.Drawing.Point(198, 44);
this.lblUpdatePachJson.ForeColor = System.Drawing.SystemColors.Highlight;
this.lblUpdatePachJson.Location = new System.Drawing.Point(166, 89);
this.lblUpdatePachJson.Name = "lblUpdatePachJson";
this.lblUpdatePachJson.Size = new System.Drawing.Size(131, 12);
this.lblUpdatePachJson.Size = new System.Drawing.Size(308, 12);
this.lblUpdatePachJson.TabIndex = 9;
this.lblUpdatePachJson.Text = "获取最新补丁信息中...";
this.lblUpdatePachJson.Text = "[ 获取最新补丁信息中... ]";
this.lblUpdatePachJson.TextAlign = System.Drawing.ContentAlignment.TopRight;
this.lblUpdatePachJson.Click += new System.EventHandler(this.lblUpdatePachJson_Click);
//
// lblVersion
//
this.lblVersion.AutoSize = true;
this.lblVersion.Location = new System.Drawing.Point(83, 61);
this.lblVersion.Name = "lblVersion";
this.lblVersion.Size = new System.Drawing.Size(0, 12);
this.lblVersion.TabIndex = 10;
//
// lblVersionTag
//
this.lblVersionTag.AutoSize = true;
this.lblVersionTag.Location = new System.Drawing.Point(12, 61);
this.lblVersionTag.Name = "lblVersionTag";
this.lblVersionTag.Size = new System.Drawing.Size(65, 12);
this.lblVersionTag.TabIndex = 9;
this.lblVersionTag.Text = "当前版本:";
//
// rbtWechat
//
this.rbtWechat.AutoSize = true;
this.rbtWechat.Checked = true;
this.rbtWechat.Location = new System.Drawing.Point(82, 7);
this.rbtWechat.Name = "rbtWechat";
this.rbtWechat.Size = new System.Drawing.Size(47, 16);
this.rbtWechat.TabIndex = 12;
this.rbtWechat.TabStop = true;
this.rbtWechat.Text = "微信";
this.rbtWechat.UseVisualStyleBackColor = true;
this.rbtWechat.CheckedChanged += new System.EventHandler(this.radioButtons_CheckedChanged);
//
// rbtQQ
//
this.rbtQQ.AutoSize = true;
this.rbtQQ.Location = new System.Drawing.Point(140, 7);
this.rbtQQ.Name = "rbtQQ";
this.rbtQQ.Size = new System.Drawing.Size(35, 16);
this.rbtQQ.TabIndex = 13;
this.rbtQQ.Text = "QQ";
this.rbtQQ.UseVisualStyleBackColor = true;
this.rbtQQ.CheckedChanged += new System.EventHandler(this.radioButtons_CheckedChanged);
//
// rbtTIM
//
this.rbtTIM.AutoSize = true;
this.rbtTIM.Location = new System.Drawing.Point(186, 7);
this.rbtTIM.Name = "rbtTIM";
this.rbtTIM.Size = new System.Drawing.Size(41, 16);
this.rbtTIM.TabIndex = 14;
this.rbtTIM.Text = "TIM";
this.rbtTIM.UseVisualStyleBackColor = true;
this.rbtTIM.CheckedChanged += new System.EventHandler(this.radioButtons_CheckedChanged);
//
// label5
//
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(12, 9);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(65, 12);
this.label5.TabIndex = 16;
this.label5.Text = "选择应用:";
//
// panelMask
//
this.panelMask.Location = new System.Drawing.Point(140, 127);
this.panelMask.Name = "panelMask";
this.panelMask.Size = new System.Drawing.Size(157, 58);
this.panelMask.TabIndex = 17;
this.panelMask.Visible = false;
//
// rbtQQLite
//
this.rbtQQLite.AutoSize = true;
this.rbtQQLite.Location = new System.Drawing.Point(235, 7);
this.rbtQQLite.Name = "rbtQQLite";
this.rbtQQLite.Size = new System.Drawing.Size(71, 16);
this.rbtQQLite.TabIndex = 18;
this.rbtQQLite.Text = "QQ轻聊版";
this.rbtQQLite.UseVisualStyleBackColor = true;
//
// FormMain
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(523, 69);
this.ClientSize = new System.Drawing.Size(490, 110);
this.Controls.Add(this.rbtQQLite);
this.Controls.Add(this.lblUpdatePachJson);
this.Controls.Add(this.panelMask);
this.Controls.Add(this.lblVersion);
this.Controls.Add(this.lblVersionTag);
this.Controls.Add(this.label5);
this.Controls.Add(this.txtPath);
this.Controls.Add(this.rbtTIM);
this.Controls.Add(this.lblPathTag);
this.Controls.Add(this.rbtQQ);
this.Controls.Add(this.btnRestore);
this.Controls.Add(this.rbtWechat);
this.Controls.Add(this.btnPatch);
this.Controls.Add(this.btnChoosePath);
this.Controls.Add(this.linkLabel1);
this.Controls.Add(this.label1);
this.Controls.Add(this.btnChoosePath);
this.Controls.Add(this.txtPath);
this.Controls.Add(this.btnPatch);
this.Controls.Add(this.label2);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MinimumSize = new System.Drawing.Size(506, 149);
this.Name = "FormMain";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "微信防撤回补丁";
this.Text = "微信/QQ/TIM防撤回补丁";
this.Load += new System.EventHandler(this.FormMain_Load);
this.ResumeLayout(false);
this.PerformLayout();
@ -145,7 +244,7 @@
}
#endregion
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label lblPathTag;
private System.Windows.Forms.Button btnPatch;
private System.Windows.Forms.TextBox txtPath;
private System.Windows.Forms.Button btnChoosePath;
@ -153,6 +252,14 @@
private System.Windows.Forms.LinkLabel linkLabel1;
private System.Windows.Forms.Button btnRestore;
private System.Windows.Forms.Label lblUpdatePachJson;
private System.Windows.Forms.Label lblVersion;
private System.Windows.Forms.Label lblVersionTag;
private System.Windows.Forms.RadioButton rbtWechat;
private System.Windows.Forms.RadioButton rbtQQ;
private System.Windows.Forms.RadioButton rbtTIM;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.Panel panelMask;
private System.Windows.Forms.RadioButton rbtQQLite;
}
}

View File

@ -1,126 +1,205 @@
using System;
using RevokeMsgPatcher.Model;
using RevokeMsgPatcher.Modifier;
using RevokeMsgPatcher.Utils;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Threading.Tasks;
using System.Web.Script.Serialization;
using System.Windows.Forms;
namespace RevokeMsgPatcher
{
public partial class FormMain : Form
{
Patcher patcher = null;
// 当前使用的修改者
private AppModifier modifier = null;
private WechatModifier wechatModifier = null;
private QQModifier qqModifier = null;
private TIMModifier timModifier = null;
private QQLiteModifier qqLiteModifier = null;
private string thisVersion;
private bool needUpdate = false;
private GAHelper ga = new GAHelper(); // Google Analytics 记录
public void InitModifier()
{
// 从配置文件中读取配置
JavaScriptSerializer serializer = new JavaScriptSerializer();
Bag bag = serializer.Deserialize<Bag>(Properties.Resources.PatchJson);
// 初始化每个应用对应的修改者
wechatModifier = new WechatModifier(bag.Apps["Wechat"]);
qqModifier = new QQModifier(bag.Apps["QQ"]);
timModifier = new TIMModifier(bag.Apps["TIM"]);
qqLiteModifier = new QQLiteModifier(bag.Apps["QQLite"]);
rbtWechat.Tag = wechatModifier;
rbtQQ.Tag = qqModifier;
rbtTIM.Tag = timModifier;
rbtQQLite.Tag = qqLiteModifier;
// 默认微信
rbtWechat.Enabled = true;
modifier = wechatModifier;
}
public FormMain()
{
InitializeComponent();
patcher = new Patcher();
txtPath.Text = Util.AutoFindInstallPath();
if (!string.IsNullOrEmpty(txtPath.Text))
{
patcher.IntallPath = txtPath.Text;
btnRestore.Enabled = File.Exists(patcher.BakPath);
}
// 标题加上版本号
string currentVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
if (currentVersion.Length > 3)
{
currentVersion = " v" + currentVersion.Substring(0, 3);
thisVersion = currentVersion.Substring(0, 3);
currentVersion = " v" + thisVersion;
}
this.Text += currentVersion;
InitModifier();
InitControls();
ga.RequestPageView($"/main/{thisVersion}", $"进入{thisVersion}版本主界面");
}
private void InitControls()
{
// 自动获取应用安装路径
txtPath.Text = modifier.FindInstallPath();
btnRestore.Enabled = false;
// 显示是否能够备份还原
if (!string.IsNullOrEmpty(txtPath.Text))
{
modifier.InitEditors(txtPath.Text);
lblVersion.Text = modifier.GetVersion();
btnRestore.Enabled = modifier.BackupExists();
}
}
private void btnPatch_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(txtPath.Text) || !Util.IsWechatInstallPath(txtPath.Text))
if (!modifier.IsAllFilesExist(txtPath.Text))
{
MessageBox.Show("请选择微信安装路径!");
MessageBox.Show("请选择正确的安装路径!");
return;
}
patcher.IntallPath = txtPath.Text;
// 记录点了什么应用的防撤回
string enName = GetCheckedRadioButtonNameEn(); // 应用英文名
string version = modifier.GetVersion(); // 应用版本
ga.RequestPageView($"{enName}/{version}/patch", "点击防撤回");
EnableAllButton(false);
// a.重新初始化编辑器
modifier.InitEditors(txtPath.Text);
// b.计算SHA1验证文件完整性寻找对应的补丁信息
try
{
btnPatch.Enabled = false;
string version = patcher.JudgeVersion();
if (!string.IsNullOrEmpty(version))
{
if (version == "done")
{
MessageBox.Show("已经安装过防撤回补丁了");
btnPatch.Enabled = true;
return;
}
if (patcher.Patch())
{
MessageBox.Show("成功安装防撤回补丁!原 WeChatWin.dll 文件已经备份到 " + patcher.BakPath + " ,如果有问题可以手动覆盖恢复");
}
else
{
MessageBox.Show("防撤回补丁安装失败!");
}
btnRestore.Enabled = File.Exists(patcher.BakPath);
}
else
{
MessageBox.Show("当前微信版本不被支持:" + Util.GetFileVersion(patcher.DllPath));
}
modifier.ValidateAndFindModifyInfo();
}
catch (BusinessException ex)
{
ga.RequestPageView($"{enName}/{version}/patch/sha1/ex/{ex.ErrorCode}", ex.Message);
MessageBox.Show(ex.Message);
return;
}
catch (IOException ex)
{
ga.RequestPageView($"{enName}/{version}/patch/sha1/ex/{ex.HResult.ToString("x4")}", ex.Message);
MessageBox.Show(ex.Message + " 请以管理员权限启动本程序,并确认当前应用(微信/QQ/TIM处于关闭状态。");
return;
}
catch (Exception ex)
{
ga.RequestPageView($"{enName}/{version}/patch/sha1/ex/{ex.HResult.ToString("x4")}", ex.Message);
MessageBox.Show(ex.Message);
return;
}
finally
{
EnableAllButton(true);
btnRestore.Enabled = modifier.BackupExists();
}
// c.打补丁
try
{
modifier.Patch();
ga.RequestPageView($"{enName}/{version}/patch/succ", "防撤回成功");
MessageBox.Show("补丁安装成功!");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
MessageBox.Show(ex.Message + " 请以管理员权限启动本程序,并确认微信处于关闭状态。");
ga.RequestPageView($"{enName}/{version}/patch/ex/{ex.HResult.ToString("x4")}", ex.Message);
MessageBox.Show(ex.Message + " 请以管理员权限启动本程序,并确认当前应用(微信/QQ/TIM处于关闭状态。");
}
btnPatch.Enabled = true;
finally
{
EnableAllButton(true);
btnRestore.Enabled = modifier.BackupExists();
}
}
private void txtPath_TextChanged(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(txtPath.Text))
if (modifier.IsAllFilesExist(txtPath.Text))
{
patcher.IntallPath = txtPath.Text;
btnRestore.Enabled = File.Exists(patcher.BakPath);
modifier.InitEditors(txtPath.Text);
btnRestore.Enabled = modifier.BackupExists();
}
else
{
btnPatch.Enabled = false;
btnRestore.Enabled = false;
}
}
private void btnChoosePath_Click(object sender, EventArgs e)
{
FolderBrowserDialog dialog = new FolderBrowserDialog();
dialog.Description = "请选择微信安装路径";
dialog.Description = "请选择安装路径";
if (dialog.ShowDialog() == DialogResult.OK)
{
if (string.IsNullOrEmpty(dialog.SelectedPath) || !Util.IsWechatInstallPath(dialog.SelectedPath))
if (string.IsNullOrEmpty(dialog.SelectedPath) || !modifier.IsAllFilesExist(dialog.SelectedPath))
{
MessageBox.Show("无法找到微信关键文件,请选择正确的微信安装路径!");
MessageBox.Show("无法找到此应用的关键文件,请选择正确的安装路径!");
}
else
{
txtPath.Text = dialog.SelectedPath;
btnRestore.Enabled = false;
// 显示是否能够备份还原
if (!string.IsNullOrEmpty(txtPath.Text))
{
modifier.InitEditors(txtPath.Text);
lblVersion.Text = modifier.GetVersion();
btnRestore.Enabled = modifier.BackupExists();
}
}
}
}
private void btnRestore_Click(object sender, EventArgs e)
{
btnRestore.Enabled = false;
EnableAllButton(false);
try
{
if (File.Exists(patcher.BakPath))
{
File.Copy(patcher.BakPath, patcher.DllPath, true);
MessageBox.Show("还原成功");
}
else
{
MessageBox.Show("备份文件不存在");
}
modifier.Restore();
MessageBox.Show("还原成功!");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
MessageBox.Show(ex.Message);
}
btnRestore.Enabled = File.Exists(patcher.BakPath);
EnableAllButton(true);
btnRestore.Enabled = modifier.BackupExists();
}
private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
@ -131,32 +210,127 @@ namespace RevokeMsgPatcher
private async void FormMain_Load(object sender, EventArgs e)
{
// 异步获取最新的补丁信息
Task<string> t = new Task<string>(() =>
string json = await HttpUtil.GetPatchJsonAsync();
if (string.IsNullOrEmpty(json))
{
return new WebClient().DownloadString("https://huiyadanli.coding.me/i/patch.json");
});
t.Start();
string json = await t;
if(string.IsNullOrEmpty(json))
{
lblUpdatePachJson.Text = "获取失败";
} else
{
patcher.SetNewPatchJson(json);
lblUpdatePachJson.Text = "获取成功";
lblUpdatePachJson.Text = "[ 获取最新补丁信息失败 ]";
}
else
{
try
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
Bag bag = serializer.Deserialize<Bag>(json);
wechatModifier.Config = bag.Apps["Wechat"];
qqModifier.Config = bag.Apps["QQ"];
timModifier.Config = bag.Apps["TIM"];
qqLiteModifier.Config = bag.Apps["QQLite"];
if (Convert.ToDecimal(bag.LatestVersion) > Convert.ToDecimal(thisVersion))
{
needUpdate = true;
lblUpdatePachJson.Text = $"[ 存在最新版本 {bag.LatestVersion} ]";
}
else
{
needUpdate = false;
lblUpdatePachJson.Text = "[ 获取成功,点击查看更多信息 ]";
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
lblUpdatePachJson.Text = "[ 更换新配置时异常 ]";
}
}
}
private void lblUpdatePachJson_Click(object sender, EventArgs e)
{
string versions = "";
patcher.TargetFiles.ForEach(t =>
string tips = "";
if (needUpdate)
{
versions += t.Version + Environment.NewLine;
});
MessageBox.Show("当前所支持的微信版本:" + Environment.NewLine + versions);
tips += "【当前存在最新版本,点击确定进入软件主页下载最新版本。】" + Environment.NewLine + Environment.NewLine;
}
tips += "支持以下版本" + Environment.NewLine;
tips += " ➯ 微信:" + wechatModifier.Config.GetSupportVersionStr() + Environment.NewLine;
tips += " ➯ QQ" + qqModifier.Config.GetSupportVersionStr() + Environment.NewLine;
tips += " ➯ QQ轻聊版" + qqLiteModifier.Config.GetSupportVersionStr() + Environment.NewLine;
tips += " ➯ TIM" + timModifier.Config.GetSupportVersionStr() + Environment.NewLine;
DialogResult dr = MessageBox.Show(tips, "当前支持防撤回的版本", MessageBoxButtons.OKCancel);
if (dr == DialogResult.OK && needUpdate)
{
System.Diagnostics.Process.Start("https://github.com/huiyadanli/RevokeMsgPatcher/releases");
}
}
private void radioButtons_CheckedChanged(object sender, EventArgs e)
{
EnableAllButton(false);
RadioButton radioButton = sender as RadioButton;
// 切换使用不同的防撤回对象
if (rbtWechat.Checked)
{
modifier = (WechatModifier)rbtWechat.Tag;
}
else if (rbtQQ.Checked)
{
modifier = (QQModifier)rbtQQ.Tag;
}
else if (rbtTIM.Checked)
{
modifier = (TIMModifier)rbtTIM.Tag;
}
else if (rbtQQLite.Checked)
{
modifier = (QQLiteModifier)rbtQQLite.Tag;
}
txtPath.Text = modifier.FindInstallPath();
ga.RequestPageView($"{GetCheckedRadioButtonNameEn()}/{lblVersion.Text}/switch", "切换标签页");
EnableAllButton(true);
lblVersion.Text = "";
btnRestore.Enabled = false;
// 显示是否能够备份还原
if (!string.IsNullOrEmpty(txtPath.Text))
{
modifier.InitEditors(txtPath.Text);
lblVersion.Text = modifier.GetVersion();
btnRestore.Enabled = modifier.BackupExists();
}
}
private string GetCheckedRadioButtonNameEn()
{
if (rbtWechat.Checked)
{
return "wechat";
}
else if (rbtQQ.Checked)
{
return "qq";
}
else if (rbtTIM.Checked)
{
return "tim";
}
else if (rbtQQLite.Checked)
{
return "qqlite";
}
return "none";
}
private void EnableAllButton(bool state)
{
foreach (Control c in this.Controls)
{
if (c is Button)
{
c.Enabled = state;
}
}
}
}
}

View File

@ -120,78 +120,289 @@
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAAAAAAAAAAAAAAAAAAAAA
AADn7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/W2t//zdHW/+bt8f/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5u3y/6Omqf/N1Nb/sbW4/83R1v/m7fH/5+3y/+ft
8v/m7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5Oru/7O3uf/O0tf/y9DU/7C0
t/+5vcD/s7i6/9TZ3f/n7PL/5+zy/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+zy/8jN
0f+1ubz/6Ozx/8LGyf/Bxsn/ioyN/56ho/+us7f/19zg/+bt8v/m7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5u3y/9/l6f+foqT/qq2w/6isrf/e5Of/rLCy/7vAw/+bnqD/rrK0/83S1v/m7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/ur7C/6eqrf/Axcj/5u3y/8PHy/+anZ//mJqc/87S1f/m7fL/tru+/6isr//n7fH/xcrN/6yw
s//d4uf/5+3x/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+zy/7a6vf+6v8L/5evx/66ytf/S2Nz/5+zy/7GzuP9vcHH/hoiI/5+jpP/L0NP/wMTI/+ft
8v/m7PH/5uzx/7a5vf+xtbj/5Orv/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7PL/pKmr/7m9wP+7wMT/tbm7/7e8v//n7PL/5+zy/9HU2f+fo6X/ztTX/62w
s/+Hi43/zdLX/+bt8f/m7fL/5+zy/+Hn7f+vsrb/tbm9/+fs8f/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+fs8v+5vcH/4efr/+Tp7v/n7PL/t7u//+fs8v/n7fL/5+3y/7i8
v/+ipaj/5u3x/9bc4P/Cx8v/dHd5/+Lo7f/n7fH/5+3y/+bt8v/d4+b/q6+y/8DFyf/m7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/9/l6f+8wcT/293x/+To8f+3u77/5+zy/+ft
8v/n7fH/5u3x/9DV2f+nqq3/0tbb/+bt8v/M0db/kZWY/7zAxP/h5+z/5+3y/+fs8v/m7PL/0Nbb/6mt
sP/W2+D/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3x/7a5vf+7se3/0M7w/7a7
vv/n7PH/5+3y/+ft8v/n7fL/5u3y/+ft8f+9wMT/qq6x/+Lo7P/g5+z/vcLG/2FkZv/S19z/4efr/+ft
8v/m7fL/6Ozy/7q+wf+zt7r/5uzx/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/m7fH/trm9/+fs
8f/n7fL/uL2//+ft8f/n7fL/6Ozy/+Xr8v+2u7//s7e6/+br8f/k6e7/q6+y/7i9wP/m7fH/4Obq/5OW
mf+nq6//3ePn/+bs8f/n7fL/5+3y/9zi5/+prrH/p6uu/+Hl6f/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/Gys//2t/j/+bt8v+4vcD/5evw/+bs8f+5vcH/rbK1/97k6v/T2Nz/pqms/+Dl6v/m7fL/1tve/6er
rv/N0tb/5+3y/+ft8v+kqKz/4+nu/97k6P/m7PL/5+3y/9LX2/+5vcH/o6ap/+fs8//n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8f+xtbj/trq8/7e8v//Axcn/rbK1/9vh5f/n7fL/5u3x/8LGyv/m7PH/qa2v/9je
4v/n7PL/6Ozx/8DFyP+qrrH/5Orv/+bs8v/Q1dr/zNHW/83T1/+tsLP/s7e5/6yvsv/Z3+P/6Ozy/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+fs8f/Y3eH/rK+z/9PX3P/n7fL/5+3y/+ft8v/m7fH/wMXI/+bs
8v/m7PL/sLW3/9LY2//m7fH/6Ozy/+Ho7P+orK//xcrN/+Po7f+1ubz/rLCy/6+ytf/P1Nj/5+3x/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/7a6vv/n7PH/5+3y/+ft8v/n7fL/5+3y/+ft
8f/Cx8r/5uzx/+ft8v/m7PL/q6+y/+bs8v/n7fL/5+3y/+bt8v/JztL/oaSn/6irrv/Hy8//5+3x/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/2+Hm/7y/wv/n7fL/5+3y/+jt
8f/m7PD/ztTY/9Xa3v/m7fL/5+3y/+fs8f+wtbf/5uzy/+ft8v/n7fL/5+3y/+fs8v/m7PH/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/sba4/+Xq
7//Z3uL/sbW4/7C0uP/X29//4ujs/8DEx//m7PH/4ufr/7W5vP/n7fH/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/k6e3/rbCz/7G1t/+1ubv/oKKl/+Xq7//n7PL/4+jt/7S4uv+tsbT/5evv/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/P1Nj/k5aY/7zBxP/m7PL/5+zz/+Tp7f+yt7r/r7O2/8jN0f/n7fH/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+bt8v/h5+v/rLCz/7q/wv+vsrb/rrO2/+Ln7P/m7fL/5u3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/29/k/+Xq7//m7PP/5u3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+bt8v/m7PL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5u3y/+bt
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft8v/n7fL/5+3y/+ft
8v/n7fL/5+3y/+ft8v/n7fL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAABAAEAQEAAAAEAIAAoQgAAFgAAACgAAABAAAAAgAAAAAEAIAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FOAJPRTgOT0U4KE5EN1BPRTh2T0U4jU9FN5FPRTiRT0U4kU9F
OJFPRTiRT0Q4j09FN35PRTdcT0U4ME9FOBRPRTgET0U4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTcATkQ4Ek9FOEZORTiHT0U3yU9FN+VPRDf3T0Q3/09F
Nv9PRDb/T0Q1/09ENf9PRDX/T0Q1/09FNv9PRDf/T0Q3+09FN+tPRTfTTkU4m09FOFhPRTgcT0U4Ak9F
OAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FOAJPRTcqT0U4eE9FOM1ORDf1T0Q2/09E
Nv9ORTn/TkZD/05IVf9NSmP/TUxt/01Ndv9NTnr/TU13/01Mb/9NS2X/TklY/05HR/9ORTr/T0U2/09E
Nv9PRTf7T0U4209FOJVPRTg8T0Q4CE9FOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4Ak5FOCRPRTiNT0Q4409F
N/1PRDX/TkU8/01JVv9MTn//S1Ol/0pWvP9KWM7/SlnU/0pZ1/9KWtj/SlrZ/0pa2P9KWtf/SlnV/0pZ
0f9KV8L/S1Ss/0xQi/9NSl//TkZC/09ENv9PRDb/T0U48U9FOKtPRTg6T0U4BAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTcATkU3Ek5F
OHJPRTjfT0Q3/05FN/9OR0n/TE59/0tUrv9KWdD/SlrY/0pa2P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa2P9KWtj/SlnU/0pWuv9MUIz/TUhV/05FOf9PRDb/T0Q3709F
OJdPRTgkT0U4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AABPRTgCT0U4Mk9FOLtPRDf7T0Q2/05HR/9MT4f/SlfC/0pZ1/9KWtj/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtj/SlnY/0pY
y/9MUZj/TUhV/05FN/9PRDf9T0U4105FN1RPRTgGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAABPRTgGTkU3XE9FN+FPRDf/TkU8/01Mc/9KVr3/SlnX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrY/0pYyv9MT4j/TkZF/05ENv9ORTfxTkU3h09FOA5PRTcAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTgIT0U4ek9FN/FPRTb/TkdM/0tSn/9KWdT/SlrY/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnX/0tVtf9NSl//TkU3/09F
N/tPRTelT0U4GE5ENwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTgKT0U4iU9FN/dORTj/TUpg/0pW
vP9KWdj/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtj/SljK/01NeP9ORTn/T0Q3/U9FOLdPRTgcT0U4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTgIT0U4hU9F
N/lPRTf/TkdJ/0pWv/9KWtn/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWdP/TE+L/05FO/9PRDf/T0U4s09FNxgAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AABPRTgCT0U4bE9FN/VPRTf/T0U3/05FOP9NTXP/SljO/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ1f9MT4z/TkU7/09E
N/1PRTihT0U3DgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAABPRTgAT0U4Rk9FN+1ORTb/TUtn/0xNe/9ORTn/TkU3/01Mcf9KWM3/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlnV/0xPiP9ORTj/T0U3+09FOHxPRTgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4Ik9FONFPRTb/TUlX/0pXxP9KWdL/TE6A/05F
Of9ORTf/TUxv/0pYzf9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWdL/TUxz/05FN/9PRTftT0U4SE9FOAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATkU4Bk5FOJ1PRDf9TkZD/0tU
sP9KWtj/SlrX/0pZ0v9MToD/TkU5/05FN/9NTHD/SljN/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pXx/9NSVn/T0Q2/09F
OM1PRTgcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4AE9F
OEhPRTfzTkU4/0xQjP9KWdf/SlrX/0pa1/9KWtf/SlnS/0xOgP9ORTn/TkU3/01McP9KWM3/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtj/S1St/05GQP9PRTf9T0U4g09FOAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAE9FOA5PRTi9T0Q2/01JWv9KWM3/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWdL/TE6B/05F
OP9ORTf/TUxx/0pYzf9KWdf/SlrX/0pa1/9KWtf/SlrX/0pZ1P9KWcz/SlrW/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlnW/0pZzf9MTXv/TkQ2/09FN+VPRDgsT0U4AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FOABORThYT0U4905FPP9LU6X/SlrY/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pZ0/9MToL/TkU5/05FN/9NTG//SljN/0pa1/9KWtf/SlrX/0pZ1P9LToL/TlOQ/0pa
1v9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pYzf9QUHH/Sla//05HTP9PRDf/T0U4k09F
OAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTgKT0U4vU9ENv9NSmT/SlnS/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnS/0xOgv9ORTj/TkU2/01Mb/9KWMz/SlrX/0pZ
0/9LToP/TkQ1/01Tlv9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ0v9NTXL/T0xh/0pa
1v9MT4n/TkU3/09FN+VPRTgmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTgAT0U4PE9F
N/FORTr/S1Ol/0pZ2P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWdP/TE+C/05F
Of9ORTf/TUxt/0pXyf9LTX//TkQ2/05ENP9NUpb/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrW/0pZ
0v9PUoX/T0U2/05Mav9KWtf/SlfC/05HSv9PRTf9T0U4eE9FOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAATkU3Ak9FOI1PRTf/TkhV/0pYzv9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pZ0v9MToL/TkU5/05FNv9NR0//TkQ1/09FNf9ORDT/TVKW/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pYzv9OUHr/T0U3/05ENf9MTXX/SlrX/0pZ1/9NTXX/T0Q2/05FOMVORTgOAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FNxRPRTfRTkQ2/0xOgP9KWtj/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnS/0xOgP9NRDb/TkQ1/09FNf9PRTX/TkQ0/01S
lv9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlnW/0tYw/9NSmH/TkU1/09FNf9ORDX/T1Wb/0pa1/9KWtj/S1Oq/05F
Ov9PRTfzT0U4OAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTg8T0U38U5FPP9LVLH/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ0v9MTHT/TkQ1/09F
Nf9PRTX/T0U1/05ENP9NU5b/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtb/SlnP/01SlP9PR0b/TkQ0/09FNf9PRTX/TkQ3/0xX
uf9KWtf/SlrX/0pYyv9OSE7/T0Q3/U9FOHpPRTcAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTgAT0U4eE5E
N/1OSFD/SljK/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ
0v9MTHP/TkQ1/09FNf9PRTX/T0U1/09FNf9ORDT/TVKV/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWc3/TFOc/09KVv9PRTb/T0U1/09F
Nf9PRTX/T0U1/09KUv9LWcz/SlrX/0pa1/9KWdf/TExz/09ENv9PRTixT0U4CAAAAAAAAAAAAAAAAAAA
AAAAAAAAT0U4Bk9FOKVPRTb/TUxt/0pZ1v9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pZ0P9MS2//TkQ1/09FNf9PRTX/T0U1/09FNf9PRTX/TkQ0/09MZP9KWMv/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1v9KWdP/S1nO/0tUp/9UVof/iYaO/7u3
sv9ORDT/T0U1/2phVP/Mycb/YllL/05ENP9OTnP/SlrW/0pa1/9KWtf/SlrZ/0tQkP9ORTb/T0U41U9F
OBoAAAAAAAAAAAAAAAAAAAAAAAAAAE5FOBBPRTjFTkQ1/0xPhP9KWtn/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZz/9MS27/TkQ1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/05E
NP9PRTf/UU1g/0xRlP9LUpv/TFat/01Yuv9NWcH/TVnB/01Zvv9NV7L/S1Oh/0tRlv9PUon/Tkpb/09I
Sf9iWk7/zsvH/9jW0/+qpZ7/T0U1/8K/u//Kx8T/0c/M/1NKOv9ORDT/TVex/0pa1/9KWtf/SlrX/0pa
2P9LVLD/TkU8/09FN/FPRTg4AAAAAAAAAAAAAAAAAAAAAAAAAABPRTgkTkU35U5FN/9LU6H/SlrY/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pYz/9MS2r/TkQ1/09FNf9PRTX/T0U1/09F
Nf9PRTX/T0U1/09FNf9PRTX/T0Q0/05ENP9ORDT/TkQ1/09GOf9PRj7/T0dA/09HQP9PRz//T0Y7/05F
Nv9ORDT/TkQ0/05ENP9PRTX/mJKJ/6unoP+HgXb/zcrG/2ZeUP/Ewb3/nJeP/66qo/9waFz/T0pX/0pZ
zv9KWtf/SlrX/0pa1/9KWtf/SlfC/05GRP9PRTf5TkU4TgAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4Mk9F
N+9ORTv/S1W0/0pa2P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pYzv9MSmf/TkQ1/09F
Nf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09F
Nf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/6Kdlf9waFv/T0U1/8TBvP9vZ1r/o56X/09F
Nf+gm5P/cmpf/0xSl/9KWtb/SlrX/0pa1/9KWtf/SlrX/0pYyv9OR0z/T0U3+09FOFgAAAAAAAAAAAAA
AAAAAAAAAAAAAE9FODpPRTfzTkU+/0tVuv9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pY
zf9MSmX/TkQ1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09F
Nf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf+QioD/jIZ8/09F
Nf/DwLv/YFdI/7y5s/9PRTX/sa2m/2FcZv9KWMr/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWM7/TkhT/09E
NvtPRThYAAAAAAAAAAAAAAAAAAAAAAAAAABPRTdCT0U39U5GQP9KVr7/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pYzP94eJT/XFNE/09FNf9+d2z/VEo7/09FNf9SSTn/f3ht/4mDeP9bUkP/T0U1/1NJ
Of+AeW7/gntw/09FNf9yal3/YFdJ/09FNf91bmH/XVRF/1ZNPv+HgHb/c2tf/3t0af9PRTX/Ukk5/4iB
d/9qYVT/WVBB/7Wxq/+uqaL/enJn/09FNf+inZX/qaWe/5yXkf9MU5z/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlnQ/01JV/9PRDb7T0U4WAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U3Qk9FN/VORkD/Sla+/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pYy/9UUWn/9PT0/6GclP9dU0X/+Pj4/4mDeP9PRTX/raih/9XT
0P+3s63/wL24/09FNf/LyMT/1NHO/8fEwP95cWX/trKt/4N8cf9PRTX/wb25/3lxZf+tqaL/zszI/9nX
1f/T0c7/T0U1/4uEev/d3Nr/nJaO/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/05ENP9OTGX/SlnT/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ0P9NSVf/T0Q2+09FOFgAAAAAAAAAAAAAAAAAAAAAAAAAAE9F
ODpPRTfzTkY+/0tWuv9KWtf/SlrX/0pa1/9KWtf/SlrX/0pYyf9MSVz/h4B2/8XCvv/PzMn/koyC/9LQ
zf/Bvrn/T0U1/+Xj4v+2sq3/qqWf/6mknf9kW03/5+bl/1BGNv9PRTX/T0U1/7ayrf+DfHH/T0U1/8G9
uf95cWX/rKeg/7ayrf+dmI//09HO/09FNf+Ykon/opyV/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09E
NP9PSUr/S1jD/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWM7/TkhT/09ENvtPRThYAAAAAAAA
AAAAAAAAAAAAAAAAAABPRTcyT0Q3705FO/9LVbT/SlrY/0pa1/9KWtf/SlrX/0pXyP9NSVv/TkQ1/8G+
uf+IgXf/ycbC/97c2/94cWX/6Ofm/1VMPP/f3dv/qaSd/5SOhf/x8fH/YFdJ/+rp6f9WTD3/T0U1/09F
Nf+2sq3/mZSL/09FNf/IxcD/eXFl/1hPQP+WkIf/wLy3/9PRzv9PRTX/mJKJ/6Kclf9PRTX/T0U1/09F
Nf9PRTX/T0U1/09FNf9ORTr/TFOg/0pa1v9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SljK/05H
TP9PRTf7T0U4WAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4JE9FOOdORDj/S1Kj/0pa2f9KWtf/SlrX/0pZ
z/9NSVj/TkQ1/1hOP//o5+b/U0o6/4uEev/r6un/UEY2/7y4s/+Ignf/hn90/+fl5P/b2db/sq2n/09F
Nf+uqqP/5uXk/9LQzf95cWX/trKt/+vq6f/Qzcr/7e3s/1xSRP9kXE7/5ePi/93b2f+rpp//W1JD/+De
3P/i4d//m5WN/09FNf9PRTX/T0U1/09FNf9ORTn/TlOX/0pZ1v9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pXw/9ORkT/T0U3+U9FOE4AAAAAAAAAAAAAAAAAAAAAAAAAAE9EOBBPRTjHTkQ1/0xP
hf9KWtn/SlrX/0pa1/9KWdP/TE5+/05FNv9SSDn/aF9S/09FNf9USjv/Zl1Q/09FNf9dVEX/XVRF/09F
Nf9fVkf/aWFT/09FNf9PRTX/T0U1/2deUf9uZln/UEY2/7ayrf+EfXL/bmZZ/1lQQf9PRTX/T0U1/15V
R/9uZln/UUc4/1JIOP+qpZ7/sq6o/2JZS/9PRTX/T0U1/09FNf9ORTj/T1ON/0pa1f9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa2P9LVbL/TkU9/09FN/NPRTg6AAAAAAAAAAAAAAAAAAAAAAAA
AABPRTgGT0U4pU9FNv9NTG7/SlrX/0pa1/9KWtf/SlrX/0pZ0/9LToL/TkU2/09FNf9PRTX/T0U1/09F
Nf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf+2sqz/g3xx/09F
Nf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/XVRF/2lgU/9PRTX/T0U1/09FNf9ORTr/T1SU/0pZ
1P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtn/TFGR/05FN/9PRTjXT0U4HAAA
AAAAAAAAAAAAAAAAAAAAAAAAT0U4AE9FOHpPRDf9TkhS/0pYyv9KWtf/SlrX/0pa1/9KWtf/SlnV/0tP
hv9ORTf/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09F
Nf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/05E
NP9ORkH/TVSh/0pa1v9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnX/01N
dP9PRDb/T0U4tU9FOAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTg+TkQ3805FPf9LVbP/SlrY/0pa
1/9KWtf/SlrX/0pa1/9KWdT/S0+J/05FN/9PRTX/T0U1/09FNf9PRTX/xMG9/2JZS/9WTD3/2dfU/46H
fv+EfXL/gHlu/5+akv+Nh33/m5aN/4uFev9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/09F
Nf9PRTX/T0U1/05ENP9QTF3/S1a3/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pYy/9OSFD/T0Q2/U9FOHxPRTgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U3Fk9F
N9VPRDb/TE+E/0pa2P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ1f9LT4v/TkU4/09FNf9PRTX/T0U1/9XT
0P9lXE7/T0U1/7i0r/9aUUL/i4V6/4qDef/g393/1NLP/6ijnP+UjoT/T0U1/09FNf9PRTX/T0U1/09F
Nf9PRTX/T0U1/09FNf9ORDT/TkQ0/05ENf9QSk7/S1e//0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa2P9LVK7/TkU7/09FN/VPRTg6AAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAE9FOAJPRTiRT0U2/05JVv9KWM7/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnV/0tQ
j/9ORTj/T0U1/09FNf/V09D/ZVxO/09FNf+4tK//WlFC/4uFev/Fwr7/p6Ka/7Svqf/V0s//lI6E/09F
Nf9PRTX/T0U1/09FNf9PRTX/T0U1/09FNf9ORDX/TkdB/05MYf9PRjz/TkU2/01LZv9KWMn/SlrY/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWdf/TU13/09ENv9PRTjJT0U4EAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4QE9FN/NORTv/S1Oo/0pa2P9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWdX/S1CS/05FOP9TSjr/1tTR/2lhU/9QRjb/uLSv/1pRQv+LhXr/+Pj4/2Rb
Tf9xaV3/+vn6/5SOhP9PRTX/T0U1/05ENP9ORDT/TkU1/05ENv9PSlX/TVCF/0tXwv9KWdT/TE+J/05F
Ov9ORTb/TUto/0pXyf9KWtj/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlfE/05H
TP9PRTf9T0U4fE9FOAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FOAxPRTjBT0Q2/01L
Z/9KWdL/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ1f9LUZT/19bY/+Xk4//l5OP/fXZq/9jW
1P+Oh37/g3xy/7OvqP9PRTX/TkU1/7y4s/+LhXz/TkU4/05FOv9ORkL/T01o/01PgP9MV7b/SlnP/0pa
1/9KWtf/SlrX/0pZ1P9MUIv/TkU7/09FNv9NS2b/SlfK/0pa2P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrY/0xQjf9ORTf/T0U3509FOCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AABPRTgAT0U4Xk9FN/lORT3/S1Op/0pa2P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnV/0tR
mP9ORTn/T0U1/09FNf9PRTX/T0U1/09FNf9PRTX/T0U1/0xLZf9NUYv/TlSY/05Ysf9KV8H/SljH/0pZ
1P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnU/0xPiv9ORTr/TkQ2/01LaP9KV8n/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pXxf9OSE7/T0U3/09FOJtPRTgGAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FOBBPRTjBTkQ2/01JXf9KWc7/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWdb/S1Gb/05FO/9PRTX/T0U1/09FNf9PRTX/T0U1/05ENP9NUpf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWdX/TFCM/05F
PP9ORTb/TUpl/0pXyP9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ1/9MTn//TkU2/09FN+lPRTgwT0U4AAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPRTcAT0U4Tk9FN/VORTn/TFCR/0pa
2P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ1v9KUp3/TkU7/09FNf9PRTX/T0U1/09F
Nf9ORDT/TVKW/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pZ1P9MUIv/TkU7/09FNv9NSmb/SlfH/0pa2P9KWtf/SlrX/0pa2P9LVbL/TkZC/09F
N/1PRDiJT0U4AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE5F
OAhPRDihT0Q3/05GRf9LVbP/SlnY/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnW/0tS
oP9ORT3/T0U1/09FNf9PRTX/TkQ0/01Slv9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnV/0xPjP9ORTz/TkU2/01KZf9KV8j/SlrX/0pa
1/9KWMn/TUlb/05FNv9PRTjRT0U4HgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAT0U3Jk9FONdORDb/TUlb/0pXyP9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWdb/SlOj/05FPv9PRTX/T0U1/05ENP9NUpb/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWdT/TFCK/05F
O/9ORTb/TUpl/0pXyP9KWdT/TE15/05FN/9PRTfxT0U4UE9FOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FNwBPRTdOT0U3705FN/9NS2z/SljO/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ1v9KU6b/TkU+/05FNf9ORDT/TVKW/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pZ1f9MUI3/TkU7/05FNv9NS2b/TE+D/05FOv9PRTf7T0U4g09FOAQAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4BE9F
N3RPRTf3TkU3/01Ndf9KWM//SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnW/0pT
qP9ORkD/TkQ0/01Slv9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlnV/0xQjf9ORj7/T0Q3/09FN/9PRTf9T0U4qU9F
OBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAABPRTgIT0U4jU9FN/tORTj/TUxy/0pYzP9KWtj/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWdb/SlSr/01FP/9NU5b/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWdH/TUtn/09F
Nv9PRTf/T0U3u09FOBxPRTcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FOA5PRTiVT0U3+U5FNv9NS2b/SlbA/0pZ
2P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pZ1v9KU6f/TlOT/0pa1v9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
2P9KWM3/TE6A/05FPP9PRDf9T0U4v09FOCBPRTgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4Ck9F
OINPRTf1TkU2/05IT/9LU6X/SlnW/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa2P9KVrr/TUpk/05EOP9PRDf9T0U3r09FNx5ORDcAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAABPRTgGT0U4ZE9FN+VPRDb/TkU+/0xNe/9KV8H/SlrY/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrY/0pYzf9MUJD/TkdI/05ENv9PRTfzT0U4kU9FOBJPRTcAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FNwJPRTc6T0U4w09EN/tPRDb/TkdK/0xQ
jf9KV8X/SlrY/0pa2P9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtj/SljO/0tSn/9OSVr/TkU4/09EN/9PRTjdT0U3XE9F
OAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4AE9F
NxRPRTd+T0U35U9FN/9ORDf/TkdO/0xOg/9KVbf/SlnR/0pa2f9KWtj/SlrX/0pa1/9KWtf/SlrX/0pa
1/9KWtf/SlrX/0pa1/9KWtf/SlrX/0pa1/9KWtj/SlrZ/0pZ1f9KV8D/S1GU/01JWv9ORTn/T0Q2/09F
N/FPRTehT0U4Kk9FOAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAT0U4Ak9FOCxORTeVT0U36U9FN/9PRDb/TkY+/01KXf9MT4P/S1St/0pX
xP9KWM7/SlnV/0pZ2P9KWtj/SlnY/0pZ2P9KWtj/SlnW/0pZ0P9KV8f/S1W2/0xQjv9NS2j/TkZD/09E
N/9PRTf/T0U3809FN7NPRThET0U3BgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0U4BE9FODBPRTiHT0U31U9F
N/dPRDb/T0U2/05FO/9ORkb/TUhV/01Mbf9NTXr/TE6A/0xPhP9MToH/TE58/01Mcf9NSVz/TkdJ/05G
Pf9ORTf/T0Q2/09EN/tORDflT0U4nU9EOEZPRTgKT0U4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAT0U4Ak9FNxZPRTdMT0U4mU9FOMtPRTfvT0U3+U9ENv1PRDb/T0U2/09FNv9PRTb/T0U2/09F
Nv9PRDb/T0Q2/09EN/lPRTfzT0U32U9FOKdPRTdgT0U4Ik9FOARPRTgAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9FOARPRTgST0U4ME9FN1JPRTh+TkU3o09F
OLFPRTi9T0U4wU9FOL9PRTi1T0U4qU9FOItPRThaT0U4Ok5FNxhPRTcGT0U4AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AABPRTgAT0U4Ak9FOARPRTgET0U4Bk9FOAZPRTgGT0U4BE9FOARPRTgCT0U4AE9FOAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA////////////////////////////////////8B////////4AAP//////+AAAH//////AAAAH
/////4AAAAH////+AAAAAP////wAAAAAP///+AAAAAAf///gAAAAAA///8AAAAAAB///wAAAAAAD//+A
AAAAAAP//wAAAAAAAf/+AAAAAAAA//4AAAAAAAB//AAAAAAAAH/8AAAAAAAAP/gAAAAAAAA/+AAAAAAA
AD/wAAAAAAAAH/AAAAAAAAAf8AAAAAAAAB/wAAAAAAAAD+AAAAAAAAAP4AAAAAAAAA/gAAAAAAAAD+AA
AAAAAAAP4AAAAAAAAA/gAAAAAAAAD+AAAAAAAAAP4AAAAAAAAA/gAAAAAAAAD+AAAAAAAAAP4AAAAAAA
AA/gAAAAAAAAD/AAAAAAAAAP8AAAAAAAAB/wAAAAAAAAH/AAAAAAAAAf+AAAAAAAAD/4AAAAAAAAP/wA
AAAAAAA//AAAAAAAAH/+AAAAAAAAf/4AAAAAAAD//wAAAAAAAf//gAAAAAAB///AAAAAAAP//8AAAAAA
B///4AAAAAAP///wAAAAAB////wAAAAAP////gAAAAD/////gAAAAf/////AAAAH//////AAAB//////
/gAA////////8A////////////////////////////////////8=
</value>
</data>
</root>

View File

@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RevokeMsgPatcher.Model
{
public class App
{
public string Name { get; set; }
public Dictionary<string, TargetInfo> FileTargetInfos { get; set; }
public Dictionary<string, List<ModifyInfo>> FileModifyInfos { get; set; }
public HashSet<string> GetSupportVersions()
{
// 使用 HashSet 防重
HashSet<string> versions = new HashSet<string>();
foreach (List<ModifyInfo> modifyInfos in FileModifyInfos.Values)
{
foreach (ModifyInfo modifyInfo in modifyInfos)
{
versions.Add(modifyInfo.Version);
}
}
return versions;
}
public string GetSupportVersionStr()
{
string str = "";
foreach (string v in GetSupportVersions())
{
str += v + "、";
}
if (str.Length > 1)
{
str = str.Substring(0, str.Length - 1);
}
return str;
}
}
}

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RevokeMsgPatcher.Model
{
public class Bag
{
public Dictionary<string, App> Apps { get; set; }
public string LatestVersion { get; set; }
public string Notice { get; set; }
}
}

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RevokeMsgPatcher.Model
{
public class Change
{
public long Position { get; set; }
public byte[] Content { get; set; }
public Change Clone()
{
Change o = new Change();
o.Position = Position;
o.Content = Content;
return o;
}
}
}

View File

@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RevokeMsgPatcher.Model
{
public class ModifyInfo
{
public string Name { get; set; }
//public string RelativePath { get; set; }
public string Version { get; set; }
public string SHA1Before { get; set; }
public string SHA1After { get; set; }
public List<Change> Changes { get; set; }
public ModifyInfo Clone()
{
ModifyInfo o = new ModifyInfo();
o.Name = Name;
o.Version = Version;
o.SHA1Before = SHA1Before;
o.SHA1After = SHA1After;
List<Change> cs = new List<Change>();
foreach(Change c in Changes)
{
cs.Add(c.Clone());
}
o.Changes = cs;
return o;
}
}
}

View File

@ -1,23 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RevokeMsgPatcher.Model
{
public class TargetFile
{
public string FileName { get; set; }
public string Version { get; set; }
public string SHA1Before { get; set; }
public string SHA1After { get; set; }
public long Position { get; set; }
public byte Content { get; set; }
}
}

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RevokeMsgPatcher.Model
{
public class TargetInfo
{
public string Name { get; set; }
public string RelativePath { get; set; }
public string Memo { get; set; }
public TargetInfo Clone()
{
TargetInfo o = new TargetInfo();
o.Name = Name;
o.RelativePath = RelativePath;
o.Memo = Memo;
return o;
}
}
}

View File

@ -0,0 +1,215 @@
using RevokeMsgPatcher.Model;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RevokeMsgPatcher.Modifier
{
/// <summary>
/// 1. 自动获取安装目录(已验证) 或者手动填写安装目录
/// 2. 验证安装目录 验证要修改的 dll 是否存在
/// 3. 判断所有 dll 是否符合防撤回要求
/// 4. 备份所有 dll // *.h.bak
/// 5. 根据每个 dll 匹配的 修改信息 循环修改
/// </summary>
public abstract class AppModifier
{
protected App config;
public App Config { set { config = value; } get { return config; } }
protected List<FileHexEditor> editors;
public string InstallPath { get; set; }
/// <summary>
/// 自动搜索应用安装路径
/// </summary>
/// <returns>应用安装路径</returns>
public abstract string FindInstallPath();
//public abstract bool ValidateAndInitialize(string installPath);
/// <summary>
/// 获取版本号
/// </summary>
/// <returns></returns>
public abstract string GetVersion();
/// <summary>
/// 判断APP安装路径内是否都存在要修改的文件
/// </summary>
/// <param name="installPath">APP安装路径</param>
/// <returns></returns>
public bool IsAllFilesExist(string installPath)
{
if (string.IsNullOrEmpty(installPath))
{
return false;
}
int success = 0;
foreach (TargetInfo info in config.FileTargetInfos.Values)
{
string filePath = Path.Combine(installPath, info.RelativePath);
if (File.Exists(filePath))
{
success++;
}
}
if (success == config.FileTargetInfos.Count)
{
return true;
}
else
{
return false;
}
}
/// <summary>
/// a.初始化修改器
/// </summary>
/// <param name="installPath">APP安装路径</param>
public void InitEditors(string installPath)
{
// 初始化文件修改器
editors = new List<FileHexEditor>();
foreach (TargetInfo info in config.FileTargetInfos.Values)
{
FileHexEditor editor = new FileHexEditor(installPath, info);
editors.Add(editor);
}
}
/// <summary>
/// b.验证文件完整性,寻找对应的补丁信息
/// </summary>
public void ValidateAndFindModifyInfo()
{
// 寻找对应文件版本与SHA1的修改信息
foreach (FileHexEditor editor in editors) // 多种文件
{
// 通过SHA1和文件版本判断是否可以打补丁 根据不同结果返回不同的提示
ModifyInfo matchingSHA1Before = null, matchingSHA1After = null, matchingVersion = null;
foreach (ModifyInfo modifyInfo in config.FileModifyInfos[editor.FileName]) // 多个版本信息
{
if (modifyInfo.Name == editor.FileName) // 保险用的无用判断
{
if (editor.FileSHA1 == modifyInfo.SHA1After)
{
matchingSHA1After = modifyInfo;
}
else if (editor.FileSHA1 == modifyInfo.SHA1Before)
{
matchingSHA1Before = modifyInfo;
}
if (editor.FileVersion == modifyInfo.Version)
{
matchingVersion = modifyInfo;
}
}
}
// 补丁前SHA1匹配上肯定是正确的dll
if (matchingSHA1Before != null)
{
editor.FileModifyInfo = matchingSHA1Before;
continue;
}
// 补丁后SHA1匹配上肯定已经打过补丁
if (matchingSHA1After != null)
{
throw new BusinessException("installed", $"你已经安装过此补丁,文件路径:{editor.FilePath}");
}
// 全部不匹配,说明不支持
if (matchingSHA1Before == null && matchingSHA1After == null && matchingVersion == null)
{
throw new BusinessException("not_support", $"不支持此版本:{editor.FileVersion},文件路径:{editor.FilePath}");
}
// SHA1不匹配版本匹配可能dll已经被其他补丁程序修改过
if ((matchingSHA1Before == null && matchingSHA1After == null) && matchingVersion != null)
{
throw new BusinessException("maybe_modified", $"程序支持此版本:{editor.FileVersion}。但是文件校验不通过,请确认是否使用过其他补丁程序。文件路径:{editor.FilePath}");
}
}
}
/// <summary>
/// c.根据补丁信息,安装补丁
/// </summary>
/// <returns></returns>
public bool Patch()
{
// 首先验证文件修改器是否没问题
foreach (FileHexEditor editor in editors)
{
if (editor.FileModifyInfo == null)
{
throw new Exception("补丁安装失败,原因:文件修改器初始化失败!");
}
}
// 再备份所有文件
foreach (FileHexEditor editor in editors)
{
editor.Backup();
}
// 打补丁!
List<FileHexEditor> done = new List<FileHexEditor>(); // 已经打上补丁的
try
{
foreach (FileHexEditor editor in editors)
{
bool success = editor.Patch();
if (!success)
{
editor.Restore();
}
done.Add(editor);
}
}
catch (Exception ex)
{
// 恢复所有已经打上补丁的文件
foreach (FileHexEditor editor in done)
{
editor.Restore();
}
throw ex;
}
return true;
}
public bool BackupExists()
{
foreach (FileHexEditor editor in editors)
{
if (!File.Exists(editor.FileBakPath))
{
return false;
}
}
return true;
}
public bool Restore()
{
if (BackupExists())
{
foreach (FileHexEditor editor in editors)
{
editor.Restore();
}
return true;
}
else
{
throw new Exception("备份文件不存在,还原失败!");
}
}
}
}

View File

@ -0,0 +1,74 @@
using RevokeMsgPatcher.Model;
using RevokeMsgPatcher.Utils;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RevokeMsgPatcher.Modifier
{
public class FileHexEditor
{
public string FileName { get; set; }
public string FilePath { get; set; }
public string FileBakPath { get; set; }
private string version;
public string FileVersion
{
get
{
if (version == null)
{
version = FileUtil.GetFileVersion(FilePath);
}
return version;
}
}
public string sha1;
public string FileSHA1
{
get
{
if (sha1 == null)
{
sha1 = FileUtil.ComputeFileSHA1(FilePath);
}
return sha1;
}
}
public TargetInfo FileTargetInfo { get; set; }
public ModifyInfo FileModifyInfo { get; set; }
public FileHexEditor(string installPath, TargetInfo target)
{
FileTargetInfo = target.Clone();
FileName = FileTargetInfo.Name;
FilePath = Path.Combine(installPath, FileTargetInfo.RelativePath);
FileBakPath = FilePath + ".h.bak";
}
public void Backup()
{
File.Copy(FilePath, FileBakPath, true);
}
public bool Patch()
{
FileUtil.EditMultiHex(FilePath, FileModifyInfo.Changes);
return true;
}
public void Restore()
{
File.Copy(FileBakPath, FilePath, true);
}
}
}

View File

@ -0,0 +1,56 @@
using RevokeMsgPatcher.Model;
using RevokeMsgPatcher.Utils;
namespace RevokeMsgPatcher.Modifier
{
class QQLiteModifier : AppModifier
{
public QQLiteModifier(App config)
{
this.config = config;
}
/// <summary>
/// 自动寻找获取微信安装路径
/// </summary>
/// <returns></returns>
public override string FindInstallPath()
{
string installPath = PathUtil.FindInstallPathFromRegistry("QQLite");
if (!IsAllFilesExist(installPath))
{
foreach (string defaultPath in PathUtil.GetDefaultInstallPaths(@"Tencent\QQLite"))
{
if (IsAllFilesExist(defaultPath))
{
return defaultPath;
}
}
}
else
{
return installPath;
}
return null;
}
/// <summary>
/// 获取整个APP的当前版本
/// </summary>
/// <returns></returns>
public override string GetVersion()
{
if (editors != null && editors.Count > 0)
{
foreach (FileHexEditor editor in editors)
{
if (editor.FileName == "IM.dll")
{
return editor.FileVersion;
}
}
}
return "";
}
}
}

View File

@ -0,0 +1,56 @@
using RevokeMsgPatcher.Model;
using RevokeMsgPatcher.Utils;
namespace RevokeMsgPatcher.Modifier
{
class QQModifier : AppModifier
{
public QQModifier(App config)
{
this.config = config;
}
/// <summary>
/// 自动寻找获取微信安装路径
/// </summary>
/// <returns></returns>
public override string FindInstallPath()
{
string installPath = PathUtil.FindInstallPathFromRegistry("{052CFB79-9D62-42E3-8A15-DE66C2C97C3E}");
if (!IsAllFilesExist(installPath))
{
foreach (string defaultPath in PathUtil.GetDefaultInstallPaths(@"Tencent\QQ"))
{
if (IsAllFilesExist(defaultPath))
{
return defaultPath;
}
}
}
else
{
return installPath;
}
return null;
}
/// <summary>
/// 获取整个APP的当前版本
/// </summary>
/// <returns></returns>
public override string GetVersion()
{
if (editors != null && editors.Count > 0)
{
foreach (FileHexEditor editor in editors)
{
if (editor.FileName == "IM.dll")
{
return editor.FileVersion;
}
}
}
return "";
}
}
}

View File

@ -0,0 +1,56 @@
using RevokeMsgPatcher.Model;
using RevokeMsgPatcher.Utils;
namespace RevokeMsgPatcher.Modifier
{
class TIMModifier : AppModifier
{
public TIMModifier(App config)
{
this.config = config;
}
/// <summary>
/// 自动寻找获取微信安装路径
/// </summary>
/// <returns></returns>
public override string FindInstallPath()
{
string installPath = PathUtil.FindInstallPathFromRegistry("TIM");
if (!IsAllFilesExist(installPath))
{
foreach (string defaultPath in PathUtil.GetDefaultInstallPaths(@"Tencent\TIM"))
{
if (IsAllFilesExist(defaultPath))
{
return defaultPath;
}
}
}
else
{
return installPath;
}
return null;
}
/// <summary>
/// 获取整个APP的当前版本
/// </summary>
/// <returns></returns>
public override string GetVersion()
{
if (editors != null && editors.Count > 0)
{
foreach (FileHexEditor editor in editors)
{
if (editor.FileName == "IM.dll")
{
return editor.FileVersion;
}
}
}
return "";
}
}
}

View File

@ -0,0 +1,72 @@
using RevokeMsgPatcher.Model;
using RevokeMsgPatcher.Utils;
namespace RevokeMsgPatcher.Modifier
{
class WechatModifier : AppModifier
{
public WechatModifier(App config)
{
this.config = config;
}
/// <summary>
/// 自动寻找获取微信安装路径
/// </summary>
/// <returns></returns>
public override string FindInstallPath()
{
string installPath = PathUtil.FindInstallPathFromRegistry("Wechat");
if (!IsAllFilesExist(installPath))
{
foreach (string defaultPath in PathUtil.GetDefaultInstallPaths(@"Tencent\Wechat"))
{
if (IsAllFilesExist(defaultPath))
{
return defaultPath;
}
}
}
else
{
return installPath;
}
return null;
}
/// <summary>
/// 获取整个APP的当前版本
/// </summary>
/// <returns></returns>
public override string GetVersion()
{
if (editors != null && editors.Count > 0)
{
foreach (FileHexEditor editor in editors)
{
if (editor.FileName == "WeChatWin.dll")
{
return editor.FileVersion;
}
}
}
return "";
}
//public override bool ValidateAndInitialize(string installPath)
//{
// // 判断是否是安装路径
// if (!IsAllBinaryFilesExist(installPath))
// {
// return false;
// }
// // 初始化十六进制文件编辑器
// // 并寻找与之配对的版本修改信息
// InitEditors(installPath);
// return true;
//}
}
}

View File

@ -1,91 +0,0 @@
using RevokeMsgPatcher.Model;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Web.Script.Serialization;
namespace RevokeMsgPatcher
{
public class Patcher
{
private string intallPath;
public string IntallPath
{
get { return intallPath; }
set
{
intallPath = value;
if (!string.IsNullOrEmpty(intallPath) && Util.IsWechatInstallPath(intallPath))
{
dllPath = Path.Combine(intallPath, "WeChatWin.dll");
bakPath = Path.Combine(intallPath, "WeChatWin.dll.h.bak");
}
else
{
intallPath = null;
dllPath = null;
bakPath = null;
}
}
}
private string dllPath;
private string bakPath;
public string DllPath { get => dllPath; }
public string BakPath { get => bakPath; }
private List<TargetFile> targetFiles;
private TargetFile currentFile;
public List<TargetFile> TargetFiles { get => targetFiles; }
public Patcher()
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
targetFiles = serializer.Deserialize<List<TargetFile>>(Properties.Resources.PatchJson);
}
public void SetNewPatchJson(string json)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
targetFiles = serializer.Deserialize<List<TargetFile>>(json);
}
public string JudgeVersion()
{
string sha1 = Util.ComputeFileSHA1(dllPath);
Debug.WriteLine(sha1);
foreach (TargetFile t in targetFiles)
{
if (sha1 == t.SHA1After)
{
return "done";
}
if (sha1 == t.SHA1Before)
{
currentFile = t;
return t.Version;
}
}
return null;
}
public bool Patch()
{
if (currentFile != null)
{
File.Copy(dllPath, bakPath, true);
bool done = Util.EditHex(dllPath, currentFile.Position, currentFile.Content);
if (!done)
{
File.Copy(bakPath, dllPath, true);
}
return done;
}
return false;
}
}
}

View File

@ -14,14 +14,18 @@ namespace RevokeMsgPatcher
[STAThread]
static void Main()
{
#if DEBUG
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new FormMain());
#else
try
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
#if DEBUG
Application.Run(new FormMain());
#else
//当前用户是管理员的时候,直接启动应用程序
//如果不是管理员,则使用启动对象启动程序,以确保使用管理员身份运行
//获得当前登录的Windows用户标示
@ -53,12 +57,13 @@ namespace RevokeMsgPatcher
//退出
Application.Exit();
}
#endif
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
#endif
}

View File

@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
// 方法是按如下所示使用“*”: :
//[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.4")]
[assembly: AssemblyFileVersion("0.4")]
[assembly: AssemblyVersion("0.6")]
[assembly: AssemblyFileVersion("0.6")]

View File

@ -61,7 +61,7 @@ namespace RevokeMsgPatcher.Properties {
}
/// <summary>
/// 查找类似 [{&quot;FileName&quot;:&quot;WeChatWin.dll&quot;,&quot;Version&quot;:&quot;2.6.8.65&quot;,&quot;SHA1Before&quot;:&quot;e01f6855a96c12c30808960903ed199a33e4952c&quot;,&quot;SHA1After&quot;:&quot;d9120569cfd0433aebea107d7b90805cbbac7518&quot;,&quot;Position&quot;:2454265,&quot;Content&quot;:117},{&quot;FileName&quot;:&quot;WeChatWin.dll&quot;,&quot;Version&quot;:&quot;2.6.8.52&quot;,&quot;SHA1Before&quot;:&quot;88131302f664df6a657c9ca49d152da536fe5729&quot;,&quot;SHA1After&quot;:&quot;8d1454b73831644181e962c1fa0ea4e2da4124a3&quot;,&quot;Position&quot;:2453049,&quot;Content&quot;:117},{&quot;FileName&quot;:&quot;WeChatWin.dll&quot;,&quot;Version&quot;:&quot;2.6.8.51&quot;,&quot;SHA1Before&quot;:&quot;d0a5517b1292a751501b00b4b1f0702db2d9fc30&quot;,&quot;SHA1After&quot;:&quot;53e7b [字符串的其余部分被截断]&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.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;; 的本地化字符串。
/// </summary>
internal static string PatchJson {
get {

File diff suppressed because one or more lines are too long

View File

@ -37,6 +37,7 @@
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Management" />
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
@ -49,17 +50,31 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="BusinessException.cs" />
<Compile Include="FormMain.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="FormMain.Designer.cs">
<DependentUpon>FormMain.cs</DependentUpon>
</Compile>
<Compile Include="Model\TargetFile.cs" />
<Compile Include="Patcher.cs" />
<Compile Include="Model\App.cs" />
<Compile Include="Model\Bag.cs" />
<Compile Include="Model\Change.cs" />
<Compile Include="Model\ModifyInfo.cs" />
<Compile Include="Model\TargetInfo.cs" />
<Compile Include="Modifier\AppModifier.cs" />
<Compile Include="Modifier\FileHexEditor.cs" />
<Compile Include="Modifier\QQLiteModifier.cs" />
<Compile Include="Modifier\QQModifier.cs" />
<Compile Include="Modifier\TIMModifier.cs" />
<Compile Include="Modifier\WechatModifier.cs" />
<Compile Include="Utils\Device.cs" />
<Compile Include="Utils\FileUtil.cs" />
<Compile Include="Utils\GAHelper.cs" />
<Compile Include="Utils\HttpUtil.cs" />
<Compile Include="Utils\PathUtil.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Util.cs" />
<EmbeddedResource Include="FormMain.resx">
<DependentUpon>FormMain.cs</DependentUpon>
</EmbeddedResource>

View File

@ -1,109 +0,0 @@
using Microsoft.Win32;
using System;
using System.Diagnostics;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace RevokeMsgPatcher
{
public class Util
{
/// <summary>
/// 自动查找安装路径
/// </summary>
/// <returns>安装路径</returns>
public static string AutoFindInstallPath()
{
// 微信的注册表路径
try
{
RegistryKey key = Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Uninstall\WeChat");
object installLocation = key.GetValue("InstallLocation");
key.Close();
if (installLocation == null || string.IsNullOrEmpty(installLocation.ToString()) || !IsWechatInstallPath(installLocation.ToString()))
{
// 从默认安装目录查找
string[] drives = Environment.GetLogicalDrives(); //获取当前计算机逻辑磁盘名称列表
foreach (string d in drives)
{
string assertPath = Path.Combine(d, @"Program Files (x86)\Tencent\WeChat");
if (IsWechatInstallPath(assertPath))
{
return assertPath;
}
}
}
else
{
return installLocation.ToString();
}
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
return null;
}
/// <summary>
/// 通过文件是否存在判断是否是安装目录
/// </summary>
/// <param name="path">安装目录</param>
/// <returns></returns>
public static bool IsWechatInstallPath(string path)
{
return File.Exists(Path.Combine(path, "WeChatWin.dll")) && File.Exists(Path.Combine(path, "WeChat.exe"));
}
/// <summary>
/// 获取文件版本
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static string GetFileVersion(string path)
{
FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(path);
return fileVersionInfo.FileVersion;
}
/// <summary>
/// 计算文件SHA1
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static string ComputeFileSHA1(string s)
{
FileStream file = new FileStream(s, FileMode.Open);
SHA1 sha1 = new SHA1CryptoServiceProvider();
byte[] retval = sha1.ComputeHash(file);
file.Close();
StringBuilder sc = new StringBuilder();
for (int i = 0; i < retval.Length; i++)
{
sc.Append(retval[i].ToString("x2"));
}
return sc.ToString();
}
/// <summary>
/// 修改文件指定位置的字节
/// </summary>
/// <param name="path">WeChatWin.dll 的路径</param>
/// <param name="position">偏移位置</param>
/// <param name="after">修改后的值</param>
/// <returns></returns>
public static bool EditHex(string path, long position, byte after)
{
using (var stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite))
{
stream.Position = position;
stream.WriteByte(after);
}
return true;
}
}
}

View File

@ -0,0 +1,151 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;
using System.Net;
using System.Security.Cryptography;
using System.Text;
namespace RevokeMsgPatcher.Utils
{
public class Device
{
private static string macID = null;
private static string osVersion = null;
private static string fingerPrint = null;
#region PROP, get it only once
public static string MacID
{
get
{
if (macID == null)
{
macID = ObtainMacID();
}
return macID;
}
}
public static string OSVersion
{
get
{
if (osVersion == null)
{
var name = (from x in new ManagementObjectSearcher("SELECT Caption FROM Win32_OperatingSystem").Get().Cast<ManagementObject>()
select x.GetPropertyValue("Caption")).FirstOrDefault();
osVersion = name != null ? name.ToString() : "Unknown";
}
return osVersion;
}
}
#endregion
/// <summary>
/// Calculate GUID
/// </summary>
/// <returns>GUID</returns>
public static string Value()
{
if (fingerPrint == null)
{
fingerPrint = GetHash(
"MAC >> " + MacID
);
}
return fingerPrint;
}
private static string GetHash(string s)
{
MD5 sec = new MD5CryptoServiceProvider();
ASCIIEncoding enc = new ASCIIEncoding();
byte[] bt = enc.GetBytes(s);
return GetHexString(sec.ComputeHash(bt));
}
private static string GetHexString(byte[] bt)
{
string s = string.Empty;
for (int i = 0; i < bt.Length; i++)
{
byte b = bt[i];
int n, n1, n2;
n = (int)b;
n1 = n & 15;
n2 = (n >> 4) & 15;
if (n2 > 9)
s += ((char)(n2 - 10 + (int)'A')).ToString();
else
s += n2.ToString();
if (n1 > 9)
s += ((char)(n1 - 10 + (int)'A')).ToString();
else
s += n1.ToString();
if ((i + 1) != bt.Length && (i + 1) % 2 == 0) s += "-";
}
return s;
}
#region Original Device ID Getting Code
public static string ObtainMacID()
{
return Identifier("Win32_NetworkAdapterConfiguration", "MACAddress", "IPEnabled");
}
private static string Identifier(string wmiClass, string wmiProperty, string wmiMustBeTrue)
{
string result = "";
try
{
ManagementClass mc = new ManagementClass(wmiClass);
ManagementObjectCollection moc = mc.GetInstances();
foreach (ManagementObject mo in moc)
{
if (mo[wmiMustBeTrue].ToString() == "True")
{
//Only get the first one
if (result == "")
{
result = mo[wmiProperty].ToString();
break;
}
}
}
}
catch
{
}
return result;
}
private static string Identifier(string wmiClass, string wmiProperty)
{
string result = "";
try
{
ManagementClass mc = new ManagementClass(wmiClass);
ManagementObjectCollection moc = mc.GetInstances();
foreach (ManagementObject mo in moc)
{
//Only get the first one
if (result == "")
{
result = mo[wmiProperty].ToString();
break;
}
}
}
catch
{
}
return result;
}
#endregion
}
}

View File

@ -0,0 +1,78 @@
using RevokeMsgPatcher.Model;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace RevokeMsgPatcher.Utils
{
public class FileUtil
{
/// <summary>
/// 获取文件版本
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static string GetFileVersion(string path)
{
FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(path);
return fileVersionInfo.FileVersion;
}
/// <summary>
/// 计算文件SHA1
/// </summary>
/// <param name="s">文件路径</param>
/// <returns></returns>
public static string ComputeFileSHA1(string s)
{
FileStream file = new FileStream(s, FileMode.Open);
SHA1 sha1 = new SHA1CryptoServiceProvider();
byte[] retval = sha1.ComputeHash(file);
file.Close();
StringBuilder sc = new StringBuilder();
for (int i = 0; i < retval.Length; i++)
{
sc.Append(retval[i].ToString("x2"));
}
return sc.ToString();
}
/// <summary>
/// 修改文件指定位置的字节
/// </summary>
/// <param name="path">文件对象的路径</param>
/// <param name="position">偏移位置</param>
/// <param name="after">修改后的值</param>
/// <returns></returns>
public static bool EditHex(string path, long position, byte after)
{
using (var stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite))
{
stream.Position = position;
stream.WriteByte(after);
}
return true;
}
/// <summary>
/// 修改文件多个指定位置的多个字节
/// </summary>
/// <param name="path">文件对象的路径</param>
/// <param name="changes">需要修改的位置和内容</param>
public static void EditMultiHex(string path, List<Change> changes)
{
using (var stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite))
{
foreach (Change change in changes)
{
stream.Seek(change.Position, SeekOrigin.Begin);
stream.Write(change.Content, 0, change.Content.Length);
}
}
}
}
}

View File

@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace RevokeMsgPatcher.Utils
{
/// <summary>
/// 用于软件的 Google Analytics 实现 By huiyadanli
/// 相关文档:
/// 指南 https://developers.google.com/analytics/devguides/collection/protocol/v1/devguide
/// 参数 https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters
/// 测试 https://ga-dev-tools.appspot.com/hit-builder/
/// </summary>
public class GAHelper
{
// 根据实际情况修改
private static readonly HttpClient client = HttpUtil.Client;
private const string GAUrl = "https://www.google-analytics.com/collect";
// 根据实际使用分析账号设置
private const string tid = "UA-80358493-2"; // GA Tracking ID / Property ID.
private static readonly string cid = Device.Value(); // Anonymous Client ID. // Guid.NewGuid().ToString()
// 屏幕分辨率(可选)
private static readonly string sr = Screen.PrimaryScreen.Bounds.Width + "x" + Screen.PrimaryScreen.Bounds.Height;
public string UserAgent { get; set; }
public GAHelper()
{
UserAgent = string.Format("Hui Google Analytics Tracker/1.0 ({0}; {1}; {2})", Environment.OSVersion.Platform.ToString(), Environment.OSVersion.Version.ToString(), Environment.OSVersion.VersionString);
}
public async Task RequestPageViewAsync(string page, string title = null)
{
try
{
if (!page.StartsWith("/"))
{
page = "/" + page;
}
// 请求参数
var values = new Dictionary<string, string>
{
{ "v", "1" }, // 当前必填1
{ "tid", tid },
{ "cid", cid },
{ "ua", UserAgent },
{ "t", "pageview" },
{ "sr", sr },
{ "dp", page },
{ "dt", title },
};
var content = new FormUrlEncodedContent(values);
var response = await client.PostAsync(GAUrl, content);
}
catch (Exception ex)
{
Console.WriteLine("GAHelper:" + ex.Message);
}
}
public void RequestPageView(string page, string title = null)
{
Task.Run(() => RequestPageViewAsync(page, title));
}
}
}

View File

@ -0,0 +1,55 @@
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
namespace RevokeMsgPatcher.Utils
{
public class HttpUtil
{
public static HttpClient Client { get; } = new HttpClient();
static HttpUtil()
{
Client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36");
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
}
/// <summary>
/// 补丁路径
/// 已经弃用的路径
/// https://swordmaker-hauls-51508.netlify.com/i/revokemsg/05.json
/// https://huiyadanli.github.io/i/revokemsg/05.json
/// </summary>
private static readonly string[] urls = new string[]
{
"https://coding.net/u/huiyadanli/p/RevokeMsgPatcher/git/raw/master/RevokeMsgPatcher.Assistant/Data/0.6/patch.json",
"https://gitee.com/huiyadanli/RevokeMsgPatcher/raw/master/RevokeMsgPatcher.Assistant/Data/0.6/patch.json",
"https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/master/RevokeMsgPatcher.Assistant/Data/0.6/patch.json"
};
private static int i = 0;
public static async Task<string> GetPatchJsonAsync()
{
try
{
return await Client.GetStringAsync(urls[i]);
}
catch (Exception ex)
{
Console.WriteLine("第" + (i + 1) + "次请求异常:[" + ex.Message + "]\nURL:" + urls[i]);
i++;
if (i > urls.Length)
{
i = 0;
return null;
}
else
{
return await GetPatchJsonAsync();
}
}
}
}
}

View File

@ -0,0 +1,81 @@
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RevokeMsgPatcher.Utils
{
public class PathUtil
{
public static void DisplayAllProgram()
{
RegistryKey uninstallKey, programKey;
uninstallKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall");
string[] programKeys = uninstallKey.GetSubKeyNames();
foreach (string keyName in programKeys)
{
programKey = uninstallKey.OpenSubKey(keyName);
Console.WriteLine(keyName + " , " + programKey.GetValue("DisplayName") + " , " + programKey.GetValue("InstallLocation"));
programKey.Close();
}
uninstallKey.Close();
}
/// <summary>
/// 从注册表中寻找安装路径
/// </summary>
/// <param name="uninstallKeyName">
/// 安装信息的注册表键名
/// 微信WeChat
/// QQ{052CFB79-9D62-42E3-8A15-DE66C2C97C3E}
/// TIMTIM
/// </param>
/// <returns>安装路径</returns>
public static string FindInstallPathFromRegistry(string uninstallKeyName)
{
try
{
RegistryKey key = Registry.LocalMachine.OpenSubKey($@"Software\Microsoft\Windows\CurrentVersion\Uninstall\{uninstallKeyName}");
if (key == null)
{
return null;
}
object installLocation = key.GetValue("InstallLocation");
key.Close();
if (installLocation != null && !string.IsNullOrEmpty(installLocation.ToString()))
{
return installLocation.ToString();
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return null;
}
/// <summary>
/// 获取所有可能的默认安装路径
/// </summary>
/// <param name="relativePath">Tencent\*</param>
/// <returns></returns>
public static List<string> GetDefaultInstallPaths(string relativePath)
{
List<string> list = new List<string>();
// 从默认安装目录查找
string[] drives = Environment.GetLogicalDrives(); //获取当前计算机逻辑磁盘名称列表
foreach (string d in drives)
{
string path = Path.Combine(d, $@"Program Files (x86)\{relativePath}");
if (Directory.Exists(path))
{
list.Add(path);
}
}
return list;
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 17 KiB