Improve parameter verification logic in HookVerifier

Refactor HookVerifier to enhance parameter type checking and add utility methods for size calculations.
This commit is contained in:
wolfcomp 2026-01-27 14:43:39 +01:00 committed by GitHub
parent 8f8f4faa12
commit 678a13d517
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,8 +1,11 @@
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices;
using Dalamud.Game; using Dalamud.Game;
using Dalamud.Logging.Internal; using Dalamud.Logging.Internal;
using InteropGenerator.Runtime;
namespace Dalamud.Hooking.Internal.Verification; namespace Dalamud.Hooking.Internal.Verification;
/// <summary> /// <summary>
@ -19,11 +22,14 @@ internal static class HookVerifier
new( new(
"ActorControlSelf", "ActorControlSelf",
"E8 ?? ?? ?? ?? 0F B7 0B 83 E9 64", "E8 ?? ?? ?? ?? 0F B7 0B 83 E9 64",
typeof(ActorControlSelfDelegate), typeof(ActorControlSelfDelegate), // TODO: change this to CS delegate
"Signature changed in Patch 7.4") // 7.4 (new parameters) "Signature changed in Patch 7.4") // 7.4 (new parameters)
]; ];
private delegate void ActorControlSelfDelegate(uint category, uint eventId, uint param1, uint param2, uint param3, uint param4, uint param5, uint param6, uint param7, uint param8, ulong targetId, byte param9); private static readonly string ClientStructsInteropNamespacePrefix = string.Join(".", nameof(FFXIVClientStructs), nameof(FFXIVClientStructs.Interop));
private delegate void ActorControlSelfDelegate(uint category, uint eventId, uint param1, uint param2, uint param3, uint param4, uint param5, uint param6, uint param7, uint param8, ulong targetId, byte param9); // TODO: change this to CS delegate
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="HookVerifier"/> class. /// Initializes a new instance of the <see cref="HookVerifier"/> class.
@ -86,7 +92,7 @@ internal static class HookVerifier
// Compare Parameter Types // Compare Parameter Types
for (var i = 0; i < passedParams.Length; i++) for (var i = 0; i < passedParams.Length; i++)
{ {
if (passedParams[i].ParameterType != enforcedParams[i].ParameterType) if (CheckParam(passedParams[i].ParameterType, enforcedParams[i].ParameterType))
{ {
mismatch = true; mismatch = true;
break; break;
@ -100,6 +106,35 @@ internal static class HookVerifier
} }
} }
private bool CheckParam(Type paramLeft, Type paramRight)
{
var sameType = paramLeft == paramRight;
return sameType || SizeOf(paramLeft) == SizeOf(paramRight);
int SizeOf(Type type) {
return type switch {
_ when type == typeof(sbyte) || type == typeof(byte) || type == typeof(bool) => 1,
_ when type == typeof(char) || type == typeof(short) || type == typeof(ushort) || type == typeof(Half) => 2,
_ when type == typeof(int) || type == typeof(uint) || type == typeof(float) => 4,
_ when type == typeof(long) || type == typeof(ulong) || type == typeof(double) || type.IsPointer || type.IsFunctionPointer || type.IsUnmanagedFunctionPointer || (type.Name == "Pointer`1" && type.Namespace.AsSpan().SequenceEqual(ClientStructsInteropNamespacePrefix)) || type == typeof(CStringPointer) => 8,
_ when type.Name.StartsWith("FixedSizeArray") => type.GetGenericArguments()[0].SizeOf() * int.Parse(type.Name[14..type.Name.IndexOf('`')]),
_ when type.GetCustomAttribute<InlineArrayAttribute>() is { Length: var length } => type.GetGenericArguments()[0].SizeOf() * length,
_ when type.IsStruct() && !type.IsGenericType && (type.StructLayoutAttribute?.Value ?? LayoutKind.Sequential) != LayoutKind.Sequential => type.StructLayoutAttribute?.Size ?? (int?)typeof(Unsafe).GetMethod("SizeOf")?.MakeGenericMethod(type).Invoke(null, null) ?? 0,
_ when type.IsEnum => Enum.GetUnderlyingType(type).SizeOf(),
_ when type.IsGenericType => Marshal.SizeOf(Activator.CreateInstance(type)!),
_ => GetSizeOf(type)
};
}
int GetSizeOf(Type type) {
try {
return Marshal.SizeOf(Activator.CreateInstance(type)!);
} catch {
return 0;
}
}
}
private record VerificationEntry(string Name, string Signature, Type TargetDelegateType, string Message) private record VerificationEntry(string Name, string Signature, Type TargetDelegateType, string Message)
{ {
public nint Address { get; set; } public nint Address { get; set; }