| /* Copyright (c) 2007, Google Inc. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following disclaimer |
| * in the documentation and/or other materials provided with the |
| * distribution. |
| * * Neither the name of Google Inc. nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| * --- |
| * Author: Joi Sigurdsson |
| * Author: Scott Francis |
| * |
| * Definition of PreamblePatcher |
| */ |
| |
| #ifndef GOOGLE_PERFTOOLS_PREAMBLE_PATCHER_H_ |
| #define GOOGLE_PERFTOOLS_PREAMBLE_PATCHER_H_ |
| |
| #include "config.h" |
| #include <windows.h> |
| |
| // compatibility shim |
| #include "base/logging.h" |
| #define SIDESTEP_ASSERT(cond) RAW_DCHECK(cond, #cond) |
| #define SIDESTEP_LOG(msg) RAW_VLOG(1, msg) |
| |
| // 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 :) |
| #ifdef _M_X64 |
| // In 64-bit mode we may need more room. In 64-bit mode all jumps must be |
| // within +/-2GB of RIP. Because of this limitation we may need to use a |
| // trampoline to jump to the replacement function if it is further than 2GB |
| // away from the target. The trampoline is 14 bytes. |
| // |
| // So 4 bytes + max instruction size (17 bytes) + 5 bytes to jump back to the |
| // original code + trampoline size. 64 bytes is a nice number :-) |
| #define MAX_PREAMBLE_STUB_SIZE (64) |
| #else |
| #define MAX_PREAMBLE_STUB_SIZE (32) |
| #endif |
| |
| // Determines if this is a 64-bit binary. |
| #ifdef _M_X64 |
| static const bool kIs64BitBinary = true; |
| #else |
| static const bool kIs64BitBinary = false; |
| #endif |
| |
| namespace sidestep { |
| |
| // 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, |
| }; |
| |
| #define SIDESTEP_TO_HRESULT(error) \ |
| MAKE_HRESULT(SEVERITY_ERROR, FACILITY_NULL, error) |
| |
| class DeleteUnsignedCharArray; |
| |
| // 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: This patching mechanism should currently only be used for |
| // non-production code, e.g. unit tests, because it is not threadsafe. |
| // See the TODO in preamble_patcher_with_stub.cc for instructions on what |
| // we need to do before using it in production code; it's fairly simple |
| // but unnecessary for now since we only intend to use it in unit tests. |
| // |
| // To patch a function, use either of the typesafe Patch() methods. You |
| // can unpatch a function using Unpatch(). |
| // |
| // Typical usage goes something like this: |
| // @code |
| // typedef int (*MyTypesafeFuncPtr)(int x); |
| // MyTypesafeFuncPtr original_func_stub; |
| // int MyTypesafeFunc(int x) { return x + 1; } |
| // int HookMyTypesafeFunc(int x) { return 1 + original_func_stub(x); } |
| // |
| // void MyPatchInitializingFunction() { |
| // original_func_stub = PreamblePatcher::Patch( |
| // MyTypesafeFunc, HookMyTypesafeFunc); |
| // if (!original_func_stub) { |
| // // ... error handling ... |
| // } |
| // |
| // // ... continue - you have patched the function successfully ... |
| // } |
| // @endcode |
| // |
| // 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. |
| // |
| // NOTE: In optimized builds, when you have very trivial functions that |
| // the compiler can reason do not have side effects, the compiler may |
| // reuse the result of calling the function with a given parameter, which |
| // may mean if you patch the function in between your patch will never get |
| // invoked. See preamble_patcher_test.cc for an example. |
| class PERFTOOLS_DLL_DECL PreamblePatcher { |
| public: |
| |
| // This is a typesafe version of RawPatch(), identical in all other |
| // ways than it takes a template parameter indicating the type of the |
| // function being patched. |
| // |
| // @param T The type of the function you are patching. Usually |
| // you will establish this type using a typedef, as in the following |
| // example: |
| // @code |
| // typedef BOOL (WINAPI *MessageBoxPtr)(HWND, LPCTSTR, LPCTSTR, UINT); |
| // MessageBoxPtr original = NULL; |
| // PreamblePatcher::Patch(MessageBox, Hook_MessageBox, &original); |
| // @endcode |
| template <class T> |
| static SideStepError Patch(T target_function, |
| T replacement_function, |
| T* original_function_stub) { |
| // NOTE: casting from a function to a pointer is contra the C++ |
| // spec. It's not safe on IA64, but is on i386. We use |
| // a C-style cast here to emphasize this is not legal C++. |
| return RawPatch((void*)(target_function), |
| (void*)(replacement_function), |
| (void**)(original_function_stub)); |
| } |
| |
| // Patches a named function imported from the named module using |
| // preamble patching. Uses RawPatch() to do the actual patching |
| // work. |
| // |
| // @param T The type of the function you are patching. Must |
| // exactly match the function you specify using module_name and |
| // function_name. |
| // |
| // @param module_name The name of the module from which the function |
| // is being imported. Note that the patch will fail if this module |
| // has not already been loaded into the current process. |
| // |
| // @param function_name The name of the function you wish to patch. |
| // |
| // @param replacement_function Your replacement function which |
| // will be called whenever code tries to call the original function. |
| // |
| // @param original_function_stub Pointer to memory that should receive a |
| // pointer that can be used (e.g. in the replacement function) to call the |
| // original function, or NULL to indicate failure. |
| // |
| // @return One of the EnSideStepError error codes; only SIDESTEP_SUCCESS |
| // indicates success. |
| template <class T> |
| static SideStepError Patch(LPCTSTR module_name, |
| LPCSTR function_name, |
| T replacement_function, |
| T* original_function_stub) { |
| SIDESTEP_ASSERT(module_name && function_name); |
| if (!module_name || !function_name) { |
| SIDESTEP_ASSERT(false && |
| "You must specify a module name and function name."); |
| return SIDESTEP_INVALID_PARAMETER; |
| } |
| HMODULE module = ::GetModuleHandle(module_name); |
| SIDESTEP_ASSERT(module != NULL); |
| if (!module) { |
| SIDESTEP_ASSERT(false && "Invalid module name."); |
| return SIDESTEP_NO_SUCH_MODULE; |
| } |
| FARPROC existing_function = ::GetProcAddress(module, function_name); |
| if (!existing_function) { |
| SIDESTEP_ASSERT( |
| false && "Did not find any function with that name in the module."); |
| return SIDESTEP_NO_SUCH_FUNCTION; |
| } |
| // NOTE: casting from a function to a pointer is contra the C++ |
| // spec. It's not safe on IA64, but is on i386. We use |
| // a C-style cast here to emphasize this is not legal C++. |
| return RawPatch((void*)existing_function, (void*)replacement_function, |
| (void**)(original_function_stub)); |
| } |
| |
| // Patches a function by overwriting its first few bytes with |
| // a jump to a different function. This is the "worker" function |
| // for each of the typesafe Patch() functions. In most cases, |
| // it is preferable to use the Patch() functions rather than |
| // this one as they do more checking at compile time. |
| // |
| // @param target_function A pointer to the function that should be |
| // patched. |
| // |
| // @param 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. |
| // |
| // @param original_function_stub Pointer to memory that should receive a |
| // pointer that can be used (e.g. in the replacement function) to call the |
| // original function, or NULL to indicate failure. |
| // |
| // @param original_function_stub Pointer to memory that should receive a |
| // pointer that can be used (e.g. in the replacement function) to call the |
| // original function, or NULL to indicate failure. |
| // |
| // @return One of the EnSideStepError error codes; only SIDESTEP_SUCCESS |
| // indicates success. |
| // |
| // @note The preamble-stub (the memory pointed to by |
| // *original_function_stub) is allocated on the heap, and (in |
| // production binaries) never destroyed, resulting in a memory leak. This |
| // will be the case until we implement safe unpatching of a method. |
| // However, it is quite difficult to unpatch a method (because other |
| // threads in the process may be using it) so we are leaving it for now. |
| // See however UnsafeUnpatch, which can be used for binaries where you |
| // know only one thread is running, e.g. unit tests. |
| static SideStepError RawPatch(void* target_function, |
| void* replacement_function, |
| void** original_function_stub); |
| |
| // Unpatches target_function and deletes the stub that previously could be |
| // used to call the original version of the function. |
| // |
| // DELETES the stub that is passed to the function. |
| // |
| // @param target_function Pointer to the target function which was |
| // previously patched, i.e. a pointer which value should match the value |
| // of the symbol prior to patching it. |
| // |
| // @param replacement_function Pointer to the function target_function |
| // was patched to. |
| // |
| // @param original_function_stub Pointer to the stub returned when |
| // patching, that could be used to call the original version of the |
| // patched function. This function will also delete the stub, which after |
| // unpatching is useless. |
| // |
| // If your original call was |
| // Patch(VirtualAlloc, MyVirtualAlloc, &origptr) |
| // then to undo it you would call |
| // Unpatch(VirtualAlloc, MyVirtualAlloc, origptr); |
| // |
| // @return One of the EnSideStepError error codes; only SIDESTEP_SUCCESS |
| // indicates success. |
| static SideStepError Unpatch(void* target_function, |
| void* replacement_function, |
| void* original_function_stub); |
| |
| // A helper routine when patching, which follows jmp instructions at |
| // function addresses, to get to the "actual" function contents. |
| // This allows us to identify two functions that are at different |
| // addresses but actually resolve to the same code. |
| // |
| // @param target_function Pointer to a function. |
| // |
| // @return Either target_function (the input parameter), or if |
| // target_function's body consists entirely of a JMP instruction, |
| // the address it JMPs to (or more precisely, the address at the end |
| // of a chain of JMPs). |
| template <class T> |
| static T ResolveTarget(T target_function) { |
| return (T)ResolveTargetImpl((unsigned char*)target_function, NULL); |
| } |
| |
| // Allocates a block of memory of size MAX_PREAMBLE_STUB_SIZE that is as |
| // close (within 2GB) as possible to target. This is done to ensure that |
| // we can perform a relative jump from target to a trampoline if the |
| // replacement function is > +-2GB from target. This means that we only need |
| // to patch 5 bytes in the target function. |
| // |
| // @param target Pointer to target function. |
| // |
| // @return Returns a block of memory of size MAX_PREAMBLE_STUB_SIZE that can |
| // be used to store a function preamble block. |
| static unsigned char* AllocPreambleBlockNear(void* target); |
| |
| // Frees a block allocated by AllocPreambleBlockNear. |
| // |
| // @param block Block that was returned by AllocPreambleBlockNear. |
| static void FreePreambleBlock(unsigned char* block); |
| |
| private: |
| friend class DeleteUnsignedCharArray; |
| |
| // Used to store data allocated for preamble stubs |
| struct PreamblePage { |
| unsigned int magic_; |
| PreamblePage* next_; |
| // This member points to a linked list of free blocks within the page |
| // or NULL if at the end |
| void* free_; |
| }; |
| |
| // In 64-bit mode, the replacement function must be within 2GB of the original |
| // target in order to only require 5 bytes for the function patch. To meet |
| // this requirement we're creating an allocator within this class to |
| // allocate blocks that are within 2GB of a given target. This member is the |
| // head of a linked list of pages used to allocate blocks that are within |
| // 2GB of the target. |
| static PreamblePage* preamble_pages_; |
| |
| // Page granularity |
| static long granularity_; |
| |
| // Page size |
| static long pagesize_; |
| |
| // Determines if the patcher has been initialized. |
| static bool initialized_; |
| |
| // Used to initialize static members. |
| static void Initialize(); |
| |
| // 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. |
| // |
| // We call VirtualProtect to make the |
| // target function writable at least for the duration of the call. |
| // |
| // @param target_function A pointer to the function that should be |
| // patched. |
| // |
| // @param 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. |
| // |
| // @param 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. |
| // |
| // @param stub_size Size in bytes of the buffer allocated for the |
| // preamble_stub |
| // |
| // @param 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. |
| // |
| // @return An error code indicating the result of patching. |
| static SideStepError RawPatchWithStubAndProtections( |
| void* target_function, |
| void* replacement_function, |
| unsigned char* preamble_stub, |
| unsigned long stub_size, |
| unsigned long* bytes_needed); |
| |
| // A helper function used by RawPatchWithStubAndProtections -- it |
| // does everything but the VirtualProtect work. Defined in |
| // preamble_patcher_with_stub.cc. |
| // |
| // @param target_function A pointer to the function that should be |
| // patched. |
| // |
| // @param 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. |
| // |
| // @param 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. |
| // |
| // @param stub_size Size in bytes of the buffer allocated for the |
| // preamble_stub |
| // |
| // @param 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. |
| // |
| // @return An error code indicating the result of patching. |
| static SideStepError RawPatchWithStub(void* target_function, |
| void* replacement_function, |
| unsigned char* preamble_stub, |
| unsigned long stub_size, |
| unsigned long* bytes_needed); |
| |
| |
| // A helper routine when patching, which follows jmp instructions at |
| // function addresses, to get to the "actual" function contents. |
| // This allows us to identify two functions that are at different |
| // addresses but actually resolve to the same code. |
| // |
| // @param target_function Pointer to a function. |
| // |
| // @param stop_before If, when following JMP instructions from |
| // target_function, we get to the address stop, we return |
| // immediately, the address that jumps to stop_before. |
| // |
| // @param stop_before_trampoline When following JMP instructions from |
| // target_function, stop before a trampoline is detected. See comment in |
| // PreamblePatcher::RawPatchWithStub for more information. This parameter |
| // has no effect in 32-bit mode. |
| // |
| // @return Either target_function (the input parameter), or if |
| // target_function's body consists entirely of a JMP instruction, |
| // the address it JMPs to (or more precisely, the address at the end |
| // of a chain of JMPs). |
| static void* ResolveTargetImpl(unsigned char* target_function, |
| unsigned char* stop_before, |
| bool stop_before_trampoline = false); |
| |
| // Helper routine that attempts to allocate a page as close (within 2GB) |
| // as possible to target. |
| // |
| // @param target Pointer to target function. |
| // |
| // @return Returns an address that is within 2GB of target. |
| static void* AllocPageNear(void* target); |
| |
| // Helper routine that determines if a target instruction is a short |
| // conditional jump. |
| // |
| // @param target Pointer to instruction. |
| // |
| // @param instruction_size Size of the instruction in bytes. |
| // |
| // @return Returns true if the instruction is a short conditional jump. |
| static bool IsShortConditionalJump(unsigned char* target, |
| unsigned int instruction_size); |
| |
| // Helper routine that determines if a target instruction is a near |
| // conditional jump. |
| // |
| // @param target Pointer to instruction. |
| // |
| // @param instruction_size Size of the instruction in bytes. |
| // |
| // @return Returns true if the instruction is a near conditional jump. |
| static bool IsNearConditionalJump(unsigned char* target, |
| unsigned int instruction_size); |
| |
| // Helper routine that determines if a target instruction is a near |
| // relative jump. |
| // |
| // @param target Pointer to instruction. |
| // |
| // @param instruction_size Size of the instruction in bytes. |
| // |
| // @return Returns true if the instruction is a near absolute jump. |
| static bool IsNearRelativeJump(unsigned char* target, |
| unsigned int instruction_size); |
| |
| // Helper routine that determines if a target instruction is a near |
| // absolute call. |
| // |
| // @param target Pointer to instruction. |
| // |
| // @param instruction_size Size of the instruction in bytes. |
| // |
| // @return Returns true if the instruction is a near absolute call. |
| static bool IsNearAbsoluteCall(unsigned char* target, |
| unsigned int instruction_size); |
| |
| // Helper routine that determines if a target instruction is a near |
| // absolute call. |
| // |
| // @param target Pointer to instruction. |
| // |
| // @param instruction_size Size of the instruction in bytes. |
| // |
| // @return Returns true if the instruction is a near absolute call. |
| static bool IsNearRelativeCall(unsigned char* target, |
| unsigned int instruction_size); |
| |
| // Helper routine that determines if a target instruction is a 64-bit MOV |
| // that uses a RIP-relative displacement. |
| // |
| // @param target Pointer to instruction. |
| // |
| // @param instruction_size Size of the instruction in bytes. |
| // |
| // @return Returns true if the instruction is a MOV with displacement. |
| static bool IsMovWithDisplacement(unsigned char* target, |
| unsigned int instruction_size); |
| |
| // Helper routine that converts a short conditional jump instruction |
| // to a near conditional jump in a target buffer. Note that the target |
| // buffer must be within 2GB of the source for the near jump to work. |
| // |
| // A short conditional jump instruction is in the format: |
| // 7x xx = Jcc rel8off |
| // |
| // @param source Pointer to instruction. |
| // |
| // @param instruction_size Size of the instruction. |
| // |
| // @param target Target buffer to write the new instruction. |
| // |
| // @param target_bytes Pointer to a buffer that contains the size |
| // of the target instruction, in bytes. |
| // |
| // @param target_size Size of the target buffer. |
| // |
| // @return Returns SIDESTEP_SUCCESS if successful, otherwise an error. |
| static SideStepError PatchShortConditionalJump(unsigned char* source, |
| unsigned int instruction_size, |
| unsigned char* target, |
| unsigned int* target_bytes, |
| unsigned int target_size); |
| |
| // Helper routine that converts an instruction that will convert various |
| // jump-like instructions to corresponding instructions in the target buffer. |
| // What this routine does is fix up the relative offsets contained in jump |
| // instructions to point back to the original target routine. Like with |
| // PatchShortConditionalJump, the target buffer must be within 2GB of the |
| // source. |
| // |
| // We currently handle the following instructions: |
| // |
| // E9 xx xx xx xx = JMP rel32off |
| // 0F 8x xx xx xx xx = Jcc rel32off |
| // FF /2 xx xx xx xx = CALL reg/mem32/mem64 |
| // E8 xx xx xx xx = CALL rel32off |
| // |
| // It should not be hard to update this function to support other |
| // instructions that jump to relative targets. |
| // |
| // @param source Pointer to instruction. |
| // |
| // @param instruction_size Size of the instruction. |
| // |
| // @param target Target buffer to write the new instruction. |
| // |
| // @param target_bytes Pointer to a buffer that contains the size |
| // of the target instruction, in bytes. |
| // |
| // @param target_size Size of the target buffer. |
| // |
| // @return Returns SIDESTEP_SUCCESS if successful, otherwise an error. |
| static SideStepError PatchNearJumpOrCall(unsigned char* source, |
| unsigned int instruction_size, |
| unsigned char* target, |
| unsigned int* target_bytes, |
| unsigned int target_size); |
| |
| // Helper routine that patches a 64-bit MOV instruction with a RIP-relative |
| // displacement. The target buffer must be within 2GB of the source. |
| // |
| // 48 8B 0D XX XX XX XX = MOV rel32off |
| // |
| // @param source Pointer to instruction. |
| // |
| // @param instruction_size Size of the instruction. |
| // |
| // @param target Target buffer to write the new instruction. |
| // |
| // @param target_bytes Pointer to a buffer that contains the size |
| // of the target instruction, in bytes. |
| // |
| // @param target_size Size of the target buffer. |
| // |
| // @return Returns SIDESTEP_SUCCESS if successful, otherwise an error. |
| static SideStepError PatchMovWithDisplacement(unsigned char* source, |
| unsigned int instruction_size, |
| unsigned char* target, |
| unsigned int* target_bytes, |
| unsigned int target_size); |
| }; |
| |
| }; // namespace sidestep |
| |
| #endif // GOOGLE_PERFTOOLS_PREAMBLE_PATCHER_H_ |