diff --git a/Images/logo.png b/Images/logo.png
new file mode 100644
index 0000000..89654d2
Binary files /dev/null and b/Images/logo.png differ
diff --git a/Images/logo.jpg b/Images/logo_old.jpg
similarity index 100%
rename from Images/logo.jpg
rename to Images/logo_old.jpg
diff --git a/Images/screenshot.png b/Images/screenshot.png
index d2441d7..3899405 100644
Binary files a/Images/screenshot.png and b/Images/screenshot.png differ
diff --git a/Images/screenshot.v0.4.png b/Images/screenshot.v0.4.png
new file mode 100644
index 0000000..d2441d7
Binary files /dev/null and b/Images/screenshot.v0.4.png differ
diff --git a/Images/screenshot.v0.5.png b/Images/screenshot.v0.5.png
new file mode 100644
index 0000000..572c262
Binary files /dev/null and b/Images/screenshot.v0.5.png differ
diff --git a/Images/wiki/qq/1.png b/Images/wiki/qq/1.png
new file mode 100644
index 0000000..17e355c
Binary files /dev/null and b/Images/wiki/qq/1.png differ
diff --git a/Images/wiki/qq/10.png b/Images/wiki/qq/10.png
new file mode 100644
index 0000000..74d7f47
Binary files /dev/null and b/Images/wiki/qq/10.png differ
diff --git a/Images/wiki/qq/11.png b/Images/wiki/qq/11.png
new file mode 100644
index 0000000..e19b011
Binary files /dev/null and b/Images/wiki/qq/11.png differ
diff --git a/Images/wiki/qq/12.png b/Images/wiki/qq/12.png
new file mode 100644
index 0000000..bd2a73c
Binary files /dev/null and b/Images/wiki/qq/12.png differ
diff --git a/Images/wiki/qq/13.png b/Images/wiki/qq/13.png
new file mode 100644
index 0000000..b982a96
Binary files /dev/null and b/Images/wiki/qq/13.png differ
diff --git a/Images/wiki/qq/2.png b/Images/wiki/qq/2.png
new file mode 100644
index 0000000..a488c07
Binary files /dev/null and b/Images/wiki/qq/2.png differ
diff --git a/Images/wiki/qq/3.png b/Images/wiki/qq/3.png
new file mode 100644
index 0000000..b17050a
Binary files /dev/null and b/Images/wiki/qq/3.png differ
diff --git a/Images/wiki/qq/4.png b/Images/wiki/qq/4.png
new file mode 100644
index 0000000..93516c6
Binary files /dev/null and b/Images/wiki/qq/4.png differ
diff --git a/Images/wiki/qq/5.png b/Images/wiki/qq/5.png
new file mode 100644
index 0000000..b283f5f
Binary files /dev/null and b/Images/wiki/qq/5.png differ
diff --git a/Images/wiki/qq/6.png b/Images/wiki/qq/6.png
new file mode 100644
index 0000000..ce52267
Binary files /dev/null and b/Images/wiki/qq/6.png differ
diff --git a/Images/wiki/qq/7.png b/Images/wiki/qq/7.png
new file mode 100644
index 0000000..c1a0ea9
Binary files /dev/null and b/Images/wiki/qq/7.png differ
diff --git a/Images/wiki/qq/8.png b/Images/wiki/qq/8.png
new file mode 100644
index 0000000..8e26d80
Binary files /dev/null and b/Images/wiki/qq/8.png differ
diff --git a/Images/wiki/qq/9.png b/Images/wiki/qq/9.png
new file mode 100644
index 0000000..80a38a4
Binary files /dev/null and b/Images/wiki/qq/9.png differ
diff --git a/Images/wiki/wechat/10_mutex.png b/Images/wiki/wechat/10_mutex.png
new file mode 100644
index 0000000..e34c7c8
Binary files /dev/null and b/Images/wiki/wechat/10_mutex.png differ
diff --git a/Images/wiki/wechat/11_push_ebp_to_ret.png b/Images/wiki/wechat/11_push_ebp_to_ret.png
new file mode 100644
index 0000000..73a2f68
Binary files /dev/null and b/Images/wiki/wechat/11_push_ebp_to_ret.png differ
diff --git a/Images/wiki/wechat/12_push_ebp_to_ret.png b/Images/wiki/wechat/12_push_ebp_to_ret.png
new file mode 100644
index 0000000..a235493
Binary files /dev/null and b/Images/wiki/wechat/12_push_ebp_to_ret.png differ
diff --git a/Images/wiki/wechat/13_push_ebp_to_ret.png b/Images/wiki/wechat/13_push_ebp_to_ret.png
new file mode 100644
index 0000000..8c86803
Binary files /dev/null and b/Images/wiki/wechat/13_push_ebp_to_ret.png differ
diff --git a/Images/wiki/wechat/14_patch_dll.png b/Images/wiki/wechat/14_patch_dll.png
new file mode 100644
index 0000000..ce8771b
Binary files /dev/null and b/Images/wiki/wechat/14_patch_dll.png differ
diff --git a/Images/wiki/wechat/1_start.png b/Images/wiki/wechat/1_start.png
new file mode 100644
index 0000000..44b5c5a
Binary files /dev/null and b/Images/wiki/wechat/1_start.png differ
diff --git a/Images/wiki/wechat/2_click_attach.png b/Images/wiki/wechat/2_click_attach.png
new file mode 100644
index 0000000..71dc8b8
Binary files /dev/null and b/Images/wiki/wechat/2_click_attach.png differ
diff --git a/Images/wiki/wechat/3_attach_wechat_exe.png b/Images/wiki/wechat/3_attach_wechat_exe.png
new file mode 100644
index 0000000..df7eff8
Binary files /dev/null and b/Images/wiki/wechat/3_attach_wechat_exe.png differ
diff --git a/Images/wiki/wechat/4_wechatwin_dll.png b/Images/wiki/wechat/4_wechatwin_dll.png
new file mode 100644
index 0000000..c329a75
Binary files /dev/null and b/Images/wiki/wechat/4_wechatwin_dll.png differ
diff --git a/Images/wiki/wechat/5_search_string.png b/Images/wiki/wechat/5_search_string.png
new file mode 100644
index 0000000..0714b02
Binary files /dev/null and b/Images/wiki/wechat/5_search_string.png differ
diff --git a/Images/wiki/wechat/6_revokemsg_1.png b/Images/wiki/wechat/6_revokemsg_1.png
new file mode 100644
index 0000000..883afe4
Binary files /dev/null and b/Images/wiki/wechat/6_revokemsg_1.png differ
diff --git a/Images/wiki/wechat/7_je_to_jmp.png b/Images/wiki/wechat/7_je_to_jmp.png
new file mode 100644
index 0000000..c54b78f
Binary files /dev/null and b/Images/wiki/wechat/7_je_to_jmp.png differ
diff --git a/Images/wiki/wechat/8_je_to_jmp.png b/Images/wiki/wechat/8_je_to_jmp.png
new file mode 100644
index 0000000..41d3b4c
Binary files /dev/null and b/Images/wiki/wechat/8_je_to_jmp.png differ
diff --git a/Images/wiki/wechat/9_je_to_jmp.png b/Images/wiki/wechat/9_je_to_jmp.png
new file mode 100644
index 0000000..d9caf2e
Binary files /dev/null and b/Images/wiki/wechat/9_je_to_jmp.png differ
diff --git a/README.md b/README.md
index 8935108..547bd7e 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,13 @@
-
+
-
+
@@ -17,43 +17,49 @@
-# :eyes:微信防撤回补丁
-适用于 Windows 下PC版微信的防撤回补丁。
+# 👀微信/QQ/TIM防撤回补丁
+适用于 Windows 下 PC 版微信/QQ/TIM的防撤回补丁。
-支持最新测试版本: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)
+
+## 📷截图

