@@ -9,6 +9,9 @@ public class WindowsPatternFinder(MemoryEditorConfig config) : IPatternFinder
99 {
1010 private const int MEM_COMMIT = 0x00001000 ;
1111 private const int PAGE_READWRITE = 0x04 ;
12+ private const int PAGE_EXECUTE_READ = 0x20 ;
13+ private const int PAGE_READONLY = 0x02 ;
14+ private const int PAGE_EXECUTE_READWRITE = 0x40 ;
1215
1316 private IntPtr _processHandle { get ; } = config . ProcessHandle ;
1417 private Process _process { get ; } = config . Process ;
@@ -73,12 +76,12 @@ unsafe public List<IntPtr> GetAddressesForPattern(byte[] pattern, int minAddr =
7376 return returnVal ;
7477 }
7578
76- public IntPtr GetAddressForPattern ( string pattern , int minAddr = 0 )
79+ public IntPtr GetAddressForPattern ( string pattern , ulong minAddr = 0 , ulong maxAddr = 0 )
7780 {
78- return GetAddressForPattern ( DataConverter . HexStringToByteArray ( pattern ) , minAddr ) ;
81+ return GetAddressForPattern ( DataConverter . HexStringToByteArray ( pattern ) , minAddr , maxAddr ) ;
7982 }
8083
81- unsafe public IntPtr GetAddressForPattern ( byte [ ] pattern , int minAddr = 0 )
84+ unsafe public IntPtr GetAddressForPattern ( byte [ ] pattern , ulong minAddr = 0 , ulong maxAddr = 0 )
8285 {
8386 var handle = _processHandle ;
8487 SYSTEM_INFO sys_info = new SYSTEM_INFO ( ) ;
@@ -97,10 +100,12 @@ unsafe public IntPtr GetAddressForPattern(byte[] pattern, int minAddr = 0)
97100
98101 while ( proc_min_address_l < proc_max_address_l )
99102 {
103+ if ( _process . HasExited )
104+ throw new InvalidOperationException ( "Process has exited." ) ;
100105 // 28 = sizeof(MEMORY_BASIC_INFORMATION)
101106 Kernel32Wrapper . VirtualQueryEx ( handle , proc_min_address , out mem_basic_info , ( uint ) sizeof ( MEMORY_BASIC_INFORMATION ) ) ;
102107
103- if ( mem_basic_info . BaseAddress . ToInt64 ( ) > minAddr )
108+ if ( mem_basic_info . BaseAddress . ToInt64 ( ) > ( long ) minAddr && ( maxAddr <= 0 || mem_basic_info . BaseAddress . ToInt64 ( ) <= ( long ) maxAddr ) )
104109 {
105110
106111 // if this memory chunk is accessible
@@ -124,6 +129,8 @@ unsafe public IntPtr GetAddressForPattern(byte[] pattern, int minAddr = 0)
124129 // move to the next memory chunk
125130 proc_min_address_l += mem_basic_info . RegionSize . ToInt64 ( ) ;
126131 proc_min_address = new IntPtr ( proc_min_address_l ) ;
132+ if ( mem_basic_info . BaseAddress == 0 && mem_basic_info . RegionSize == 0 )
133+ throw new InvalidOperationException ( "Process invalid." ) ;
127134 }
128135
129136 return IntPtr . Zero ;
@@ -153,10 +160,10 @@ public nint GetAddressForPatternInModule(string moduleName, byte[] pattern, long
153160 return IntPtr . Zero ;
154161 }
155162
156- public IntPtr GetAddressForString ( string text , Encoding encoding , int minAddr = 0 )
163+ public IntPtr GetAddressForString ( string text , Encoding encoding , ulong minAddr = 0 , ulong maxAddr = 0 )
157164 {
158165 var asBytes = encoding . GetBytes ( text ) ;
159- return GetAddressForPattern ( asBytes , minAddr ) ;
166+ return GetAddressForPattern ( asBytes , minAddr , maxAddr ) ;
160167 }
161168
162169 public List < IntPtr > GetAddressesForString ( string text , Encoding encoding , int minAddr = 0 )
@@ -216,6 +223,84 @@ private static List<int> SearchPatternMulti(byte[] src, byte[] pattern)
216223 return returnData ;
217224 }
218225
226+ unsafe public nint GetAddressForPatternWithWildcards ( string pattern , ulong minAddr = 0 )
227+ {
228+ byte [ ] convertedByteArray = ConvertPattern ( pattern ) ;
229+ var handle = _processHandle ;
230+ SYSTEM_INFO sys_info = new SYSTEM_INFO ( ) ;
231+ Kernel32Wrapper . GetSystemInfo ( out sys_info ) ;
232+
233+ IntPtr proc_min_address = sys_info . minimumApplicationAddress ;
234+ IntPtr proc_max_address = sys_info . maximumApplicationAddress ;
235+
236+ // saving the values as long ints so I won't have to do a lot of casts later
237+ long proc_min_address_l = ( long ) proc_min_address ;
238+ long proc_max_address_l = ( long ) proc_max_address ;
239+
240+
241+ MEMORY_BASIC_INFORMATION mem_basic_info = new MEMORY_BASIC_INFORMATION ( ) ;
242+ IntPtr bytesRead = IntPtr . Zero ; // number of bytes read with ReadProcessMemory
243+
244+ while ( proc_min_address_l < proc_max_address_l )
245+ {
246+ if ( _process . HasExited )
247+ throw new InvalidOperationException ( "Process has exited." ) ;
248+ // 28 = sizeof(MEMORY_BASIC_INFORMATION)
249+ Kernel32Wrapper . VirtualQueryEx ( handle , proc_min_address , out mem_basic_info , ( uint ) sizeof ( MEMORY_BASIC_INFORMATION ) ) ;
250+
251+ if ( mem_basic_info . BaseAddress . ToInt64 ( ) > ( long ) minAddr )
252+ {
253+
254+ // if this memory chunk is accessible
255+ if ( ( mem_basic_info . Protect == PAGE_READWRITE ||
256+ mem_basic_info . Protect == PAGE_EXECUTE_READ ||
257+ mem_basic_info . Protect == PAGE_READONLY ||
258+ mem_basic_info . Protect == PAGE_EXECUTE_READWRITE )
259+ && mem_basic_info . State == MEM_COMMIT )
260+ {
261+ byte [ ] buffer = new byte [ mem_basic_info . RegionSize . ToInt64 ( ) ] ;
262+
263+ // read everything in the buffer above
264+ Kernel32Wrapper . ReadProcessMemory ( handle , mem_basic_info . BaseAddress , buffer , buffer . Length , out bytesRead ) ;
265+ if ( bytesRead . ToInt64 ( ) > 0 )
266+ {
267+ var ret = SearchPatternWithWildcards ( buffer , convertedByteArray ) ;
268+ if ( ret > - 1 )
269+ {
270+ return new IntPtr ( mem_basic_info . BaseAddress . ToInt64 ( ) + ( nint ) ret ) ;
271+ }
272+ }
273+ }
274+ }
275+ // move to the next memory chunk
276+ proc_min_address_l += mem_basic_info . RegionSize . ToInt64 ( ) ;
277+ proc_min_address = new IntPtr ( proc_min_address_l ) ;
278+ if ( mem_basic_info . BaseAddress == 0 && mem_basic_info . RegionSize == 0 )
279+ throw new InvalidOperationException ( "Process invalid." ) ;
280+ }
281+
282+ return IntPtr . Zero ;
283+ }
284+
285+ private static int SearchPatternWithWildcards ( byte [ ] src , byte [ ] pattern )
286+ {
287+ int c = src . Length - pattern . Length + 1 ;
288+ int j ;
289+ for ( int i = 0 ; i < c ; i ++ )
290+ {
291+ if ( pattern [ 0 ] != 0x00 && src [ i ] != pattern [ 0 ] )
292+ continue ;
293+ for ( j = pattern . Length - 1 ; j >= 1 ; j -- )
294+ {
295+ if ( pattern [ j ] != 0x00 && src [ i + j ] != pattern [ j ] )
296+ break ;
297+ }
298+ if ( j == 0 )
299+ return i ;
300+ }
301+ return - 1 ;
302+ }
303+
219304 public IntPtr GetAddressForPatternInModuleWithWildcards ( string moduleName , string pattern , long maxBufferSize = - 1 , long offsetAddress = 0 )
220305 {
221306 byte [ ] convertedByteArray = ConvertPattern ( pattern ) ;
0 commit comments