When FindTrampolineInRange() can't locate a suitable trampoline in the existing
free list, TrampolineAlloc() calls BlockAlloc() to create a new pool of
trampolines. BlockAlloc() links the last node of the new free list to the
beginning of the existing free list. But it did NOT link the head of the
existing free list back to the tail of the new list via the pPrevTrampoline
pointer.
If that old head node was ever used for a trampoline, ListRemove() was unable
to update its predecessor to properly remove it from the free list. That node
would get pulled for use again if a hook needed another trampoline in its
address range. Changing the hook address could misdirect the previous
function(s) that used the same trampoline.
When FindTrampolineInRange() can't locate a suitable trampoline in the existing free list, TrampolineAlloc() calls BlockAlloc() to create a new pool of trampolines. BlockAlloc() links the last node of the new free list to the beginning of the existing free list. But it did NOT link the head of the existing free list back to the tail of the new list via the pPrevTrampoline pointer.
If that old head node was ever used for a trampoline, ListRemove() was unable to update its predecessor to properly remove it from the free list. That node would get pulled for use again if a hook needed another trampoline in its address range. Changing the hook address could misdirect the previous function(s) that used the same trampoline.