1717 */
1818public class WinProcess implements WinApi {
1919
20- private final int processId ;
21- private final WinNT .HANDLE handle ;
22- private final WinDef .HWND window ;
20+ protected final int processId ;
21+ protected final WinNT .HANDLE handle ;
22+ protected final WinDef .HWND window ;
23+
24+ protected final long maxContentAddress ;
2325
2426 /**
2527 * Creates a new instance of the {@link WinProcess} class.
@@ -42,6 +44,8 @@ public WinProcess(String executableName) {
4244 if (this .getWindowTitle ().isEmpty ()) {
4345 throw new IllegalStateException ("Window for process " + this .processId + " not found" );
4446 }
47+
48+ this .maxContentAddress = this .getModuleAddress ("wow64cpu.dll" );
4549 }
4650
4751 /**
@@ -105,15 +109,15 @@ public byte[] readBytes(long address, int length) {
105109 * <p>
106110 * It will return -1 if no address was found.
107111 *
108- * @param address The address to start searching from.
109- * @param size The maximum amount of bytes to search .
112+ * @param minAddress The minimum address to start searching from.
113+ * @param maxAddress The maximum address to stop searching at .
110114 * @param searchBytes The bytes to search for.
111115 * @return The address of the first matching bytes.
112116 */
113- public long findInMemory (long address , long size , byte [] searchBytes ) {
117+ public long findInMemory (long minAddress , long maxAddress , byte [] searchBytes ) {
114118 int chunkSize = 1024 * 64 ;
115119
116- for (long cursor = address ; cursor < ( address + size ) ; cursor += chunkSize ) {
120+ for (long cursor = minAddress ; cursor < maxAddress ; cursor += chunkSize ) {
117121 byte [] chunk = this .readBytes (cursor , chunkSize + searchBytes .length );
118122
119123 for (int i = 0 ; i < chunk .length - searchBytes .length ; i ++) {
@@ -139,15 +143,14 @@ public long findInMemory(long address, long size, byte[] searchBytes) {
139143 * <p>
140144 * It will return -1 if no address was found.
141145 *
142- * @param address The address to start searching from.
143- * @param size The maximum amount of bytes to search .
146+ * @param minAddress The address to start searching from.
147+ * @param maxAddress The address to stop searching at .
144148 * @param searchBytes The bytes to search for.
145149 * @param condition The condition function to call for each matching address.
146150 * @return The address of the first matching bytes.
147151 */
148- public long findInMemory (long address , long size , byte [] searchBytes , SearchCondition condition ) {
149- long cursor = address ;
150- long maxAddress = size - address ;
152+ public long findInMemory (long minAddress , long maxAddress , byte [] searchBytes , SearchCondition condition ) {
153+ long cursor = minAddress ;
151154 int index = 0 ;
152155 while (cursor < maxAddress ) {
153156 long target = this .findInMemory (cursor , maxAddress , searchBytes );
@@ -160,6 +163,23 @@ public long findInMemory(long address, long size, byte[] searchBytes, SearchCond
160163 return -1 ;
161164 }
162165
166+ /**
167+ * Check if the given bytes are at the given address.
168+ *
169+ * @param address The address to check.
170+ * @param bytes The bytes to check.
171+ * @return True if the bytes are at the given address.
172+ */
173+ public boolean hasBytes (long address , int ... bytes ) {
174+ byte [] chunk = this .readBytes (address , bytes .length );
175+ for (int i = 0 ; i < chunk .length ; i ++) {
176+ if (chunk [i ] != (byte ) bytes [i ]) {
177+ return false ;
178+ }
179+ }
180+ return true ;
181+ }
182+
163183 /**
164184 * Find the address of a text inside the memory.
165185 * If there are multiple matches of the text, the given index will be used to select the correct one.
@@ -170,8 +190,20 @@ public long findInMemory(long address, long size, byte[] searchBytes, SearchCond
170190 * @return The address of the text at the given index
171191 */
172192 public long findAddressOfText (long start , String text , int index ) {
173- long maxAddress = this .getMaxProcessAddress ();
174- return this .findInMemory (start , maxAddress , text .getBytes (), (address , matchIndex ) -> matchIndex == index );
193+ return this .findAddressOfText (start , text , (address , matchIndex ) -> matchIndex == index );
194+ }
195+
196+ /**
197+ * Find the address of a text inside the memory.
198+ * If there are multiple matches of the text, the given index will be used to select the correct one.
199+ *
200+ * @param start The address to start searching from.
201+ * @param text The text to search for.
202+ * @param condition The condition function to call for each matching address.
203+ * @return The address of the text at the given index
204+ */
205+ public long findAddressOfText (long start , String text , SearchCondition condition ) {
206+ return this .findInMemory (start , this .maxContentAddress , text .getBytes (), condition );
175207 }
176208
177209 /**
@@ -192,6 +224,43 @@ public long findAddressUsingPath(String... path) {
192224 return cursor ;
193225 }
194226
227+ /**
228+ * Find an address by matching multiple rules inside the memory.
229+ * It will start searching for the first rule and continues the next at the position where the previous match was found.
230+ *
231+ * @param rules The list of rules to search for.
232+ * @return The final addresses after all rules were matched.
233+ */
234+ public long findAddressUsingRules (SearchRule ... rules ) {
235+ long cursor = -1 ;
236+ for (SearchRule rule : rules ) {
237+ cursor = this .findAddressOfText (cursor + 1 , rule .getText (), rule .getCondition ());
238+ if (cursor == -1 ) {
239+ return -1 ;
240+ }
241+ }
242+ return cursor ;
243+ }
244+
245+ /**
246+ * Find the base address of the given module name.
247+ *
248+ * @param moduleName The name of the module.
249+ * @return The base address of the module.
250+ */
251+ public long getModuleAddress (String moduleName ) {
252+ return this .getModuleAddress (this .processId , moduleName );
253+ }
254+
255+ /**
256+ * Collect all module addresses and their size of the given process.
257+ *
258+ * @return A list of module addresses and their size.
259+ */
260+ public Map <Long , Long > getModules () {
261+ return this .getModules (this .processId );
262+ }
263+
195264 /**
196265 * Find the first address of the modules.
197266 *
@@ -262,6 +331,15 @@ public void close() {
262331 Kernel32 .INSTANCE .CloseHandle (this .handle );
263332 }
264333
334+ /**
335+ * Get the highest memory address with relevant content.
336+ *
337+ * @return The highest memory address with relevant content.
338+ */
339+ public long getMaxContentAddress () {
340+ return this .maxContentAddress ;
341+ }
342+
265343 /**
266344 * Search condition function to check if the address matches additional criteria.
267345 */
@@ -277,4 +355,23 @@ public interface SearchCondition {
277355 boolean matches (long address , int index );
278356 }
279357
358+ public static class SearchRule {
359+
360+ private final String text ;
361+ private final SearchCondition condition ;
362+
363+ public SearchRule (String text , SearchCondition condition ) {
364+ this .text = text ;
365+ this .condition = condition ;
366+ }
367+
368+ public String getText () {
369+ return this .text ;
370+ }
371+
372+ public SearchCondition getCondition () {
373+ return this .condition ;
374+ }
375+ }
376+
280377}
0 commit comments