View Javadoc

1   // WindowsHeap.java, created Aug 16, 2004 1:41:00 PM 2004 by jwhaley
2   // Copyright (C) 2004 John Whaley <jwhaley@alum.mit.edu>
3   // Licensed under the terms of the CPL; see LICENSE.txt for details.
4   package edu.stanford.suif.keepresident;
5   
6   import java.util.Iterator;
7   import java.util.LinkedList;
8   import java.util.List;
9   import java.util.NoSuchElementException;
10  
11  /***
12   * WindowsHeap
13   * 
14   * @author jwhaley
15   * @version $Id: WindowsHeap.java,v 1.6 2004/08/18 21:45:50 jwhaley Exp $
16   */
17  public class WindowsHeap {
18      
19      public static final int[] SystemInfo = new int[9];
20      
21      // Offsets for SYSTEM_INFO structure.
22      public static final int dwOemId = 0;
23      public static final int dwPageSize = 1;
24      public static final int lpMinimumApplicationAddress = 2;
25      public static final int lpMaximumApplicationAddress = 3;
26      public static final int dwActiveProcessorMask = 4;
27      public static final int dwNumberOfProcessors = 5;
28      public static final int dwProcessorType = 6;
29      public static final int dwAllocationGranularity = 7;
30      public static final int wProcessorLevelAndRevision = 8;
31      
32      public static void initSystemInfo(KernelInterface i) {
33          int p = KernelInterface.GetIntArrayElements(SystemInfo);
34          int result = i.call("GetSystemInfo", p);
35          KernelInterface.ReleaseIntArrayElements(SystemInfo, p);
36      }
37      
38      public static int TECHNIQUE = 2;
39      
40      public static void main(String[] args) throws Exception {
41          KernelInterface i = new KernelInterface();
42          initSystemInfo(i);
43          WindowsHeap dis = new WindowsHeap(i);
44          int r;
45          
46          // Increase process working set size.
47          int proc = i.call("GetCurrentProcess");
48          int min = 100000000;
49          int max = 300000000;
50          i.call_nz("SetProcessWorkingSetSize", proc, min, max);
51          
52          Thread.sleep(5000);
53          System.out.println("Starting...");
54          
55          if (TECHNIQUE == 1) {
56              // Use HeapWalk
57              int minSize = 1;
58              long time = System.currentTimeMillis();
59              r = dis.lockAllHeaps(minSize);
60              time = System.currentTimeMillis() - time;
61              System.out.println("HeapWalk: Locked "+r+" bytes in "+time+" ms");
62          } else if (TECHNIQUE == 2) {
63              // Use VirtualQueryEx
64              long time = System.currentTimeMillis();
65              int total = dis.lockAllVM();
66              time = System.currentTimeMillis() - time;
67              System.out.println("VirtualQueryEx: Locked "+total+" bytes in "+time+" ms");
68          } else if (TECHNIQUE == 3) {
69              int lowAddress = SystemInfo[lpMinimumApplicationAddress];
70              int highAddress = SystemInfo[lpMaximumApplicationAddress];
71              int step = SystemInfo[dwPageSize];
72              
73              long time = System.currentTimeMillis();
74              r = dis.lockAllMemory(lowAddress, highAddress, step);
75              time = System.currentTimeMillis() - time;
76              System.out.println("IsBadReadPtr: Locked "+r+" bytes in "+time+" ms");
77          }
78          
79          System.out.println("Sleeping before exit...");
80          Thread.sleep(5000);
81          
82      }
83      
84      public WindowsHeap(KernelInterface i) {
85          this.i = i;
86          this.locks = new LinkedList();
87      }
88      
89      KernelInterface i;
90      List locks;
91      
92      /***
93       * Walks over the given range of memory, attempting to lock every piece
94       * that is accessible.  Returns the number of bytes successfully locked.
95       * 
96       * @param start  start address of memory range
97       * @param end  end address of memory range
98       * @param step  amount to step
99       * @return  bytes successfully locked
100      */
101     public int lockAllMemory(int start, int end, int step) {
102         int totalSize = 0;
103         for (int p = start; p < end; p += step) {
104             if (IsBadReadPtr(p, step)) continue;
105             try {
106                 VirtualLock(p, step);
107                 locks.add(new int[] {p, step});
108                 totalSize += step;
109             } catch (KernelException x) {
110                 // VirtualLock() call failed.
111             }
112         }
113         return totalSize;
114     }
115     
116     public void releaseAllLocks() {
117         for (Iterator it = locks.iterator(); it.hasNext(); ) {
118             int[] a = (int[]) it.next();
119             try {
120                 VirtualUnlock(a[0], a[1]);
121             } catch (KernelException x) {
122             }
123             it.remove();
124         }
125     }
126     
127     public int getLockedBytes() {
128         int total = 0;
129         for (Iterator it = locks.iterator(); it.hasNext(); ) {
130             int[] a = (int[]) it.next();
131             total += a[1];
132         }
133         return total;
134     }
135     
136     public boolean IsBadReadPtr(int p, int size) {
137         int r = i.call("IsBadReadPtr", p, size);
138         return r != 0;
139     }
140     
141     public int lockAllHeaps(int minSize) {
142         int[] heaps = GetProcessHeaps();
143         int totalBytes = 0;
144         for (int j = 0; j < heaps.length; ++j) {
145             int heap = heaps[j];
146             System.out.println("Heap handle: "+heap);
147             HeapWalk w = new HeapWalk(i, heap);
148             while (w.hasNext()) {
149                 int[] result = (int[]) w.next();
150                 if (result[1] < minSize) continue;
151                 System.out.println("  Memory pointer: 0x"+Integer.toHexString(result[0]));
152                 System.out.println("  Memory size: "+result[1]);
153                 try {
154                     VirtualLock(result[0], result[1]);
155                     locks.add(new int[] {result[0], result[1]});
156                     totalBytes += result[1];
157                 } catch (KernelException x) {
158                     System.out.println("  Exception: "+x.getMessage());
159                 }
160             }
161         }
162         return totalBytes;
163     }
164     
165     public void VirtualLock(int addr, int size) {
166         int r = i.call_nz("VirtualLock", addr, size);
167     }
168     
169     public void VirtualUnlock(int addr, int size) {
170         int r = i.call_nz("VirtualUnlock", addr, size);
171     }
172     
173     public int[] GetProcessHeaps() {
174         int num = 256;
175         for (;;) {
176             int[] heaps = new int[num];
177             int pHeaps = KernelInterface.GetIntArrayElements(heaps);
178             int result = i.call("GetProcessHeaps", num, pHeaps);
179             KernelInterface.ReleaseIntArrayElements(heaps, pHeaps);
180             if (result > num) {
181                 num = result;
182                 continue;
183             }
184             int[] res = new int[result];
185             System.arraycopy(heaps, 0, res, 0, result);
186             return res;
187         }
188     }
189     
190     public static HeapWalk getHeapWalker(KernelInterface i, int handle) {
191         return new HeapWalk(i, handle);
192     }
193     
194     public static class HeapWalk implements Iterator {
195 
196         KernelInterface i;
197         int heapHandle;
198         int[] sProcessHeapEntry;
199         boolean more;
200         
201         public HeapWalk(KernelInterface i, int handle) {
202             this.i = i;
203             this.heapHandle = handle;
204             this.sProcessHeapEntry = new int[8];
205             gotoNext();
206         }
207         
208         private void gotoNext() {
209             int pProcessHeapEntry = KernelInterface.GetIntArrayElements(sProcessHeapEntry);
210             int result = i.call("HeapWalk", heapHandle, pProcessHeapEntry);
211             KernelInterface.ReleaseIntArrayElements(sProcessHeapEntry, pProcessHeapEntry);
212             more = result != 0;
213         }
214         
215         public int lpData() {
216             return sProcessHeapEntry[0];
217         }
218         
219         public int cbData() {
220             return sProcessHeapEntry[1];
221         }
222         
223         /* (non-Javadoc)
224          * @see java.util.Iterator#hasNext()
225          */
226         public boolean hasNext() {
227             return more;
228         }
229 
230         /* (non-Javadoc)
231          * @see java.util.Iterator#next()
232          */
233         public Object next() {
234             return nextEntry();
235         }
236         
237         public int[] nextEntry() {
238             if (!more) throw new NoSuchElementException();
239             int[] result = new int[sProcessHeapEntry.length];
240             System.arraycopy(sProcessHeapEntry, 0, result, 0, result.length);
241             gotoNext();
242             return result;
243         }
244 
245         /* (non-Javadoc)
246          * @see java.util.Iterator#remove()
247          */
248         public void remove() {
249             throw new UnsupportedOperationException();
250         }
251         
252     }
253     
254     public static VMWalker getVMWalker(KernelInterface i, int process) {
255         return new VMWalker(i, process);
256     }
257     
258     public int lockAllVM() {
259         int proc = i.call("GetCurrentProcess");
260         int total = 0;
261         VMWalker w = new VMWalker(i, proc);
262         while (w.hasNext()) {
263             int[] a = w.nextEntry();
264             if (a[VMWalker.State] == VMWalker.MEM_COMMIT) {
265                 switch (a[VMWalker.Protect]) {
266                 case VMWalker.PAGE_READONLY:
267                 case VMWalker.PAGE_READWRITE:
268                 case VMWalker.PAGE_EXECUTE:
269                 case VMWalker.PAGE_EXECUTE_READ:
270                 case VMWalker.PAGE_EXECUTE_READWRITE:
271                     try {
272                         VirtualLock(a[VMWalker.BaseAddress], a[VMWalker.RegionSize]);
273                         locks.add(new int[] {a[VMWalker.BaseAddress], a[VMWalker.RegionSize]});
274                         //System.out.println("Locked 0x"+Integer.toHexString(a[VMWalker.BaseAddress])+", "+a[VMWalker.RegionSize]);
275                         total += a[VMWalker.RegionSize];
276                     } catch (KernelException x) {
277                     }
278                     break;
279                 default:
280                     break;
281                 }
282             }
283         }
284         return total;
285     }
286     
287     public int printAllVM() {
288         int proc = i.call("GetCurrentProcess");
289         int total = 0;
290         VMWalker w = new VMWalker(i, proc);
291         while (w.hasNext()) {
292             int[] a = w.nextEntry();
293             System.out.println("Virtual memory region:");
294             System.out.println("  BaseAddress:       0x"+Integer.toHexString(a[0]));
295             System.out.println("  AllocationBase:    0x"+Integer.toHexString(a[1]));
296             System.out.println("  AllocationProtect: 0x"+Integer.toHexString(a[2]));
297             System.out.println("  RegionSize:        0x"+Integer.toHexString(a[3]));
298             System.out.println("  State:             0x"+Integer.toHexString(a[4]));
299             System.out.println("  Protect:           0x"+Integer.toHexString(a[5]));
300             System.out.println("  Type:              0x"+Integer.toHexString(a[6]));
301             if (a[VMWalker.State] == VMWalker.MEM_COMMIT) {
302                 switch (a[VMWalker.Protect]) {
303                 case VMWalker.PAGE_READONLY:
304                 case VMWalker.PAGE_READWRITE:
305                 case VMWalker.PAGE_EXECUTE:
306                 case VMWalker.PAGE_EXECUTE_READ:
307                 case VMWalker.PAGE_EXECUTE_READWRITE:
308                     total += a[VMWalker.RegionSize];
309                     break;
310                 default:
311                     break;
312                 }
313             }
314         }
315         return total;
316     }
317     
318     public static class VMWalker implements Iterator {
319         KernelInterface i;
320         int maxAppAddress;
321         int processHandle;
322         int lpMem;
323         int[] sMBI;
324         
325         public VMWalker(KernelInterface i, int process) {
326             sMBI = new int[7];
327             this.processHandle = process;
328             this.i = i;
329             setMaxAppAddress();
330             gotoNext();
331         }
332         
333         private void setMaxAppAddress() {
334             int[] a = new int[256];
335             int p = KernelInterface.GetIntArrayElements(a);
336             int result = i.call("GetSystemInfo", p);
337             KernelInterface.ReleaseIntArrayElements(a, p);
338             maxAppAddress = a[3];
339         }
340         
341         public static final int BaseAddress = 0;
342         public static final int AllocationBase = 1;
343         public static final int AllocationProtect = 2;
344         public static final int RegionSize = 3;
345         public static final int State = 4;
346         public static final int Protect = 5;
347         public static final int Type = 6;
348         
349         // State
350         public static final int MEM_COMMIT = 0x1000;
351         public static final int MEM_FREE = 0x10000;
352         public static final int MEM_RESERVE = 0x2000;
353         
354         // Protect
355         public static final int PAGE_NOACCESS     = 0x0001;
356         public static final int PAGE_READONLY     = 0x0002;
357         public static final int PAGE_READWRITE    = 0x0004;
358         public static final int PAGE_WRITECOPY    = 0x0008;
359         public static final int PAGE_EXECUTE      = 0x0010;
360         public static final int PAGE_EXECUTE_READ = 0x0020;
361         public static final int PAGE_EXECUTE_READWRITE = 0x0040;
362         public static final int PAGE_EXECUTE_WRITECOPY = 0x0080;
363         public static final int PAGE_GUARD        = 0x0100;
364         public static final int PAGE_NOCACHE      = 0x0200;
365         
366         // Type
367         public static final int MEM_IMAGE = 0x01000000;
368         public static final int MEM_MAPPED = 0x40000;
369         public static final int MEM_PRIVATE = 0x20000;
370         
371         private int gotoNext() {
372             int pMBI = KernelInterface.GetIntArrayElements(sMBI);
373             int result = i.call_nz("VirtualQueryEx", processHandle, lpMem, pMBI, sMBI.length*4);
374             KernelInterface.ReleaseIntArrayElements(sMBI, pMBI);
375             lpMem = sMBI[BaseAddress] + sMBI[RegionSize];
376             return result;
377         }
378         
379         /* (non-Javadoc)
380          * @see java.util.Iterator#hasNext()
381          */
382         public boolean hasNext() {
383             return lpMem < maxAppAddress;
384         }
385         
386         /* (non-Javadoc)
387          * @see java.util.Iterator#next()
388          */
389         public Object next() {
390             return nextEntry();
391         }
392         
393         public int[] nextEntry() {
394             if (!hasNext()) throw new NoSuchElementException();
395             int[] result = new int[sMBI.length];
396             System.arraycopy(sMBI, 0, result, 0, result.length);
397             gotoNext();
398             return result;
399         }
400         
401         /* (non-Javadoc)
402          * @see java.util.Iterator#remove()
403          */
404         public void remove() {
405             throw new UnsupportedOperationException();
406         }
407         
408     }
409 }