Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
michael@0 | 2 | // Use of this source code is governed by a BSD-style license that can be |
michael@0 | 3 | // found in the LICENSE file. |
michael@0 | 4 | |
michael@0 | 5 | // Implementation of PreamblePatcher |
michael@0 | 6 | |
michael@0 | 7 | #include "sandbox/win/src/sidestep/preamble_patcher.h" |
michael@0 | 8 | |
michael@0 | 9 | #include "sandbox/win/src/sandbox_nt_util.h" |
michael@0 | 10 | #include "sandbox/win/src/sidestep/mini_disassembler.h" |
michael@0 | 11 | |
michael@0 | 12 | // Definitions of assembly statements we need |
michael@0 | 13 | #define ASM_JMP32REL 0xE9 |
michael@0 | 14 | #define ASM_INT3 0xCC |
michael@0 | 15 | |
michael@0 | 16 | namespace { |
michael@0 | 17 | |
michael@0 | 18 | // Very basic memcpy. We are copying 4 to 12 bytes most of the time, so there |
michael@0 | 19 | // is no attempt to optimize this code or have a general purpose function. |
michael@0 | 20 | // We don't want to call the crt from this code. |
michael@0 | 21 | inline void* RawMemcpy(void* destination, const void* source, size_t bytes) { |
michael@0 | 22 | const char* from = reinterpret_cast<const char*>(source); |
michael@0 | 23 | char* to = reinterpret_cast<char*>(destination); |
michael@0 | 24 | |
michael@0 | 25 | for (size_t i = 0; i < bytes ; i++) |
michael@0 | 26 | to[i] = from[i]; |
michael@0 | 27 | |
michael@0 | 28 | return destination; |
michael@0 | 29 | } |
michael@0 | 30 | |
michael@0 | 31 | // Very basic memset. We are filling 1 to 7 bytes most of the time, so there |
michael@0 | 32 | // is no attempt to optimize this code or have a general purpose function. |
michael@0 | 33 | // We don't want to call the crt from this code. |
michael@0 | 34 | inline void* RawMemset(void* destination, int value, size_t bytes) { |
michael@0 | 35 | char* to = reinterpret_cast<char*>(destination); |
michael@0 | 36 | |
michael@0 | 37 | for (size_t i = 0; i < bytes ; i++) |
michael@0 | 38 | to[i] = static_cast<char>(value); |
michael@0 | 39 | |
michael@0 | 40 | return destination; |
michael@0 | 41 | } |
michael@0 | 42 | |
michael@0 | 43 | } // namespace |
michael@0 | 44 | |
michael@0 | 45 | #define ASSERT(a, b) DCHECK_NT(a) |
michael@0 | 46 | |
michael@0 | 47 | namespace sidestep { |
michael@0 | 48 | |
michael@0 | 49 | SideStepError PreamblePatcher::RawPatchWithStub( |
michael@0 | 50 | void* target_function, |
michael@0 | 51 | void* replacement_function, |
michael@0 | 52 | unsigned char* preamble_stub, |
michael@0 | 53 | size_t stub_size, |
michael@0 | 54 | size_t* bytes_needed) { |
michael@0 | 55 | if ((NULL == target_function) || |
michael@0 | 56 | (NULL == replacement_function) || |
michael@0 | 57 | (NULL == preamble_stub)) { |
michael@0 | 58 | ASSERT(false, (L"Invalid parameters - either pTargetFunction or " |
michael@0 | 59 | L"pReplacementFunction or pPreambleStub were NULL.")); |
michael@0 | 60 | return SIDESTEP_INVALID_PARAMETER; |
michael@0 | 61 | } |
michael@0 | 62 | |
michael@0 | 63 | // TODO(V7:joi) Siggi and I just had a discussion and decided that both |
michael@0 | 64 | // patching and unpatching are actually unsafe. We also discussed a |
michael@0 | 65 | // method of making it safe, which is to freeze all other threads in the |
michael@0 | 66 | // process, check their thread context to see if their eip is currently |
michael@0 | 67 | // inside the block of instructions we need to copy to the stub, and if so |
michael@0 | 68 | // wait a bit and try again, then unfreeze all threads once we've patched. |
michael@0 | 69 | // Not implementing this for now since we're only using SideStep for unit |
michael@0 | 70 | // testing, but if we ever use it for production code this is what we |
michael@0 | 71 | // should do. |
michael@0 | 72 | // |
michael@0 | 73 | // NOTE: Stoyan suggests we can write 8 or even 10 bytes atomically using |
michael@0 | 74 | // FPU instructions, and on newer processors we could use cmpxchg8b or |
michael@0 | 75 | // cmpxchg16b. So it might be possible to do the patching/unpatching |
michael@0 | 76 | // atomically and avoid having to freeze other threads. Note though, that |
michael@0 | 77 | // doing it atomically does not help if one of the other threads happens |
michael@0 | 78 | // to have its eip in the middle of the bytes you change while you change |
michael@0 | 79 | // them. |
michael@0 | 80 | unsigned char* target = reinterpret_cast<unsigned char*>(target_function); |
michael@0 | 81 | |
michael@0 | 82 | // Let's disassemble the preamble of the target function to see if we can |
michael@0 | 83 | // patch, and to see how much of the preamble we need to take. We need 5 |
michael@0 | 84 | // bytes for our jmp instruction, so let's find the minimum number of |
michael@0 | 85 | // instructions to get 5 bytes. |
michael@0 | 86 | MiniDisassembler disassembler; |
michael@0 | 87 | unsigned int preamble_bytes = 0; |
michael@0 | 88 | while (preamble_bytes < 5) { |
michael@0 | 89 | InstructionType instruction_type = |
michael@0 | 90 | disassembler.Disassemble(target + preamble_bytes, &preamble_bytes); |
michael@0 | 91 | if (IT_JUMP == instruction_type) { |
michael@0 | 92 | ASSERT(false, (L"Unable to patch because there is a jump instruction " |
michael@0 | 93 | L"in the first 5 bytes.")); |
michael@0 | 94 | return SIDESTEP_JUMP_INSTRUCTION; |
michael@0 | 95 | } else if (IT_RETURN == instruction_type) { |
michael@0 | 96 | ASSERT(false, (L"Unable to patch because function is too short")); |
michael@0 | 97 | return SIDESTEP_FUNCTION_TOO_SMALL; |
michael@0 | 98 | } else if (IT_GENERIC != instruction_type) { |
michael@0 | 99 | ASSERT(false, (L"Disassembler encountered unsupported instruction " |
michael@0 | 100 | L"(either unused or unknown")); |
michael@0 | 101 | return SIDESTEP_UNSUPPORTED_INSTRUCTION; |
michael@0 | 102 | } |
michael@0 | 103 | } |
michael@0 | 104 | |
michael@0 | 105 | if (NULL != bytes_needed) |
michael@0 | 106 | *bytes_needed = preamble_bytes + 5; |
michael@0 | 107 | |
michael@0 | 108 | // Inv: preamble_bytes is the number of bytes (at least 5) that we need to |
michael@0 | 109 | // take from the preamble to have whole instructions that are 5 bytes or more |
michael@0 | 110 | // in size total. The size of the stub required is cbPreamble + size of |
michael@0 | 111 | // jmp (5) |
michael@0 | 112 | if (preamble_bytes + 5 > stub_size) { |
michael@0 | 113 | NOTREACHED_NT(); |
michael@0 | 114 | return SIDESTEP_INSUFFICIENT_BUFFER; |
michael@0 | 115 | } |
michael@0 | 116 | |
michael@0 | 117 | // First, copy the preamble that we will overwrite. |
michael@0 | 118 | RawMemcpy(reinterpret_cast<void*>(preamble_stub), |
michael@0 | 119 | reinterpret_cast<void*>(target), preamble_bytes); |
michael@0 | 120 | |
michael@0 | 121 | // Now, make a jmp instruction to the rest of the target function (minus the |
michael@0 | 122 | // preamble bytes we moved into the stub) and copy it into our preamble-stub. |
michael@0 | 123 | // find address to jump to, relative to next address after jmp instruction |
michael@0 | 124 | #pragma warning(push) |
michael@0 | 125 | #pragma warning(disable:4244) |
michael@0 | 126 | // This assignment generates a warning because it is 32 bit specific. |
michael@0 | 127 | int relative_offset_to_target_rest |
michael@0 | 128 | = ((reinterpret_cast<unsigned char*>(target) + preamble_bytes) - |
michael@0 | 129 | (preamble_stub + preamble_bytes + 5)); |
michael@0 | 130 | #pragma warning(pop) |
michael@0 | 131 | // jmp (Jump near, relative, displacement relative to next instruction) |
michael@0 | 132 | preamble_stub[preamble_bytes] = ASM_JMP32REL; |
michael@0 | 133 | // copy the address |
michael@0 | 134 | RawMemcpy(reinterpret_cast<void*>(preamble_stub + preamble_bytes + 1), |
michael@0 | 135 | reinterpret_cast<void*>(&relative_offset_to_target_rest), 4); |
michael@0 | 136 | |
michael@0 | 137 | // Inv: preamble_stub points to assembly code that will execute the |
michael@0 | 138 | // original function by first executing the first cbPreamble bytes of the |
michael@0 | 139 | // preamble, then jumping to the rest of the function. |
michael@0 | 140 | |
michael@0 | 141 | // Overwrite the first 5 bytes of the target function with a jump to our |
michael@0 | 142 | // replacement function. |
michael@0 | 143 | // (Jump near, relative, displacement relative to next instruction) |
michael@0 | 144 | target[0] = ASM_JMP32REL; |
michael@0 | 145 | |
michael@0 | 146 | // Find offset from instruction after jmp, to the replacement function. |
michael@0 | 147 | #pragma warning(push) |
michael@0 | 148 | #pragma warning(disable:4244) |
michael@0 | 149 | int offset_to_replacement_function = |
michael@0 | 150 | reinterpret_cast<unsigned char*>(replacement_function) - |
michael@0 | 151 | reinterpret_cast<unsigned char*>(target) - 5; |
michael@0 | 152 | #pragma warning(pop) |
michael@0 | 153 | // complete the jmp instruction |
michael@0 | 154 | RawMemcpy(reinterpret_cast<void*>(target + 1), |
michael@0 | 155 | reinterpret_cast<void*>(&offset_to_replacement_function), 4); |
michael@0 | 156 | // Set any remaining bytes that were moved to the preamble-stub to INT3 so |
michael@0 | 157 | // as not to cause confusion (otherwise you might see some strange |
michael@0 | 158 | // instructions if you look at the disassembly, or even invalid |
michael@0 | 159 | // instructions). Also, by doing this, we will break into the debugger if |
michael@0 | 160 | // some code calls into this portion of the code. If this happens, it |
michael@0 | 161 | // means that this function cannot be patched using this patcher without |
michael@0 | 162 | // further thought. |
michael@0 | 163 | if (preamble_bytes > 5) { |
michael@0 | 164 | RawMemset(reinterpret_cast<void*>(target + 5), ASM_INT3, |
michael@0 | 165 | preamble_bytes - 5); |
michael@0 | 166 | } |
michael@0 | 167 | |
michael@0 | 168 | // Inv: The memory pointed to by target_function now points to a relative |
michael@0 | 169 | // jump instruction that jumps over to the preamble_stub. The preamble |
michael@0 | 170 | // stub contains the first stub_size bytes of the original target |
michael@0 | 171 | // function's preamble code, followed by a relative jump back to the next |
michael@0 | 172 | // instruction after the first cbPreamble bytes. |
michael@0 | 173 | |
michael@0 | 174 | return SIDESTEP_SUCCESS; |
michael@0 | 175 | } |
michael@0 | 176 | |
michael@0 | 177 | }; // namespace sidestep |
michael@0 | 178 | |
michael@0 | 179 | #undef ASSERT |