Uninformed: Informative Information for the Uninformed

Vol 6» 2007.Jan

Non-page-aligned Block VirtualAddress

In all normal cases, relocation blocks will be created with a page-aligned VirtualAddress. However, it's unclear if non-page-aligned VirtualAddress's will be handled correctly when relocations are processed. There are some interesting implications of non-page-aligned VirtualAddress's. In many applications, such as the dynamic loader, it's critical that addresses referenced through RVAs are validated so as to prevent references being made to external addresses. For example, if relocations were processed in kernel-mode, it would be critical that checks be performed to ensure that RVAs don't end up making it possible to reference kernel-mode addresses. The reason why non-page-aligned VirtualAddress's are interesting is because they leave open the possibility of this type of attack.

Consider the scenario of a binary that is relocated to 0x7ffe0000, ignoring for the moment that SharedUserData already exists at this location. Now, consider that this binary has a relocation block with a virtual address of 0x1ffff. This address is not page-aligned. Now, consider that this relocation block has a fixup descriptor that indicates that at offset 0x4 into this page, a certain type of fixup should be performed. This would equate to modifying memory at 0x80000003, a kernel-mode address. If relocations were being processed in kernel-mode, like they are on Windows Vista for ASLR, then a failure to check that the actual address being written to would result in a dangerous condition.

Here's an example of some code that attempts to test out this idea:

static VOID TestNonPageAlignedBlocks(
      __in PPE_IMAGE Image,
      __in PRELOC_FUZZ_CONTEXT FuzzContext)
   PRELOCATION_BLOCK_CONTEXT KillerBlock = AllocateRelocationBlockContext(1);


   KillerBlock->Rva       = 0x10001;
   KillerBlock->Fixups[0] = (3 << 12) | 0;

In this example, a custom relocation block is created with one fixup descriptor. The VirtualAddress associated with the block is set to 0x10001 and the first fixup descriptor is set to modify offset 0 into that RVA. If the binary that is hosting these relocations is relocated to 0x10000, a write should occur to 0x20001 when processing the relocations. Here are the results from a few initial tests:

Application Results

The relocation fixup is processed and results in a write to 0x20001.

Ignores the relocation fixup, but only because it writes outside of the executable from what it would appear.

Parses the relocation block without issue.