// Copyright (c) 2010 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. // exploitability_win.cc: Windows specific exploitability engine. // // Provides a guess at the exploitability of the crash for the Windows // platform given a minidump and process_state. // // Author: Cris Neckar #include "processor/exploitability_win.h" #include "google_breakpad/common/minidump_exception_win32.h" #include "processor/logging.h" #include "processor/scoped_ptr.h" namespace google_breakpad { // The cutoff that we use to judge if and address is likely an offset // from null. static const u_int64_t kProbableNullOffset = 4096; // The various cutoffs for the different ratings. static const size_t kHighCutoff = 85; static const size_t kMediumCutoff = 65; static const size_t kLowCutoff = 45; static const size_t kInterestingCutoff = 25; // Predefined incremental values for conditional weighting. static const size_t kTinyBump = 5; static const size_t kSmallBump = 20; static const size_t kMediumBump = 50; static const size_t kLargeBump = 70; static const size_t kHugeBump = 90; ExploitabilityWin::ExploitabilityWin(Minidump *dump, ProcessState *process_state) : Exploitability(dump, process_state) { } ExploitabilityRating ExploitabilityWin::CheckPlatformExploitability() { MinidumpException *exception = dump_->GetException(); if (!exception) return EXPLOITABILITY_ERR_PROCESSING; const MDRawExceptionStream *raw_exception = exception->exception(); if (!raw_exception) return EXPLOITABILITY_ERR_PROCESSING; u_int64_t address = raw_exception->exception_record.exception_address; u_int32_t exception_code = raw_exception->exception_record.exception_code; u_int32_t exception_flags = raw_exception->exception_record.exception_flags; u_int32_t exploitability_weight = 0; switch (exception_code) { // This is almost certainly recursion. case MD_EXCEPTION_CODE_WIN_STACK_OVERFLOW: exploitability_weight += kTinyBump; break; // These exceptions tend to be benign and we can generally ignore them. case MD_EXCEPTION_CODE_WIN_INTEGER_DIVIDE_BY_ZERO: case MD_EXCEPTION_CODE_WIN_INTEGER_OVERFLOW: case MD_EXCEPTION_CODE_WIN_FLOAT_DIVIDE_BY_ZERO: case MD_EXCEPTION_CODE_WIN_FLOAT_INEXACT_RESULT: case MD_EXCEPTION_CODE_WIN_FLOAT_OVERFLOW: case MD_EXCEPTION_CODE_WIN_FLOAT_UNDERFLOW: case MD_EXCEPTION_CODE_WIN_IN_PAGE_ERROR: exploitability_weight += kTinyBump; break; // These exceptions will typically mean that we have jumped where we // shouldn't. case MD_EXCEPTION_CODE_WIN_ILLEGAL_INSTRUCTION: case MD_EXCEPTION_CODE_WIN_FLOAT_INVALID_OPERATION: case MD_EXCEPTION_CODE_WIN_PRIVILEGED_INSTRUCTION: exploitability_weight += kLargeBump; break; // These represent bugs in exception handlers. case MD_EXCEPTION_CODE_WIN_INVALID_DISPOSITION: case MD_EXCEPTION_CODE_WIN_NONCONTINUABLE_EXCEPTION: exploitability_weight += kSmallBump; break; case MD_EXCEPTION_CODE_WIN_HEAP_CORRUPTION: case MD_EXCEPTION_CODE_WIN_STACK_BUFFER_OVERRUN: exploitability_weight += kHugeBump; break; case MD_EXCEPTION_CODE_WIN_GUARD_PAGE_VIOLATION: exploitability_weight += kLargeBump; break; case MD_EXCEPTION_CODE_WIN_ACCESS_VIOLATION: bool near_null = (address <= kProbableNullOffset); if (raw_exception->exception_record.number_parameters >= 1) { MDAccessViolationTypeWin av_type = static_cast (raw_exception->exception_record.exception_information[0]); switch (av_type) { case MD_ACCESS_VIOLATION_WIN_READ: if (near_null) exploitability_weight += kSmallBump; else exploitability_weight += kMediumBump; break; case MD_ACCESS_VIOLATION_WIN_WRITE: if (near_null) exploitability_weight += kSmallBump; else exploitability_weight += kHugeBump; break; case MD_ACCESS_VIOLATION_WIN_EXEC: if (near_null) exploitability_weight += kSmallBump; else exploitability_weight += kHugeBump; break; default: return EXPLOITABILITY_ERR_PROCESSING; break; } } else { return EXPLOITABILITY_ERR_PROCESSING; } } // Based on the calculated weight we return a simplified classification. if (exploitability_weight > kHighCutoff) return EXPLOITABILITY_HIGH; if (exploitability_weight > kMediumCutoff) return EXPLOITABLITY_MEDIUM; if (exploitability_weight > kLowCutoff) return EXPLOITABILITY_LOW; if (exploitability_weight > kInterestingCutoff) return EXPLOITABILITY_INTERESTING; return EXPLOITABILITY_NONE; } } // namespace google_breakpad