Implement chain hooking

Chain hooking is a means which detects whether a hook is already
present, and instead of overwriting it, attempts to call the existing
hook functions in a chain.

There's two primary ways a function can be hooked:

- forward chain (overwrite the first 5 bytes to an long jump), or
- reverse chain (uses microsoft's built-in safe reverse-chaining
  bytecode before the function to allow safer hooking)

It takes in to account both hook types when looking for chains.  If it's
unsafe to do either of those types of hooks, it will revert to the
standard unhook/rehook method.

Also, if the current hook is not a chain hook, it will now preserve the
original bytes of the function on unhook and restore them on rehook
rather than forcibly restore the older bytes, that way if a forward
chain hook is added to our hook, we safely restore it on rehook.