1+ using System . Globalization ;
2+ using System . Runtime . InteropServices ;
3+ using CounterStrikeSharp . API . Core ;
4+ using CounterStrikeSharp . API . Modules . Memory ;
5+
6+ namespace FixRandomSpawn ;
7+
8+ public unsafe partial class MemoryPatch
9+ {
10+ [ LibraryImport ( "libc" , EntryPoint = "mprotect" ) ]
11+ private static partial int MProtect ( nint address , int len , int protect ) ;
12+
13+ [ LibraryImport ( "kernel32.dll" ) ]
14+ [ return : MarshalAs ( UnmanagedType . Bool ) ]
15+ private unsafe static partial bool VirtualProtect ( nint address , int dwSize , int newProtect , int * oldProtect ) ;
16+
17+ private readonly Dictionary < int , List < byte > > oldPattern_ = [ ] ;
18+ private readonly string modulePath_ ;
19+ private nint addr_ ;
20+
21+ public MemoryPatch ( string ? modulePath = null )
22+ {
23+ modulePath_ = modulePath ?? Addresses . ServerPath ;
24+ }
25+
26+ public void Init ( string signature )
27+ {
28+ addr_ = NativeAPI . FindSignature ( modulePath_ , signature ) ;
29+ }
30+
31+ public void Apply ( string patchSignature , int offset = 0 )
32+ {
33+ if ( string . IsNullOrEmpty ( patchSignature ) || oldPattern_ . ContainsKey ( offset ) ) return ;
34+
35+ byte [ ] bytes = [ .. patchSignature . Split ( ' ' ) . Select ( b => byte . Parse ( b , NumberStyles . HexNumber ) ) ] ;
36+ byte * ptrAddr = GetPtr < byte > ( offset ) ;
37+
38+ SetMemAccess ( ptrAddr , bytes . Length ) ;
39+
40+ for ( int i = 0 ; i < bytes . Length ; i ++ )
41+ {
42+ oldPattern_ [ offset ] = [ ] ;
43+ oldPattern_ [ offset ] . Add ( ptrAddr [ i ] ) ;
44+
45+ ptrAddr [ i ] = bytes [ i ] ;
46+ }
47+ }
48+
49+ public void Restore ( )
50+ {
51+ if ( oldPattern_ . Count == 0 ) return ;
52+
53+ foreach ( var ( offset , pattern ) in oldPattern_ )
54+ {
55+ byte * ptrAddr = GetPtr < byte > ( offset ) ;
56+
57+ for ( int i = 0 ; i < pattern . Count ; i ++ )
58+ {
59+ ptrAddr [ i ] = pattern [ i ] ;
60+ }
61+ }
62+ }
63+
64+ private T * GetPtr < T > ( int offset = 0 ) where T : unmanaged => ( T * ) ( addr_ + offset ) ;
65+
66+ private bool SetMemAccess < T > ( T * ptrAddr , int size ) where T : unmanaged
67+ {
68+ nint addr = ( nint ) ptrAddr ;
69+
70+ if ( addr == nint . Zero )
71+ throw new ArgumentNullException ( nameof ( ptrAddr ) ) ;
72+
73+ const int PAGESIZE = 4096 ;
74+
75+ nint LALIGN ( nint addr ) => addr & ~ ( PAGESIZE - 1 ) ;
76+ int LALDIF ( nint addr ) => ( int ) ( addr % PAGESIZE ) ;
77+
78+ int * oldProtect = stackalloc int [ 1 ] ;
79+
80+ return RuntimeInformation . IsOSPlatform ( OSPlatform . Linux ) ?
81+ MProtect ( LALIGN ( addr ) , size + LALDIF ( addr ) , 7 ) == 0 : VirtualProtect ( addr , size , 0x40 , oldProtect ) ;
82+ }
83+ }
0 commit comments