├── .github
├── ISSUE_TEMPLATE
│ ├── config.yml
│ └── new_version.yml
└── workflows
│ └── build.yml
├── .gitignore
├── Images
├── give_a_star.png
├── logo.png
├── logo_old.jpg
├── revoke.jpg
├── screenshot.mi.png
├── screenshot.png
├── screenshot.v0.4.png
├── screenshot.v0.5.png
├── screenshot.v0.6.png
├── screenshot.v0.7.png
├── screenshot.v0.8.png
├── screenshot.v0.9.png
├── watch_release.png
└── wiki
│ ├── qq
│ ├── 1.png
│ ├── 10.png
│ ├── 11.png
│ ├── 12.png
│ ├── 13.png
│ ├── 2.png
│ ├── 3.png
│ ├── 4.png
│ ├── 5.png
│ ├── 6.png
│ ├── 7.png
│ ├── 8.png
│ └── 9.png
│ └── wechat
│ ├── 10_mutex.png
│ ├── 11_push_ebp_to_ret.png
│ ├── 12_push_ebp_to_ret.png
│ ├── 13_push_ebp_to_ret.png
│ ├── 14_patch_dll.png
│ ├── 1_start.png
│ ├── 2_click_attach.png
│ ├── 3_attach_wechat_exe.png
│ ├── 4_wechatwin_dll.png
│ ├── 5_search_string.png
│ ├── 6_revokemsg_1.png
│ ├── 7_je_to_jmp.png
│ ├── 8_je_to_jmp.png
│ └── 9_je_to_jmp.png
├── LICENSE
├── README.md
├── RevokeMsgPatcher.Assistant
├── App.config
├── Data
│ ├── 0.7
│ │ └── patch.json
│ ├── 0.8
│ │ └── patch.json
│ ├── 0.9
│ │ └── patch.json
│ ├── 1.0
│ │ └── patch.json
│ ├── 1.1
│ │ └── patch.json
│ ├── 1.2
│ │ └── patch.json
│ ├── 1.3
│ │ └── patch.json
│ ├── 1.4
│ │ └── patch.json
│ ├── 1.5
│ │ └── patch.json
│ ├── 1.6
│ │ └── patch.json
│ ├── 1.7
│ │ └── patch.json
│ ├── 1.8
│ │ └── patch.json
│ ├── 1.9
│ │ └── patch.json
│ └── 2.0
│ │ └── patch.json
├── FormAssisant.Designer.cs
├── FormAssisant.cs
├── FormAssisant.resx
├── JsonData.cs
├── Program.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
└── RevokeMsgPatcher.Assistant.csproj
├── RevokeMsgPatcher.Launcher
├── App.config
├── FormMain.Designer.cs
├── FormMain.cs
├── FormMain.resx
├── Program.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
└── RevokeMsgPatcher.Launcher.csproj
├── RevokeMsgPatcher.MultiInstance
├── App.config
├── FormMultiInstance.Designer.cs
├── FormMultiInstance.cs
├── FormMultiInstance.resx
├── ProcessUtil.cs
├── Program.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── README.md
├── RevokeMsgPatcher.MultiInstance.csproj
├── WechatProcess.cs
└── app.manifest
├── RevokeMsgPatcher.sln
├── RevokeMsgPatcher
├── App.config
├── BusinessException.cs
├── FormMain.Designer.cs
├── FormMain.cs
├── FormMain.resx
├── Forms
│ ├── FormLiteLoaderQQNT.Designer.cs
│ ├── FormLiteLoaderQQNT.cs
│ ├── FormLiteLoaderQQNT.resx
│ ├── FormPatchInfo.Designer.cs
│ ├── FormPatchInfo.cs
│ ├── FormPatchInfo.resx
│ └── UIController.cs
├── Matcher
│ ├── BoyerMooreMatcher.cs
│ ├── FuzzyMatcher.cs
│ └── ModifyFinder.cs
├── Model
│ ├── App.cs
│ ├── Bag.cs
│ ├── Change.cs
│ ├── CommonModifyInfo.cs
│ ├── Json
│ │ ├── LiteLoaderPackage.cs
│ │ ├── LiteLoaderPluginsManifest.cs
│ │ ├── ReleaseApiRes.cs
│ │ └── VersionJson.cs
│ ├── LiteLoaderRowData.cs
│ ├── ModifyInfo.cs
│ ├── ReplacePattern.cs
│ └── TargetInfo.cs
├── Modifier
│ ├── AppModifier.cs
│ ├── FileHexEditor.cs
│ ├── QQLiteModifier.cs
│ ├── QQModifier.cs
│ ├── QQNTModifier.cs
│ ├── TIMModifier.cs
│ ├── WechatModifier.cs
│ └── WeixinModifier.cs
├── Program.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── RevokeMsgPatcher.csproj
├── Utils
│ ├── ByteUtil.cs
│ ├── Device.cs
│ ├── FileUtil.cs
│ ├── GAHelper.cs
│ ├── HttpUtil.cs
│ ├── PathUtil.cs
│ ├── ProxySpeedTester.cs
│ └── VersionUtil.cs
├── app.manifest
├── icon.ico
└── packages.config
└── appveyor.yml
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/.github/ISSUE_TEMPLATE/config.yml
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/new_version.yml:
--------------------------------------------------------------------------------
1 | name: 版本支持
2 | description: 发现有未支持的版本,且 Issue 列表中暂无人提出相同版本未支持的问题,可以通过创建这个 Issue 进行反馈
3 | title: "[未支持版本]: "
4 | assignees:
5 | - huiyadanli
6 | body:
7 | - type: markdown
8 | attributes:
9 | value: |
10 | 请按下方的要求填写完整的问题表单,方便作者进行更新。
11 |
12 | - type: checkboxes
13 | id: lastest
14 | attributes:
15 | label: 请先确认当前使用的 微信/QQ/TIM防撤回补丁 是最新版本!
16 | description: 提交此 Issue 前请先确认你使用的是[最新 Release 版本的软件](https://github.com/huiyadanli/RevokeMsgPatcher/releases)
17 | options:
18 | - label: 我确认当前使用的是最新版
19 | required: true
20 |
21 | - type: input
22 | id: version
23 | attributes:
24 | label: 微信/QQ 版本
25 | description: |
26 | 请填写完整版本号,并写清楚是正式版还是测试版。
27 | placeholder: 例:微信正式版 3.6.0.18
28 | validations:
29 | required: true
30 |
31 | - type: input
32 | id: url
33 | attributes:
34 | label: 对应版本的下载地址
35 | description: 如果是从某个链接下载的对应版本,请把链接附上。测试版本请务必附上下载链接!
36 | placeholder: 例:https://dldir1.qq.com/weixin/Windows/WeChatSetup.exe
37 |
38 | - type: textarea
39 | id: tips
40 | attributes:
41 | label: 软件提示了什么?
42 | description: 你的操作流程简述,和软件安装补丁失败后的提示,建议附上截图。
43 | validations:
44 | required: true
45 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: .Net Build
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | Reason:
7 | description: 'Reasons for temporary build'
8 | required: true
9 | default: 'No reason.Just do it.'
10 | push:
11 | branches:
12 | - master
13 | paths-ignore:
14 | - '**/*.md'
15 | - .gitignore
16 | - .editorconfig
17 | - appveyor.yml
18 |
19 | pull_request:
20 | branches:
21 | - master
22 | paths-ignore:
23 | - '**/*.md'
24 | - .gitignore
25 | - .editorconfig
26 | - appveyor.yml
27 |
28 | env:
29 | # Path to the solution file relative to the root of the project.
30 | SOLUTION_FILE_PATH: .
31 |
32 | # Configuration type to build.
33 | # You can convert this to a build matrix if you need coverage of multiple configuration types.
34 | # https://docs.github.com/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
35 | #BUILD_CONFIGURATION: [Debug , Release]
36 |
37 | jobs:
38 | build:
39 | name: ${{matrix.BUILD_CONFIGURATION}}
40 | runs-on: windows-2019
41 | strategy:
42 | matrix:
43 | BUILD_CONFIGURATION: ['Debug', 'Release']
44 | steps:
45 | - uses: actions/checkout@v2
46 |
47 | - name: Add MSBuild to PATH
48 | uses: microsoft/setup-msbuild@v1.0.2
49 |
50 | - name: Restore NuGet packages
51 | working-directory: ${{env.GITHUB_WORKSPACE}}
52 | run: nuget restore ${{env.SOLUTION_FILE_PATH}}
53 |
54 | - name: Build ${{matrix.BUILD_CONFIGURATION}}
55 | working-directory: ${{env.GITHUB_WORKSPACE}}
56 | # Add additional options to the MSBuild command line here (like platform or verbosity level).
57 | # See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference
58 | run: msbuild /m /p:Configuration=${{matrix.BUILD_CONFIGURATION}} ${{env.SOLUTION_FILE_PATH}}
59 |
60 | - name: Upload Artifact
61 | uses: actions/upload-artifact@v4
62 | with:
63 | name: RevokeMsgPatcher-${{matrix.BUILD_CONFIGURATION}}
64 | path: |
65 | .\RevokeMsgPatcher\bin
66 | !.\RevokeMsgPatcher\bin\**\RevokeMsgPatcher.exe.config
67 | !.\RevokeMsgPatcher\bin\**\RevokeMsgPatcher.pdb
68 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # User-specific files
2 | *.suo
3 | *.user
4 | *.userosscache
5 | *.sln.docstates
6 | .vs/
7 |
8 | # User-specific files (MonoDevelop/Xamarin Studio)
9 | *.userprefs
10 |
11 | # Build results
12 | [Dd]ebug/
13 | [Dd]ebugPublic/
14 | [Rr]elease/
15 | [Rr]eleases/
16 | x64/
17 | x86/
18 | bld/
19 | [Bb]in/
20 | [Oo]bj/
21 | [Ll]og/
22 |
23 | # Mine
24 | Temp/
25 | /packages/
26 |
--------------------------------------------------------------------------------
/Images/give_a_star.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/give_a_star.png
--------------------------------------------------------------------------------
/Images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/logo.png
--------------------------------------------------------------------------------
/Images/logo_old.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/logo_old.jpg
--------------------------------------------------------------------------------
/Images/revoke.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/revoke.jpg
--------------------------------------------------------------------------------
/Images/screenshot.mi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/screenshot.mi.png
--------------------------------------------------------------------------------
/Images/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/screenshot.png
--------------------------------------------------------------------------------
/Images/screenshot.v0.4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/screenshot.v0.4.png
--------------------------------------------------------------------------------
/Images/screenshot.v0.5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/screenshot.v0.5.png
--------------------------------------------------------------------------------
/Images/screenshot.v0.6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/screenshot.v0.6.png
--------------------------------------------------------------------------------
/Images/screenshot.v0.7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/screenshot.v0.7.png
--------------------------------------------------------------------------------
/Images/screenshot.v0.8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/screenshot.v0.8.png
--------------------------------------------------------------------------------
/Images/screenshot.v0.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/screenshot.v0.9.png
--------------------------------------------------------------------------------
/Images/watch_release.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/watch_release.png
--------------------------------------------------------------------------------
/Images/wiki/qq/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/wiki/qq/1.png
--------------------------------------------------------------------------------
/Images/wiki/qq/10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/wiki/qq/10.png
--------------------------------------------------------------------------------
/Images/wiki/qq/11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/wiki/qq/11.png
--------------------------------------------------------------------------------
/Images/wiki/qq/12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/wiki/qq/12.png
--------------------------------------------------------------------------------
/Images/wiki/qq/13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/wiki/qq/13.png
--------------------------------------------------------------------------------
/Images/wiki/qq/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/wiki/qq/2.png
--------------------------------------------------------------------------------
/Images/wiki/qq/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/wiki/qq/3.png
--------------------------------------------------------------------------------
/Images/wiki/qq/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/wiki/qq/4.png
--------------------------------------------------------------------------------
/Images/wiki/qq/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/wiki/qq/5.png
--------------------------------------------------------------------------------
/Images/wiki/qq/6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/wiki/qq/6.png
--------------------------------------------------------------------------------
/Images/wiki/qq/7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/wiki/qq/7.png
--------------------------------------------------------------------------------
/Images/wiki/qq/8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/wiki/qq/8.png
--------------------------------------------------------------------------------
/Images/wiki/qq/9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/wiki/qq/9.png
--------------------------------------------------------------------------------
/Images/wiki/wechat/10_mutex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/wiki/wechat/10_mutex.png
--------------------------------------------------------------------------------
/Images/wiki/wechat/11_push_ebp_to_ret.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/wiki/wechat/11_push_ebp_to_ret.png
--------------------------------------------------------------------------------
/Images/wiki/wechat/12_push_ebp_to_ret.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/wiki/wechat/12_push_ebp_to_ret.png
--------------------------------------------------------------------------------
/Images/wiki/wechat/13_push_ebp_to_ret.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/wiki/wechat/13_push_ebp_to_ret.png
--------------------------------------------------------------------------------
/Images/wiki/wechat/14_patch_dll.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/wiki/wechat/14_patch_dll.png
--------------------------------------------------------------------------------
/Images/wiki/wechat/1_start.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/wiki/wechat/1_start.png
--------------------------------------------------------------------------------
/Images/wiki/wechat/2_click_attach.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/wiki/wechat/2_click_attach.png
--------------------------------------------------------------------------------
/Images/wiki/wechat/3_attach_wechat_exe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/wiki/wechat/3_attach_wechat_exe.png
--------------------------------------------------------------------------------
/Images/wiki/wechat/4_wechatwin_dll.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/wiki/wechat/4_wechatwin_dll.png
--------------------------------------------------------------------------------
/Images/wiki/wechat/5_search_string.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/wiki/wechat/5_search_string.png
--------------------------------------------------------------------------------
/Images/wiki/wechat/6_revokemsg_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/wiki/wechat/6_revokemsg_1.png
--------------------------------------------------------------------------------
/Images/wiki/wechat/7_je_to_jmp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/wiki/wechat/7_je_to_jmp.png
--------------------------------------------------------------------------------
/Images/wiki/wechat/8_je_to_jmp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/wiki/wechat/8_je_to_jmp.png
--------------------------------------------------------------------------------
/Images/wiki/wechat/9_je_to_jmp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/Images/wiki/wechat/9_je_to_jmp.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | # 👀微信/QQ/TIM防撤回补丁
18 | 适用于 Windows 下 PC 版微信/QQ/TIM的防撤回补丁。**支持最新版微信/QQ/TIM**,其中微信能够选择安装多开功能。
19 |
20 |
21 |
22 | 下载地址:
23 | **[⚡️点我下载最新版本](https://github.com/huiyadanli/RevokeMsgPatcher/releases/download/2.0/RevokeMsgPatcher.v2.0.zip)** |
24 | [☁备用下载-蓝奏云](https://wwmy.lanzouq.com/b0fot7dpe) 密码:coco|
25 | [☁备用下载-百度云](https://pan.baidu.com/s/15ilr78t8F1-VW8eUZSkr_Q?pwd=3rrj)
26 |
27 | 相关文档:
28 | **[✔支持哪些版本](https://github.com/huiyadanli/RevokeMsgPatcher/wiki/%E7%89%88%E6%9C%AC%E6%94%AF%E6%8C%81)** |
29 | [❓常见问题](https://github.com/huiyadanli/RevokeMsgPatcher/wiki#%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98) |
30 | [📖查看完整文档](https://github.com/huiyadanli/RevokeMsgPatcher/wiki)
31 |
32 | 原理与方法:
33 | [📗微信](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) |
34 | [📕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) |
35 | [📘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)
36 | **(本人不参与方法寻找,仅做特征搬运)**
37 |
38 | 附带产物:[一个通用的微信多开工具](https://github.com/huiyadanli/RevokeMsgPatcher/tree/master/RevokeMsgPatcher.MultiInstance)
39 |
40 | ## 📷截图
41 | 
42 |
43 | ## 🔨使用方法
44 |
45 | 1. 首先,你的系统需要满足以下条件:
46 |
47 | * Windows 7 或更高版本,**不支持XP**。
48 | * [.NET Framework 4.5.2](https://www.microsoft.com/en-us/download/details.aspx?id=42642) 或更高版本。**低于此版本在打开程序时可能无反应,或者直接报错**。
49 |
50 | 2. 使用本程序前,先关闭微信/QQ/TIM。
51 |
52 | 3. **以管理员身份运行本程序**,等待右下角获取最新的补丁信息。
53 |
54 | 4. 选择微信/QQ/TIM的安装路径。如果你用的安装版的微信/QQ/TIM,正常情况下本程序会自动从注册表中获取安装路径,绿色版需要手动选择路径。
55 |
56 | 5. 点击防撤回。界面可能会出现一段时间的无响应,请耐心等待。**由于修改了微信的 WeChatWin.dll 文件、QQ/TIM的 IM.dll 文件,杀毒软件可能会弹出警告,放行即可。**
57 |
58 | 注意:微信/QQ/TIM更新之后要重新安装补丁!
59 |
60 | ## 💡致谢
61 |
62 | 本项目早期内容源自 [wechat_anti_revoke](https://github.com/36huo/wechat_anti_revoke) 项目。
63 |
64 | QQNT 防撤回依赖于 [LiteLoaderQQNT](https://github.com/LiteLoaderQQNT/LiteLoaderQQNT),修补依赖于 [DLLHijackMethod](https://github.com/LiteLoaderQQNT/QQNTFileVerifyPatch/tree/DLLHijackMethod) 并集成了以下插件:
65 |
66 | * [插件列表查看 LL-plugin-list-viewer](https://github.com/ltxhhz/LL-plugin-list-viewer)
67 | * [防撤回 LiteLoaderQQNT-Anti-Recall](https://github.com/xh321/LiteLoaderQQNT-Anti-Recall)
68 |
69 | 微信4.0版本后的防撤回特征来自于 [BetterWX](https://github.com/zetaloop/BetterWX)
70 |
71 | ## ❤️投喂
72 |
73 | 觉的好用的话,可以支持作者哟ヾ(・ω・`。)
74 | * [⚡爱发电](https://afdian.com/@huiyadanli)
75 | * [🍚微信赞赏](https://github.com/huiyadanli/huiyadanli/blob/master/DONATE.md)
76 |
77 | ## 📄License
78 | [GPLv3](https://github.com/huiyadanli/RevokeMsgPatcher/blob/master/LICENSE)
79 |
80 | 
81 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.Assistant/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.Assistant/FormAssisant.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace RevokeMsgPatcher.Assistant
2 | {
3 | partial class FormAssisant
4 | {
5 | ///
6 | /// 必需的设计器变量。
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// 清理所有正在使用的资源。
12 | ///
13 | /// 如果应释放托管资源,为 true;否则为 false。
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows 窗体设计器生成的代码
24 |
25 | ///
26 | /// 设计器支持所需的方法 - 不要修改
27 | /// 使用代码编辑器修改此方法的内容。
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.txtInfo = new System.Windows.Forms.TextBox();
32 | this.btnSearch = new System.Windows.Forms.Button();
33 | this.btnGetVersion = new System.Windows.Forms.Button();
34 | this.SuspendLayout();
35 | //
36 | // txtInfo
37 | //
38 | this.txtInfo.Location = new System.Drawing.Point(12, 12);
39 | this.txtInfo.Multiline = true;
40 | this.txtInfo.Name = "txtInfo";
41 | this.txtInfo.Size = new System.Drawing.Size(484, 182);
42 | this.txtInfo.TabIndex = 0;
43 | //
44 | // btnSearch
45 | //
46 | this.btnSearch.Location = new System.Drawing.Point(12, 211);
47 | this.btnSearch.Name = "btnSearch";
48 | this.btnSearch.Size = new System.Drawing.Size(75, 23);
49 | this.btnSearch.TabIndex = 1;
50 | this.btnSearch.Text = "查找测试";
51 | this.btnSearch.UseVisualStyleBackColor = true;
52 | this.btnSearch.Click += new System.EventHandler(this.btnSearch_Click);
53 | //
54 | // btnGetVersion
55 | //
56 | this.btnGetVersion.Location = new System.Drawing.Point(106, 211);
57 | this.btnGetVersion.Name = "btnGetVersion";
58 | this.btnGetVersion.Size = new System.Drawing.Size(91, 23);
59 | this.btnGetVersion.TabIndex = 2;
60 | this.btnGetVersion.Text = "获取文件版本";
61 | this.btnGetVersion.UseVisualStyleBackColor = true;
62 | this.btnGetVersion.Click += new System.EventHandler(this.btnGetVersion_Click);
63 | //
64 | // FormAssisant
65 | //
66 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
67 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
68 | this.ClientSize = new System.Drawing.Size(508, 252);
69 | this.Controls.Add(this.btnGetVersion);
70 | this.Controls.Add(this.btnSearch);
71 | this.Controls.Add(this.txtInfo);
72 | this.Name = "FormAssisant";
73 | this.Text = "冷血无情的助手界面";
74 | this.Load += new System.EventHandler(this.FormMain_Load);
75 | this.ResumeLayout(false);
76 | this.PerformLayout();
77 |
78 | }
79 |
80 | #endregion
81 |
82 | private System.Windows.Forms.TextBox txtInfo;
83 | private System.Windows.Forms.Button btnSearch;
84 | private System.Windows.Forms.Button btnGetVersion;
85 | }
86 | }
87 |
88 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.Assistant/FormAssisant.cs:
--------------------------------------------------------------------------------
1 | using RevokeMsgPatcher.Matcher;
2 | using RevokeMsgPatcher.Model;
3 | using RevokeMsgPatcher.Utils;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Windows.Forms;
9 |
10 | namespace RevokeMsgPatcher.Assistant
11 | {
12 | public partial class FormAssisant : Form
13 | {
14 | public FormAssisant()
15 | {
16 | InitializeComponent();
17 | }
18 |
19 | private void FormMain_Load(object sender, EventArgs e)
20 | {
21 | JsonData obj = new JsonData();
22 | string json = obj.BagJson();
23 | Console.WriteLine(json);
24 |
25 | DirectoryInfo directory = new DirectoryInfo("../../Data/" + obj.Bag().LatestVersion);
26 | if (!directory.Exists)
27 | {
28 | directory.Create();
29 | }
30 | string path = Path.Combine(directory.FullName, "patch.json");
31 | File.WriteAllText(path, json);
32 |
33 | txtInfo.AppendText("生成完毕!位置:" + path + Environment.NewLine);
34 | }
35 |
36 | private void btnSearch_Click(object sender, EventArgs e)
37 | {
38 | byte[] fileByteArray = File.ReadAllBytes(@"");
39 | byte[] searchBytes = ByteUtil.HexStringToByteArray("1C E9 9D 00 00 00 8B 45 E8 8D 55 EC 52 89 5D EC 68 3F 3F 3F 54 8B 08 50 FF 51 78 85 C0 79 2D 8D 45 0C C7 45 0C");
40 | byte[] replaceBytes = ByteUtil.HexStringToByteArray("1C E9 9D 00 00 00 8B 45 E8 8D 55 EC 52 89 5D EC EB 09 90 90 90 8B 08 50 FF 51 78 85 C0 79 2D 8D 45 0C C7 45 0C");
41 | //int[] indexs = FuzzyMatcher.MatchAll(fileByteArray, searchBytes);
42 | int[] indexs = FuzzyMatcher.MatchNotReplaced(fileByteArray, searchBytes, replaceBytes);
43 | txtInfo.AppendText("查找结果位置:" + string.Join(",", indexs) + Environment.NewLine);
44 | // 371130
45 |
46 | List changes = ComputChanges(indexs, searchBytes, replaceBytes);
47 | foreach (Change c in changes)
48 | {
49 | txtInfo.AppendText("替换位置:" + Convert.ToString(c.Position, 16) + " 替换内容:" + ByteUtil.ByteArrayToHexString(c.Content) + Environment.NewLine);
50 | }
51 |
52 | }
53 |
54 | public static List ComputChanges(int[] indexs, byte[] searchBytes, byte[] replaceBytes)
55 | {
56 | if (searchBytes.Length != replaceBytes.Length)
57 | {
58 | throw new Exception("查询串与替换串长度不同!");
59 | }
60 | // 一个替换串存在多个替换点的情况
61 | List changeOffsets = new List(); // 查询串与替换串变化偏移
62 | List diff = null;
63 | for (int i = 0; i < searchBytes.Length; i++)
64 | {
65 | if (searchBytes[i] != replaceBytes[i])
66 | {
67 | if (diff == null)
68 | {
69 | diff = new List();
70 | Change offset = new Change
71 | {
72 | Position = i
73 | };
74 | changeOffsets.Add(offset);
75 | }
76 | diff.Add(replaceBytes[i]);
77 | }
78 | else
79 | {
80 | if (diff != null)
81 | {
82 | changeOffsets.Last().Content = diff.ToArray();
83 | diff = null;
84 | }
85 | }
86 | }
87 | // 最后一位也是要被替换的情况
88 | if (diff != null)
89 | {
90 | changeOffsets.Last().Content = diff.ToArray();
91 | diff = null;
92 | }
93 |
94 | if (changeOffsets.Count == 0)
95 | {
96 | throw new Exception("查询串与替换串完全相同!请确认补丁信息的正确性。");
97 | }
98 |
99 | List changes = new List();
100 | foreach (int index in indexs)
101 | {
102 | foreach (Change offset in changeOffsets)
103 | {
104 | Change c = offset.Clone();
105 | c.Position += index;
106 | changes.Add(c);
107 | }
108 | }
109 | return changes;
110 | }
111 |
112 | private void btnGetVersion_Click(object sender, EventArgs e)
113 | {
114 | string version = FileUtil.GetFileVersion(@"");
115 | txtInfo.AppendText("文件版本:" + version + Environment.NewLine);
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.Assistant/FormAssisant.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.Assistant/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using System.Windows.Forms;
6 |
7 | namespace RevokeMsgPatcher.Assistant
8 | {
9 | static class Program
10 | {
11 | ///
12 | /// 应用程序的主入口点。
13 | ///
14 | [STAThread]
15 | static void Main()
16 | {
17 | Application.EnableVisualStyles();
18 | Application.SetCompatibleTextRenderingDefault(false);
19 | Application.Run(new FormAssisant());
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.Assistant/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // 有关程序集的一般信息由以下
6 | // 控制。更改这些特性值可修改
7 | // 与程序集关联的信息。
8 | [assembly: AssemblyTitle("RevokeMsgPatcher.Assistant")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("RevokeMsgPatcher.Assistant")]
13 | [assembly: AssemblyCopyright("Copyright © 2019")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // 将 ComVisible 设置为 false 会使此程序集中的类型
18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
19 | //请将此类型的 ComVisible 特性设置为 true。
20 | [assembly: ComVisible(false)]
21 |
22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
23 | [assembly: Guid("6992004f-17e6-45bf-8d72-180a31e9c23c")]
24 |
25 | // 程序集的版本信息由下列四个值组成:
26 | //
27 | // 主版本
28 | // 次版本
29 | // 生成号
30 | // 修订号
31 | //
32 | // 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
33 | // 方法是按如下所示使用“*”: :
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.Assistant/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // 此代码由工具生成。
4 | // 运行时版本:4.0.30319.42000
5 | //
6 | // 对此文件的更改可能会导致不正确的行为,并且如果
7 | // 重新生成代码,这些更改将会丢失。
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace RevokeMsgPatcher.Assistant.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// 一个强类型的资源类,用于查找本地化的字符串等。
17 | ///
18 | // 此类是由 StronglyTypedResourceBuilder
19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
20 | // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
21 | // (以 /str 作为命令选项),或重新生成 VS 项目。
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// 返回此类使用的缓存的 ResourceManager 实例。
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RevokeMsgPatcher.Assistant.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// 重写当前线程的 CurrentUICulture 属性,对
51 | /// 使用此强类型资源类的所有资源查找执行重写。
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.Assistant/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.Assistant/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // 此代码由工具生成。
4 | // 运行时版本:4.0.30319.42000
5 | //
6 | // 对此文件的更改可能会导致不正确的行为,并且如果
7 | // 重新生成代码,这些更改将会丢失。
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace RevokeMsgPatcher.Assistant.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.1.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.Assistant/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.Assistant/RevokeMsgPatcher.Assistant.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {6992004F-17E6-45BF-8D72-180A31E9C23C}
8 | WinExe
9 | RevokeMsgPatcher.Assistant
10 | RevokeMsgPatcher.Assistant
11 | v4.5.2
12 | 512
13 | true
14 | publish\
15 | true
16 | Disk
17 | false
18 | Foreground
19 | 7
20 | Days
21 | false
22 | false
23 | true
24 | 0
25 | 1.0.0.%2a
26 | false
27 | false
28 | true
29 |
30 |
31 |
32 | AnyCPU
33 | true
34 | full
35 | false
36 | bin\Debug\
37 | DEBUG;TRACE
38 | prompt
39 | 4
40 |
41 |
42 | AnyCPU
43 | pdbonly
44 | true
45 | bin\Release\
46 | TRACE
47 | prompt
48 | 4
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | Form
67 |
68 |
69 | FormAssisant.cs
70 |
71 |
72 |
73 |
74 |
75 | FormAssisant.cs
76 |
77 |
78 | ResXFileCodeGenerator
79 | Resources.Designer.cs
80 | Designer
81 |
82 |
83 | True
84 | Resources.resx
85 | True
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 | SettingsSingleFileGenerator
103 | Settings.Designer.cs
104 |
105 |
106 | True
107 | Settings.settings
108 | True
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 | False
117 | .NET Framework 3.5 SP1
118 | false
119 |
120 |
121 |
122 |
123 | {977bf781-ced8-4389-9404-0fa08fdf21df}
124 | RevokeMsgPatcher
125 |
126 |
127 |
128 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.Launcher/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.Launcher/FormMain.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace RevokeMsgPatcher.Launcher
2 | {
3 | partial class FormMain
4 | {
5 | ///
6 | /// 必需的设计器变量。
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// 清理所有正在使用的资源。
12 | ///
13 | /// 如果应释放托管资源,为 true;否则为 false。
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows 窗体设计器生成的代码
24 |
25 | ///
26 | /// 设计器支持所需的方法 - 不要修改
27 | /// 使用代码编辑器修改此方法的内容。
28 | ///
29 | private void InitializeComponent()
30 | {
31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormMain));
32 | this.tabControl = new System.Windows.Forms.TabControl();
33 | this.tabQQNT = new System.Windows.Forms.TabPage();
34 | this.tabControl.SuspendLayout();
35 | this.SuspendLayout();
36 | //
37 | // tabControl
38 | //
39 | this.tabControl.Controls.Add(this.tabQQNT);
40 | this.tabControl.Dock = System.Windows.Forms.DockStyle.Fill;
41 | this.tabControl.Location = new System.Drawing.Point(0, 0);
42 | this.tabControl.Name = "tabControl";
43 | this.tabControl.SelectedIndex = 0;
44 | this.tabControl.Size = new System.Drawing.Size(411, 446);
45 | this.tabControl.TabIndex = 0;
46 | //
47 | // tabQQNT
48 | //
49 | this.tabQQNT.Location = new System.Drawing.Point(4, 22);
50 | this.tabQQNT.Name = "tabQQNT";
51 | this.tabQQNT.Padding = new System.Windows.Forms.Padding(3);
52 | this.tabQQNT.Size = new System.Drawing.Size(403, 420);
53 | this.tabQQNT.TabIndex = 0;
54 | this.tabQQNT.Text = "QQNT";
55 | this.tabQQNT.UseVisualStyleBackColor = true;
56 | //
57 | // FormMain
58 | //
59 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
60 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
61 | this.ClientSize = new System.Drawing.Size(411, 446);
62 | this.Controls.Add(this.tabControl);
63 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
64 | this.Name = "FormMain";
65 | this.Text = "RevokeMsgPatcher 防撤回启动器";
66 | this.tabControl.ResumeLayout(false);
67 | this.ResumeLayout(false);
68 |
69 | }
70 |
71 | #endregion
72 |
73 | private System.Windows.Forms.TabControl tabControl;
74 | private System.Windows.Forms.TabPage tabQQNT;
75 | }
76 | }
77 |
78 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.Launcher/FormMain.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Data;
5 | using System.Drawing;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Windows.Forms;
10 |
11 | namespace RevokeMsgPatcher.Launcher
12 | {
13 | public partial class FormMain : Form
14 | {
15 | public FormMain()
16 | {
17 | InitializeComponent();
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.Launcher/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using System.Windows.Forms;
6 |
7 | namespace RevokeMsgPatcher.Launcher
8 | {
9 | internal static class Program
10 | {
11 | ///
12 | /// 应用程序的主入口点。
13 | ///
14 | [STAThread]
15 | static void Main()
16 | {
17 | Application.EnableVisualStyles();
18 | Application.SetCompatibleTextRenderingDefault(false);
19 | Application.Run(new FormMain());
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.Launcher/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // 有关程序集的一般信息由以下
6 | // 控制。更改这些特性值可修改
7 | // 与程序集关联的信息。
8 | [assembly: AssemblyTitle("RevokeMsgPatcher.Launcher")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("RevokeMsgPatcher.Launcher")]
13 | [assembly: AssemblyCopyright("Copyright © 2024")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // 将 ComVisible 设置为 false 会使此程序集中的类型
18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
19 | //请将此类型的 ComVisible 特性设置为 true。
20 | [assembly: ComVisible(false)]
21 |
22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
23 | [assembly: Guid("b1d05208-e291-406b-a8b4-f673ec784b1c")]
24 |
25 | // 程序集的版本信息由下列四个值组成:
26 | //
27 | // 主版本
28 | // 次版本
29 | // 生成号
30 | // 修订号
31 | //
32 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
33 | //通过使用 "*",如下所示:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.Launcher/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // 此代码由工具生成。
4 | // 运行时版本: 4.0.30319.42000
5 | //
6 | // 对此文件的更改可能导致不正确的行为,如果
7 | // 重新生成代码,则所做更改将丢失。
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace RevokeMsgPatcher.Launcher.Properties
12 | {
13 |
14 |
15 | ///
16 | /// 强类型资源类,用于查找本地化字符串等。
17 | ///
18 | // 此类是由 StronglyTypedResourceBuilder
19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
20 | // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
21 | // (以 /str 作为命令选项),或重新生成 VS 项目。
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources
26 | {
27 |
28 | private static global::System.Resources.ResourceManager resourceMan;
29 |
30 | private static global::System.Globalization.CultureInfo resourceCulture;
31 |
32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
33 | internal Resources()
34 | {
35 | }
36 |
37 | ///
38 | /// 返回此类使用的缓存 ResourceManager 实例。
39 | ///
40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
41 | internal static global::System.Resources.ResourceManager ResourceManager
42 | {
43 | get
44 | {
45 | if ((resourceMan == null))
46 | {
47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RevokeMsgPatcher.Launcher.Properties.Resources", typeof(Resources).Assembly);
48 | resourceMan = temp;
49 | }
50 | return resourceMan;
51 | }
52 | }
53 |
54 | ///
55 | /// 重写当前线程的 CurrentUICulture 属性,对
56 | /// 使用此强类型资源类的所有资源查找执行重写。
57 | ///
58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
59 | internal static global::System.Globalization.CultureInfo Culture
60 | {
61 | get
62 | {
63 | return resourceCulture;
64 | }
65 | set
66 | {
67 | resourceCulture = value;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.Launcher/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.Launcher/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace RevokeMsgPatcher.Launcher.Properties
12 | {
13 |
14 |
15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
18 | {
19 |
20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
21 |
22 | public static Settings Default
23 | {
24 | get
25 | {
26 | return defaultInstance;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.Launcher/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.Launcher/RevokeMsgPatcher.Launcher.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {B1D05208-E291-406B-A8B4-F673EC784B1C}
8 | WinExe
9 | RevokeMsgPatcher.Launcher
10 | RevokeMsgPatcher.Launcher
11 | v4.7.2
12 | 512
13 | true
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | Form
51 |
52 |
53 | FormMain.cs
54 |
55 |
56 |
57 |
58 | FormMain.cs
59 |
60 |
61 | ResXFileCodeGenerator
62 | Resources.Designer.cs
63 | Designer
64 |
65 |
66 | True
67 | Resources.resx
68 |
69 |
70 | SettingsSingleFileGenerator
71 | Settings.Designer.cs
72 |
73 |
74 | True
75 | Settings.settings
76 | True
77 |
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.MultiInstance/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.MultiInstance/FormMultiInstance.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Windows.Forms;
5 |
6 | namespace RevokeMsgPatcher.MultiInstance
7 | {
8 | public partial class FormMultiInstance : Form
9 | {
10 | public FormMultiInstance()
11 | {
12 | InitializeComponent();
13 |
14 | // 标题加上版本号
15 | string currentVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
16 | if (currentVersion.Length > 3)
17 | {
18 | currentVersion = " v" + currentVersion.Substring(0, 3);
19 | }
20 | this.Text += currentVersion;
21 | }
22 |
23 | private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
24 | {
25 | Process.Start("https://github.com/huiyadanli/RevokeMsgPatcher");
26 | }
27 |
28 | private void btnStartTimer_Click(object sender, EventArgs e)
29 | {
30 | mutexHandleCloseTimer.Start();
31 | btnStartTimer.Enabled = false;
32 | btnStopTimer.Enabled = true;
33 | }
34 |
35 | private void btnStopTimer_Click(object sender, EventArgs e)
36 | {
37 | mutexHandleCloseTimer.Stop();
38 | btnStartTimer.Enabled = true;
39 | btnStopTimer.Enabled = false;
40 | }
41 |
42 | private List wechatProcesses = new List();
43 |
44 | private void mutexHandleCloseTimer_Tick(object sender, EventArgs e)
45 | {
46 | Process[] processes = Process.GetProcessesByName("WeChat");
47 | Console.WriteLine("WeChat进程数:" + processes.Length);
48 | // 添加新进程
49 | foreach (Process p in processes)
50 | {
51 | int i = 0;
52 | for (i = 0; i < wechatProcesses.Count; i++)
53 | {
54 | WechatProcess wechatProcess = wechatProcesses[i];
55 | if (wechatProcess.Proc.Id == p.Id)
56 | {
57 | break;
58 | }
59 | }
60 | if (i == wechatProcesses.Count)
61 | {
62 | wechatProcesses.Add(new WechatProcess(p));
63 | }
64 | }
65 | // 关闭所有存在互斥句柄的进程
66 | int num = 0;
67 | for (int i = wechatProcesses.Count - 1; i >= 0; i--)
68 | {
69 | WechatProcess wechatProcess = wechatProcesses[i];
70 | if (!wechatProcess.MutexClosed)
71 | {
72 | wechatProcess.MutexClosed = ProcessUtil.CloseMutexHandle(wechatProcess.Proc);
73 | Console.WriteLine("进程:" + wechatProcess.Proc.Id + ",关闭互斥句柄:" + wechatProcess.MutexClosed);
74 | }
75 | else
76 | {
77 | if (wechatProcess.Proc.HasExited)
78 | {
79 | // 移除不存在的线程
80 | wechatProcesses.RemoveAt(i);
81 | }
82 | else
83 | {
84 | num++;
85 | }
86 |
87 | }
88 | }
89 | lblProcNum.Text = "当前微信数量:" + num.ToString();
90 | }
91 |
92 | private void btnKillAll_Click(object sender, EventArgs e)
93 | {
94 | Process[] processes = Process.GetProcessesByName("WeChat");
95 | if (processes.Length > 0)
96 | {
97 | foreach (Process p in processes)
98 | {
99 | p.Kill();
100 | }
101 | MessageBox.Show("已经关闭所有微信进程,共" + processes.Length + "个", "提示");
102 | }
103 | else
104 | {
105 | MessageBox.Show("当前无微信进程", "提示");
106 | }
107 | }
108 |
109 | private void btnCloseAllMutex_Click(object sender, EventArgs e)
110 | {
111 | Process[] processes = Process.GetProcessesByName("WeChat");
112 | ProcessUtil.CloseMutexHandle(processes);
113 | }
114 |
115 | private void lblHowToUse_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
116 | {
117 | Process.Start("https://github.com/huiyadanli/RevokeMsgPatcher/tree/master/RevokeMsgPatcher.MultiInstance");
118 | }
119 |
120 | private void FormMultiInstance_FormClosed(object sender, FormClosedEventArgs e)
121 | {
122 | mutexHandleCloseTimer.Stop();
123 | }
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.MultiInstance/FormMultiInstance.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | 17, 17
122 |
123 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.MultiInstance/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using System.Windows.Forms;
6 |
7 | namespace RevokeMsgPatcher.MultiInstance
8 | {
9 | static class Program
10 | {
11 | ///
12 | /// 应用程序的主入口点。
13 | ///
14 | [STAThread]
15 | static void Main()
16 | {
17 | Application.EnableVisualStyles();
18 | Application.SetCompatibleTextRenderingDefault(false);
19 | Application.Run(new FormMultiInstance());
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.MultiInstance/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // 有关程序集的一般信息由以下
6 | // 控制。更改这些特性值可修改
7 | // 与程序集关联的信息。
8 | [assembly: AssemblyTitle("RevokeMsgPatcher.MultiInstance")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("RevokeMsgPatcher.MultiInstance")]
13 | [assembly: AssemblyCopyright("Copyright © 2019")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // 将 ComVisible 设置为 false 会使此程序集中的类型
18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
19 | //请将此类型的 ComVisible 特性设置为 true。
20 | [assembly: ComVisible(false)]
21 |
22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
23 | [assembly: Guid("73043ca8-af54-4591-9174-40fb6e0a3d36")]
24 |
25 | // 程序集的版本信息由下列四个值组成:
26 | //
27 | // 主版本
28 | // 次版本
29 | // 生成号
30 | // 修订号
31 | //
32 | // 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
33 | // 方法是按如下所示使用“*”: :
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("0.1")]
36 | [assembly: AssemblyFileVersion("0.1")]
37 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.MultiInstance/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // 此代码由工具生成。
4 | // 运行时版本:4.0.30319.42000
5 | //
6 | // 对此文件的更改可能会导致不正确的行为,并且如果
7 | // 重新生成代码,这些更改将会丢失。
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace RevokeMsgPatcher.MultiInstance.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// 一个强类型的资源类,用于查找本地化的字符串等。
17 | ///
18 | // 此类是由 StronglyTypedResourceBuilder
19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
20 | // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
21 | // (以 /str 作为命令选项),或重新生成 VS 项目。
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// 返回此类使用的缓存的 ResourceManager 实例。
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RevokeMsgPatcher.MultiInstance.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// 重写当前线程的 CurrentUICulture 属性,对
51 | /// 使用此强类型资源类的所有资源查找执行重写。
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.MultiInstance/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.MultiInstance/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // 此代码由工具生成。
4 | // 运行时版本:4.0.30319.42000
5 | //
6 | // 对此文件的更改可能会导致不正确的行为,并且如果
7 | // 重新生成代码,这些更改将会丢失。
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace RevokeMsgPatcher.MultiInstance.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.1.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.MultiInstance/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.MultiInstance/README.md:
--------------------------------------------------------------------------------
1 | ## 一个通用的微信多开工具
2 |
3 | 此工具可以无视微信版本进行多开。
4 |
5 | **⚠如果你曾使用过“PC版微信/QQ/TIM防撤回补丁”,并对微信安装了防撤回/多开的补丁,此时微信本身已经支持多开,请勿重复使用本工具!!!**
6 |
7 | ## 📷截图
8 | 
9 |
10 | ## 🔨使用方法
11 |
12 | ⚔自动模式(一般用户使用这个模式即可):
13 |
14 | 点击【启动多开】之后,就可以启动多个微信了。
15 |
16 | 注意:启动多个微信频率太快时,可能会失败。
17 |
18 | 🏹手动模式:
19 |
20 | 关闭所有微信进程:功能就是关闭所有微信进程,微信在某种启动失败的情况下会残留进程(无界面),一般不会遇到这种情况。
21 |
22 | 清理所有微信互斥句柄:功能就是把所有微信判断是否多开的标志全部清理掉,实现多开。如果只使用这个按钮实现多开的话,每次开启一个微信之后都要点一下这个按钮。
23 |
24 | ## ❤Thanks
25 |
26 | [微信电脑端多开分析与原理](https://mp.weixin.qq.com/s/bb7XMxop7e8rd7YqQ88nyA)
27 |
28 | ## 📄License
29 | GPLv3
30 |
31 | 
32 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.MultiInstance/RevokeMsgPatcher.MultiInstance.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {73043CA8-AF54-4591-9174-40FB6E0A3D36}
8 | WinExe
9 | RevokeMsgPatcher.MultiInstance
10 | RevokeMsgPatcher.MultiInstance
11 | v4.5.2
12 | 512
13 | true
14 |
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 | app.manifest
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | Form
54 |
55 |
56 | FormMultiInstance.cs
57 |
58 |
59 |
60 |
61 |
62 |
63 | FormMultiInstance.cs
64 |
65 |
66 | ResXFileCodeGenerator
67 | Resources.Designer.cs
68 | Designer
69 |
70 |
71 | True
72 | Resources.resx
73 | True
74 |
75 |
76 |
77 | SettingsSingleFileGenerator
78 | Settings.Designer.cs
79 |
80 |
81 | True
82 | Settings.settings
83 | True
84 |
85 |
86 |
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.MultiInstance/WechatProcess.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 |
3 | namespace RevokeMsgPatcher.MultiInstance
4 | {
5 | public class WechatProcess
6 | {
7 | public Process Proc { get; set; }
8 |
9 | public bool MutexClosed { get; set; }
10 |
11 | public WechatProcess(Process p)
12 | {
13 | Proc = p;
14 | MutexClosed = false;
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.MultiInstance/app.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
51 |
52 |
53 |
54 | true
55 |
56 |
57 |
58 |
59 |
60 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.10.35013.160
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RevokeMsgPatcher", "RevokeMsgPatcher\RevokeMsgPatcher.csproj", "{977BF781-CED8-4389-9404-0FA08FDF21DF}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RevokeMsgPatcher.Assistant", "RevokeMsgPatcher.Assistant\RevokeMsgPatcher.Assistant.csproj", "{6992004F-17E6-45BF-8D72-180A31E9C23C}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RevokeMsgPatcher.MultiInstance", "RevokeMsgPatcher.MultiInstance\RevokeMsgPatcher.MultiInstance.csproj", "{73043CA8-AF54-4591-9174-40FB6E0A3D36}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RevokeMsgPatcher.Launcher", "RevokeMsgPatcher.Launcher\RevokeMsgPatcher.Launcher.csproj", "{B1D05208-E291-406B-A8B4-F673EC784B1C}"
13 | EndProject
14 | Global
15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 | Debug|Any CPU = Debug|Any CPU
17 | Release|Any CPU = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {977BF781-CED8-4389-9404-0FA08FDF21DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {977BF781-CED8-4389-9404-0FA08FDF21DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {977BF781-CED8-4389-9404-0FA08FDF21DF}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {977BF781-CED8-4389-9404-0FA08FDF21DF}.Release|Any CPU.Build.0 = Release|Any CPU
24 | {6992004F-17E6-45BF-8D72-180A31E9C23C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25 | {6992004F-17E6-45BF-8D72-180A31E9C23C}.Debug|Any CPU.Build.0 = Debug|Any CPU
26 | {6992004F-17E6-45BF-8D72-180A31E9C23C}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {6992004F-17E6-45BF-8D72-180A31E9C23C}.Release|Any CPU.Build.0 = Release|Any CPU
28 | {73043CA8-AF54-4591-9174-40FB6E0A3D36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {73043CA8-AF54-4591-9174-40FB6E0A3D36}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {73043CA8-AF54-4591-9174-40FB6E0A3D36}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {73043CA8-AF54-4591-9174-40FB6E0A3D36}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {B1D05208-E291-406B-A8B4-F673EC784B1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {B1D05208-E291-406B-A8B4-F673EC784B1C}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {B1D05208-E291-406B-A8B4-F673EC784B1C}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {B1D05208-E291-406B-A8B4-F673EC784B1C}.Release|Any CPU.Build.0 = Release|Any CPU
36 | EndGlobalSection
37 | GlobalSection(SolutionProperties) = preSolution
38 | HideSolutionNode = FALSE
39 | EndGlobalSection
40 | GlobalSection(ExtensibilityGlobals) = postSolution
41 | SolutionGuid = {56DAEA8C-77F7-4E55-A7AF-CE9F23F2C1A6}
42 | EndGlobalSection
43 | EndGlobal
44 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/BusinessException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace RevokeMsgPatcher
4 | {
5 | class BusinessException : ApplicationException
6 | {
7 | public string ErrorCode { get; protected set; }
8 |
9 | public BusinessException(string errcode, string message) : base(message)
10 | {
11 | ErrorCode = errcode;
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Forms/FormPatchInfo.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace RevokeMsgPatcher.Forms
2 | {
3 | partial class FormPatchInfo
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.rtbPatchInfo = new System.Windows.Forms.RichTextBox();
32 | this.btnOK = new System.Windows.Forms.Button();
33 | this.btnCancel = new System.Windows.Forms.Button();
34 | this.label1 = new System.Windows.Forms.Label();
35 | this.SuspendLayout();
36 | //
37 | // rtbPatchInfo
38 | //
39 | this.rtbPatchInfo.Location = new System.Drawing.Point(12, 45);
40 | this.rtbPatchInfo.Name = "rtbPatchInfo";
41 | this.rtbPatchInfo.Size = new System.Drawing.Size(489, 158);
42 | this.rtbPatchInfo.TabIndex = 0;
43 | this.rtbPatchInfo.Text = "";
44 | //
45 | // btnOK
46 | //
47 | this.btnOK.Location = new System.Drawing.Point(345, 209);
48 | this.btnOK.Name = "btnOK";
49 | this.btnOK.Size = new System.Drawing.Size(75, 23);
50 | this.btnOK.TabIndex = 1;
51 | this.btnOK.Text = "确定";
52 | this.btnOK.UseVisualStyleBackColor = true;
53 | //
54 | // btnCancel
55 | //
56 | this.btnCancel.Location = new System.Drawing.Point(426, 209);
57 | this.btnCancel.Name = "btnCancel";
58 | this.btnCancel.Size = new System.Drawing.Size(75, 23);
59 | this.btnCancel.TabIndex = 2;
60 | this.btnCancel.Text = "取消";
61 | this.btnCancel.UseVisualStyleBackColor = true;
62 | //
63 | // label1
64 | //
65 | this.label1.Location = new System.Drawing.Point(12, 9);
66 | this.label1.Name = "label1";
67 | this.label1.Size = new System.Drawing.Size(489, 33);
68 | this.label1.TabIndex = 3;
69 | this.label1.Text = "注意:请勿随意输入补丁信息,错误的补丁信息将导致本软件无法正常使用。在被恶意情况下可以修改/破坏系统任意位置文件";
70 | //
71 | // FormPatchInfo
72 | //
73 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
74 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
75 | this.ClientSize = new System.Drawing.Size(513, 241);
76 | this.Controls.Add(this.label1);
77 | this.Controls.Add(this.btnCancel);
78 | this.Controls.Add(this.btnOK);
79 | this.Controls.Add(this.rtbPatchInfo);
80 | this.Name = "FormPatchInfo";
81 | this.Text = "请输入补丁信息";
82 | this.ResumeLayout(false);
83 |
84 | }
85 |
86 | #endregion
87 |
88 | private System.Windows.Forms.RichTextBox rtbPatchInfo;
89 | private System.Windows.Forms.Button btnOK;
90 | private System.Windows.Forms.Button btnCancel;
91 | private System.Windows.Forms.Label label1;
92 | }
93 | }
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Forms/FormPatchInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Data;
5 | using System.Drawing;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Windows.Forms;
10 |
11 | namespace RevokeMsgPatcher.Forms
12 | {
13 | public partial class FormPatchInfo : Form
14 | {
15 | public FormPatchInfo()
16 | {
17 | InitializeComponent();
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Forms/FormPatchInfo.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Forms/UIController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.Windows.Forms;
8 |
9 | namespace RevokeMsgPatcher.Forms
10 | {
11 | public class UIController
12 | {
13 | public static void AddCategoryCheckBoxToPanel(Panel panel, string[] categories, string[] installed)
14 | {
15 | if (categories != null && categories.Length != 0)
16 | {
17 | panel.Controls.Clear();
18 | for (int i = 0; i < categories.Length; i++)
19 | {
20 | CheckBox chk = new CheckBox
21 | {
22 | Text = categories[i],
23 | Name = "chkCategoriesIndex" + i,
24 | Checked = true,
25 | AutoSize = true
26 | };
27 | if (installed.Contains(categories[i]))
28 | {
29 | chk.Text = chk.Text + "(已安装)";
30 | chk.Enabled = false;
31 | }
32 | panel.Controls.Add(chk);
33 | }
34 | }
35 | else
36 | {
37 | AddMsgToPanel(panel, "无功能选项");
38 | }
39 | }
40 |
41 | public static void AddMsgToPanel(Panel panel, string msg)
42 | {
43 | panel.Controls.Clear();
44 | Label label = new Label
45 | {
46 | Name = "lblCategoriesMsg",
47 | Text = msg,
48 | TextAlign = ContentAlignment.MiddleLeft,
49 | Size = new Size(panel.Width, panel.Height)
50 | };
51 | panel.Controls.Add(label);
52 | }
53 |
54 | public static List GetCategoriesFromPanel(Panel panel)
55 | {
56 | List categories = new List();
57 | foreach (Control ctrl in panel.Controls)
58 | {
59 | if (ctrl is CheckBox checkBox)
60 | {
61 | if (checkBox.Enabled && checkBox.Checked)
62 | {
63 | categories.Add(checkBox.Text);
64 | }
65 | }
66 | else if (ctrl is Label label)
67 | {
68 | return null; // 如果是标签, 说明是精准匹配, 直接返回null
69 | }
70 | }
71 | return categories;
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Matcher/BoyerMooreMatcher.cs:
--------------------------------------------------------------------------------
1 | namespace RevokeMsgPatcher.Matcher
2 | {
3 | public class BoyerMooreMatcher
4 | {
5 | private static int AlphabetSize = 256;
6 |
7 | private static int Max(int a, int b) { return (a > b) ? a : b; }
8 |
9 | static int[] PreprocessToBuildBadCharactorHeuristic(byte[] pattern)
10 | {
11 | int m = pattern.Length;
12 | int[] badCharactorShifts = new int[AlphabetSize];
13 |
14 | for (int i = 0; i < AlphabetSize; i++)
15 | {
16 | //badCharactorShifts[i] = -1;
17 | badCharactorShifts[i] = m;
18 | }
19 |
20 | // fill the actual value of last occurrence of a character
21 | for (int i = 0; i < m; i++)
22 | {
23 | //badCharactorShifts[(int)pattern[i]] = i;
24 | badCharactorShifts[(int)pattern[i]] = m - 1 - i;
25 | }
26 |
27 | return badCharactorShifts;
28 | }
29 |
30 | static int[] PreprocessToBuildGoodSuffixHeuristic(byte[] pattern)
31 | {
32 | int m = pattern.Length;
33 | int[] goodSuffixShifts = new int[m];
34 | int[] suffixLengthArray = GetSuffixLengthArray(pattern);
35 |
36 | for (int i = 0; i < m; ++i)
37 | {
38 | goodSuffixShifts[i] = m;
39 | }
40 |
41 | int j = 0;
42 | for (int i = m - 1; i >= -1; --i)
43 | {
44 | if (i == -1 || suffixLengthArray[i] == i + 1)
45 | {
46 | for (; j < m - 1 - i; ++j)
47 | {
48 | if (goodSuffixShifts[j] == m)
49 | {
50 | goodSuffixShifts[j] = m - 1 - i;
51 | }
52 | }
53 | }
54 | }
55 |
56 | for (int i = 0; i < m - 1; ++i)
57 | {
58 | goodSuffixShifts[m - 1 - suffixLengthArray[i]] = m - 1 - i;
59 | }
60 |
61 | return goodSuffixShifts;
62 | }
63 |
64 | static int[] GetSuffixLengthArray(byte[] pattern)
65 | {
66 | int m = pattern.Length;
67 | int[] suffixLengthArray = new int[m];
68 |
69 | int f = 0, g = 0, i = 0;
70 |
71 | suffixLengthArray[m - 1] = m;
72 |
73 | g = m - 1;
74 | for (i = m - 2; i >= 0; --i)
75 | {
76 | if (i > g && suffixLengthArray[i + m - 1 - f] < i - g)
77 | {
78 | suffixLengthArray[i] = suffixLengthArray[i + m - 1 - f];
79 | }
80 | else
81 | {
82 | if (i < g)
83 | {
84 | g = i;
85 | }
86 | f = i;
87 |
88 | // find different preceded character suffix
89 | while (g >= 0 && pattern[g] == pattern[g + m - 1 - f])
90 | {
91 | --g;
92 | }
93 | suffixLengthArray[i] = f - g;
94 | }
95 | }
96 |
97 | return suffixLengthArray;
98 | }
99 |
100 | public static bool TryMatch(byte[] text, byte[] pattern, out int firstShift)
101 | {
102 | firstShift = -1;
103 | int n = text.Length;
104 | int m = pattern.Length;
105 | int s = 0; // s is shift of the pattern with respect to text
106 | int j = 0;
107 |
108 | // fill the bad character and good suffix array by preprocessing
109 | int[] badCharShifts = PreprocessToBuildBadCharactorHeuristic(pattern);
110 | int[] goodSuffixShifts = PreprocessToBuildGoodSuffixHeuristic(pattern);
111 |
112 | while (s <= (n - m))
113 | {
114 | // starts matching from the last character of the pattern
115 | j = m - 1;
116 |
117 | // keep reducing index j of pattern while characters of
118 | // pattern and text are matching at this shift s
119 | while (j >= 0 && pattern[j] == text[s + j])
120 | {
121 | j--;
122 | }
123 |
124 | // if the pattern is present at current shift, then index j
125 | // will become -1 after the above loop
126 | if (j < 0)
127 | {
128 | firstShift = s;
129 | return true;
130 | }
131 | else
132 | {
133 | // shift the pattern so that the bad character in text
134 | // aligns with the last occurrence of it in pattern. the
135 | // max function is used to make sure that we get a positive
136 | // shift. We may get a negative shift if the last occurrence
137 | // of bad character in pattern is on the right side of the
138 | // current character.
139 | //s += Max(1, j - badCharShifts[(int)text[s + j]]);
140 | // now, compare bad char shift and good suffix shift to find best
141 | s += Max(goodSuffixShifts[j], badCharShifts[(int)text[s + j]] - (m - 1) + j);
142 | }
143 | }
144 |
145 | return false;
146 | }
147 |
148 | public static int[] MatchAll(byte[] text, byte[] pattern)
149 | {
150 | int n = text.Length;
151 | int m = pattern.Length;
152 | int s = 0; // s is shift of the pattern with respect to text
153 | int j = 0;
154 | int[] shiftIndexes = new int[n - m + 1];
155 | int c = 0;
156 |
157 | // fill the bad character and good suffix array by preprocessing
158 | int[] badCharShifts = PreprocessToBuildBadCharactorHeuristic(pattern);
159 | int[] goodSuffixShifts = PreprocessToBuildGoodSuffixHeuristic(pattern);
160 |
161 | while (s <= (n - m))
162 | {
163 | // starts matching from the last character of the pattern
164 | j = m - 1;
165 |
166 | // keep reducing index j of pattern while characters of
167 | // pattern and text are matching at this shift s
168 | while (j >= 0 && pattern[j] == text[s + j])
169 | {
170 | j--;
171 | }
172 |
173 | // if the pattern is present at current shift, then index j
174 | // will become -1 after the above loop
175 | if (j < 0)
176 | {
177 | shiftIndexes[c] = s;
178 | c++;
179 |
180 | // shift the pattern so that the next character in text
181 | // aligns with the last occurrence of it in pattern.
182 | // the condition s+m < n is necessary for the case when
183 | // pattern occurs at the end of text
184 | //s += (s + m < n) ? m - badCharShifts[(int)text[s + m]] : 1;
185 | s += goodSuffixShifts[0];
186 | }
187 | else
188 | {
189 | // shift the pattern so that the bad character in text
190 | // aligns with the last occurrence of it in pattern. the
191 | // max function is used to make sure that we get a positive
192 | // shift. We may get a negative shift if the last occurrence
193 | // of bad character in pattern is on the right side of the
194 | // current character.
195 | //s += Max(1, j - badCharShifts[(int)text[s + j]]);
196 | // now, compare bad char shift and good suffix shift to find best
197 | s += Max(goodSuffixShifts[j], badCharShifts[(int)text[s + j]] - (m - 1) + j);
198 | }
199 | }
200 |
201 | int[] shifts = new int[c];
202 | for (int y = 0; y < c; y++)
203 | {
204 | shifts[y] = shiftIndexes[y];
205 | }
206 |
207 | return shifts;
208 | }
209 | }
210 | }
211 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Matcher/FuzzyMatcher.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 |
5 | namespace RevokeMsgPatcher.Matcher
6 | {
7 | ///
8 | /// 对16进制数据进行通配符查找
9 | ///
10 | public class FuzzyMatcher
11 | {
12 | public const byte wildcard = 0x3F; // 通配符
13 |
14 | ///
15 | /// 通配符匹配所有符合查找串的位置
16 | ///
17 | /// 被查找对象
18 | /// 查找串
19 | ///
20 | public static int[] MatchAll(byte[] content, byte[] pattern)
21 | {
22 | byte[] head = GetHead(pattern);
23 | int[] indexs = BoyerMooreMatcher.MatchAll(content, head);
24 | // 头串和查找串相同则直接返回,不同则继续判断是否符合查询串
25 | if (head.Length == pattern.Length)
26 | {
27 | return indexs;
28 | }
29 | else
30 | {
31 | List res = new List();
32 | foreach (int index in indexs)
33 | {
34 | if (IsEqual(content, index, pattern))
35 | {
36 | res.Add(index);
37 | }
38 | }
39 | return res.ToArray();
40 | }
41 | }
42 |
43 | ///
44 | /// 通配符匹配所有符合查找串的位置,并排除已经替换的情况
45 | ///
46 | /// 被查找对象
47 | /// 查找串
48 | /// 替换串
49 | ///
50 | public static int[] MatchNotReplaced(byte[] content, byte[] searchBytes, byte[] replaceBytes)
51 | {
52 | byte[] head = GetHead(searchBytes);
53 | int[] indexs = BoyerMooreMatcher.MatchAll(content, head);
54 | // 头串和查找串相同则直接返回,不同则继续判断是否符合查询串
55 | List res = new List();
56 | if (head.Length != searchBytes.Length)
57 | {
58 | foreach (int index in indexs)
59 | {
60 | if (IsEqual(content, index, searchBytes))
61 | {
62 | res.Add(index);
63 | }
64 | }
65 | indexs = res.ToArray();
66 | }
67 | // 判断是否与替换串相同
68 | res = new List();
69 | foreach (int index in indexs)
70 | {
71 | if (!IsEqual(content, index, replaceBytes))
72 | {
73 | res.Add(index);
74 | }
75 | }
76 | return res.ToArray();
77 | }
78 |
79 | ///
80 | /// 获取头串
81 | ///
82 | /// 完整查找串
83 | ///
84 | private static byte[] GetHead(byte[] whole)
85 | {
86 | int len = whole.Length;
87 | for (int i = 0; i < whole.Length; i++)
88 | {
89 | if (whole[i] == wildcard)
90 | {
91 | len = i;
92 | break;
93 | }
94 | }
95 | if (len == 0)
96 | {
97 | throw new Exception("不正确的通配符位置!");
98 | }
99 | return whole.Take(len).ToArray();
100 | }
101 |
102 | ///
103 | /// 确认整个查找串是否匹配
104 | ///
105 | /// 被查找对象
106 | /// 头串匹配位置
107 | /// 完整查找串
108 | ///
109 | public static bool IsEqual(byte[] content, int start, byte[] whole)
110 | {
111 | int i = 0;
112 | for (i = 0; i < whole.Length; i++)
113 | {
114 | if (whole[i] == wildcard)
115 | {
116 | continue;
117 | }
118 | if (content[start + i] != whole[i])
119 | {
120 | break;
121 | }
122 | }
123 | if (i == whole.Length)
124 | {
125 | return true;
126 | }
127 | else
128 | {
129 | return false;
130 | }
131 | }
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Matcher/ModifyFinder.cs:
--------------------------------------------------------------------------------
1 | using RevokeMsgPatcher.Model;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Diagnostics;
5 | using System.IO;
6 | using System.Linq;
7 |
8 | namespace RevokeMsgPatcher.Matcher
9 | {
10 | public class ModifyFinder
11 | {
12 | // TODO 该逻辑需要优化!
13 | public static List FindChanges(string path, List replacePatterns)
14 | {
15 | Stopwatch sw = new Stopwatch();
16 | sw.Start();
17 | // 读取整个文件(dll)
18 | byte[] fileByteArray = File.ReadAllBytes(path);
19 | Console.WriteLine("读取文件耗时:{0}ms.", sw.Elapsed.TotalMilliseconds);
20 |
21 | List changes = new List(); // 匹配且需要替换的地方
22 |
23 | // 查找所有替换点
24 | int matchNum = 0; // 匹配数量
25 | foreach (ReplacePattern pattern in replacePatterns)
26 | {
27 | // 所有的匹配点位
28 | int[] matchIndexs = FuzzyMatcher.MatchAll(fileByteArray, pattern.Search);
29 | Console.WriteLine("匹配{0}耗时:{1}ms.", pattern.Category, sw.Elapsed.TotalMilliseconds);
30 | if (matchIndexs.Length >= 1)
31 | {
32 | for (int i = 0; i < matchIndexs.Length; i++)
33 | {
34 | matchNum++;
35 | // 与要替换的串不一样才需要替换(当前的特征肯定不一样)
36 | if (!FuzzyMatcher.IsEqual(fileByteArray, matchIndexs[i], pattern.Replace))
37 | {
38 | changes.Add(new Change(matchIndexs[i], pattern.Replace));
39 | }
40 | }
41 | }
42 | }
43 |
44 | // 匹配数和期望的匹配数不一致时报错(当前一个特征会出现多次)
45 | if (matchNum < replacePatterns.Count)
46 | {
47 | Tuple> res = IsAllReplaced(fileByteArray, replacePatterns);
48 | if (res.Item1)
49 | {
50 | throw new BusinessException("match_already_replace", "特征比对:当前应用已经安装了对应功能的补丁!");
51 | }
52 | else
53 | {
54 | if (res.Item2.Count > 0)
55 | {
56 | throw new BusinessException("match_inconformity", $"特征比对:以下功能补丁已经安装,请取消勾选!\n已安装功能:【{string.Join("、", res.Item2)}】");
57 | }
58 | else
59 | {
60 | throw new BusinessException("match_inconformity", $"特征比对:当前特征码匹配数[{matchNum}]和期望的匹配数[{replacePatterns.Count}]不一致。\n" +
61 | $"出现此种情况的一般有如下可能:\n" +
62 | $"1. 你可能已经安装了某个功能的补丁,请选择未安装功能进行安装。\n" +
63 | $"2. 如果当前版本为最新版本,特征码可能出现变化(可能性比较低),请联系作者处理。");
64 | }
65 | }
66 | }
67 | else
68 | {
69 | // 匹配数和需要替换的数量不一致时,可能时部分/所有特征已经被替换
70 | if (matchNum != changes.Count)
71 | {
72 | // 此逻辑在当前特征配置下不会进入,因为查找串和替换串当前全部都是不相同的
73 | if (changes.Count == 0)
74 | {
75 | throw new BusinessException("match_already_replace", "特征比对:当前应用已经安装了所选功能补丁!");
76 | }
77 | else
78 | {
79 | throw new BusinessException("match_part_replace", "特征比对:部分特征已经被替换,请确认是否有使用过其他防撤回/多开补丁!");
80 | }
81 |
82 | }
83 | else
84 | {
85 | // 匹配数和需要替换的数量一致时才是正常状态
86 | return changes;
87 | }
88 | }
89 | }
90 |
91 | public static SortedSet FindReplacedFunction(string path, List replacePatterns)
92 | {
93 | Stopwatch sw = new Stopwatch();
94 | sw.Start();
95 | byte[] fileByteArray = File.ReadAllBytes(path);
96 | Console.WriteLine("读取文件耗时:{0}ms.", sw.Elapsed.TotalMilliseconds);
97 | Tuple> res = IsAllReplaced(fileByteArray, replacePatterns);
98 | Console.WriteLine("匹配耗时:{0}ms.", sw.Elapsed.TotalMilliseconds);
99 | return res.Item2;
100 | }
101 |
102 | private static Tuple> IsAllReplaced(byte[] partByteArray, List replacePatterns)
103 | {
104 | int matchNum = 0;
105 | SortedSet alreadyReplaced = new SortedSet(); // 已经被替换特征的功能
106 | foreach (ReplacePattern pattern in replacePatterns)
107 | {
108 | int[] searchMatchIndexs = FuzzyMatcher.MatchAll(partByteArray, pattern.Search);
109 | int[] replaceMatchIndexs = FuzzyMatcher.MatchAll(partByteArray, pattern.Replace);
110 | // 查找串没有,但是替换串存在,也就是说明这个功能已经完全完成替换
111 | if (searchMatchIndexs.Length == 0 && replaceMatchIndexs.Length > 0)
112 | {
113 | alreadyReplaced.Add(pattern.Category);
114 | }
115 | }
116 | return new Tuple>(matchNum >= replacePatterns.Count, alreadyReplaced);
117 | }
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Model/App.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace RevokeMsgPatcher.Model
8 | {
9 | public class App
10 | {
11 | public string Name { get; set; }
12 |
13 | public Dictionary FileTargetInfos { get; set; }
14 |
15 | public Dictionary> FileModifyInfos { get; set; }
16 |
17 | ///
18 | /// 通用的修改特征
19 | ///
20 | public Dictionary> FileCommonModifyInfos { get; set; }
21 |
22 | public HashSet GetSupportVersions()
23 | {
24 | // 使用 HashSet 防重
25 | HashSet versions = new HashSet();
26 | // 精准
27 | if (FileModifyInfos != null)
28 | {
29 | foreach (List modifyInfos in FileModifyInfos.Values)
30 | {
31 | foreach (ModifyInfo modifyInfo in modifyInfos)
32 | {
33 | versions.Add(modifyInfo.Version);
34 | }
35 | }
36 | }
37 | // 模糊 范围
38 | if (FileCommonModifyInfos != null)
39 | {
40 | foreach (List commonModifyInfos in FileCommonModifyInfos.Values)
41 | {
42 | foreach (CommonModifyInfo commonModifyInfo in commonModifyInfos)
43 | {
44 | string end = string.IsNullOrEmpty(commonModifyInfo.EndVersion) ? "最新版" : commonModifyInfo.EndVersion;
45 | versions.Add(commonModifyInfo.StartVersion + "~" + end);
46 | }
47 | }
48 | }
49 | return versions;
50 | }
51 |
52 | public string GetSupportVersionStr()
53 | {
54 | string str = "";
55 | foreach (string v in GetSupportVersions())
56 | {
57 | str += v + "、";
58 | }
59 | if (str.Length > 1)
60 | {
61 | str = str.Substring(0, str.Length - 1);
62 | }
63 | return str;
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Model/Bag.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace RevokeMsgPatcher.Model
8 | {
9 | public class Bag
10 | {
11 | public Dictionary Apps { get; set; }
12 |
13 | public string LatestVersion { get; set; }
14 |
15 | public string Notice { get; set; }
16 |
17 | public string NoticeUrl { get; set; }
18 |
19 | public int PatchVersion { get; set; }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Model/Change.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace RevokeMsgPatcher.Model
8 | {
9 | public class Change
10 | {
11 | public long Position { get; set; }
12 |
13 | public byte[] Content { get; set; }
14 |
15 | public Change()
16 | {
17 |
18 | }
19 |
20 | public Change(long position, byte[] content)
21 | {
22 | Position = position;
23 | Content = content;
24 | }
25 |
26 | public Change Clone()
27 | {
28 | Change o = new Change();
29 | o.Position = Position;
30 | o.Content = Content;
31 | return o;
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Model/CommonModifyInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace RevokeMsgPatcher.Model
9 | {
10 | public class CommonModifyInfo
11 | {
12 | public string Name { get; set; }
13 |
14 | public string StartVersion { get; set; }
15 |
16 | public string EndVersion { get; set; }
17 |
18 | public List ReplacePatterns { get; set; }
19 |
20 | public CommonModifyInfo Clone()
21 | {
22 | CommonModifyInfo o = new CommonModifyInfo();
23 | o.Name = Name;
24 | o.StartVersion = StartVersion;
25 | o.EndVersion = EndVersion;
26 | List cs = new List();
27 | foreach (ReplacePattern c in ReplacePatterns)
28 | {
29 | cs.Add(c.Clone());
30 | }
31 | o.ReplacePatterns = cs;
32 | return o;
33 | }
34 |
35 | public List GetCategories()
36 | {
37 | if (ReplacePatterns != null && ReplacePatterns.Count > 0)
38 | {
39 | return ReplacePatterns.Select(p => p.Category).ToList();
40 | }
41 | else
42 | {
43 | return new List();
44 | }
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Model/Json/LiteLoaderPackage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace RevokeMsgPatcher.Model.Json
8 | {
9 | internal class LiteLoaderPackage
10 | {
11 | public string Name { get; set; }
12 | public string Version { get; set; }
13 | public bool Private { get; set; }
14 | public string Description { get; set; }
15 | public string ProductName { get; set; }
16 | public string Homepage { get; set; }
17 | public bool SideEffects { get; set; }
18 | public string Main { get; set; }
19 | public string BuildVersion { get; set; }
20 | public bool IsPureShell { get; set; }
21 | public bool IsByteCodeShell { get; set; }
22 | public string Platform { get; set; }
23 | public string EleArch { get; set; }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Model/Json/LiteLoaderPluginsManifest.cs:
--------------------------------------------------------------------------------
1 | namespace RevokeMsgPatcher.Model.Json
2 | {
3 |
4 | ///
5 | /// 只有部分信息,主要是拿版本号
6 | /// https://github.com/xh321/LiteLoaderQQNT-Anti-Recall/blob/master/manifest.json
7 | ///
8 | internal class LiteLoaderPluginsManifest
9 | {
10 | public string Type { get; set; }
11 | public string Name { get; set; }
12 | public string Slug { get; set; }
13 | public string Description { get; set; }
14 | public string Version { get; set; }
15 | public string Icon { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Model/Json/ReleaseApiRes.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace RevokeMsgPatcher.Model.Json
5 | {
6 | internal class ReleaseApiRes
7 | {
8 |
9 | public string Url { get; set; }
10 | public string AssetsUrl { get; set; }
11 | public string UploadUrl { get; set; }
12 | public string HtmlUrl { get; set; }
13 | public int Id { get; set; }
14 | public string NodeId { get; set; }
15 | public string TagName { get; set; }
16 | public string TargetCommitish { get; set; }
17 | public string Name { get; set; }
18 | public bool Draft { get; set; }
19 | public bool Prerelease { get; set; }
20 | public DateTime CreatedAt { get; set; }
21 | public DateTime PublishedAt { get; set; }
22 | public List Assets { get; set; }
23 | public string TarballUrl { get; set; }
24 | public string ZipballUrl { get; set; }
25 | public string Body { get; set; }
26 | }
27 |
28 | public class Asset
29 | {
30 | public string Url { get; set; }
31 | public int Id { get; set; }
32 | public string NodeId { get; set; }
33 | public string Name { get; set; }
34 | public object Label { get; set; }
35 | public string ContentType { get; set; }
36 | public string State { get; set; }
37 | public int Size { get; set; }
38 | public int DownloadCount { get; set; }
39 | public string CreatedAt { get; set; }
40 | public string UpdatedAt { get; set; }
41 | public string BrowserDownloadUrl { get; set; }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Model/Json/VersionJson.cs:
--------------------------------------------------------------------------------
1 | namespace RevokeMsgPatcher.Model.Json
2 | {
3 | internal class VersionJson
4 | {
5 | public string Name { get; set; }
6 | public string Version { get; set; }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Model/ModifyInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace RevokeMsgPatcher.Model
9 | {
10 | public class ModifyInfo
11 | {
12 | public string Name { get; set; }
13 |
14 | public string Version { get; set; }
15 |
16 | public string SHA1Before { get; set; }
17 |
18 | public string SHA1After { get; set; }
19 |
20 | public List Changes { get; set; }
21 |
22 | public ModifyInfo Clone()
23 | {
24 | ModifyInfo o = new ModifyInfo();
25 | o.Name = Name;
26 | o.Version = Version;
27 | o.SHA1Before = SHA1Before;
28 | o.SHA1After = SHA1After;
29 | List cs = new List();
30 | foreach(Change c in Changes)
31 | {
32 | cs.Add(c.Clone());
33 | }
34 | o.Changes = cs;
35 | return o;
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Model/ReplacePattern.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace RevokeMsgPatcher.Model
4 | {
5 | public class ReplacePattern
6 | {
7 | public byte[] Search { get; set; }
8 |
9 | public byte[] Replace { get; set; }
10 |
11 | public string Category { get; set; }
12 |
13 | ///
14 | /// 悬浮气泡提示
15 | ///
16 | public string Tips { get; set; }
17 |
18 | ///
19 | /// 同类冲突标签
20 | ///
21 | public string SimilarCategories { get; set; }
22 |
23 | ///
24 | /// 选择同类冲突标签时的提示
25 | ///
26 | public string ChooseSimilarCategoriesMsg { get; set; }
27 |
28 | public ReplacePattern Clone()
29 | {
30 | ReplacePattern o = new ReplacePattern();
31 | o.Search = Search;
32 | o.Replace = Replace;
33 | return o;
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Model/TargetInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace RevokeMsgPatcher.Model
8 | {
9 | public class TargetInfo
10 | {
11 | public string Name { get; set; }
12 |
13 | public string RelativePath { get; set; }
14 |
15 | public string Memo { get; set; }
16 |
17 | public string StartVersion { get; set; }
18 |
19 | public string EndVersion { get; set; }
20 |
21 | public TargetInfo Clone()
22 | {
23 | TargetInfo o = new TargetInfo();
24 | o.Name = Name;
25 | o.RelativePath = RelativePath;
26 | o.Memo = Memo;
27 | return o;
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Modifier/FileHexEditor.cs:
--------------------------------------------------------------------------------
1 | using RevokeMsgPatcher.Model;
2 | using RevokeMsgPatcher.Utils;
3 | using System.Collections.Generic;
4 | using System.IO;
5 |
6 | namespace RevokeMsgPatcher.Modifier
7 | {
8 | public class FileHexEditor
9 | {
10 | public string FileName { get; set; }
11 |
12 | public string FilePath { get; set; }
13 |
14 | public string FileBakPath { get; set; }
15 |
16 | private string fileReplacedPath;
17 |
18 | private string version;
19 | public string FileVersion
20 | {
21 | get
22 | {
23 | if (version == null)
24 | {
25 | version = FileUtil.GetFileVersion(FilePath);
26 | }
27 | return version;
28 | }
29 | }
30 |
31 | public string BackupFileVersion
32 | {
33 | get
34 | {
35 | return FileUtil.GetFileVersion(FileBakPath);
36 | }
37 | }
38 |
39 | public string sha1;
40 | public string FileSHA1
41 | {
42 | get
43 | {
44 | if (sha1 == null)
45 | {
46 | sha1 = FileUtil.ComputeFileSHA1(FilePath);
47 | }
48 | return sha1;
49 | }
50 | }
51 |
52 | public TargetInfo FileTargetInfo { get; set; }
53 |
54 | ///
55 | /// 通过比对SHA1得到的特定版本的修改信息
56 | ///
57 | public ModifyInfo FileModifyInfo { get; set; }
58 |
59 | ///
60 | /// 通过比对版本范围得到的通用查找替换的修改信息(特征码替换信息)
61 | ///
62 | public CommonModifyInfo FileCommonModifyInfo { get; set; }
63 |
64 | ///
65 | /// 将要执行的修改
66 | ///
67 | public List TargetChanges { get; set; }
68 |
69 | public FileHexEditor(string installPath, TargetInfo target)
70 | {
71 | FileTargetInfo = target.Clone();
72 | FileName = FileTargetInfo.Name;
73 | FilePath = Path.Combine(installPath, FileTargetInfo.RelativePath);
74 | FileBakPath = FilePath + ".h.bak";
75 | fileReplacedPath = FilePath + ".h.process";
76 | }
77 |
78 | ///
79 | /// 备份
80 | ///
81 | public void Backup()
82 | {
83 | // 不覆盖同版本的备份文件
84 | if (File.Exists(FileBakPath))
85 | {
86 | if (FileVersion != BackupFileVersion)
87 | {
88 | File.Copy(FilePath, FileBakPath, true);
89 | }
90 | }
91 | else
92 | {
93 | File.Copy(FilePath, FileBakPath, true);
94 | }
95 |
96 | }
97 |
98 | ///
99 | /// 打补丁
100 | ///
101 | ///
102 | public bool Patch()
103 | {
104 | if (TargetChanges == null)
105 | {
106 | throw new BusinessException("change_null", "在安装补丁时,变更的内容为空!");
107 | }
108 |
109 | FileUtil.EditMultiHex(FilePath, TargetChanges);
110 | return true;
111 | }
112 |
113 | ///
114 | /// 还原
115 | ///
116 | public void Restore()
117 | {
118 | File.Copy(FileBakPath, FilePath, true);
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Modifier/QQLiteModifier.cs:
--------------------------------------------------------------------------------
1 | using RevokeMsgPatcher.Model;
2 | using RevokeMsgPatcher.Utils;
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | namespace RevokeMsgPatcher.Modifier
7 | {
8 | class QQLiteModifier : AppModifier
9 | {
10 | public QQLiteModifier(App config)
11 | {
12 | this.config = config;
13 | }
14 |
15 | public override void AfterPatchSuccess()
16 | {
17 | }
18 |
19 | public override void AfterPatchFail()
20 | {
21 | }
22 |
23 | ///
24 | /// 自动寻找获取微信安装路径
25 | ///
26 | ///
27 | public override string FindInstallPath()
28 | {
29 | try
30 | {
31 | string installPath = PathUtil.FindInstallPathFromRegistry("QQLite");
32 | if (!IsAllFilesExist(installPath))
33 | {
34 | List defaultPathList = PathUtil.GetDefaultInstallPaths(@"Tencent\QQLite");
35 | foreach (string defaultPath in defaultPathList)
36 | {
37 | if (IsAllFilesExist(defaultPath))
38 | {
39 | return defaultPath;
40 | }
41 | }
42 | }
43 | else
44 | {
45 | return installPath;
46 | }
47 | }
48 | catch (Exception e)
49 | {
50 | Console.WriteLine(e.Message);
51 | }
52 | return null;
53 | }
54 |
55 | ///
56 | /// 获取整个APP的当前版本
57 | ///
58 | ///
59 | public override string GetVersion()
60 | {
61 | if (editors != null && editors.Count > 0)
62 | {
63 | foreach (FileHexEditor editor in editors)
64 | {
65 | if (editor.FileName == "IM.dll")
66 | {
67 | return editor.FileVersion;
68 | }
69 | }
70 | }
71 | return "";
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Modifier/QQModifier.cs:
--------------------------------------------------------------------------------
1 | using RevokeMsgPatcher.Model;
2 | using RevokeMsgPatcher.Utils;
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | namespace RevokeMsgPatcher.Modifier
7 | {
8 | class QQModifier : AppModifier
9 | {
10 | public QQModifier(App config)
11 | {
12 | this.config = config;
13 | }
14 |
15 | public override void AfterPatchSuccess()
16 | {
17 | }
18 |
19 | public override void AfterPatchFail()
20 | {
21 | }
22 |
23 | ///
24 | /// 自动寻找获取微信安装路径
25 | ///
26 | ///
27 | public override string FindInstallPath()
28 | {
29 | try
30 | {
31 | string installPath = PathUtil.FindInstallPathFromRegistry("{052CFB79-9D62-42E3-8A15-DE66C2C97C3E}");
32 | if (!IsAllFilesExist(installPath))
33 | {
34 | List defaultPathList = PathUtil.GetDefaultInstallPaths(@"Tencent\QQ");
35 | foreach (string defaultPath in defaultPathList)
36 | {
37 | if (IsAllFilesExist(defaultPath))
38 | {
39 | return defaultPath;
40 | }
41 | }
42 | }
43 | else
44 | {
45 | return installPath;
46 | }
47 | }
48 | catch (Exception e)
49 | {
50 | Console.WriteLine(e.Message);
51 | }
52 | return null;
53 | }
54 |
55 | ///
56 | /// 获取整个APP的当前版本
57 | ///
58 | ///
59 | public override string GetVersion()
60 | {
61 | if (editors != null && editors.Count > 0)
62 | {
63 | foreach (FileHexEditor editor in editors)
64 | {
65 | if (editor.FileName == "IM.dll")
66 | {
67 | return editor.FileVersion;
68 | }
69 | }
70 | }
71 | return "";
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Modifier/QQNTModifier.cs:
--------------------------------------------------------------------------------
1 | using RevokeMsgPatcher.Model;
2 | using RevokeMsgPatcher.Utils;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 | using System.IO;
7 | using System.Text.RegularExpressions;
8 | using System.Windows.Forms;
9 |
10 | namespace RevokeMsgPatcher.Modifier
11 | {
12 | class QQNTModifier : AppModifier
13 | {
14 | public QQNTModifier(App config)
15 | {
16 | this.config = config;
17 | }
18 |
19 | ///
20 | /// 自动寻找获取微信安装路径
21 | ///
22 | ///
23 | public override string FindInstallPath()
24 | {
25 | return "请在新弹出的窗口内进行 LiteLoaderQQNT 的安装与更新!";
26 | // try
27 | // {
28 | // string installPath = PathUtil.FindInstallPathFromRegistryWOW6432Node("QQ");
29 | // if (!string.IsNullOrEmpty(installPath))
30 | // {
31 | // installPath = Path.GetDirectoryName(installPath);
32 | // if (IsAllFilesExist(installPath))
33 | // {
34 | // return installPath;
35 | // }
36 | // }
37 | //
38 | // installPath = PathUtil.FindInstallPathFromRegistry("QQNT");
39 | // if (!IsAllFilesExist(installPath))
40 | // {
41 | // List defaultPathList = PathUtil.GetDefaultInstallPaths(@"Tencent\QQNT");
42 | // foreach (string defaultPath in defaultPathList)
43 | // {
44 | // if (IsAllFilesExist(defaultPath))
45 | // {
46 | // return defaultPath;
47 | // }
48 | // }
49 | // }
50 | // else
51 | // {
52 | // return installPath;
53 | // }
54 | // }
55 | // catch (Exception e)
56 | // {
57 | // Console.WriteLine(e.Message);
58 | // }
59 | //
60 | // return null;
61 | }
62 |
63 | ///
64 | /// 获取整个APP的当前版本
65 | ///
66 | ///
67 | public override string GetVersion()
68 | {
69 | if (editors != null && editors.Count > 0)
70 | {
71 | foreach (FileHexEditor editor in editors)
72 | {
73 | if (editor.FileName == "QQ.exe")
74 | {
75 | return editor.FileVersion;
76 | }
77 | }
78 | }
79 |
80 | return "";
81 | }
82 |
83 | public string GetIndexJsPath()
84 | {
85 | if (string.IsNullOrEmpty(InstallPath))
86 | {
87 | throw new Exception("未获取到QQNT安装路径或者QQNT安装路径不合法");
88 | }
89 |
90 | string indexPath = Path.Combine(InstallPath, @"resources\app\app_launcher\index.js");
91 | if (!File.Exists(indexPath))
92 | {
93 | throw new Exception("未找到index.js文件");
94 | }
95 |
96 | return indexPath;
97 | }
98 |
99 | public string GetLiteLoaderPath()
100 | {
101 | return Path.Combine(Application.StartupPath, @"LiteLoaderQQNT");
102 | }
103 |
104 | public override void AfterPatchSuccess()
105 | {
106 | string indexPath = GetIndexJsPath();
107 | string content = File.ReadAllText(indexPath);
108 | // 正则 require\(String.raw`.*`\);
109 | string pattern = @"require\(String.raw`.*`\);";
110 | string liteLoaderPath = GetLiteLoaderPath();
111 | if (!Directory.Exists(liteLoaderPath))
112 | {
113 | MessageBox.Show("LiteLoaderQQNT文件夹不存在,仅安装QQNT去验证补丁", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
114 | return;
115 | }
116 |
117 | string replacement = $"require(String.raw`{liteLoaderPath}`);";
118 | if (Regex.IsMatch(content, pattern))
119 | {
120 | content = Regex.Replace(content, pattern, replacement);
121 | }
122 | else
123 | {
124 | content = replacement + "\n" + content;
125 | }
126 |
127 | File.WriteAllText(indexPath, content);
128 | }
129 |
130 | public override void AfterPatchFail()
131 | {
132 | try
133 | {
134 | string indexPath = GetIndexJsPath();
135 | string content = File.ReadAllText(indexPath);
136 | string pattern = @"require\(String.raw`.*`\);\n";
137 | if (Regex.IsMatch(content, pattern))
138 | {
139 | content = Regex.Replace(content, pattern, "");
140 | File.WriteAllText(indexPath, content);
141 | }
142 | }
143 | catch (Exception e)
144 | {
145 | Debug.WriteLine(e);
146 | }
147 | }
148 |
149 | public new bool Restore()
150 | {
151 | AfterPatchFail();
152 | return base.Restore();
153 | }
154 | }
155 | }
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Modifier/TIMModifier.cs:
--------------------------------------------------------------------------------
1 | using RevokeMsgPatcher.Model;
2 | using RevokeMsgPatcher.Utils;
3 |
4 | namespace RevokeMsgPatcher.Modifier
5 | {
6 | class TIMModifier : AppModifier
7 | {
8 |
9 | public TIMModifier(App config)
10 | {
11 | this.config = config;
12 | }
13 |
14 | public override void AfterPatchSuccess()
15 | {
16 | }
17 |
18 | public override void AfterPatchFail()
19 | {
20 | }
21 |
22 | ///
23 | /// 自动寻找获取微信安装路径
24 | ///
25 | ///
26 | public override string FindInstallPath()
27 | {
28 | string installPath = PathUtil.FindInstallPathFromRegistry("TIM");
29 | if (!IsAllFilesExist(installPath))
30 | {
31 | foreach (string defaultPath in PathUtil.GetDefaultInstallPaths(@"Tencent\TIM"))
32 | {
33 | if (IsAllFilesExist(defaultPath))
34 | {
35 | return defaultPath;
36 | }
37 | }
38 | }
39 | else
40 | {
41 | return installPath;
42 | }
43 | return null;
44 | }
45 |
46 | ///
47 | /// 获取整个APP的当前版本
48 | ///
49 | ///
50 | public override string GetVersion()
51 | {
52 | if (editors != null && editors.Count > 0)
53 | {
54 | foreach (FileHexEditor editor in editors)
55 | {
56 | if (editor.FileName == "IM.dll")
57 | {
58 | return editor.FileVersion;
59 | }
60 | }
61 | }
62 | return "";
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Modifier/WechatModifier.cs:
--------------------------------------------------------------------------------
1 | using RevokeMsgPatcher.Model;
2 | using RevokeMsgPatcher.Utils;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.IO;
6 |
7 | namespace RevokeMsgPatcher.Modifier
8 | {
9 | class WechatModifier : AppModifier
10 | {
11 |
12 | public WechatModifier(App config)
13 | {
14 | this.config = config;
15 | }
16 |
17 | public override void AfterPatchSuccess()
18 | {
19 | }
20 |
21 | public override void AfterPatchFail()
22 | {
23 | }
24 |
25 | ///
26 | /// 自动寻找获取微信安装路径
27 | ///
28 | ///
29 | public override string FindInstallPath()
30 | {
31 | try
32 | {
33 | string installPath = PathUtil.FindInstallPathFromRegistry("Wechat");
34 | string realPath = GetRealInstallPath(installPath);
35 | if (string.IsNullOrEmpty(realPath))
36 | {
37 | List defaultPathList = PathUtil.GetDefaultInstallPaths(@"Tencent\Wechat");
38 | foreach (string defaultPath in defaultPathList)
39 | {
40 | realPath = GetRealInstallPath(defaultPath);
41 | if (!string.IsNullOrEmpty(realPath))
42 | {
43 | return defaultPath;
44 | }
45 | }
46 | }
47 | else
48 | {
49 | return realPath;
50 | }
51 | }
52 | catch (Exception e)
53 | {
54 | Console.WriteLine(e.Message);
55 | }
56 | return null;
57 | }
58 |
59 | ///
60 | /// 微信 3.5.0.4 改变了目录结构
61 | ///
62 | ///
63 | ///
64 | private string GetRealInstallPath(string basePath)
65 | {
66 | if (basePath == null)
67 | {
68 | return null;
69 | }
70 | if (IsAllFilesExist(basePath))
71 | {
72 | return basePath;
73 | }
74 | DirectoryInfo[] directories = new DirectoryInfo(basePath).GetDirectories();
75 | PathUtil.SortByLastWriteTimeDesc(ref directories); // 按修改时间倒序
76 | foreach (DirectoryInfo folder in directories)
77 | {
78 | if (IsAllFilesExist(folder.FullName))
79 | {
80 | return folder.FullName;
81 | }
82 | }
83 | return null;
84 | }
85 |
86 |
87 | ///
88 | /// 获取整个APP的当前版本
89 | ///
90 | ///
91 | public override string GetVersion()
92 | {
93 | if (editors != null && editors.Count > 0)
94 | {
95 | foreach (FileHexEditor editor in editors)
96 | {
97 | if (editor.FileName == "WeChatWin.dll")
98 | {
99 | return editor.FileVersion;
100 | }
101 | }
102 | }
103 | return "";
104 | }
105 |
106 | //public override bool ValidateAndInitialize(string installPath)
107 | //{
108 | // // 判断是否是安装路径
109 | // if (!IsAllBinaryFilesExist(installPath))
110 | // {
111 | // return false;
112 | // }
113 |
114 | // // 初始化十六进制文件编辑器
115 | // // 并寻找与之配对的版本修改信息
116 | // InitEditors(installPath);
117 |
118 | // return true;
119 | //}
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Modifier/WeixinModifier.cs:
--------------------------------------------------------------------------------
1 | using RevokeMsgPatcher.Model;
2 | using RevokeMsgPatcher.Utils;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.IO;
6 |
7 | namespace RevokeMsgPatcher.Modifier
8 | {
9 | class WeixinModifier : AppModifier
10 | {
11 |
12 | public WeixinModifier(App config)
13 | {
14 | this.config = config;
15 | }
16 |
17 | public override void AfterPatchSuccess()
18 | {
19 | }
20 |
21 | public override void AfterPatchFail()
22 | {
23 | }
24 |
25 | ///
26 | /// 自动寻找获取微信安装路径
27 | ///
28 | ///
29 | public override string FindInstallPath()
30 | {
31 | try
32 | {
33 | string installPath = PathUtil.FindInstallPathFromRegistryWOW6432Node("Weixin");
34 | string realPath = null;
35 | if (!string.IsNullOrEmpty(installPath))
36 | {
37 | installPath = Path.GetDirectoryName(installPath);
38 | realPath = GetRealInstallPath(installPath);
39 | }
40 | if (string.IsNullOrEmpty(realPath))
41 | {
42 | List defaultPathList = PathUtil.GetDefaultInstallPaths(@"Tencent\Weixin");
43 | foreach (string defaultPath in defaultPathList)
44 | {
45 | realPath = GetRealInstallPath(defaultPath);
46 | if (!string.IsNullOrEmpty(realPath))
47 | {
48 | return defaultPath;
49 | }
50 | }
51 | }
52 | else
53 | {
54 | return realPath;
55 | }
56 | }
57 | catch (Exception e)
58 | {
59 | Console.WriteLine(e.Message);
60 | }
61 | return null;
62 | }
63 |
64 | ///
65 | /// 微信目录结构
66 | ///
67 | ///
68 | ///
69 | private string GetRealInstallPath(string basePath)
70 | {
71 | if (basePath == null)
72 | {
73 | return null;
74 | }
75 | DirectoryInfo[] directories = new DirectoryInfo(basePath).GetDirectories();
76 | PathUtil.SortByLastWriteTimeDesc(ref directories); // 按修改时间倒序
77 | foreach (DirectoryInfo folder in directories)
78 | {
79 | if (IsAllFilesExist(folder.FullName))
80 | {
81 | return folder.FullName;
82 | }
83 | }
84 | return null;
85 | }
86 |
87 |
88 | ///
89 | /// 获取整个APP的当前版本
90 | ///
91 | ///
92 | public override string GetVersion()
93 | {
94 | if (editors != null && editors.Count > 0)
95 | {
96 | foreach (FileHexEditor editor in editors)
97 | {
98 | if (editor.FileName == "Weixin.dll")
99 | {
100 | return editor.FileVersion;
101 | }
102 | }
103 | }
104 | return "";
105 | }
106 |
107 | //public override bool ValidateAndInitialize(string installPath)
108 | //{
109 | // // 判断是否是安装路径
110 | // if (!IsAllBinaryFilesExist(installPath))
111 | // {
112 | // return false;
113 | // }
114 |
115 | // // 初始化十六进制文件编辑器
116 | // // 并寻找与之配对的版本修改信息
117 | // InitEditors(installPath);
118 |
119 | // return true;
120 | //}
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using System.Windows.Forms;
6 |
7 | namespace RevokeMsgPatcher
8 | {
9 | static class Program
10 | {
11 | ///
12 | /// 应用程序的主入口点。
13 | ///
14 | [STAThread]
15 | static void Main()
16 | {
17 |
18 |
19 | #if DEBUG
20 | Application.EnableVisualStyles();
21 | Application.SetCompatibleTextRenderingDefault(false);
22 | Application.Run(new FormMain());
23 | #else
24 | try
25 | {
26 | Application.EnableVisualStyles();
27 | Application.SetCompatibleTextRenderingDefault(false);
28 |
29 | //当前用户是管理员的时候,直接启动应用程序
30 | //如果不是管理员,则使用启动对象启动程序,以确保使用管理员身份运行
31 | //获得当前登录的Windows用户标示
32 | System.Security.Principal.WindowsIdentity identity = System.Security.Principal.WindowsIdentity.GetCurrent();
33 | System.Security.Principal.WindowsPrincipal principal = new System.Security.Principal.WindowsPrincipal(identity);
34 | //判断当前登录用户是否为管理员
35 | if (principal.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator))
36 | {
37 | //如果是管理员,则直接运行
38 | Application.Run(new FormMain());
39 | }
40 | else
41 | {
42 | //创建启动对象
43 | System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
44 | startInfo.UseShellExecute = true;
45 | startInfo.WorkingDirectory = Environment.CurrentDirectory;
46 | startInfo.FileName = Application.ExecutablePath;
47 | //设置启动动作,确保以管理员身份运行
48 | startInfo.Verb = "runas";
49 | try
50 | {
51 | System.Diagnostics.Process.Start(startInfo);
52 | }
53 | catch
54 | {
55 | return;
56 | }
57 | //退出
58 | Application.Exit();
59 | }
60 |
61 | }
62 | catch (Exception ex)
63 | {
64 | MessageBox.Show(ex.Message + "\n" + ex.StackTrace.Trim(), "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
65 | }
66 | #endif
67 | }
68 |
69 |
70 | static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
71 | {
72 | MessageBox.Show(e.Exception.Message + "\n" + e.Exception.StackTrace.Trim(), "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
73 | }
74 |
75 | static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
76 | {
77 | MessageBox.Show((e.ExceptionObject as Exception).Message + "\n" + (e.ExceptionObject as Exception).StackTrace.Trim(), "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // 有关程序集的一般信息由以下
6 | // 控制。更改这些特性值可修改
7 | // 与程序集关联的信息。
8 | [assembly: AssemblyTitle("RevokeMsgPatcher")]
9 | [assembly: AssemblyDescription("微信防撤回补丁")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("huiyadanli")]
12 | [assembly: AssemblyProduct("RevokeMsgPatcher")]
13 | [assembly: AssemblyCopyright("Copyright © 2019-2021")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // 将 ComVisible 设置为 false 会使此程序集中的类型
18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
19 | //请将此类型的 ComVisible 特性设置为 true。
20 | [assembly: ComVisible(false)]
21 |
22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
23 | [assembly: Guid("977bf781-ced8-4389-9404-0fa08fdf21df")]
24 |
25 | // 程序集的版本信息由下列四个值组成:
26 | //
27 | // 主版本
28 | // 次版本
29 | // 生成号
30 | // 修订号
31 | //
32 | // 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
33 | // 方法是按如下所示使用“*”: :
34 | //[assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("2.0")]
36 | [assembly: AssemblyFileVersion("2.0")]
37 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // 此代码由工具生成。
4 | // 运行时版本:4.0.30319.42000
5 | //
6 | // 对此文件的更改可能会导致不正确的行为,并且如果
7 | // 重新生成代码,这些更改将会丢失。
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace RevokeMsgPatcher.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// 一个强类型的资源类,用于查找本地化的字符串等。
17 | ///
18 | // 此类是由 StronglyTypedResourceBuilder
19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
20 | // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
21 | // (以 /str 作为命令选项),或重新生成 VS 项目。
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// 返回此类使用的缓存的 ResourceManager 实例。
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RevokeMsgPatcher.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// 重写当前线程的 CurrentUICulture 属性,对
51 | /// 使用此强类型资源类的所有资源查找执行重写。
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 |
63 | ///
64 | /// 查找类似 {"Apps":{"Wechat":{"Name":"WeChat","FileTargetInfos":{"WeChatWin.dll":{"Name":"WeChatWin.dll","RelativePath":"WeChatWin.dll","Memo":null,"StartVersion":"1.0.0.0","EndVersion":null},"WeChat.exe":{"Name":"WeChat.exe","RelativePath":"../WeChat.exe","Memo":null,"StartVersion":"3.7.0.0","EndVersion":"3.7.0.26"}},"FileModifyInfos":{"WeChat.exe":[],"WeChatWin.dll":[{"Name":"WeChatWin.dll","Version":"3.3.5.25","SHA1Before":"3e94753ccbc2799d98f3c741377e99bdae33b4cf","SHA1After":"ab98f83fc16674ac4911380882c79c3ca4c2f [字符串的其余部分被截断]"; 的本地化字符串。
65 | ///
66 | internal static string PatchJson {
67 | get {
68 | return ResourceManager.GetString("PatchJson", resourceCulture);
69 | }
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // 此代码由工具生成。
4 | // 运行时版本:4.0.30319.42000
5 | //
6 | // 对此文件的更改可能会导致不正确的行为,并且如果
7 | // 重新生成代码,这些更改将会丢失。
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace RevokeMsgPatcher.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.1.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/RevokeMsgPatcher.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {977BF781-CED8-4389-9404-0FA08FDF21DF}
8 | WinExe
9 | RevokeMsgPatcher
10 | RevokeMsgPatcher
11 | v4.5.2
12 | 512
13 | true
14 |
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 | icon.ico
37 |
38 |
39 | app.manifest
40 |
41 |
42 |
43 | ..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | Form
64 |
65 |
66 | FormMain.cs
67 |
68 |
69 | Form
70 |
71 |
72 | FormLiteLoaderQQNT.cs
73 |
74 |
75 | Form
76 |
77 |
78 | FormPatchInfo.cs
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 | FormMain.cs
116 |
117 |
118 | FormLiteLoaderQQNT.cs
119 |
120 |
121 | FormPatchInfo.cs
122 |
123 |
124 | ResXFileCodeGenerator
125 | Resources.Designer.cs
126 | Designer
127 |
128 |
129 | True
130 | Resources.resx
131 | True
132 |
133 |
134 |
135 |
136 | SettingsSingleFileGenerator
137 | Settings.Designer.cs
138 |
139 |
140 | True
141 | Settings.settings
142 | True
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Utils/ByteUtil.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace RevokeMsgPatcher.Utils
8 | {
9 | public class ByteUtil
10 | {
11 | public static byte[] HexStringToByteArray(string hex)
12 | {
13 | hex = hex.Replace(" ", "");
14 | return Enumerable.Range(0, hex.Length)
15 | .Where(x => x % 2 == 0)
16 | .Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
17 | .ToArray();
18 | }
19 |
20 |
21 | public static string ByteArrayToHexString(byte[] data)
22 | {
23 | StringBuilder sb = new StringBuilder(data.Length * 3);
24 | foreach (byte b in data)
25 | {
26 | sb.Append(Convert.ToString(b, 16).PadLeft(2, '0').PadRight(3, ' '));
27 | }
28 | return sb.ToString().ToUpper();
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Utils/Device.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Management;
5 | using System.Net;
6 | using System.Security.Cryptography;
7 | using System.Text;
8 |
9 | namespace RevokeMsgPatcher.Utils
10 | {
11 | public class Device
12 | {
13 | private static string macID = null;
14 | private static string osVersion = null;
15 |
16 | private static string fingerPrint = null;
17 |
18 | #region PROP, get it only once
19 |
20 | public static string MacID
21 | {
22 | get
23 | {
24 | if (macID == null)
25 | {
26 | macID = ObtainMacID();
27 | }
28 | return macID;
29 | }
30 | }
31 |
32 | public static string OSVersion
33 | {
34 | get
35 | {
36 | if (osVersion == null)
37 | {
38 | var name = (from x in new ManagementObjectSearcher("SELECT Caption FROM Win32_OperatingSystem").Get().Cast()
39 | select x.GetPropertyValue("Caption")).FirstOrDefault();
40 | osVersion = name != null ? name.ToString() : "Unknown";
41 | }
42 | return osVersion;
43 | }
44 | }
45 | #endregion
46 |
47 | ///
48 | /// Calculate GUID
49 | ///
50 | /// GUID
51 | public static string Value()
52 | {
53 | try
54 | {
55 | if (fingerPrint == null)
56 | {
57 | fingerPrint = GetHash(
58 | "MAC >> " + MacID
59 | );
60 | }
61 | return fingerPrint;
62 | }
63 | catch
64 | {
65 | return Guid.NewGuid().ToString();
66 | }
67 |
68 | }
69 |
70 | private static string GetHash(string s)
71 | {
72 | MD5 sec = new MD5CryptoServiceProvider();
73 | ASCIIEncoding enc = new ASCIIEncoding();
74 | byte[] bt = enc.GetBytes(s);
75 | return GetHexString(sec.ComputeHash(bt));
76 | }
77 |
78 | private static string GetHexString(byte[] bt)
79 | {
80 | string s = string.Empty;
81 | for (int i = 0; i < bt.Length; i++)
82 | {
83 | byte b = bt[i];
84 | int n, n1, n2;
85 | n = (int)b;
86 | n1 = n & 15;
87 | n2 = (n >> 4) & 15;
88 | if (n2 > 9)
89 | s += ((char)(n2 - 10 + (int)'A')).ToString();
90 | else
91 | s += n2.ToString();
92 | if (n1 > 9)
93 | s += ((char)(n1 - 10 + (int)'A')).ToString();
94 | else
95 | s += n1.ToString();
96 | if ((i + 1) != bt.Length && (i + 1) % 2 == 0) s += "-";
97 | }
98 | return s;
99 | }
100 |
101 |
102 | #region Original Device ID Getting Code
103 |
104 | public static string ObtainMacID()
105 | {
106 | return Identifier("Win32_NetworkAdapterConfiguration", "MACAddress", "IPEnabled");
107 | }
108 |
109 | private static string Identifier(string wmiClass, string wmiProperty, string wmiMustBeTrue)
110 | {
111 | string result = "";
112 | try
113 | {
114 | ManagementClass mc = new ManagementClass(wmiClass);
115 | ManagementObjectCollection moc = mc.GetInstances();
116 | foreach (ManagementObject mo in moc)
117 | {
118 | if (mo[wmiMustBeTrue].ToString() == "True")
119 | {
120 | //Only get the first one
121 | if (result == "")
122 | {
123 | result = mo[wmiProperty].ToString();
124 | break;
125 | }
126 | }
127 | }
128 | }
129 | catch
130 | {
131 | }
132 | return result;
133 | }
134 |
135 | private static string Identifier(string wmiClass, string wmiProperty)
136 | {
137 | string result = "";
138 | try
139 | {
140 | ManagementClass mc = new ManagementClass(wmiClass);
141 | ManagementObjectCollection moc = mc.GetInstances();
142 | foreach (ManagementObject mo in moc)
143 | {
144 | //Only get the first one
145 | if (result == "")
146 | {
147 | result = mo[wmiProperty].ToString();
148 | break;
149 | }
150 | }
151 | }
152 | catch
153 | {
154 | }
155 | return result;
156 | }
157 | #endregion
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Utils/FileUtil.cs:
--------------------------------------------------------------------------------
1 | using RevokeMsgPatcher.Model;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using System.Security.Cryptography;
6 | using System.Text;
7 |
8 | namespace RevokeMsgPatcher.Utils
9 | {
10 | public class FileUtil
11 | {
12 | ///
13 | /// 获取文件版本
14 | ///
15 | ///
16 | ///
17 | public static string GetFileVersion(string path)
18 | {
19 | if (File.Exists(path))
20 | {
21 | FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(path);
22 | return fileVersionInfo.FileVersion;
23 | }
24 | else
25 | {
26 | return null;
27 | }
28 |
29 | }
30 |
31 | ///
32 | /// 计算文件SHA1
33 | ///
34 | /// 文件路径
35 | ///
36 | public static string ComputeFileSHA1(string s)
37 | {
38 | File.SetAttributes(s, FileAttributes.Normal);
39 | FileStream file = new FileStream(s, FileMode.Open);
40 | SHA1 sha1 = new SHA1CryptoServiceProvider();
41 | byte[] retval = sha1.ComputeHash(file);
42 | file.Close();
43 |
44 | StringBuilder sc = new StringBuilder();
45 | for (int i = 0; i < retval.Length; i++)
46 | {
47 | sc.Append(retval[i].ToString("x2"));
48 | }
49 | return sc.ToString();
50 | }
51 |
52 | ///
53 | /// 修改文件指定位置的字节
54 | ///
55 | /// 文件对象的路径
56 | /// 偏移位置
57 | /// 修改后的值
58 | ///
59 | public static bool EditHex(string path, long position, byte after)
60 | {
61 | using (var stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite))
62 | {
63 | stream.Position = position;
64 | stream.WriteByte(after);
65 | }
66 | return true;
67 |
68 | }
69 |
70 | ///
71 | /// 修改文件多个指定位置的多个字节
72 | ///
73 | /// 文件对象的路径
74 | /// 需要修改的位置和内容
75 | public static void EditMultiHex(string path, List changes)
76 | {
77 | using (var stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite))
78 | {
79 | foreach (Change change in changes)
80 | {
81 | stream.Seek(change.Position, SeekOrigin.Begin);
82 | foreach(byte b in change.Content)
83 | {
84 | // 跳过通配符
85 | if(b == 0x3F)
86 | {
87 | stream.ReadByte();
88 | }
89 | else
90 | {
91 | stream.WriteByte(b);
92 | }
93 | }
94 | }
95 | }
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Utils/GAHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net.Http;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.Web.Script.Serialization;
8 | using System.Windows.Forms;
9 |
10 | namespace RevokeMsgPatcher.Utils
11 | {
12 | ///
13 | /// 用于软件的 Google Analytics 实现 By huiyadanli
14 | /// 20230409 更新 GA4 的实现
15 | /// 相关文档:
16 | /// #GA指南(过时) https://developers.google.com/analytics/devguides/collection/protocol/v1/devguide
17 | /// #GA参数(过时) https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters
18 | /// GA4教程 https://firebase.google.com/codelabs/firebase_mp
19 | /// 测试 https://ga-dev-tools.google/ga4/event-builder/
20 | ///
21 | public class GAHelper
22 | {
23 | private static GAHelper instance = null;
24 | private static readonly object obj = new object();
25 |
26 | public static GAHelper Instance
27 | {
28 | get
29 | {
30 | //lock (obj)
31 | //{
32 | if (instance == null)
33 | {
34 | instance = new GAHelper();
35 | }
36 | return instance;
37 | //}
38 | }
39 | }
40 |
41 | // 根据实际情况修改
42 | private static readonly HttpClient client = HttpUtil.Client;
43 |
44 | private const string GAUrl = "https://www.google-analytics.com/mp/collect?api_secret=urKlcc29TSy3OIkHr8yFSQ&measurement_id=G-BE6FRPZS1W";
45 |
46 | private static readonly string cid = Device.Value(); // Anonymous Client ID. // Guid.NewGuid().ToString()
47 |
48 |
49 | public string UserAgent { get; set; }
50 |
51 | public GAHelper()
52 | {
53 | UserAgent = $"Hui Google Analytics Tracker/1.0 ({Environment.OSVersion.Platform.ToString()}; {Environment.OSVersion.Version.ToString()}; {Environment.OSVersion.VersionString})";
54 | }
55 |
56 | public async Task RequestPageViewAsync(string page, string title = null)
57 | {
58 | try
59 | {
60 | if (page.StartsWith("/"))
61 | {
62 | page = page.Remove(0, 1);
63 | }
64 | page = page.Replace("/", "_").Replace(".", "_");
65 | // 请求参数
66 | var values = new Dictionary
67 | {
68 | { "client_id",UserAgent},
69 | { "user_id", cid },
70 | { "non_personalized_ads", "false" },
71 | { "events", new List>()
72 | {
73 | new Dictionary()
74 | {
75 | { "name",page },
76 | {
77 | "params",
78 | new Dictionary()
79 | {
80 | { "engagement_time_msec", "1"},
81 | }
82 | },
83 | }
84 | }
85 | },
86 | };
87 | var serializer = new JavaScriptSerializer();
88 | var json = serializer.Serialize(values);
89 | var content = new StringContent(json, Encoding.UTF8, "application/json");
90 | var response = await client.PostAsync(GAUrl, content);
91 | // Console.WriteLine(response.ToString());
92 | }
93 | catch (Exception ex)
94 | {
95 |
96 | Console.WriteLine("GAHelper:" + ex.Message);
97 | Console.WriteLine(ex.StackTrace);
98 | }
99 | }
100 |
101 | public void RequestPageView(string page, string title = null)
102 | {
103 | Task.Run(() => RequestPageViewAsync(page, title));
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Utils/HttpUtil.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Net.Http;
4 | using System.Threading.Tasks;
5 |
6 | namespace RevokeMsgPatcher.Utils
7 | {
8 | public class HttpUtil
9 | {
10 | public static HttpClient Client { get; } = new HttpClient();
11 |
12 | static HttpUtil()
13 | {
14 | 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");
15 | ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
16 | }
17 |
18 | ///
19 | /// 补丁路径
20 | /// 已经弃用的路径
21 | /// https://swordmaker-hauls-51508.netlify.com/i/revokemsg/05.json
22 | /// https://huiyadanli.github.io/i/revokemsg/05.json
23 | /// 会自动跳转,没用了
24 | /// https://gitee.com/huiyadanli/RevokeMsgPatcher/raw/master/RevokeMsgPatcher.Assistant/Data/1.2/patch.json
25 | /// 需要登录,没用了
26 | /// https://huiyadanli.coding.net/p/RevokeMsgPatcher/d/RevokeMsgPatcher/git/raw/master/RevokeMsgPatcher.Assistant/Data/1.6/patch.json
27 | ///
28 |
29 | public static string PatchVersion
30 | {
31 | get
32 | {
33 | string currentVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
34 | if (currentVersion.Length > 3)
35 | {
36 | return currentVersion.Substring(0, 3);
37 | }
38 |
39 | return "1.6";
40 | }
41 | }
42 |
43 | private static readonly string[] urls = new string[]
44 | {
45 | $"https://hui-config.oss-cn-hangzhou.aliyuncs.com/{PatchVersion}/patch.json",
46 | $"https://mirror.ghproxy.com/https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/master/RevokeMsgPatcher.Assistant/Data/{PatchVersion}/patch.json",
47 | $"https://raw.gitmirror.com/huiyadanli/RevokeMsgPatcher/master/RevokeMsgPatcher.Assistant/Data/{PatchVersion}/patch.json",
48 | $"https://cdn.jsdelivr.net/gh/huiyadanli/RevokeMsgPatcher@master/RevokeMsgPatcher.Assistant/Data/{PatchVersion}/patch.json",
49 | $"https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/master/RevokeMsgPatcher.Assistant/Data/{PatchVersion}/patch.json",
50 | };
51 |
52 | public static async Task GetPatchJsonAsync()
53 | {
54 | int i = 0;
55 | while (i < urls.Length)
56 | {
57 | try
58 | {
59 | string json = await Client.GetStringAsync(urls[i]);
60 | if (!string.IsNullOrEmpty(json) && json.Contains("LatestVersion"))
61 | {
62 | return json;
63 | }
64 | else
65 | {
66 | Console.WriteLine("第" + (i + 1) + "次请求获得的数据并非期望数据\nURL:" + urls[i]);
67 | GAHelper.Instance.RequestPageView($"/main/json/request_ex/{i + 1}/not_my_json", "第" + (i + 1) + "次请求获得的数据并非期望数据");
68 | }
69 | }
70 | catch (Exception ex)
71 | {
72 | Console.WriteLine("第" + (i + 1) + "次请求异常:[" + ex.Message + "]\nURL:" + urls[i]);
73 | GAHelper.Instance.RequestPageView($"/main/json/request_ex/{i + 1}/{ex.Message}", "第" + (i + 1) + "次请求异常:[" + ex.Message + "]");
74 | }
75 | i++;
76 | }
77 | return null;
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Utils/PathUtil.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Win32;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace RevokeMsgPatcher.Utils
10 | {
11 | public class PathUtil
12 | {
13 | public static void DisplayAllProgram()
14 | {
15 | RegistryKey uninstallKey, programKey;
16 | uninstallKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall");
17 | string[] programKeys = uninstallKey.GetSubKeyNames();
18 | foreach (string keyName in programKeys)
19 | {
20 | programKey = uninstallKey.OpenSubKey(keyName);
21 | Console.WriteLine(keyName + " , " + programKey.GetValue("DisplayName") + " , " + programKey.GetValue("InstallLocation"));
22 | programKey.Close();
23 | }
24 |
25 | uninstallKey.Close();
26 | }
27 |
28 | ///
29 | /// 从注册表中寻找安装路径
30 | ///
31 | ///
32 | /// 安装信息的注册表键名
33 | /// 微信:WeChat
34 | /// QQ:{052CFB79-9D62-42E3-8A15-DE66C2C97C3E}
35 | /// TIM:TIM
36 | ///
37 | /// 安装路径
38 | public static string FindInstallPathFromRegistry(string uninstallKeyName)
39 | {
40 | try
41 | {
42 | RegistryKey key = Registry.LocalMachine.OpenSubKey($@"Software\Microsoft\Windows\CurrentVersion\Uninstall\{uninstallKeyName}");
43 | if (key == null)
44 | {
45 | return null;
46 | }
47 |
48 | object installLocation = key.GetValue("InstallLocation");
49 | key.Close();
50 | if (installLocation != null && !string.IsNullOrEmpty(installLocation.ToString()))
51 | {
52 | return installLocation.ToString();
53 | }
54 | }
55 | catch (Exception e)
56 | {
57 | Console.WriteLine(e.Message);
58 | }
59 |
60 | return null;
61 | }
62 |
63 |
64 | public static string FindInstallPathFromRegistryWOW6432Node(string uninstallKeyName)
65 | {
66 | try
67 | {
68 | RegistryKey key = Registry.LocalMachine.OpenSubKey($@"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{uninstallKeyName}");
69 | if (key == null)
70 | {
71 | return null;
72 | }
73 |
74 | object installLocation = key.GetValue("UninstallString");
75 | key.Close();
76 | if (installLocation != null && !string.IsNullOrEmpty(installLocation.ToString()))
77 | {
78 | return installLocation.ToString().Replace("\"","");
79 | }
80 | }
81 | catch (Exception e)
82 | {
83 | Console.WriteLine(e.Message);
84 | }
85 |
86 | return null;
87 | }
88 |
89 | ///
90 | /// 获取所有可能的默认安装路径
91 | ///
92 | /// Tencent\*
93 | ///
94 | public static List GetDefaultInstallPaths(string relativePath)
95 | {
96 | List list = new List();
97 | // 从默认安装目录查找
98 | string[] drives = Environment.GetLogicalDrives(); //获取当前计算机逻辑磁盘名称列表
99 | foreach (string d in drives)
100 | {
101 | string path = Path.Combine(d, $@"Program Files (x86)\{relativePath}");
102 | if (Directory.Exists(path))
103 | {
104 | list.Add(path);
105 | }
106 | else
107 | {
108 | path = Path.Combine(d, $@"Program Files\{relativePath}");
109 | if (Directory.Exists(path))
110 | {
111 | list.Add(path);
112 | }
113 | }
114 | }
115 |
116 | return list;
117 | }
118 |
119 | ///
120 | /// 按文件夹修改时间倒序
121 | ///
122 | ///
123 | public static void SortByLastWriteTimeDesc(ref DirectoryInfo[] dirs)
124 | {
125 | Array.Sort(dirs, delegate(DirectoryInfo x, DirectoryInfo y) { return y.LastWriteTime.CompareTo(x.LastWriteTime); });
126 | }
127 | }
128 | }
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Utils/ProxySpeedTester.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Net.Http;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 |
8 | namespace RevokeMsgPatcher.Utils
9 | {
10 | public class ProxySpeedTester
11 | {
12 | public static readonly string TargetUrl = "https://raw.githubusercontent.com/LiteLoaderQQNT/LiteLoaderQQNT/refs/heads/main/package.json";
13 |
14 | private static readonly HttpClient _httpClient = new HttpClient() { Timeout = TimeSpan.FromSeconds(5) };
15 |
16 | public static readonly List ProxyUrls = new List()
17 | {
18 | "{0}",
19 | "https://mirror.ghproxy.com/{0}",
20 | "https://hub.gitmirror.com/{0}",
21 | "https://ghproxy.cc/{0}",
22 | "https://www.ghproxy.cc/{0}",
23 | "https://ghproxy.cn/{0}",
24 | "https://ghproxy.net/{0}"
25 | };
26 |
27 | ///
28 | /// 获得最快的代理地址
29 | ///
30 | ///
31 | /// 最快的代理地址,结果
32 | public static async Task> GetFastestProxyAsync(string target)
33 | {
34 | return await GetFastestProxyAsync(ProxyUrls, target);
35 | }
36 |
37 | public static async Task> GetFastestProxyAsync(List proxyAddresses, string target)
38 | {
39 | var tasks = new List>>(); // 修改为包含成功标志的元组
40 | var cts = new CancellationTokenSource();
41 |
42 | foreach (var proxy in proxyAddresses)
43 | {
44 | // 如果目标地址为空且代理地址为默认地址,则跳过
45 | if (string.IsNullOrEmpty(target) && proxy == "{0}")
46 | {
47 | continue;
48 | }
49 |
50 | tasks.Add(TestProxyAsync(proxy, target, cts.Token));
51 | }
52 |
53 | while (tasks.Count > 0)
54 | {
55 | var firstCompletedTask = await Task.WhenAny(tasks);
56 | tasks.Remove(firstCompletedTask);
57 |
58 | var result = await firstCompletedTask;
59 | if (result.Item3) // 检查是否成功
60 | {
61 | cts.Cancel(); // 取消所有其他请求
62 | return new Tuple(result.Item1, result.Item2); // 返回第一个成功的代理地址
63 | }
64 | }
65 |
66 | return new Tuple(string.Empty, string.Empty); // 如果没有成功的结果,返回空
67 | }
68 |
69 | private static async Task> TestProxyAsync(string proxyAddress, string target, CancellationToken cancellationToken)
70 | {
71 | try
72 | {
73 | // 模拟代理测试请求
74 | var response = await _httpClient.GetAsync(string.Format(proxyAddress, target), cancellationToken);
75 | response.EnsureSuccessStatusCode();
76 | return new Tuple(proxyAddress.Replace("{0}", ""), await response.Content.ReadAsStringAsync(), true);
77 | }
78 | catch (Exception e)
79 | {
80 | return new Tuple(proxyAddress.Replace("{0}", ""), e.Message, false);
81 | }
82 | }
83 | }
84 | }
--------------------------------------------------------------------------------
/RevokeMsgPatcher/Utils/VersionUtil.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace RevokeMsgPatcher.Utils
8 | {
9 | public class VersionUtil
10 | {
11 | ///
12 | /// 版本比较
13 | /// 0 相等
14 | /// 1 大与
15 | /// -1 小于
16 | /// 为空的版本最大
17 | ///
18 | /// 版本1
19 | /// 版本2
20 | ///
21 | public static int Compare(string v1, string v2)
22 | {
23 | if (string.IsNullOrEmpty(v1))
24 | {
25 | return 1;
26 | }
27 | if (string.IsNullOrEmpty(v2))
28 | {
29 | return -1;
30 | }
31 |
32 | string[] v1s = v1.Split('.');
33 | string[] v2s = v2.Split('.');
34 | int len = Math.Max(v1s.Length, v2s.Length);
35 | for (int i = 0; i < len; i++)
36 | {
37 | int i1 = 0, i2 = 0;
38 | if (i < v1s.Length)
39 | {
40 | i1 = Convert.ToInt32(v1s[i]);
41 | }
42 | if (i < v2s.Length)
43 | {
44 | i2 = Convert.ToInt32(v2s[i]);
45 | }
46 | if (i1 == i2)
47 | {
48 | continue;
49 | }
50 | else if (i1 > i2)
51 | {
52 | return 1;
53 | }
54 | else if (i1 < i2)
55 | {
56 | return -1;
57 | }
58 | }
59 | return 0;
60 | }
61 |
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/app.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
51 |
52 |
53 |
54 | true
55 |
56 |
57 |
58 |
59 |
60 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/RevokeMsgPatcher/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huiyadanli/RevokeMsgPatcher/7f971f48c0423f0bda856f862182635df2d771a0/RevokeMsgPatcher/icon.ico
--------------------------------------------------------------------------------
/RevokeMsgPatcher/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | image:
2 | - Visual Studio 2022
3 |
4 | configuration: Release
5 |
6 | artifacts:
7 | - path: bin\Release\
8 | name: RevokeMsgPatcher
9 |
--------------------------------------------------------------------------------