AppModifier.cs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. using RevokeMsgPatcher.Model;
  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. namespace RevokeMsgPatcher.Modifier
  9. {
  10. /// <summary>
  11. /// 1. 自动获取安装目录(已验证) 或者手动填写安装目录
  12. /// 2. 验证安装目录 验证要修改的 dll 是否存在
  13. /// 3. 判断所有 dll 是否符合防撤回要求
  14. /// 4. 备份所有 dll // *.h.bak
  15. /// 5. 根据每个 dll 匹配的 修改信息 循环修改
  16. /// </summary>
  17. public abstract class AppModifier
  18. {
  19. protected App config;
  20. public App Config { set { config = value; } get { return config; } }
  21. protected List<FileHexEditor> editors;
  22. public string InstallPath { get; set; }
  23. /// <summary>
  24. /// 自动搜索应用安装路径
  25. /// </summary>
  26. /// <returns>应用安装路径</returns>
  27. public abstract string FindInstallPath();
  28. //public abstract bool ValidateAndInitialize(string installPath);
  29. /// <summary>
  30. /// 获取版本号
  31. /// </summary>
  32. /// <returns></returns>
  33. public abstract string GetVersion();
  34. /// <summary>
  35. /// 判断APP安装路径内是否都存在要修改的文件
  36. /// </summary>
  37. /// <param name="installPath">APP安装路径</param>
  38. /// <returns></returns>
  39. public bool IsAllFilesExist(string installPath)
  40. {
  41. if (string.IsNullOrEmpty(installPath))
  42. {
  43. return false;
  44. }
  45. int success = 0;
  46. foreach (TargetInfo info in config.FileTargetInfos.Values)
  47. {
  48. string filePath = Path.Combine(installPath, info.RelativePath);
  49. if (File.Exists(filePath))
  50. {
  51. success++;
  52. }
  53. }
  54. if (success == config.FileTargetInfos.Count)
  55. {
  56. return true;
  57. }
  58. else
  59. {
  60. return false;
  61. }
  62. }
  63. /// <summary>
  64. /// a.初始化修改器
  65. /// </summary>
  66. /// <param name="installPath">APP安装路径</param>
  67. public void InitEditors(string installPath)
  68. {
  69. // 初始化文件修改器
  70. editors = new List<FileHexEditor>();
  71. foreach (TargetInfo info in config.FileTargetInfos.Values)
  72. {
  73. FileHexEditor editor = new FileHexEditor(installPath, info);
  74. editors.Add(editor);
  75. }
  76. }
  77. /// <summary>
  78. /// b.验证文件完整性,寻找对应的补丁信息
  79. /// </summary>
  80. public void ValidateAndFindModifyInfo()
  81. {
  82. // 寻找对应文件版本与SHA1的修改信息
  83. foreach (FileHexEditor editor in editors) // 多种文件
  84. {
  85. // 通过SHA1和文件版本判断是否可以打补丁 根据不同结果返回不同的提示
  86. ModifyInfo matchingSHA1Before = null, matchingSHA1After = null, matchingVersion = null;
  87. foreach (ModifyInfo modifyInfo in config.FileModifyInfos[editor.FileName]) // 多个版本信息
  88. {
  89. if (modifyInfo.Name == editor.FileName) // 保险用的无用判断
  90. {
  91. if (editor.FileSHA1 == modifyInfo.SHA1After)
  92. {
  93. matchingSHA1After = modifyInfo;
  94. }
  95. else if (editor.FileSHA1 == modifyInfo.SHA1Before)
  96. {
  97. matchingSHA1Before = modifyInfo;
  98. }
  99. if (editor.FileVersion == modifyInfo.Version)
  100. {
  101. matchingVersion = modifyInfo;
  102. }
  103. }
  104. }
  105. // 补丁前SHA1匹配上,肯定是正确的dll
  106. if (matchingSHA1Before != null)
  107. {
  108. editor.FileModifyInfo = matchingSHA1Before;
  109. continue;
  110. }
  111. // 补丁后SHA1匹配上,肯定已经打过补丁
  112. if (matchingSHA1After != null)
  113. {
  114. throw new BusinessException("installed", $"你已经安装过此补丁,文件路径:{editor.FilePath}");
  115. }
  116. // 全部不匹配,说明不支持
  117. if (matchingSHA1Before == null && matchingSHA1After == null && matchingVersion == null)
  118. {
  119. throw new BusinessException("not_support", $"不支持此版本:{editor.FileVersion},文件路径:{editor.FilePath}");
  120. }
  121. // SHA1不匹配,版本匹配,可能dll已经被其他补丁程序修改过
  122. if ((matchingSHA1Before == null && matchingSHA1After == null) && matchingVersion != null)
  123. {
  124. throw new BusinessException("maybe_modified", $"程序支持此版本:{editor.FileVersion}。但是文件校验不通过,请确认是否使用过其他补丁程序。文件路径:{editor.FilePath}");
  125. }
  126. }
  127. }
  128. /// <summary>
  129. /// c.根据补丁信息,安装补丁
  130. /// </summary>
  131. /// <returns></returns>
  132. public bool Patch()
  133. {
  134. // 首先验证文件修改器是否没问题
  135. foreach (FileHexEditor editor in editors)
  136. {
  137. if (editor.FileModifyInfo == null)
  138. {
  139. throw new Exception("补丁安装失败,原因:文件修改器初始化失败!");
  140. }
  141. }
  142. // 再备份所有文件
  143. foreach (FileHexEditor editor in editors)
  144. {
  145. editor.Backup();
  146. }
  147. // 打补丁!
  148. List<FileHexEditor> done = new List<FileHexEditor>(); // 已经打上补丁的
  149. try
  150. {
  151. foreach (FileHexEditor editor in editors)
  152. {
  153. bool success = editor.Patch();
  154. if (!success)
  155. {
  156. editor.Restore();
  157. }
  158. done.Add(editor);
  159. }
  160. }
  161. catch (Exception ex)
  162. {
  163. // 恢复所有已经打上补丁的文件
  164. foreach (FileHexEditor editor in done)
  165. {
  166. editor.Restore();
  167. }
  168. throw ex;
  169. }
  170. return true;
  171. }
  172. public bool BackupExists()
  173. {
  174. foreach (FileHexEditor editor in editors)
  175. {
  176. if (!File.Exists(editor.FileBakPath))
  177. {
  178. return false;
  179. }
  180. }
  181. return true;
  182. }
  183. public bool Restore()
  184. {
  185. if (BackupExists())
  186. {
  187. foreach (FileHexEditor editor in editors)
  188. {
  189. editor.Restore();
  190. }
  191. return true;
  192. }
  193. else
  194. {
  195. throw new Exception("备份文件不存在,还原失败!");
  196. }
  197. }
  198. }
  199. }