1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Definition of PreamblePatcher
6
7#ifndef SANDBOX_SRC_SIDESTEP_PREAMBLE_PATCHER_H__
8#define SANDBOX_SRC_SIDESTEP_PREAMBLE_PATCHER_H__
9
10#include <stddef.h>
11
12namespace sidestep {
13
14// Maximum size of the preamble stub. We overwrite at least the first 5
15// bytes of the function. Considering the worst case scenario, we need 4
16// bytes + the max instruction size + 5 more bytes for our jump back to
17// the original code. With that in mind, 32 is a good number :)
18const size_t kMaxPreambleStubSize = 32;
19
20// Possible results of patching/unpatching
21enum SideStepError {
22  SIDESTEP_SUCCESS = 0,
23  SIDESTEP_INVALID_PARAMETER,
24  SIDESTEP_INSUFFICIENT_BUFFER,
25  SIDESTEP_JUMP_INSTRUCTION,
26  SIDESTEP_FUNCTION_TOO_SMALL,
27  SIDESTEP_UNSUPPORTED_INSTRUCTION,
28  SIDESTEP_NO_SUCH_MODULE,
29  SIDESTEP_NO_SUCH_FUNCTION,
30  SIDESTEP_ACCESS_DENIED,
31  SIDESTEP_UNEXPECTED,
32};
33
34// Implements a patching mechanism that overwrites the first few bytes of
35// a function preamble with a jump to our hook function, which is then
36// able to call the original function via a specially-made preamble-stub
37// that imitates the action of the original preamble.
38//
39// Note that there are a number of ways that this method of patching can
40// fail.  The most common are:
41//    - If there is a jump (jxx) instruction in the first 5 bytes of
42//    the function being patched, we cannot patch it because in the
43//    current implementation we do not know how to rewrite relative
44//    jumps after relocating them to the preamble-stub.  Note that
45//    if you really really need to patch a function like this, it
46//    would be possible to add this functionality (but at some cost).
47//    - If there is a return (ret) instruction in the first 5 bytes
48//    we cannot patch the function because it may not be long enough
49//    for the jmp instruction we use to inject our patch.
50//    - If there is another thread currently executing within the bytes
51//    that are copied to the preamble stub, it will crash in an undefined
52//    way.
53//
54// If you get any other error than the above, you're either pointing the
55// patcher at an invalid instruction (e.g. into the middle of a multi-
56// byte instruction, or not at memory containing executable instructions)
57// or, there may be a bug in the disassembler we use to find
58// instruction boundaries.
59class PreamblePatcher {
60 public:
61  // Patches target_function to point to replacement_function using a provided
62  // preamble_stub of stub_size bytes.
63  // Returns An error code indicating the result of patching.
64  template <class T>
65  static SideStepError Patch(T target_function, T replacement_function,
66                             void* preamble_stub, size_t stub_size) {
67    return RawPatchWithStub(target_function, replacement_function,
68                            reinterpret_cast<unsigned char*>(preamble_stub),
69                            stub_size, NULL);
70  }
71
72 private:
73
74  // Patches a function by overwriting its first few bytes with
75  // a jump to a different function.  This is similar to the RawPatch
76  // function except that it uses the stub allocated by the caller
77  // instead of allocating it.
78  //
79  // To use this function, you first have to call VirtualProtect to make the
80  // target function writable at least for the duration of the call.
81  //
82  // target_function: A pointer to the function that should be
83  // patched.
84  //
85  // replacement_function: A pointer to the function that should
86  // replace the target function.  The replacement function must have
87  // exactly the same calling convention and parameters as the original
88  // function.
89  //
90  // preamble_stub: A pointer to a buffer where the preamble stub
91  // should be copied. The size of the buffer should be sufficient to
92  // hold the preamble bytes.
93  //
94  // stub_size: Size in bytes of the buffer allocated for the
95  // preamble_stub
96  //
97  // bytes_needed: Pointer to a variable that receives the minimum
98  // number of bytes required for the stub.  Can be set to NULL if you're
99  // not interested.
100  //
101  // Returns An error code indicating the result of patching.
102  static SideStepError RawPatchWithStub(void* target_function,
103                                        void *replacement_function,
104                                        unsigned char* preamble_stub,
105                                        size_t stub_size,
106                                        size_t* bytes_needed);
107};
108
109};  // namespace sidestep
110
111#endif  // SANDBOX_SRC_SIDESTEP_PREAMBLE_PATCHER_H__
112