Skip to content

Commit e14ae4a

Browse files
committed
Fix a lot of bugs in MetahookInstaller
1 parent 30b1753 commit e14ae4a

File tree

3 files changed

+35
-18
lines changed

3 files changed

+35
-18
lines changed

.serena/memories/MetahookInstaller.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,7 @@ svencoop 目标为 svencoop.exe]
101101
- 历史脚本链路:`scripts/install-helper-*.bat` 与该 GUI 工具职责重叠,说明安装器逻辑由批处理向 UI 工具演进。
102102

103103
## 注意事项
104-
- `HasImportedModule``BinaryReader.ReadString()` 读取 PE 导入模块名(PE 中通常是 C 风格零结尾字符串),存在解析不稳风险,可能导致 SDL 依赖判定为假阴性。
105-
- `PluginInfoComparer``Equals` 是大小写不敏感,但 `GetHashCode` 直接用默认 `string.GetHashCode()`,与比较语义不完全一致,可能造成 `Distinct` 去重边界异常。
106104
- 路径发现与配置文件读写大量依赖当前工作目录(如 `./Build``./lang`),若启动目录变化,可能出现“找不到 Build/语言配置”的行为偏差。
107-
- `GetLibraryFolders` / `GetInstallDirFromManifest` 采用行文本拆分解析 VDF/ACF,鲁棒性弱于正式 VDF 解析器;遇到格式变化可能失效。
108105
- 卸载逻辑基于固定白名单路径删除,覆盖面有限且不做备份;用户手工放入同路径下的内容存在被删除风险。
109106
- 桌面工程未显式请求提权;当目标游戏目录在受保护路径(如 `Program Files`)时,安装/卸载可能抛出权限异常(代码中已提示但不自动提权)。
110107

toolsrc/MetahookInstaller/MetahookInstallerAvalonia/MetahookInstallerAvalonia.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
<PackageReference Include="Irihi.Ursa.ReactiveUIExtension" Version="1.1.0" />
2929
<PackageReference Include="Irihi.Ursa.Themes.Semi" Version="1.13.0" />
3030
<PackageReference Include="ReactiveUI.Avalonia" Version="11.3.0" />
31+
<PackageReference Include="Gameloop.Vdf" Version="0.6.2" />
3132
<PackageReference Include="securifybv.ShellLink" Version="0.1.0" />
3233
<PackageReference Include="Semi.Avalonia" Version="11.3.7" />
3334
<PackageReference Include="Xaml.Behaviors.Avalonia" Version="11.3.6.6" />

toolsrc/MetahookInstaller/MetahookInstallerAvalonia/ViewModels/MainViewModel.cs

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
using MetahookInstallerAvalonia.Lang;
55
using Microsoft.Win32;
66
using ReactiveUI;
7+
using Gameloop.Vdf;
8+
using Gameloop.Vdf.Linq;
79
using ShellLink;
810
using System;
911
using System.Collections.Generic;
@@ -105,6 +107,16 @@ public static bool IsLegitimatePE(string dllPath)
105107
return false;
106108
}
107109
}
110+
private static string ReadNullTerminatedAscii(BinaryReader reader)
111+
{
112+
var bytes = new System.Collections.Generic.List<byte>();
113+
byte b;
114+
while ((b = reader.ReadByte()) != 0)
115+
{
116+
bytes.Add(b);
117+
}
118+
return System.Text.Encoding.ASCII.GetString(bytes.ToArray());
119+
}
108120
private static long RvaToFileOffset(BinaryReader stream, int lfanew, uint rva)
109121
{
110122
try
@@ -204,7 +216,7 @@ public static bool HasImportedModule(string dllPath, string targetModule)
204216
if (nameFileOffset == -1)
205217
continue;
206218
stream.Position = nameFileOffset;
207-
string moduleName = reader.ReadString().ToLowerInvariant();
219+
string moduleName = ReadNullTerminatedAscii(reader).ToLowerInvariant();
208220
if (moduleName == targetModule)
209221
return true;
210222
}
@@ -487,31 +499,38 @@ private string[] GetLibraryFolders()
487499
var configPath = Path.Combine(_steamPath, "steamapps", "libraryfolders.vdf");
488500
if (File.Exists(configPath))
489501
{
490-
var config = File.ReadAllText(configPath);
491-
var lines = config.Split('\n');
492-
foreach (var line in lines)
502+
try
493503
{
494-
if (line.Contains("\"path\""))
504+
var vdf = VdfConvert.Deserialize(File.ReadAllText(configPath));
505+
foreach (var entry in vdf.Value.Children<VProperty>())
495506
{
496-
var path = line.Split('"')[3].Replace("\\\\", "\\");
497-
libraryFolders.Add(path);
507+
var pathToken = entry.Value["path"];
508+
if (pathToken != null)
509+
{
510+
libraryFolders.Add(pathToken.ToString());
511+
}
498512
}
499513
}
514+
catch
515+
{
516+
// Fallback: ignore parse errors, return what we have
517+
}
500518
}
501519

502520
return [.. libraryFolders];
503521
}
504522
private static string? GetInstallDirFromManifest(string manifest)
505523
{
506-
var lines = manifest.Split('\n');
507-
foreach (var line in lines)
524+
try
508525
{
509-
if (line.Contains("\"installdir\""))
510-
{
511-
return line.Split('"')[3];
512-
}
526+
var vdf = VdfConvert.Deserialize(manifest);
527+
var installDir = vdf.Value["installdir"];
528+
return installDir?.ToString();
529+
}
530+
catch
531+
{
532+
return null;
513533
}
514-
return null;
515534
}
516535
private static string? GetSteamPath()
517536
{
@@ -570,7 +589,7 @@ public bool Equals(PluginInfo? x, PluginInfo? y)
570589
}
571590
public int GetHashCode(PluginInfo obj)
572591
{
573-
return obj?.Name?.GetHashCode() ?? 0;
592+
return obj?.Name?.ToLowerInvariant().GetHashCode() ?? 0;
574593
}
575594
}
576595
private readonly ObservableCollection<PluginInfo> _plugins = [];

0 commit comments

Comments
 (0)