Calculating the size of Bitmap object dynamically in Win32k exploitation

Explain

  1. The theory behind this technique is allocate a bunch of ACCEL objects on kernel pool pages, those objects will be settle at the start of pool page (Each page is 4096 bytes in size) and left a satisfaction space for Bitmap object.

  2. Because the algorithm of Windows Kernel Pool Allocator, once a new kernel object was allocated with the size less than the left space of a page, the requested memory will thus fall on the left space of page which splits starting from the end (Yes, it’s not conjunct with the memory in used).

  3. After we draw the kernel pool blue picture, each ACCEL object will follow by a Bitmap object and the left a slight gap between two objects in a same page. Combine with the information leaked of kernel object address, we can do the math on ACCEL and Bitmap. Suppose that Bitmap object is always less than 0x500 bytes, we have an ACCEL object which is located at the start of pool page with an address after Bitmap object, the distance between two objects mins by page size will be the size of Bitmap object if the gap size is less than 0x500.

Illustration

  1. To make sure all Bitmap object fall onto the end of page, firstly we allocate a bunch of Bitmap to filling the fragment spaces, as we don’t know how many fragment spaces which are equal to the Bitmap size are out there, we will spary a lot of object by used CreateBitmap API:
+----------------------------------+
| bla...................| flagment |
+----------------------------------|
|                                  |
|               Unused             |
|                                  |
+----------------------------------+
        Kernel Pool Layout
  1. Allocating a bunch of ACCEL at the start of page, the allocation size of ACCEL is a pool page size, which is 0x4096 bytes in size, mins 0x500 bytes for Bitmap object.
+----------------------------------+
| bla...................|  Bitmap  | <- The size flagment space is now filling with a Bitmap object,
+----------------------------------|    and rest of Bitmap will fall onto the position we excepted.
|        ACCEL      |              | <- We don't know the actually size of Bitmap, but we left a enough space for it, which is 0x500 bytes in size
+----------------------------------+
|        ACCEL      |              |
+----------------------------------+
|        ACCEL      |              |
+----------------------------------+
        Kernel Pool Layout
  1. Allocating rest of Bitmap objects, all of these objects will fall onto the end of page as we excepted.
+----------------------------------+
| bla...................|  Bitmap  |
+----------------------------------|
|        ACCEL      |   |  Bitmap  | <- There have a unused space between two objects
+----------------------------------+
|        ACCEL      |   |  Bitmap  |
+----------------------------------+
|        ACCEL      |   |  Bitmap  |
+----------------------------------+
        Kernel Pool Layout
  1. Expose (leaking) the kernel object address of ACCEL and Bitmap object, there are a lot of techniques to archieve the goal. One of technique is read the GdiShareHandles array in PEB data structure. Finally, we mins ACCEL address by Bitmap address, if the result is less that 0x500 (The gap must not cross a whole pages at most), it means that there are ACCEL and Bitmap fell on the same page, finally we mins the value by a page size, that is the actually size of Bitmap object we wanted.