Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend DynamicHooks to support virtual functions #617

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ namespace CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;

public abstract class BaseMemoryFunction : NativeObject
{
private static Dictionary<string, IntPtr> _createdFunctions = new();
private static Dictionary<string, IntPtr> _createdFunctions = new();

private static Dictionary<IntPtr, Dictionary<int, IntPtr>> _createdOffsetFunctions = new();

private static IntPtr CreateValveFunctionBySignature(string signature, DataType returnType,
DataType[] argumentTypes)
Expand Down Expand Up @@ -45,6 +47,30 @@ private static IntPtr CreateValveFunctionBySignature(string signature, string bi
}

return function;
}

private static IntPtr CreateValveFunctionByOffset(IntPtr objectPtr, int offset, DataType returnType,
DataType[] argumentTypes)
{
if (!_createdOffsetFunctions.TryGetValue(objectPtr, out var createdFunctions))
{
createdFunctions = new Dictionary<int, IntPtr>();
_createdOffsetFunctions[objectPtr] = createdFunctions;
}

if (!createdFunctions.TryGetValue(offset, out var function))
{
try
{
function = NativeAPI.CreateVirtualFunction(objectPtr, offset,
argumentTypes.Length, (int)returnType, argumentTypes.Cast<object>().ToArray());
createdFunctions[offset] = function;
} catch (Exception)
{
}
}

return function;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might need a better way? if we pass another entity instance (ptr) with the same offset it will probably try to hook the same function again and fail? (untested currently, will answer here when I can test it)

}

