toolkit/crashreporter/google-breakpad/src/processor/disassembler_x86.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 // copyright notice, this list of conditions and the following disclaimer
     2 // in the documentation and/or other materials provided with the
     3 // distribution.
     4 //     * Neither the name of Google Inc. nor the names of its
     5 // contributors may be used to endorse or promote products derived from
     6 // this software without specific prior written permission.
     7 //
     8 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     9 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    10 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    11 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    12 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    13 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    14 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    15 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    16 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    17 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    18 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    20 // disassembler_x86.cc: simple x86 disassembler.
    21 //
    22 // Provides single step disassembly of x86 bytecode and flags instructions
    23 // that utilize known bad register values.
    24 //
    25 // Author: Cris Neckar
    27 #include "processor/disassembler_x86.h"
    29 #include <string.h>
    30 #include <unistd.h>
    32 namespace google_breakpad {
    34 DisassemblerX86::DisassemblerX86(const uint8_t *bytecode,
    35                                  uint32_t size,
    36                                  uint32_t virtual_address) :
    37                                      bytecode_(bytecode),
    38                                      size_(size),
    39                                      virtual_address_(virtual_address),
    40                                      current_byte_offset_(0),
    41                                      current_inst_offset_(0),
    42                                      instr_valid_(false),
    43                                      register_valid_(false),
    44                                      pushed_bad_value_(false),
    45                                      end_of_block_(false),
    46                                      flags_(0) {
    47   libdis::x86_init(libdis::opt_none, NULL, NULL);
    48 }
    50 DisassemblerX86::~DisassemblerX86() {
    51   if (instr_valid_)
    52     libdis::x86_oplist_free(&current_instr_);
    54   libdis::x86_cleanup();
    55 }
    57 uint32_t DisassemblerX86::NextInstruction() {
    58   if (instr_valid_)
    59     libdis::x86_oplist_free(&current_instr_);
    61   if (current_byte_offset_ >= size_) {
    62     instr_valid_ = false;
    63     return 0;
    64   }
    65   uint32_t instr_size = 0;
    66   instr_size = libdis::x86_disasm((unsigned char *)bytecode_, size_,
    67                           virtual_address_, current_byte_offset_,
    68                           &current_instr_);
    69   if (instr_size == 0) {
    70     instr_valid_ = false;
    71     return 0;
    72   }
    74   current_byte_offset_ += instr_size;
    75   current_inst_offset_++;
    76   instr_valid_ = libdis::x86_insn_is_valid(&current_instr_);
    77   if (!instr_valid_)
    78     return 0;
    80   if (current_instr_.type == libdis::insn_return)
    81     end_of_block_ = true;
    82   libdis::x86_op_t *src = libdis::x86_get_src_operand(&current_instr_);
    83   libdis::x86_op_t *dest = libdis::x86_get_dest_operand(&current_instr_);
    85   if (register_valid_) {
    86     switch (current_instr_.group) {
    87       // Flag branches based off of bad registers and calls that occur
    88       // after pushing bad values.
    89       case libdis::insn_controlflow:
    90         switch (current_instr_.type) {
    91           case libdis::insn_jmp:
    92           case libdis::insn_jcc:
    93           case libdis::insn_call:
    94           case libdis::insn_callcc:
    95             if (dest) {
    96               switch (dest->type) {
    97                 case libdis::op_expression:
    98                   if (dest->data.expression.base.id == bad_register_.id)
    99                     flags_ |= DISX86_BAD_BRANCH_TARGET;
   100                   break;
   101                 case libdis::op_register:
   102                   if (dest->data.reg.id == bad_register_.id)
   103                     flags_ |= DISX86_BAD_BRANCH_TARGET;
   104                   break;
   105                 default:
   106                   if (pushed_bad_value_ &&
   107                       (current_instr_.type == libdis::insn_call ||
   108                       current_instr_.type == libdis::insn_callcc))
   109                     flags_ |= DISX86_BAD_ARGUMENT_PASSED;
   110                   break;
   111               }
   112             }
   113             break;
   114           default:
   115             break;
   116         }
   117         break;
   119       // Flag block data operations that use bad registers for src or dest.
   120       case libdis::insn_string:
   121         if (dest && dest->type == libdis::op_expression &&
   122             dest->data.expression.base.id == bad_register_.id)
   123           flags_ |= DISX86_BAD_BLOCK_WRITE;
   124         if (src && src->type == libdis::op_expression &&
   125             src->data.expression.base.id == bad_register_.id)
   126           flags_ |= DISX86_BAD_BLOCK_READ;
   127         break;
   129       // Flag comparisons based on bad data.
   130       case libdis::insn_comparison:
   131         if ((dest && dest->type == libdis::op_expression &&
   132             dest->data.expression.base.id == bad_register_.id) ||
   133             (src && src->type == libdis::op_expression &&
   134             src->data.expression.base.id == bad_register_.id) ||
   135             (dest && dest->type == libdis::op_register &&
   136             dest->data.reg.id == bad_register_.id) ||
   137             (src && src->type == libdis::op_register &&
   138             src->data.reg.id == bad_register_.id))
   139           flags_ |= DISX86_BAD_COMPARISON;
   140         break;
   142       // Flag any other instruction which derefs a bad register for
   143       // src or dest.
   144       default:
   145         if (dest && dest->type == libdis::op_expression &&
   146             dest->data.expression.base.id == bad_register_.id)
   147           flags_ |= DISX86_BAD_WRITE;
   148         if (src && src->type == libdis::op_expression &&
   149             src->data.expression.base.id == bad_register_.id)
   150           flags_ |= DISX86_BAD_READ;
   151         break;
   152     }
   153   }
   155   // When a register is marked as tainted check if it is pushed.
   156   // TODO(cdn): may also want to check for MOVs into EBP offsets.
   157   if (register_valid_ && dest && current_instr_.type == libdis::insn_push) {
   158     switch (dest->type) {
   159       case libdis::op_expression:
   160         if (dest->data.expression.base.id == bad_register_.id ||
   161             dest->data.expression.index.id == bad_register_.id)
   162           pushed_bad_value_ = true;
   163         break;
   164       case libdis::op_register:
   165         if (dest->data.reg.id == bad_register_.id)
   166           pushed_bad_value_ = true;
   167         break;
   168       default:
   169         break;
   170     }
   171   }
   173   // Check if a tainted register value is clobbered.
   174   // For conditional MOVs and XCHGs assume that
   175   // there is a hit.
   176   if (register_valid_) {
   177     switch (current_instr_.type) {
   178       case libdis::insn_xor:
   179         if (src && src->type == libdis::op_register &&
   180             dest && dest->type == libdis::op_register &&
   181             src->data.reg.id == bad_register_.id &&
   182             src->data.reg.id == dest->data.reg.id)
   183           register_valid_ = false;
   184         break;
   185       case libdis::insn_pop:
   186       case libdis::insn_mov:
   187       case libdis::insn_movcc:
   188         if (dest && dest->type == libdis::op_register &&
   189             dest->data.reg.id == bad_register_.id)
   190           register_valid_ = false;
   191         break;
   192       case libdis::insn_popregs:
   193         register_valid_ = false;
   194         break;
   195       case libdis::insn_xchg:
   196       case libdis::insn_xchgcc:
   197         if (dest && dest->type == libdis::op_register &&
   198             src && src->type == libdis::op_register) {
   199           if (dest->data.reg.id == bad_register_.id)
   200             memcpy(&bad_register_, &src->data.reg, sizeof(libdis::x86_reg_t));
   201           else if (src->data.reg.id == bad_register_.id)
   202             memcpy(&bad_register_, &dest->data.reg, sizeof(libdis::x86_reg_t));
   203         }
   204         break;
   205       default:
   206         break;
   207     }
   208   }
   210   return instr_size;
   211 }
   213 bool DisassemblerX86::setBadRead() {
   214   if (!instr_valid_)
   215     return false;
   217   libdis::x86_op_t *operand = libdis::x86_get_src_operand(&current_instr_);
   218   if (!operand || operand->type != libdis::op_expression)
   219     return false;
   221   memcpy(&bad_register_, &operand->data.expression.base,
   222          sizeof(libdis::x86_reg_t));
   223   register_valid_ = true;
   224   return true;
   225 }
   227 bool DisassemblerX86::setBadWrite() {
   228   if (!instr_valid_)
   229     return false;
   231   libdis::x86_op_t *operand = libdis::x86_get_dest_operand(&current_instr_);
   232   if (!operand || operand->type != libdis::op_expression)
   233     return false;
   235   memcpy(&bad_register_, &operand->data.expression.base,
   236          sizeof(libdis::x86_reg_t));
   237   register_valid_ = true;
   238   return true;
   239 }
   241 }  // namespace google_breakpad

mercurial