## 🔨使用方法
-**请以管理员身份运行本程序,由于修改了微信的 `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
-
+## ❤️Thanks
-## :heart:Thanks
[wechat_anti_revoke](https://github.com/36huo/wechat_anti_revoke)
-## 📃License
+## 📄License
GPLv3

diff --git a/RevokeMsgPatcher.Assistant/App.config b/RevokeMsgPatcher.Assistant/App.config
new file mode 100644
index 0000000..8e15646
--- /dev/null
+++ b/RevokeMsgPatcher.Assistant/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/RevokeMsgPatcher.Assistant/Data/0.6/patch.json b/RevokeMsgPatcher.Assistant/Data/0.6/patch.json
new file mode 100644
index 0000000..b812451
--- /dev/null
+++ b/RevokeMsgPatcher.Assistant/Data/0.6/patch.json
@@ -0,0 +1 @@
+{"Apps":{"Wechat":{"Name":"Wechat","FileTargetInfos":{"WeChatWin.dll":{"Name":"WeChatWin.dll","RelativePath":"WeChatWin.dll","Memo":null}},"FileModifyInfos":{"WeChatWin.dll":[{"Name":"WeChatWin.dll","Version":"2.7.1.88","SHA1Before":"034059bad50dd793140952391bfa7936133e69b4","SHA1After":"dd6d80c30ca9e0ea9f7d2f1add498fc9aa4bc7a0","Changes":[{"Position":2499465,"Content":[235]},{"Position":7952304,"Content":[195]}]},{"Name":"WeChatWin.dll","Version":"2.7.1.85","SHA1Before":"de0df4e138b72460450f66c029e33f4510f5e2df","SHA1After":"fbd35720aaff3cdcfd3ff18ea503dc06450e5c99","Changes":[{"Position":2499465,"Content":[235]},{"Position":7952000,"Content":[195]}]},{"Name":"WeChatWin.dll","Version":"2.7.1.82","SHA1Before":"20e111a18872bf6c7148a897c11da26c1ec95520","SHA1After":"1e0741d325ca6b1cd2402b829a3d13a2524af617","Changes":[{"Position":2499465,"Content":[235]},{"Position":7951952,"Content":[195]}]},{"Name":"WeChatWin.dll","Version":"2.7.1.74","SHA1Before":"b1eaf7edc074a88be5d0f89230436cc2084d24d2","SHA1After":"eb3d74ccd87a09059a005f4972861898fc3de463","Changes":[{"Position":2499465,"Content":[235]},{"Position":7951696,"Content":[195]}]},{"Name":"WeChatWin.dll","Version":"2.7.1.65","SHA1Before":"8346b97d264725da924d240c6eb77df3e693385e","SHA1After":"42bab2c9c79ef4f2088c00ea6d817973e14a5e6e","Changes":[{"Position":2495545,"Content":[235]}]},{"Name":"WeChatWin.dll","Version":"2.7.1.59","SHA1Before":"df954d403edaca89cd5394927a325a0023e93281","SHA1After":"6aa22460c91bb5c5e2f0ec1af99b8a5f6d4318c0","Changes":[{"Position":2496073,"Content":[235]}]},{"Name":"WeChatWin.dll","Version":"2.7.1.43","SHA1Before":"39cd9e09e1a3eac09e6808749bff525c9e3216ce","SHA1After":"7b829f1ff0217e346a80f9510fdd7634ddd49445","Changes":[{"Position":2494169,"Content":[235]}]},{"Name":"WeChatWin.dll","Version":"2.7.0.70","SHA1Before":"3b0601864aff3c1d792f812ad1ca05f02aa761e3","SHA1After":"1e8734d32b0a8c12758e30f99c77f729991fb071","Changes":[{"Position":2475657,"Content":[235]}]},{"Name":"WeChatWin.dll","Version":"2.7.0.65","SHA1Before":"063c2e05a0df1bdb8987c2d978d93499bd2052ba","SHA1After":"5ed4c09a4f18643b967f063a824d7e65d0567f8a","Changes":[{"Position":2475449,"Content":[117]}]},{"Name":"WeChatWin.dll","Version":"2.6.8.68","SHA1Before":"2e9417f4276b12fe32ca7b4fee49272a4a2af334","SHA1After":"699602ee3cbb9ae5714f6e6ebc658c875a6c66e6","Changes":[{"Position":2454006,"Content":[116]}]},{"Name":"WeChatWin.dll","Version":"2.6.8.65","SHA1Before":"e01f6855a96c12c30808960903ed199a33e4952c","SHA1After":"d9120569cfd0433aebea107d7b90805cbbac7518","Changes":[{"Position":2454265,"Content":[117]}]},{"Name":"WeChatWin.dll","Version":"2.6.8.52","SHA1Before":"88131302f664df6a657c9ca49d152da536fe5729","SHA1After":"8d1454b73831644181e962c1fa0ea4e2da4124a3","Changes":[{"Position":2453049,"Content":[117]}]},{"Name":"WeChatWin.dll","Version":"2.6.8.51","SHA1Before":"d0a5517b1292a751501b00b4b1f0702db2d9fc30","SHA1After":"53e7b1525d49bf2c3250a8131ff0ba2510779b78","Changes":[{"Position":2452614,"Content":[116]}]},{"Name":"WeChatWin.dll","Version":"2.6.8.37","SHA1Before":"7e01f8b04a158a4a50bc5a6e67c2fb8b02233170","SHA1After":"a1895004415fe9bcd7e690bd6e482b833b515599","Changes":[{"Position":2452614,"Content":[116]}]},{"Name":"WeChatWin.dll","Version":"2.6.7.57","SHA1Before":"80a91aaf941bcb1c24a7d672838ac73e9ebb2e40","SHA1After":"a0d3f9a45a835f97aef7fe0872387d8cfb5c25a4","Changes":[{"Position":2433413,"Content":[116]}]},{"Name":"WeChatWin.dll","Version":"2.6.7.40","SHA1Before":"04bd0cb28df6630b518f42a3f9c2caa4a9359fbc","SHA1After":"13c91cf1d4609959771fd137b9a86a5ca365e1b6","Changes":[{"Position":2432934,"Content":[116]}]},{"Name":"WeChatWin.dll","Version":"2.6.7.32","SHA1Before":"a02519c1007ee6723947c262c720d63c619f633e","SHA1After":"f3007471ca8734c29783c25f0bb49949a783a44","Changes":[{"Position":2432806,"Content":[116]}]},{"Name":"WeChatWin.dll","Version":"2.6.6.28","SHA1Before":"0b19cb17a62c3ea0efce0fb675a1d3b17845cba3","SHA1After":"260948656725446b818ea668273ceff02ddfb44d","Changes":[{"Position":2401678,"Content":[116]}]}]}},"QQ":{"Name":"QQ","FileTargetInfos":{"IM.dll":{"Name":"IM.dll","RelativePath":"Bin\\IM.dll","Memo":null}},"FileModifyInfos":{"IM.dll":[{"Name":"IM.dll","Version":"9.2.2.26569","SHA1Before":"434254e76c520789558e075af677821258536311","SHA1After":"237c9e489a97858a175f0f7c72ade4ebcbac7a69","Changes":[{"Position":371146,"Content":[235,9,144,144,144]},{"Position":371687,"Content":[235,9,144,144,144]},{"Position":372117,"Content":[235,8,144,144,144,144]}]},{"Name":"IM.dll","Version":"9.2.1.26546","SHA1Before":"8d8ea2c2cbf43f5acf8d684b153e90035352d5f5","SHA1After":"7d194dd5be03982b533d7375c93d9a72587fe28d","Changes":[{"Position":369545,"Content":[235,9,144,144,144]},{"Position":370086,"Content":[235,9,144,144,144]},{"Position":370516,"Content":[235,8,144,144,144,144]}]},{"Name":"IM.dll","Version":"9.2.0.26453","SHA1Before":"c1935ca6347b0c2a7e6108a7f8ee0643d39deb66","SHA1After":"42811188a7e7b346a6a3c1066936b98c747acaf6","Changes":[{"Position":353794,"Content":[235,9,144,144,144]},{"Position":354335,"Content":[235,9,144,144,144]},{"Position":354767,"Content":[235,8,144,144,144,144]}]},{"Name":"IM.dll","Version":"9.2.0.26389","SHA1Before":"6f8855fb80acfa456f8f69989fe949308fe4d154","SHA1After":"f6b8e05a178b9b10ba17c597fa0a44b7a2a966a8","Changes":[{"Position":356808,"Content":[235,9,144,144,144]},{"Position":357349,"Content":[235,9,144,144,144]},{"Position":357781,"Content":[235,8,144,144,144,144]}]},{"Name":"IM.dll","Version":"9.1.9.26361","SHA1Before":"022d3433d13d07a354c38816f61cb0b7ac60d3fd","SHA1After":"873a57c1fb51cdd099c8cb7108b5ab5cb4459557","Changes":[{"Position":354270,"Content":[235,9,144,144,144]},{"Position":354811,"Content":[235,9,144,144,144]},{"Position":355243,"Content":[235,8,144,144,144,144]}]},{"Name":"IM.dll","Version":"9.1.9.26346","SHA1Before":"895eb70f707b8222e6460c91492b1281e525059b","SHA1After":"0bb83990e2b5b5f23b7b43249941ff638201af54","Changes":[{"Position":354270,"Content":[235,9,144,144,144]},{"Position":354811,"Content":[235,9,144,144,144]},{"Position":355243,"Content":[235,8,144,144,144,144]}]},{"Name":"IM.dll","Version":"9.1.8.26211","SHA1Before":"a950d3cf5e8925f7775624271105ef78d9c5cb57","SHA1After":"dffc1cb87b91e6467e13c935611f2f7fd76b9a8d","Changes":[{"Position":337135,"Content":[235,9,144,144,144]},{"Position":337676,"Content":[235,9,144,144,144]},{"Position":338108,"Content":[235,8,144,144,144,144]}]},{"Name":"IM.dll","Version":"9.1.7.25980","SHA1Before":"c6632339fbe675312a70ae4620e70699c258cd36","SHA1After":"e9ddc5cc681950796fc8fe4c55f580428c890b51","Changes":[{"Position":327839,"Content":[235,9,144,144,144]},{"Position":328380,"Content":[235,9,144,144,144]},{"Position":328812,"Content":[235,8,144,144,144,144]}]},{"Name":"IM.dll","Version":"9.0.4.23786","SHA1Before":"69a714f4eadb09f1453f6f022d4adbcd801cfab8","SHA1After":"b48e77a924076b3ebdffc4af514c868c551d2bca","Changes":[{"Position":318321,"Content":[235,7,144,144,144]},{"Position":318862,"Content":[235,7,144,144,144]},{"Position":319379,"Content":[235,7,144,144,144]}]}]}},"TIM":{"Name":"TIM","FileTargetInfos":{"IM.dll":{"Name":"IM.dll","RelativePath":"Bin\\IM.dll","Memo":null}},"FileModifyInfos":{"IM.dll":[{"Name":"IM.dll","Version":"2.3.2.21173","SHA1Before":"ecf3e69f3fb100ffe2fee095ffded591b9781024","SHA1After":"0514d1304e7ac46b4d33386ec3313888f5ae7171","Changes":[{"Position":317322,"Content":[235,9,144,144,144]},{"Position":317863,"Content":[235,9,144,144,144]},{"Position":318295,"Content":[235,8,144,144,144,144]}]}]}},"QQLite":{"Name":"QQLite","FileTargetInfos":{"IM.dll":{"Name":"IM.dll","RelativePath":"Bin\\IM.dll","Memo":null}},"FileModifyInfos":{"IM.dll":[{"Name":"IM.dll","Version":"7.9.14314.0","SHA1Before":"2e97d7671963fa148a1beeda6ce4964314310593","SHA1After":"723c008fb53435ead20fa6f2e951c9a4a8ff46da","Changes":[{"Position":148741,"Content":[235,2,144,144]},{"Position":149689,"Content":[235,2,144,144]}]},{"Name":"IM.dll","Version":"7.9.14308.0","SHA1Before":"b8a7a873178706b97be11c25f13bcf09e9e578a2","SHA1After":"c5bf533c7af6996b42d1fb2a0fb3f26dfd52f8bf","Changes":[{"Position":148741,"Content":[235,2,144,144]},{"Position":149689,"Content":[235,2,144,144]}]}]}}},"LatestVersion":"0.6","Notice":""}
\ No newline at end of file
diff --git a/RevokeMsgPatcher.Assistant/FormAssisant.Designer.cs b/RevokeMsgPatcher.Assistant/FormAssisant.Designer.cs
new file mode 100644
index 0000000..6ddb778
--- /dev/null
+++ b/RevokeMsgPatcher.Assistant/FormAssisant.Designer.cs
@@ -0,0 +1,61 @@
+namespace RevokeMsgPatcher.Assistant
+{
+ partial class FormAssisant
+ {
+ ///
+ /// 必需的设计器变量。
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// 清理所有正在使用的资源。
+ ///
+ /// 如果应释放托管资源,为 true;否则为 false。
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows 窗体设计器生成的代码
+
+ ///
+ /// 设计器支持所需的方法 - 不要修改
+ /// 使用代码编辑器修改此方法的内容。
+ ///
+ 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;
+ }
+}
+
diff --git a/RevokeMsgPatcher.Assistant/FormAssisant.cs b/RevokeMsgPatcher.Assistant/FormAssisant.cs
new file mode 100644
index 0000000..d5e189c
--- /dev/null
+++ b/RevokeMsgPatcher.Assistant/FormAssisant.cs
@@ -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);
+ }
+ }
+}
diff --git a/RevokeMsgPatcher.Assistant/FormAssisant.resx b/RevokeMsgPatcher.Assistant/FormAssisant.resx
new file mode 100644
index 0000000..1af7de1
--- /dev/null
+++ b/RevokeMsgPatcher.Assistant/FormAssisant.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/RevokeMsgPatcher.Assistant/JsonData.cs b/RevokeMsgPatcher.Assistant/JsonData.cs
new file mode 100644
index 0000000..1520b65
--- /dev/null
+++ b/RevokeMsgPatcher.Assistant/JsonData.cs
@@ -0,0 +1,539 @@
+using RevokeMsgPatcher.Model;
+using System.Collections.Generic;
+using System.Web.Script.Serialization;
+
+namespace RevokeMsgPatcher
+{
+ ///
+ /// 补丁信息
+ ///
+ 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 AppConfig()
+ {
+ return new Dictionary
+ {
+ { "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
+ {
+ {
+ "WeChatWin.dll",
+ new TargetInfo
+ {
+ Name = "WeChatWin.dll",
+ RelativePath = "WeChatWin.dll"
+ }
+ }
+ },
+ FileModifyInfos = new Dictionary>
+ {
+ {
+ "WeChatWin.dll",
+ new List
+ {
+ new ModifyInfo {
+ Name="WeChatWin.dll",
+ Version="2.7.1.88",
+ SHA1Before="034059bad50dd793140952391bfa7936133e69b4",
+ SHA1After="dd6d80c30ca9e0ea9f7d2f1add498fc9aa4bc7a0",
+ Changes = new List
+ {
+ 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
+ {
+ 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
+ {
+ 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
+ {
+ 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
+ {
+ 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { new Change {Position=2401678,Content=new byte[] { 116} } } }
+ }
+ }
+ }
+ };
+ }
+
+ public App QQ()
+ {
+ return new App
+ {
+ Name = "QQ",
+ FileTargetInfos = new Dictionary
+ {
+ {
+ "IM.dll",
+ new TargetInfo
+ {
+ Name = "IM.dll",
+ RelativePath = @"Bin\IM.dll"
+ }
+ }
+ },
+ FileModifyInfos = new Dictionary>
+ {
+ {
+ "IM.dll",
+ new List
+ {
+ new ModifyInfo
+ {
+ Name = "IM.dll",
+ Version = "9.2.2.26569",
+ SHA1Before = "434254e76c520789558e075af677821258536311",
+ SHA1After = "237c9e489a97858a175f0f7c72ade4ebcbac7a69",
+ Changes = new List
+ {
+ 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
+ {
+ 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
+ {
+ 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
+ {
+ 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
+ {
+ 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
+ {
+ 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
+ {
+ 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
+ {
+ 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
+ {
+ 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
+ {
+ {
+ "IM.dll",
+ new TargetInfo
+ {
+ Name = "IM.dll",
+ RelativePath = @"Bin\IM.dll"
+ }
+ }
+ },
+ FileModifyInfos = new Dictionary>
+ {
+ {
+ "IM.dll",
+ new List
+ {
+ new ModifyInfo
+ {
+ Name = "IM.dll",
+ Version = "2.3.2.21173",
+ SHA1Before = "ecf3e69f3fb100ffe2fee095ffded591b9781024",
+ SHA1After = "0514d1304e7ac46b4d33386ec3313888f5ae7171",
+ Changes = new List
+ {
+ 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
+ {
+ {
+ "IM.dll",
+ new TargetInfo
+ {
+ Name = "IM.dll",
+ RelativePath = @"Bin\IM.dll"
+ }
+ }
+ },
+ FileModifyInfos = new Dictionary>
+ {
+ {
+ "IM.dll",
+ new List
+ {
+ new ModifyInfo
+ {
+ Name = "IM.dll",
+ Version = "7.9.14314.0",
+ SHA1Before = "2e97d7671963fa148a1beeda6ce4964314310593",
+ SHA1After = "723c008fb53435ead20fa6f2e951c9a4a8ff46da",
+ Changes = new List
+ {
+ 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
+ {
+ new Change
+ {
+ Position = 0x00024505,
+ Content = new byte[] { 0xEB, 0x02, 0x90, 0x90 }
+ },
+ new Change
+ {
+ Position = 0x000248B9,
+ Content = new byte[] { 0xEB, 0x02, 0x90, 0x90 }
+ }
+ }
+ }
+ }
+ }
+ }
+ };
+ }
+ }
+}
diff --git a/RevokeMsgPatcher.Assistant/Program.cs b/RevokeMsgPatcher.Assistant/Program.cs
new file mode 100644
index 0000000..7509010
--- /dev/null
+++ b/RevokeMsgPatcher.Assistant/Program.cs
@@ -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
+ {
+ ///
+ /// 应用程序的主入口点。
+ ///
+ [STAThread]
+ static void Main()
+ {
+ Application.EnableVisualStyles();
+ Application.SetCompatibleTextRenderingDefault(false);
+ Application.Run(new FormAssisant());
+ }
+ }
+}
diff --git a/RevokeMsgPatcher.Assistant/Properties/AssemblyInfo.cs b/RevokeMsgPatcher.Assistant/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..b3a3ffb
--- /dev/null
+++ b/RevokeMsgPatcher.Assistant/Properties/AssemblyInfo.cs
@@ -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")]
diff --git a/RevokeMsgPatcher.Assistant/Properties/Resources.Designer.cs b/RevokeMsgPatcher.Assistant/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..92146a4
--- /dev/null
+++ b/RevokeMsgPatcher.Assistant/Properties/Resources.Designer.cs
@@ -0,0 +1,71 @@
+//------------------------------------------------------------------------------
+//
+// 此代码由工具生成。
+// 运行时版本: 4.0.30319.42000
+//
+// 对此文件的更改可能导致不正确的行为,如果
+// 重新生成代码,则所做更改将丢失。
+//
+//------------------------------------------------------------------------------
+
+namespace RevokeMsgPatcher.Assistant.Properties
+{
+
+
+ ///
+ /// 强类型资源类,用于查找本地化字符串等。
+ ///
+ // 此类是由 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()
+ {
+ }
+
+ ///
+ /// 返回此类使用的缓存 ResourceManager 实例。
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// 覆盖当前线程的 CurrentUICulture 属性
+ /// 使用此强类型的资源类的资源查找。
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture
+ {
+ get
+ {
+ return resourceCulture;
+ }
+ set
+ {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/RevokeMsgPatcher.Assistant/Properties/Resources.resx b/RevokeMsgPatcher.Assistant/Properties/Resources.resx
new file mode 100644
index 0000000..af7dbeb
--- /dev/null
+++ b/RevokeMsgPatcher.Assistant/Properties/Resources.resx
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/RevokeMsgPatcher.Assistant/Properties/Settings.Designer.cs b/RevokeMsgPatcher.Assistant/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..50ea233
--- /dev/null
+++ b/RevokeMsgPatcher.Assistant/Properties/Settings.Designer.cs
@@ -0,0 +1,30 @@
+//------------------------------------------------------------------------------
+//
+// 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.
+//
+//------------------------------------------------------------------------------
+
+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;
+ }
+ }
+ }
+}
diff --git a/RevokeMsgPatcher.Assistant/Properties/Settings.settings b/RevokeMsgPatcher.Assistant/Properties/Settings.settings
new file mode 100644
index 0000000..3964565
--- /dev/null
+++ b/RevokeMsgPatcher.Assistant/Properties/Settings.settings
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/RevokeMsgPatcher.Assistant/RevokeMsgPatcher.Assistant.csproj b/RevokeMsgPatcher.Assistant/RevokeMsgPatcher.Assistant.csproj
new file mode 100644
index 0000000..bc77f12
--- /dev/null
+++ b/RevokeMsgPatcher.Assistant/RevokeMsgPatcher.Assistant.csproj
@@ -0,0 +1,113 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {6992004F-17E6-45BF-8D72-180A31E9C23C}
+ WinExe
+ RevokeMsgPatcher.Assistant
+ RevokeMsgPatcher.Assistant
+ v4.5
+ 512
+ true
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ false
+ true
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Form
+
+
+ FormAssisant.cs
+
+
+
+
+
+ FormAssisant.cs
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+ Designer
+
+
+ True
+ Resources.resx
+
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+ True
+ Settings.settings
+ True
+
+
+
+
+
+
+
+ {977bf781-ced8-4389-9404-0fa08fdf21df}
+ RevokeMsgPatcher
+
+
+
+
+ False
+ .NET Framework 3.5 SP1
+ false
+
+
+
+
\ No newline at end of file
diff --git a/RevokeMsgPatcher.MultiInstance/App.config b/RevokeMsgPatcher.MultiInstance/App.config
new file mode 100644
index 0000000..8e15646
--- /dev/null
+++ b/RevokeMsgPatcher.MultiInstance/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/RevokeMsgPatcher.MultiInstance/FormMultiInstance.Designer.cs b/RevokeMsgPatcher.MultiInstance/FormMultiInstance.Designer.cs
new file mode 100644
index 0000000..11b3e4a
--- /dev/null
+++ b/RevokeMsgPatcher.MultiInstance/FormMultiInstance.Designer.cs
@@ -0,0 +1,186 @@
+namespace RevokeMsgPatcher.MultiInstance
+{
+ partial class FormMultiInstance
+ {
+ ///
+ /// 必需的设计器变量。
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// 清理所有正在使用的资源。
+ ///
+ /// 如果应释放托管资源,为 true;否则为 false。
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows 窗体设计器生成的代码
+
+ ///
+ /// 设计器支持所需的方法 - 不要修改
+ /// 使用代码编辑器修改此方法的内容。
+ ///
+ 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;
+ }
+}
+
diff --git a/RevokeMsgPatcher.MultiInstance/FormMultiInstance.cs b/RevokeMsgPatcher.MultiInstance/FormMultiInstance.cs
new file mode 100644
index 0000000..1f566ef
--- /dev/null
+++ b/RevokeMsgPatcher.MultiInstance/FormMultiInstance.cs
@@ -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");
+ }
+
+ ///
+ /// 从注册表中寻找安装路径
+ ///
+ ///
+ /// 安装信息的注册表键名
+ /// 微信:WeChat
+ /// QQ:{052CFB79-9D62-42E3-8A15-DE66C2C97C3E}
+ /// TIM:TIM
+ ///
+ /// 安装路径
+ 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;
+ }
+ }
+}
diff --git a/RevokeMsgPatcher.MultiInstance/FormMultiInstance.resx b/RevokeMsgPatcher.MultiInstance/FormMultiInstance.resx
new file mode 100644
index 0000000..1af7de1
--- /dev/null
+++ b/RevokeMsgPatcher.MultiInstance/FormMultiInstance.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/RevokeMsgPatcher.MultiInstance/Program.cs b/RevokeMsgPatcher.MultiInstance/Program.cs
new file mode 100644
index 0000000..e94f7ef
--- /dev/null
+++ b/RevokeMsgPatcher.MultiInstance/Program.cs
@@ -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
+ {
+ ///
+ /// 应用程序的主入口点。
+ ///
+ [STAThread]
+ static void Main()
+ {
+ Application.EnableVisualStyles();
+ Application.SetCompatibleTextRenderingDefault(false);
+ Application.Run(new FormMultiInstance());
+ }
+ }
+}
diff --git a/RevokeMsgPatcher.MultiInstance/Properties/AssemblyInfo.cs b/RevokeMsgPatcher.MultiInstance/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..ed57d68
--- /dev/null
+++ b/RevokeMsgPatcher.MultiInstance/Properties/AssemblyInfo.cs
@@ -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")]
diff --git a/RevokeMsgPatcher.MultiInstance/Properties/Resources.Designer.cs b/RevokeMsgPatcher.MultiInstance/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..6847c43
--- /dev/null
+++ b/RevokeMsgPatcher.MultiInstance/Properties/Resources.Designer.cs
@@ -0,0 +1,71 @@
+//------------------------------------------------------------------------------
+//
+// 此代码由工具生成。
+// 运行时版本: 4.0.30319.42000
+//
+// 对此文件的更改可能导致不正确的行为,如果
+// 重新生成代码,则所做更改将丢失。
+//
+//------------------------------------------------------------------------------
+
+namespace RevokeMsgPatcher.MultiInstance.Properties
+{
+
+
+ ///
+ /// 强类型资源类,用于查找本地化字符串等。
+ ///
+ // 此类是由 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()
+ {
+ }
+
+ ///
+ /// 返回此类使用的缓存 ResourceManager 实例。
+ ///
+ [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;
+ }
+ }
+
+ ///
+ /// 覆盖当前线程的 CurrentUICulture 属性
+ /// 使用此强类型的资源类的资源查找。
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture
+ {
+ get
+ {
+ return resourceCulture;
+ }
+ set
+ {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/RevokeMsgPatcher.MultiInstance/Properties/Resources.resx b/RevokeMsgPatcher.MultiInstance/Properties/Resources.resx
new file mode 100644
index 0000000..af7dbeb
--- /dev/null
+++ b/RevokeMsgPatcher.MultiInstance/Properties/Resources.resx
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/RevokeMsgPatcher.MultiInstance/Properties/Settings.Designer.cs b/RevokeMsgPatcher.MultiInstance/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..46fb148
--- /dev/null
+++ b/RevokeMsgPatcher.MultiInstance/Properties/Settings.Designer.cs
@@ -0,0 +1,30 @@
+//------------------------------------------------------------------------------
+//
+// 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.
+//
+//------------------------------------------------------------------------------
+
+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;
+ }
+ }
+ }
+}
diff --git a/RevokeMsgPatcher.MultiInstance/Properties/Settings.settings b/RevokeMsgPatcher.MultiInstance/Properties/Settings.settings
new file mode 100644
index 0000000..3964565
--- /dev/null
+++ b/RevokeMsgPatcher.MultiInstance/Properties/Settings.settings
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/RevokeMsgPatcher.MultiInstance/RevokeMsgPatcher.MultiInstance.csproj b/RevokeMsgPatcher.MultiInstance/RevokeMsgPatcher.MultiInstance.csproj
new file mode 100644
index 0000000..2ed2fcd
--- /dev/null
+++ b/RevokeMsgPatcher.MultiInstance/RevokeMsgPatcher.MultiInstance.csproj
@@ -0,0 +1,82 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {73043CA8-AF54-4591-9174-40FB6E0A3D36}
+ WinExe
+ RevokeMsgPatcher.MultiInstance
+ RevokeMsgPatcher.MultiInstance
+ v4.5
+ 512
+ true
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Form
+
+
+ FormMultiInstance.cs
+
+
+
+
+ FormMultiInstance.cs
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+ Designer
+
+
+ True
+ Resources.resx
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+ True
+ Settings.settings
+ True
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/RevokeMsgPatcher.sln b/RevokeMsgPatcher.sln
index e632b93..829e586 100644
--- a/RevokeMsgPatcher.sln
+++ b/RevokeMsgPatcher.sln
@@ -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
diff --git a/RevokeMsgPatcher/BusinessException.cs b/RevokeMsgPatcher/BusinessException.cs
new file mode 100644
index 0000000..2b865e3
--- /dev/null
+++ b/RevokeMsgPatcher/BusinessException.cs
@@ -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;
+ }
+ }
+}
diff --git a/RevokeMsgPatcher/FormMain.Designer.cs b/RevokeMsgPatcher/FormMain.Designer.cs
index b8c0d0f..99c35d8 100644
--- a/RevokeMsgPatcher/FormMain.Designer.cs
+++ b/RevokeMsgPatcher/FormMain.Designer.cs
@@ -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;
}
}
diff --git a/RevokeMsgPatcher/FormMain.cs b/RevokeMsgPatcher/FormMain.cs
index a7a9649..08f183e 100644
--- a/RevokeMsgPatcher/FormMain.cs
+++ b/RevokeMsgPatcher/FormMain.cs
@@ -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(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 t = new Task(() =>
+ 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(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;
+ }
+ }
}
}
}
diff --git a/RevokeMsgPatcher/FormMain.resx b/RevokeMsgPatcher/FormMain.resx
index 97c6724..629e234 100644
--- a/RevokeMsgPatcher/FormMain.resx
+++ b/RevokeMsgPatcher/FormMain.resx
@@ -120,78 +120,289 @@
- 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=
\ No newline at end of file
diff --git a/RevokeMsgPatcher/Model/App.cs b/RevokeMsgPatcher/Model/App.cs
new file mode 100644
index 0000000..cbeaf54
--- /dev/null
+++ b/RevokeMsgPatcher/Model/App.cs
@@ -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 FileTargetInfos { get; set; }
+
+ public Dictionary> FileModifyInfos { get; set; }
+
+ public HashSet GetSupportVersions()
+ {
+ // 使用 HashSet 防重
+ HashSet versions = new HashSet();
+ foreach (List 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;
+ }
+ }
+}
diff --git a/RevokeMsgPatcher/Model/Bag.cs b/RevokeMsgPatcher/Model/Bag.cs
new file mode 100644
index 0000000..c84dd6a
--- /dev/null
+++ b/RevokeMsgPatcher/Model/Bag.cs
@@ -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 Apps { get; set; }
+
+ public string LatestVersion { get; set; }
+
+ public string Notice { get; set; }
+ }
+}
diff --git a/RevokeMsgPatcher/Model/Change.cs b/RevokeMsgPatcher/Model/Change.cs
new file mode 100644
index 0000000..df3c99f
--- /dev/null
+++ b/RevokeMsgPatcher/Model/Change.cs
@@ -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;
+ }
+ }
+}
diff --git a/RevokeMsgPatcher/Model/ModifyInfo.cs b/RevokeMsgPatcher/Model/ModifyInfo.cs
new file mode 100644
index 0000000..c83a39b
--- /dev/null
+++ b/RevokeMsgPatcher/Model/ModifyInfo.cs
@@ -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 Changes { get; set; }
+
+ public ModifyInfo Clone()
+ {
+ ModifyInfo o = new ModifyInfo();
+ o.Name = Name;
+ o.Version = Version;
+ o.SHA1Before = SHA1Before;
+ o.SHA1After = SHA1After;
+ List cs = new List();
+ foreach(Change c in Changes)
+ {
+ cs.Add(c.Clone());
+ }
+ o.Changes = cs;
+ return o;
+ }
+ }
+}
diff --git a/RevokeMsgPatcher/Model/TargetFile.cs b/RevokeMsgPatcher/Model/TargetFile.cs
deleted file mode 100644
index f4c8819..0000000
--- a/RevokeMsgPatcher/Model/TargetFile.cs
+++ /dev/null
@@ -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; }
- }
-}
diff --git a/RevokeMsgPatcher/Model/TargetInfo.cs b/RevokeMsgPatcher/Model/TargetInfo.cs
new file mode 100644
index 0000000..28a1dd2
--- /dev/null
+++ b/RevokeMsgPatcher/Model/TargetInfo.cs
@@ -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;
+ }
+ }
+}
diff --git a/RevokeMsgPatcher/Modifier/AppModifier.cs b/RevokeMsgPatcher/Modifier/AppModifier.cs
new file mode 100644
index 0000000..827520e
--- /dev/null
+++ b/RevokeMsgPatcher/Modifier/AppModifier.cs
@@ -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
+{
+ ///
+ /// 1. 自动获取安装目录(已验证) 或者手动填写安装目录
+ /// 2. 验证安装目录 验证要修改的 dll 是否存在
+ /// 3. 判断所有 dll 是否符合防撤回要求
+ /// 4. 备份所有 dll // *.h.bak
+ /// 5. 根据每个 dll 匹配的 修改信息 循环修改
+ ///
+ public abstract class AppModifier
+ {
+ protected App config;
+
+ public App Config { set { config = value; } get { return config; } }
+
+ protected List editors;
+
+ public string InstallPath { get; set; }
+
+ ///
+ /// 自动搜索应用安装路径
+ ///
+ /// 应用安装路径
+ public abstract string FindInstallPath();
+
+ //public abstract bool ValidateAndInitialize(string installPath);
+
+ ///
+ /// 获取版本号
+ ///
+ ///
+ public abstract string GetVersion();
+
+ ///
+ /// 判断APP安装路径内是否都存在要修改的文件
+ ///
+ /// APP安装路径
+ ///
+ 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;
+ }
+ }
+
+ ///
+ /// a.初始化修改器
+ ///
+ /// APP安装路径
+ public void InitEditors(string installPath)
+ {
+ // 初始化文件修改器
+ editors = new List();
+ foreach (TargetInfo info in config.FileTargetInfos.Values)
+ {
+ FileHexEditor editor = new FileHexEditor(installPath, info);
+ editors.Add(editor);
+ }
+
+ }
+
+ ///
+ /// b.验证文件完整性,寻找对应的补丁信息
+ ///
+ 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}");
+ }
+ }
+ }
+
+ ///
+ /// c.根据补丁信息,安装补丁
+ ///
+ ///
+ public bool Patch()
+ {
+ // 首先验证文件修改器是否没问题
+ foreach (FileHexEditor editor in editors)
+ {
+ if (editor.FileModifyInfo == null)
+ {
+ throw new Exception("补丁安装失败,原因:文件修改器初始化失败!");
+ }
+ }
+ // 再备份所有文件
+ foreach (FileHexEditor editor in editors)
+ {
+ editor.Backup();
+ }
+ // 打补丁!
+ List done = new List(); // 已经打上补丁的
+ 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("备份文件不存在,还原失败!");
+ }
+ }
+ }
+}
diff --git a/RevokeMsgPatcher/Modifier/FileHexEditor.cs b/RevokeMsgPatcher/Modifier/FileHexEditor.cs
new file mode 100644
index 0000000..d4ecb16
--- /dev/null
+++ b/RevokeMsgPatcher/Modifier/FileHexEditor.cs
@@ -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);
+ }
+ }
+}
diff --git a/RevokeMsgPatcher/Modifier/QQLiteModifier.cs b/RevokeMsgPatcher/Modifier/QQLiteModifier.cs
new file mode 100644
index 0000000..45af711
--- /dev/null
+++ b/RevokeMsgPatcher/Modifier/QQLiteModifier.cs
@@ -0,0 +1,56 @@
+using RevokeMsgPatcher.Model;
+using RevokeMsgPatcher.Utils;
+
+namespace RevokeMsgPatcher.Modifier
+{
+ class QQLiteModifier : AppModifier
+ {
+ public QQLiteModifier(App config)
+ {
+ this.config = config;
+ }
+
+ ///
+ /// 自动寻找获取微信安装路径
+ ///
+ ///
+ 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;
+ }
+
+ ///
+ /// 获取整个APP的当前版本
+ ///
+ ///
+ public override string GetVersion()
+ {
+ if (editors != null && editors.Count > 0)
+ {
+ foreach (FileHexEditor editor in editors)
+ {
+ if (editor.FileName == "IM.dll")
+ {
+ return editor.FileVersion;
+ }
+ }
+ }
+ return "";
+ }
+ }
+}
diff --git a/RevokeMsgPatcher/Modifier/QQModifier.cs b/RevokeMsgPatcher/Modifier/QQModifier.cs
new file mode 100644
index 0000000..e52dde8
--- /dev/null
+++ b/RevokeMsgPatcher/Modifier/QQModifier.cs
@@ -0,0 +1,56 @@
+using RevokeMsgPatcher.Model;
+using RevokeMsgPatcher.Utils;
+
+namespace RevokeMsgPatcher.Modifier
+{
+ class QQModifier : AppModifier
+ {
+ public QQModifier(App config)
+ {
+ this.config = config;
+ }
+
+ ///
+ /// 自动寻找获取微信安装路径
+ ///
+ ///
+ 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;
+ }
+
+ ///
+ /// 获取整个APP的当前版本
+ ///
+ ///
+ public override string GetVersion()
+ {
+ if (editors != null && editors.Count > 0)
+ {
+ foreach (FileHexEditor editor in editors)
+ {
+ if (editor.FileName == "IM.dll")
+ {
+ return editor.FileVersion;
+ }
+ }
+ }
+ return "";
+ }
+ }
+}
diff --git a/RevokeMsgPatcher/Modifier/TIMModifier.cs b/RevokeMsgPatcher/Modifier/TIMModifier.cs
new file mode 100644
index 0000000..37938b8
--- /dev/null
+++ b/RevokeMsgPatcher/Modifier/TIMModifier.cs
@@ -0,0 +1,56 @@
+using RevokeMsgPatcher.Model;
+using RevokeMsgPatcher.Utils;
+
+namespace RevokeMsgPatcher.Modifier
+{
+ class TIMModifier : AppModifier
+ {
+
+ public TIMModifier(App config)
+ {
+ this.config = config;
+ }
+ ///
+ /// 自动寻找获取微信安装路径
+ ///
+ ///
+ 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;
+ }
+
+ ///
+ /// 获取整个APP的当前版本
+ ///
+ ///
+ public override string GetVersion()
+ {
+ if (editors != null && editors.Count > 0)
+ {
+ foreach (FileHexEditor editor in editors)
+ {
+ if (editor.FileName == "IM.dll")
+ {
+ return editor.FileVersion;
+ }
+ }
+ }
+ return "";
+ }
+ }
+}
diff --git a/RevokeMsgPatcher/Modifier/WechatModifier.cs b/RevokeMsgPatcher/Modifier/WechatModifier.cs
new file mode 100644
index 0000000..ace78e8
--- /dev/null
+++ b/RevokeMsgPatcher/Modifier/WechatModifier.cs
@@ -0,0 +1,72 @@
+using RevokeMsgPatcher.Model;
+using RevokeMsgPatcher.Utils;
+
+namespace RevokeMsgPatcher.Modifier
+{
+ class WechatModifier : AppModifier
+ {
+
+ public WechatModifier(App config)
+ {
+ this.config = config;
+ }
+
+ ///
+ /// 自动寻找获取微信安装路径
+ ///
+ ///
+ 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;
+ }
+
+ ///
+ /// 获取整个APP的当前版本
+ ///
+ ///
+ 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;
+ //}
+ }
+}
diff --git a/RevokeMsgPatcher/Patcher.cs b/RevokeMsgPatcher/Patcher.cs
deleted file mode 100644
index 8e69281..0000000
--- a/RevokeMsgPatcher/Patcher.cs
+++ /dev/null
@@ -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 targetFiles;
- private TargetFile currentFile;
-
- public List TargetFiles { get => targetFiles; }
-
- public Patcher()
- {
- JavaScriptSerializer serializer = new JavaScriptSerializer();
- targetFiles = serializer.Deserialize>(Properties.Resources.PatchJson);
- }
-
- public void SetNewPatchJson(string json)
- {
- JavaScriptSerializer serializer = new JavaScriptSerializer();
- targetFiles = serializer.Deserialize>(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;
- }
-
- }
-}
diff --git a/RevokeMsgPatcher/Program.cs b/RevokeMsgPatcher/Program.cs
index 7c19d17..5046c55 100644
--- a/RevokeMsgPatcher/Program.cs
+++ b/RevokeMsgPatcher/Program.cs
@@ -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
}
diff --git a/RevokeMsgPatcher/Properties/AssemblyInfo.cs b/RevokeMsgPatcher/Properties/AssemblyInfo.cs
index 8154376..dd4e1df 100644
--- a/RevokeMsgPatcher/Properties/AssemblyInfo.cs
+++ b/RevokeMsgPatcher/Properties/AssemblyInfo.cs
@@ -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")]
diff --git a/RevokeMsgPatcher/Properties/Resources.Designer.cs b/RevokeMsgPatcher/Properties/Resources.Designer.cs
index a9f5581..23c3ae0 100644
--- a/RevokeMsgPatcher/Properties/Resources.Designer.cs
+++ b/RevokeMsgPatcher/Properties/Resources.Designer.cs
@@ -61,7 +61,7 @@ namespace RevokeMsgPatcher.Properties {
}
///
- /// 查找类似 [{"FileName":"WeChatWin.dll","Version":"2.6.8.65","SHA1Before":"e01f6855a96c12c30808960903ed199a33e4952c","SHA1After":"d9120569cfd0433aebea107d7b90805cbbac7518","Position":2454265,"Content":117},{"FileName":"WeChatWin.dll","Version":"2.6.8.52","SHA1Before":"88131302f664df6a657c9ca49d152da536fe5729","SHA1After":"8d1454b73831644181e962c1fa0ea4e2da4124a3","Position":2453049,"Content":117},{"FileName":"WeChatWin.dll","Version":"2.6.8.51","SHA1Before":"d0a5517b1292a751501b00b4b1f0702db2d9fc30","SHA1After":"53e7b [字符串的其余部分被截断]"; 的本地化字符串。
+ /// 查找类似 {"Apps":{"Wechat":{"Name":"Wechat","FileTargetInfos":{"WeChatWin.dll":{"Name":"WeChatWin.dll","RelativePath":"WeChatWin.dll","Memo":null}},"FileModifyInfos":{"WeChatWin.dll":[{"Name":"WeChatWin.dll","Version":"2.7.1.88","SHA1Before":"034059bad50dd793140952391bfa7936133e69b4","SHA1After":"dd6d80c30ca9e0ea9f7d2f1add498fc9aa4bc7a0","Changes":[{"Position":2499465,"Content":[235]},{"Position":7952304,"Content":[195]}]},{"Name":"WeChatWin.dll","Version":"2.7.1.85","SHA1Before":"de0df4e138b72460450f66c029e33f4510f [字符串的其余部分被截断]"; 的本地化字符串。
///
internal static string PatchJson {
get {
diff --git a/RevokeMsgPatcher/Properties/Resources.resx b/RevokeMsgPatcher/Properties/Resources.resx
index 166c0e1..84120cf 100644
--- a/RevokeMsgPatcher/Properties/Resources.resx
+++ b/RevokeMsgPatcher/Properties/Resources.resx
@@ -118,6 +118,6 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- [{"FileName":"WeChatWin.dll","Version":"2.6.8.65","SHA1Before":"e01f6855a96c12c30808960903ed199a33e4952c","SHA1After":"d9120569cfd0433aebea107d7b90805cbbac7518","Position":2454265,"Content":117},{"FileName":"WeChatWin.dll","Version":"2.6.8.52","SHA1Before":"88131302f664df6a657c9ca49d152da536fe5729","SHA1After":"8d1454b73831644181e962c1fa0ea4e2da4124a3","Position":2453049,"Content":117},{"FileName":"WeChatWin.dll","Version":"2.6.8.51","SHA1Before":"d0a5517b1292a751501b00b4b1f0702db2d9fc30","SHA1After":"53e7b1525d49bf2c3250a8131ff0ba2510779b78","Position":2452614,"Content":116},{"FileName":"WeChatWin.dll","Version":"2.6.8.37","SHA1Before":"7e01f8b04a158a4a50bc5a6e67c2fb8b02233170","SHA1After":"a1895004415fe9bcd7e690bd6e482b833b515599","Position":2452614,"Content":116},{"FileName":"WeChatWin.dll","Version":"2.6.7.57","SHA1Before":"80a91aaf941bcb1c24a7d672838ac73e9ebb2e40","SHA1After":"a0d3f9a45a835f97aef7fe0872387d8cfb5c25a4","Position":2433413,"Content":116},{"FileName":"WeChatWin.dll","Version":"2.6.7.40","SHA1Before":"04bd0cb28df6630b518f42a3f9c2caa4a9359fbc","SHA1After":"13c91cf1d4609959771fd137b9a86a5ca365e1b6","Position":2432934,"Content":116},{"FileName":"WeChatWin.dll","Version":"2.6.7.32","SHA1Before":"a02519c1007ee6723947c262c720d63c619f633e","SHA1After":"f3007471ca8734c29783c25f0bb49949a783a44","Position":2432806,"Content":116},{"FileName":"WeChatWin.dll","Version":"2.6.6.28","SHA1Before":"0b19cb17a62c3ea0efce0fb675a1d3b17845cba3","SHA1After":"260948656725446b818ea668273ceff02ddfb44d","Position":2401678,"Content":116}]
+ {"Apps":{"Wechat":{"Name":"Wechat","FileTargetInfos":{"WeChatWin.dll":{"Name":"WeChatWin.dll","RelativePath":"WeChatWin.dll","Memo":null}},"FileModifyInfos":{"WeChatWin.dll":[{"Name":"WeChatWin.dll","Version":"2.7.1.88","SHA1Before":"034059bad50dd793140952391bfa7936133e69b4","SHA1After":"dd6d80c30ca9e0ea9f7d2f1add498fc9aa4bc7a0","Changes":[{"Position":2499465,"Content":[235]},{"Position":7952304,"Content":[195]}]},{"Name":"WeChatWin.dll","Version":"2.7.1.85","SHA1Before":"de0df4e138b72460450f66c029e33f4510f5e2df","SHA1After":"fbd35720aaff3cdcfd3ff18ea503dc06450e5c99","Changes":[{"Position":2499465,"Content":[235]},{"Position":7952000,"Content":[195]}]},{"Name":"WeChatWin.dll","Version":"2.7.1.82","SHA1Before":"20e111a18872bf6c7148a897c11da26c1ec95520","SHA1After":"1e0741d325ca6b1cd2402b829a3d13a2524af617","Changes":[{"Position":2499465,"Content":[235]},{"Position":7951952,"Content":[195]}]},{"Name":"WeChatWin.dll","Version":"2.7.1.74","SHA1Before":"b1eaf7edc074a88be5d0f89230436cc2084d24d2","SHA1After":"eb3d74ccd87a09059a005f4972861898fc3de463","Changes":[{"Position":2499465,"Content":[235]},{"Position":7951696,"Content":[195]}]},{"Name":"WeChatWin.dll","Version":"2.7.1.65","SHA1Before":"8346b97d264725da924d240c6eb77df3e693385e","SHA1After":"42bab2c9c79ef4f2088c00ea6d817973e14a5e6e","Changes":[{"Position":2495545,"Content":[235]}]},{"Name":"WeChatWin.dll","Version":"2.7.1.59","SHA1Before":"df954d403edaca89cd5394927a325a0023e93281","SHA1After":"6aa22460c91bb5c5e2f0ec1af99b8a5f6d4318c0","Changes":[{"Position":2496073,"Content":[235]}]},{"Name":"WeChatWin.dll","Version":"2.7.1.43","SHA1Before":"39cd9e09e1a3eac09e6808749bff525c9e3216ce","SHA1After":"7b829f1ff0217e346a80f9510fdd7634ddd49445","Changes":[{"Position":2494169,"Content":[235]}]},{"Name":"WeChatWin.dll","Version":"2.7.0.70","SHA1Before":"3b0601864aff3c1d792f812ad1ca05f02aa761e3","SHA1After":"1e8734d32b0a8c12758e30f99c77f729991fb071","Changes":[{"Position":2475657,"Content":[235]}]},{"Name":"WeChatWin.dll","Version":"2.7.0.65","SHA1Before":"063c2e05a0df1bdb8987c2d978d93499bd2052ba","SHA1After":"5ed4c09a4f18643b967f063a824d7e65d0567f8a","Changes":[{"Position":2475449,"Content":[117]}]},{"Name":"WeChatWin.dll","Version":"2.6.8.68","SHA1Before":"2e9417f4276b12fe32ca7b4fee49272a4a2af334","SHA1After":"699602ee3cbb9ae5714f6e6ebc658c875a6c66e6","Changes":[{"Position":2454006,"Content":[116]}]},{"Name":"WeChatWin.dll","Version":"2.6.8.65","SHA1Before":"e01f6855a96c12c30808960903ed199a33e4952c","SHA1After":"d9120569cfd0433aebea107d7b90805cbbac7518","Changes":[{"Position":2454265,"Content":[117]}]},{"Name":"WeChatWin.dll","Version":"2.6.8.52","SHA1Before":"88131302f664df6a657c9ca49d152da536fe5729","SHA1After":"8d1454b73831644181e962c1fa0ea4e2da4124a3","Changes":[{"Position":2453049,"Content":[117]}]},{"Name":"WeChatWin.dll","Version":"2.6.8.51","SHA1Before":"d0a5517b1292a751501b00b4b1f0702db2d9fc30","SHA1After":"53e7b1525d49bf2c3250a8131ff0ba2510779b78","Changes":[{"Position":2452614,"Content":[116]}]},{"Name":"WeChatWin.dll","Version":"2.6.8.37","SHA1Before":"7e01f8b04a158a4a50bc5a6e67c2fb8b02233170","SHA1After":"a1895004415fe9bcd7e690bd6e482b833b515599","Changes":[{"Position":2452614,"Content":[116]}]},{"Name":"WeChatWin.dll","Version":"2.6.7.57","SHA1Before":"80a91aaf941bcb1c24a7d672838ac73e9ebb2e40","SHA1After":"a0d3f9a45a835f97aef7fe0872387d8cfb5c25a4","Changes":[{"Position":2433413,"Content":[116]}]},{"Name":"WeChatWin.dll","Version":"2.6.7.40","SHA1Before":"04bd0cb28df6630b518f42a3f9c2caa4a9359fbc","SHA1After":"13c91cf1d4609959771fd137b9a86a5ca365e1b6","Changes":[{"Position":2432934,"Content":[116]}]},{"Name":"WeChatWin.dll","Version":"2.6.7.32","SHA1Before":"a02519c1007ee6723947c262c720d63c619f633e","SHA1After":"f3007471ca8734c29783c25f0bb49949a783a44","Changes":[{"Position":2432806,"Content":[116]}]},{"Name":"WeChatWin.dll","Version":"2.6.6.28","SHA1Before":"0b19cb17a62c3ea0efce0fb675a1d3b17845cba3","SHA1After":"260948656725446b818ea668273ceff02ddfb44d","Changes":[{"Position":2401678,"Content":[116]}]}]}},"QQ":{"Name":"QQ","FileTargetInfos":{"IM.dll":{"Name":"IM.dll","RelativePath":"Bin\\IM.dll","Memo":null}},"FileModifyInfos":{"IM.dll":[{"Name":"IM.dll","Version":"9.2.2.26569","SHA1Before":"434254e76c520789558e075af677821258536311","SHA1After":"237c9e489a97858a175f0f7c72ade4ebcbac7a69","Changes":[{"Position":371146,"Content":[235,9,144,144,144]},{"Position":371687,"Content":[235,9,144,144,144]},{"Position":372117,"Content":[235,8,144,144,144,144]}]},{"Name":"IM.dll","Version":"9.2.1.26546","SHA1Before":"8d8ea2c2cbf43f5acf8d684b153e90035352d5f5","SHA1After":"7d194dd5be03982b533d7375c93d9a72587fe28d","Changes":[{"Position":369545,"Content":[235,9,144,144,144]},{"Position":370086,"Content":[235,9,144,144,144]},{"Position":370516,"Content":[235,8,144,144,144,144]}]},{"Name":"IM.dll","Version":"9.2.0.26453","SHA1Before":"c1935ca6347b0c2a7e6108a7f8ee0643d39deb66","SHA1After":"42811188a7e7b346a6a3c1066936b98c747acaf6","Changes":[{"Position":353794,"Content":[235,9,144,144,144]},{"Position":354335,"Content":[235,9,144,144,144]},{"Position":354767,"Content":[235,8,144,144,144,144]}]},{"Name":"IM.dll","Version":"9.2.0.26389","SHA1Before":"6f8855fb80acfa456f8f69989fe949308fe4d154","SHA1After":"f6b8e05a178b9b10ba17c597fa0a44b7a2a966a8","Changes":[{"Position":356808,"Content":[235,9,144,144,144]},{"Position":357349,"Content":[235,9,144,144,144]},{"Position":357781,"Content":[235,8,144,144,144,144]}]},{"Name":"IM.dll","Version":"9.1.9.26361","SHA1Before":"022d3433d13d07a354c38816f61cb0b7ac60d3fd","SHA1After":"873a57c1fb51cdd099c8cb7108b5ab5cb4459557","Changes":[{"Position":354270,"Content":[235,9,144,144,144]},{"Position":354811,"Content":[235,9,144,144,144]},{"Position":355243,"Content":[235,8,144,144,144,144]}]},{"Name":"IM.dll","Version":"9.1.9.26346","SHA1Before":"895eb70f707b8222e6460c91492b1281e525059b","SHA1After":"0bb83990e2b5b5f23b7b43249941ff638201af54","Changes":[{"Position":354270,"Content":[235,9,144,144,144]},{"Position":354811,"Content":[235,9,144,144,144]},{"Position":355243,"Content":[235,8,144,144,144,144]}]},{"Name":"IM.dll","Version":"9.1.8.26211","SHA1Before":"a950d3cf5e8925f7775624271105ef78d9c5cb57","SHA1After":"dffc1cb87b91e6467e13c935611f2f7fd76b9a8d","Changes":[{"Position":337135,"Content":[235,9,144,144,144]},{"Position":337676,"Content":[235,9,144,144,144]},{"Position":338108,"Content":[235,8,144,144,144,144]}]},{"Name":"IM.dll","Version":"9.1.7.25980","SHA1Before":"c6632339fbe675312a70ae4620e70699c258cd36","SHA1After":"e9ddc5cc681950796fc8fe4c55f580428c890b51","Changes":[{"Position":327839,"Content":[235,9,144,144,144]},{"Position":328380,"Content":[235,9,144,144,144]},{"Position":328812,"Content":[235,8,144,144,144,144]}]},{"Name":"IM.dll","Version":"9.0.4.23786","SHA1Before":"69a714f4eadb09f1453f6f022d4adbcd801cfab8","SHA1After":"b48e77a924076b3ebdffc4af514c868c551d2bca","Changes":[{"Position":318321,"Content":[235,7,144,144,144]},{"Position":318862,"Content":[235,7,144,144,144]},{"Position":319379,"Content":[235,7,144,144,144]}]}]}},"TIM":{"Name":"TIM","FileTargetInfos":{"IM.dll":{"Name":"IM.dll","RelativePath":"Bin\\IM.dll","Memo":null}},"FileModifyInfos":{"IM.dll":[{"Name":"IM.dll","Version":"2.3.2.21173","SHA1Before":"ecf3e69f3fb100ffe2fee095ffded591b9781024","SHA1After":"0514d1304e7ac46b4d33386ec3313888f5ae7171","Changes":[{"Position":317322,"Content":[235,9,144,144,144]},{"Position":317863,"Content":[235,9,144,144,144]},{"Position":318295,"Content":[235,8,144,144,144,144]}]}]}},"QQLite":{"Name":"QQLite","FileTargetInfos":{"IM.dll":{"Name":"IM.dll","RelativePath":"Bin\\IM.dll","Memo":null}},"FileModifyInfos":{"IM.dll":[{"Name":"IM.dll","Version":"7.9.14314.0","SHA1Before":"2e97d7671963fa148a1beeda6ce4964314310593","SHA1After":"723c008fb53435ead20fa6f2e951c9a4a8ff46da","Changes":[{"Position":148741,"Content":[235,2,144,144]},{"Position":149689,"Content":[235,2,144,144]}]},{"Name":"IM.dll","Version":"7.9.14308.0","SHA1Before":"b8a7a873178706b97be11c25f13bcf09e9e578a2","SHA1After":"c5bf533c7af6996b42d1fb2a0fb3f26dfd52f8bf","Changes":[{"Position":148741,"Content":[235,2,144,144]},{"Position":149689,"Content":[235,2,144,144]}]}]}}},"LatestVersion":"0.6","Notice":""}
\ No newline at end of file
diff --git a/RevokeMsgPatcher/RevokeMsgPatcher.csproj b/RevokeMsgPatcher/RevokeMsgPatcher.csproj
index 5b77683..561f33e 100644
--- a/RevokeMsgPatcher/RevokeMsgPatcher.csproj
+++ b/RevokeMsgPatcher/RevokeMsgPatcher.csproj
@@ -37,6 +37,7 @@
+
@@ -49,17 +50,31 @@
+
Form
FormMain.cs
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
FormMain.cs
diff --git a/RevokeMsgPatcher/Util.cs b/RevokeMsgPatcher/Util.cs
deleted file mode 100644
index 3b40939..0000000
--- a/RevokeMsgPatcher/Util.cs
+++ /dev/null
@@ -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
- {
-
- ///
- /// 自动查找安装路径
- ///
- /// 安装路径
- 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;
- }
-
- ///
- /// 通过文件是否存在判断是否是安装目录
- ///
- /// 安装目录
- ///
- public static bool IsWechatInstallPath(string path)
- {
- return File.Exists(Path.Combine(path, "WeChatWin.dll")) && File.Exists(Path.Combine(path, "WeChat.exe"));
- }
-
- ///
- /// 获取文件版本
- ///
- ///
- ///
- public static string GetFileVersion(string path)
- {
- FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(path);
- return fileVersionInfo.FileVersion;
- }
-
- ///
- /// 计算文件SHA1
- ///
- ///
- ///
- 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();
- }
-
- ///
- /// 修改文件指定位置的字节
- ///
- /// WeChatWin.dll 的路径
- /// 偏移位置
- /// 修改后的值
- ///
- 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;
-
- }
- }
-}
diff --git a/RevokeMsgPatcher/Utils/Device.cs b/RevokeMsgPatcher/Utils/Device.cs
new file mode 100644
index 0000000..be4d155
--- /dev/null
+++ b/RevokeMsgPatcher/Utils/Device.cs
@@ -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()
+ select x.GetPropertyValue("Caption")).FirstOrDefault();
+ osVersion = name != null ? name.ToString() : "Unknown";
+ }
+ return osVersion;
+ }
+ }
+ #endregion
+
+ ///
+ /// Calculate GUID
+ ///
+ /// GUID
+ 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
+ }
+}
diff --git a/RevokeMsgPatcher/Utils/FileUtil.cs b/RevokeMsgPatcher/Utils/FileUtil.cs
new file mode 100644
index 0000000..e7bb263
--- /dev/null
+++ b/RevokeMsgPatcher/Utils/FileUtil.cs
@@ -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
+ {
+ ///
+ /// 获取文件版本
+ ///
+ ///
+ ///
+ public static string GetFileVersion(string path)
+ {
+ FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(path);
+ return fileVersionInfo.FileVersion;
+ }
+
+ ///
+ /// 计算文件SHA1
+ ///
+ /// 文件路径
+ ///
+ 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();
+ }
+
+ ///
+ /// 修改文件指定位置的字节
+ ///
+ /// 文件对象的路径
+ /// 偏移位置
+ /// 修改后的值
+ ///
+ 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;
+
+ }
+
+ ///
+ /// 修改文件多个指定位置的多个字节
+ ///
+ /// 文件对象的路径
+ /// 需要修改的位置和内容
+ public static void EditMultiHex(string path, List 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);
+ }
+ }
+ }
+ }
+}
diff --git a/RevokeMsgPatcher/Utils/GAHelper.cs b/RevokeMsgPatcher/Utils/GAHelper.cs
new file mode 100644
index 0000000..fa8fd79
--- /dev/null
+++ b/RevokeMsgPatcher/Utils/GAHelper.cs
@@ -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
+{
+ ///
+ /// 用于软件的 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/
+ ///
+ 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
+ {
+ { "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));
+ }
+ }
+}
diff --git a/RevokeMsgPatcher/Utils/HttpUtil.cs b/RevokeMsgPatcher/Utils/HttpUtil.cs
new file mode 100644
index 0000000..90972d2
--- /dev/null
+++ b/RevokeMsgPatcher/Utils/HttpUtil.cs
@@ -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;
+ }
+
+ ///
+ /// 补丁路径
+ /// 已经弃用的路径
+ /// https://swordmaker-hauls-51508.netlify.com/i/revokemsg/05.json
+ /// https://huiyadanli.github.io/i/revokemsg/05.json
+ ///
+ 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 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();
+ }
+ }
+ }
+ }
+}
diff --git a/RevokeMsgPatcher/Utils/PathUtil.cs b/RevokeMsgPatcher/Utils/PathUtil.cs
new file mode 100644
index 0000000..61c547c
--- /dev/null
+++ b/RevokeMsgPatcher/Utils/PathUtil.cs
@@ -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();
+ }
+
+ ///
+ /// 从注册表中寻找安装路径
+ ///
+ ///
+ /// 安装信息的注册表键名
+ /// 微信:WeChat
+ /// QQ:{052CFB79-9D62-42E3-8A15-DE66C2C97C3E}
+ /// TIM:TIM
+ ///
+ /// 安装路径
+ 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;
+ }
+
+ ///
+ /// 获取所有可能的默认安装路径
+ ///
+ /// Tencent\*
+ ///
+ public static List GetDefaultInstallPaths(string relativePath)
+ {
+ List list = new List();
+ // 从默认安装目录查找
+ 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;
+ }
+ }
+}
diff --git a/RevokeMsgPatcher/icon.ico b/RevokeMsgPatcher/icon.ico
index cf59834..28f14bd 100644
Binary files a/RevokeMsgPatcher/icon.ico and b/RevokeMsgPatcher/icon.ico differ