// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Definition of PreamblePatcher #ifndef SANDBOX_SRC_SIDESTEP_PREAMBLE_PATCHER_H__ #define SANDBOX_SRC_SIDESTEP_PREAMBLE_PATCHER_H__ #include <stddef.h> namespace sidestep { // Maximum size of the preamble stub. We overwrite at least the first 5 // bytes of the function. Considering the worst case scenario, we need 4 // bytes + the max instruction size + 5 more bytes for our jump back to // the original code. With that in mind, 32 is a good number :) const size_t kMaxPreambleStubSize = 32; // Possible results of patching/unpatching enum SideStepError { SIDESTEP_SUCCESS = 0, SIDESTEP_INVALID_PARAMETER, SIDESTEP_INSUFFICIENT_BUFFER, SIDESTEP_JUMP_INSTRUCTION, SIDESTEP_FUNCTION_TOO_SMALL, SIDESTEP_UNSUPPORTED_INSTRUCTION, SIDESTEP_NO_SUCH_MODULE, SIDESTEP_NO_SUCH_FUNCTION, SIDESTEP_ACCESS_DENIED, SIDESTEP_UNEXPECTED, }; // Implements a patching mechanism that overwrites the first few bytes of // a function preamble with a jump to our hook function, which is then // able to call the original function via a specially-made preamble-stub // that imitates the action of the original preamble. // // Note that there are a number of ways that this method of patching can // fail. The most common are: // - If there is a jump (jxx) instruction in the first 5 bytes of // the function being patched, we cannot patch it because in the // current implementation we do not know how to rewrite relative // jumps after relocating them to the preamble-stub. Note that // if you really really need to patch a function like this, it // would be possible to add this functionality (but at some cost). // - If there is a return (ret) instruction in the first 5 bytes // we cannot patch the function because it may not be long enough // for the jmp instruction we use to inject our patch. // - If there is another thread currently executing within the bytes // that are copied to the preamble stub, it will crash in an undefined // way. // // If you get any other error than the above, you're either pointing the // patcher at an invalid instruction (e.g. into the middle of a multi- // byte instruction, or not at memory containing executable instructions) // or, there may be a bug in the disassembler we use to find // instruction boundaries. class PreamblePatcher { public: // Patches target_function to point to replacement_function using a provided // preamble_stub of stub_size bytes. // Returns An error code indicating the result of patching. template <class T> static SideStepError Patch(T target_function, T replacement_function, void* preamble_stub, size_t stub_size) { return RawPatchWithStub(target_function, replacement_function, reinterpret_cast<unsigned char*>(preamble_stub), stub_size, NULL); } private: // Patches a function by overwriting its first few bytes with // a jump to a different function. This is similar to the RawPatch // function except that it uses the stub allocated by the caller // instead of allocating it. // // To use this function, you first have to call VirtualProtect to make the // target function writable at least for the duration of the call. // // target_function: A pointer to the function that should be // patched. // // replacement_function: A pointer to the function that should // replace the target function. The replacement function must have // exactly the same calling convention and parameters as the original // function. // // preamble_stub: A pointer to a buffer where the preamble stub // should be copied. The size of the buffer should be sufficient to // hold the preamble bytes. // // stub_size: Size in bytes of the buffer allocated for the // preamble_stub // // bytes_needed: Pointer to a variable that receives the minimum // number of bytes required for the stub. Can be set to NULL if you're // not interested. // // Returns An error code indicating the result of patching. static SideStepError RawPatchWithStub(void* target_function, void *replacement_function, unsigned char* preamble_stub, size_t stub_size, size_t* bytes_needed); }; }; // namespace sidestep #endif // SANDBOX_SRC_SIDESTEP_PREAMBLE_PATCHER_H__