55
66namespace 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+ }
0 commit comments