public BaseMemoryFunction(string signature, DataType returnType, DataType[] parameters) : base(
Expand All @@ -55,6 +81,14 @@ public BaseMemoryFunction(string signature, DataType returnType, DataType[] para
public BaseMemoryFunction(string signature, string binarypath, DataType returnType, DataType[] parameters) : base(
CreateValveFunctionBySignature(signature, binarypath, returnType, parameters))
{
}

/// <summary>
/// <b>WARNING:</b> this is only supposed to be used with <see cref="VirtualFunctionVoid"/> and <see cref="VirtualFunctionWithReturn{TResult}"/>
/// </summary>
internal BaseMemoryFunction(IntPtr objectPtr, int offset, DataType returnType, DataType[] parameters) : base(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This and related constructors are internal because they should not be used randomly. People should only use the exposed VirtualFunctionVoid and VirtualFunctionWithReturn versions

CreateValveFunctionByOffset(objectPtr, offset, returnType, parameters))
{
}

public void Hook(Func<DynamicHook, HookResult> handler, HookMode mode)
Expand All @@ -76,4 +110,4 @@ protected void InvokeInternalVoid(params object[] args)
{
NativeAPI.ExecuteVirtualFunction<object>(Handle, args);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
using System;
/*
* This file is part of CounterStrikeSharp.
* CounterStrikeSharp is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CounterStrikeSharp is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
*/

namespace CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;

#pragma warning disable CS8601 // Possible null reference assignment.
#pragma warning disable CS8604 // Possible null reference argument.
#pragma warning disable CS8604 // Possible null reference argument.

public class MemoryFunctionVoid : BaseMemoryFunction
{
public MemoryFunctionVoid(string signature) : base(signature, DataType.DATA_TYPE_VOID, Array.Empty<DataType>())
Expand All @@ -13,14 +27,18 @@ public MemoryFunctionVoid(string signature) : base(signature, DataType.DATA_TYPE

public MemoryFunctionVoid(string signature, string binarypath) : base(signature, binarypath, DataType.DATA_TYPE_VOID, Array.Empty<DataType>())
{
}

internal MemoryFunctionVoid(IntPtr objectPtr, int offset) : base(objectPtr, offset, DataType.DATA_TYPE_VOID, Array.Empty<DataType>())
{
}

public void Invoke()
{
InvokeInternalVoid();
}
}
}

public class MemoryFunctionVoid<T1> : BaseMemoryFunction
{
public MemoryFunctionVoid(string signature) : base(signature, DataType.DATA_TYPE_VOID,
Expand All @@ -33,6 +51,11 @@ public MemoryFunctionVoid(string signature, string binarypath) : base(signature,
{
}

internal MemoryFunctionVoid(IntPtr objectPtr, int offset) : base(objectPtr, offset, DataType.DATA_TYPE_VOID,
new[] { typeof(T1).ToValidDataType() })
{
}

public void Invoke(T1 arg1)
{
InvokeInternalVoid(arg1);
Expand All @@ -51,6 +74,11 @@ public MemoryFunctionVoid(string signature, string binarypath) : base(signature,
{
}

internal MemoryFunctionVoid(IntPtr objectPtr, int offset) : base(objectPtr, offset, DataType.DATA_TYPE_VOID,
new[] { typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType() })
{
}

public void Invoke(T1 arg1, T2 arg2)
{
InvokeInternalVoid(arg1, arg2);
Expand All @@ -69,6 +97,11 @@ public MemoryFunctionVoid(string signature, string binarypath) : base(signature,
{
}

internal MemoryFunctionVoid(IntPtr objectPtr, int offset) : base(objectPtr, offset, DataType.DATA_TYPE_VOID,
new[] { typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(), typeof(T3).ToValidDataType() })
{
}

public void Invoke(T1 arg1, T2 arg2, T3 arg3)
{
InvokeInternalVoid(arg1, arg2, arg3);
Expand All @@ -95,12 +128,21 @@ public MemoryFunctionVoid(string signature, string binarypath) : base(signature,
{
}

internal MemoryFunctionVoid(IntPtr objectPtr, int offset) : base(objectPtr, offset, DataType.DATA_TYPE_VOID,
new[]
{
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(),
typeof(T3).ToValidDataType(), typeof(T4).ToValidDataType()
})
{
}

public void Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4)
{
InvokeInternalVoid(arg1, arg2, arg3, arg4);
}
}
}

public class MemoryFunctionVoid<T1, T2, T3, T4, T5> : BaseMemoryFunction
{
public MemoryFunctionVoid(string signature) : base(signature, DataType.DATA_TYPE_VOID,
Expand All @@ -123,6 +165,16 @@ public MemoryFunctionVoid(string signature, string binarypath) : base(signature,
{
}

internal MemoryFunctionVoid(IntPtr objectPtr, int offset) : base(objectPtr, offset, DataType.DATA_TYPE_VOID,
new[]
{
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(),
typeof(T3).ToValidDataType(), typeof(T4).ToValidDataType(),
typeof(T5).ToValidDataType()
})
{
}

public void Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5)
{
InvokeInternalVoid(arg1, arg2, arg3, arg4, arg5);
Expand Down Expand Up @@ -151,6 +203,16 @@ public MemoryFunctionVoid(string signature, string binarypath) : base(signature,
{
}

internal MemoryFunctionVoid(IntPtr objectPtr, int offset) : base(objectPtr, offset, DataType.DATA_TYPE_VOID,
new[]
{
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(),
typeof(T3).ToValidDataType(), typeof(T4).ToValidDataType(),
typeof(T5).ToValidDataType(), typeof(T6).ToValidDataType()
})
{
}

public void Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6)
{
InvokeInternalVoid(arg1, arg2, arg3, arg4, arg5, arg6);
Expand Down Expand Up @@ -181,6 +243,17 @@ public MemoryFunctionVoid(string signature, string binarypath) : base(signature,
{
}

internal MemoryFunctionVoid(IntPtr objectPtr, int offset) : base(objectPtr, offset, DataType.DATA_TYPE_VOID,
new[]
{
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(),
typeof(T3).ToValidDataType(), typeof(T4).ToValidDataType(),
typeof(T5).ToValidDataType(), typeof(T6).ToValidDataType(),
typeof(T7).ToValidDataType()
})
{
}

public void Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7)
{
InvokeInternalVoid(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
Expand Down Expand Up @@ -211,12 +284,23 @@ public MemoryFunctionVoid(string signature, string binarypath) : base(signature,
{
}

internal MemoryFunctionVoid(IntPtr objectPtr, int offset) : base(objectPtr, offset, DataType.DATA_TYPE_VOID,
new[]
{
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(),
typeof(T3).ToValidDataType(), typeof(T4).ToValidDataType(),
typeof(T5).ToValidDataType(), typeof(T6).ToValidDataType(),
typeof(T7).ToValidDataType(), typeof(T8).ToValidDataType()
})
{
}

public void Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8)
{
InvokeInternalVoid(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
}
}

public class MemoryFunctionVoid<T1, T2, T3, T4, T5, T6, T7, T8, T9> : BaseMemoryFunction
{
public MemoryFunctionVoid(string signature) : base(signature, DataType.DATA_TYPE_VOID,
Expand All @@ -243,6 +327,18 @@ public MemoryFunctionVoid(string signature, string binarypath) : base(signature,
{
}

internal MemoryFunctionVoid(IntPtr objectPtr, int offset) : base(objectPtr, offset, DataType.DATA_TYPE_VOID,
new[]
{
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(),
typeof(T3).ToValidDataType(), typeof(T4).ToValidDataType(),
typeof(T5).ToValidDataType(), typeof(T6).ToValidDataType(),
typeof(T7).ToValidDataType(), typeof(T8).ToValidDataType(),
typeof(T9).ToValidDataType()
})
{
}

public void Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9)
{
InvokeInternalVoid(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
Expand Down Expand Up @@ -275,11 +371,23 @@ public MemoryFunctionVoid(string signature, string binarypath) : base(signature,
{
}

internal MemoryFunctionVoid(IntPtr objectPtr, int offset) : base(objectPtr, offset, DataType.DATA_TYPE_VOID,
new[]
{
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(),
typeof(T3).ToValidDataType(), typeof(T4).ToValidDataType(),
typeof(T5).ToValidDataType(), typeof(T6).ToValidDataType(),
typeof(T7).ToValidDataType(), typeof(T8).ToValidDataType(),
typeof(T9).ToValidDataType(), typeof(T10).ToValidDataType()
})
{
}

public void Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10)
{
InvokeInternalVoid(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
}
}

#pragma warning restore CS8601 // Possible null reference assignment.
#pragma warning restore CS8604 // Possible null reference argument.
#pragma warning restore CS8604 // Possible null reference argument.
Loading
Loading