Skip to content

Commit 512431d

Browse files
committed
update MemoryPatch
1 parent fc0843e commit 512431d

File tree

4 files changed

+59
-18
lines changed

4 files changed

+59
-18
lines changed

FixRandomSpawn.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
</PropertyGroup>
99

1010
<ItemGroup>
11-
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.303" />
11+
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.305" />
1212
</ItemGroup>
1313

1414
</Project>

Plugin/GameRules.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public void Init(bool hotReload, Plugin plugin)
1515

1616
plugin.RegisterListener<Listeners.OnMapStart>(manName =>
1717
{
18-
Server.NextFrame(() =>
18+
Server.NextWorldUpdate(() =>
1919
{
2020
FindGameRules();
2121
});

Plugin/MemoryPatch.cs

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
namespace FixRandomSpawn;
77

8-
public unsafe partial class MemoryPatch
8+
public unsafe partial class MemoryPatch(string? modulePath = null)
99
{
1010
[LibraryImport("libc", EntryPoint = "mprotect")]
1111
private static partial int MProtect(nint address, int len, int protect);
@@ -14,15 +14,24 @@ public unsafe partial class MemoryPatch
1414
[return: MarshalAs(UnmanagedType.Bool)]
1515
private unsafe static partial bool VirtualProtect(nint address, int dwSize, int newProtect, int* oldProtect);
1616

17+
private readonly string modulePath_ = modulePath ?? Addresses.ServerPath;
1718
private readonly Dictionary<int, List<byte>> oldPattern_ = [];
18-
private readonly string modulePath_;
1919
private nint addr_;
2020

21-
public MemoryPatch(string? modulePath = null)
21+
private enum MemoryAccess
2222
{
23-
modulePath_ = modulePath ?? Addresses.ServerPath;
23+
Read = 1,
24+
Write,
25+
Exec = 4
2426
}
2527

28+
private const int PAGE_READONLY = 0x2;
29+
private const int PAGE_READWRITE = 0x4;
30+
private const int PAGE_EXECUTE_READ = 0x20;
31+
private const int PAGE_EXECUTE_READWRITE = 0x40;
32+
33+
private const int PAGESIZE = 4096;
34+
2635
public void Init(string signature)
2736
{
2837
addr_ = NativeAPI.FindSignature(modulePath_, signature);
@@ -33,15 +42,14 @@ public void Apply(string patchSignature, int offset = 0)
3342
if (string.IsNullOrEmpty(patchSignature) || oldPattern_.ContainsKey(offset)) return;
3443

3544
byte[] bytes = [.. patchSignature.Split(' ').Select(b => byte.Parse(b, NumberStyles.HexNumber))];
36-
byte* ptrAddr = GetPtr<byte>(offset);
45+
oldPattern_[offset] = [];
3746

38-
SetMemAccess(ptrAddr, bytes.Length);
47+
byte* ptrAddr = GetPtr<byte>(offset);
48+
SetMemAccess(ptrAddr, bytes.Length, MemoryAccess.Read | MemoryAccess.Write | MemoryAccess.Exec);
3949

4050
for (int i = 0; i < bytes.Length; i++)
4151
{
42-
oldPattern_[offset] = [];
4352
oldPattern_[offset].Add(ptrAddr[i]);
44-
4553
ptrAddr[i] = bytes[i];
4654
}
4755
}
@@ -53,31 +61,62 @@ public void Restore()
5361
foreach (var (offset, pattern) in oldPattern_)
5462
{
5563
byte* ptrAddr = GetPtr<byte>(offset);
64+
SetMemAccess(ptrAddr, pattern.Count, MemoryAccess.Read | MemoryAccess.Write | MemoryAccess.Exec);
5665

5766
for (int i = 0; i < pattern.Count; i++)
5867
{
5968
ptrAddr[i] = pattern[i];
6069
}
70+
71+
oldPattern_.Remove(offset);
6172
}
6273
}
6374

64-
private T* GetPtr<T>(int offset = 0) where T: unmanaged => (T*)(addr_ + offset);
75+
public void Write<T>(T data, int offset = 0) where T: unmanaged
76+
{
77+
T* ptrAddr = GetPtr<T>(offset);
78+
SetMemAccess(ptrAddr, sizeof(T), MemoryAccess.Write | MemoryAccess.Read | MemoryAccess.Exec);
79+
80+
*ptrAddr = data;
81+
}
82+
83+
public T Read<T>(int offset = 0) where T: unmanaged
84+
{
85+
T* ptrAddr = GetPtr<T>(offset);
86+
SetMemAccess(ptrAddr, sizeof(T), MemoryAccess.Read | MemoryAccess.Exec);
87+
88+
return *ptrAddr;
89+
}
90+
91+
private T* GetPtr<T>(int offset = 0) where T: unmanaged
92+
{
93+
return (T*)(addr_ + offset);
94+
}
6595

66-
private bool SetMemAccess<T>(T* ptrAddr, int size) where T: unmanaged
96+
private bool SetMemAccess<T>(T* ptrAddr, int size, MemoryAccess access) where T: unmanaged
6797
{
6898
nint addr = (nint)ptrAddr;
6999

70100
if (addr == nint.Zero)
71101
throw new ArgumentNullException(nameof(ptrAddr));
72102

73-
const int PAGESIZE = 4096;
74-
75103
nint LALIGN(nint addr) => addr & ~(PAGESIZE-1);
76104
int LALDIF(nint addr) => (int)(addr % PAGESIZE);
77105

106+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
107+
{
108+
return MProtect(LALIGN(addr), size + LALDIF(addr), (int)access) == 0;
109+
}
110+
78111
int* oldProtect = stackalloc int[1];
112+
int prot = access switch
113+
{
114+
MemoryAccess.Read => PAGE_READONLY,
115+
MemoryAccess.Write => PAGE_READWRITE,
116+
MemoryAccess.Exec => PAGE_EXECUTE_READ,
117+
_ => PAGE_EXECUTE_READWRITE
118+
};
79119

80-
return RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ?
81-
MProtect(LALIGN(addr), size + LALDIF(addr), 7) == 0 : VirtualProtect(addr, size, 0x40, oldProtect);
120+
return VirtualProtect(addr, size, prot, oldProtect);
82121
}
83-
}
122+
}

Plugin/Plugin.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
using CounterStrikeSharp.API.Core;
2+
using CounterStrikeSharp.API.Core.Attributes;
23

34
namespace FixRandomSpawn;
45

6+
[MinimumApiVersion(305)]
57
public sealed partial class Plugin : BasePlugin
68
{
79
public override string ModuleName { get; } = "FixRandomSpawn";
8-
public override string ModuleVersion { get; } = "1.1.0";
10+
public override string ModuleVersion { get; } = "1.1.2";
911
public override string ModuleAuthor { get; } = "xstage";
1012

1113
private readonly GameRules gameRules_ = new GameRules();

0 commit comments

Comments
 (0)