Esempio n. 1
0
 def foCreateForException(cBugReport, oCdbWrapper, uExceptionCode, sExceptionDescription):
   uStackFramesCount = dxBugIdConfig["uMaxStackFramesCount"];
   if uExceptionCode == STATUS_STACK_OVERFLOW:
     # In order to detect a recursion loop, we need more stack frames:
     uStackFramesCount += (dxBugIdConfig["uMinStackRecursionLoops"] + 1) * dxBugIdConfig["uMaxStackRecursionLoopSize"]
   oProcess = cProcess.foCreate(oCdbWrapper);
   if not oCdbWrapper.bCdbRunning: return None;
   oStack = cStack.foCreate(oCdbWrapper, uStackFramesCount);
   if not oCdbWrapper.bCdbRunning: return None;
   oException = cException.foCreate(oCdbWrapper, uExceptionCode, sExceptionDescription, oStack);
   if not oCdbWrapper.bCdbRunning: return None;
   # If this exception was not caused by the application, but by cdb itself, None is return. This is not a bug.
   if oException is None: return None;
   # Create a preliminary error report.
   oBugReport = cBugReport(
     oCdbWrapper = oCdbWrapper,
     sBugTypeId = oException.sTypeId,
     sBugDescription = oException.sDescription,
     sSecurityImpact = oException.sSecurityImpact,
     oProcess = oProcess,
     oStack = oStack,
   );
   # Perform exception specific analysis:
   foAnalyzeException = dfoAnalyzeException_by_uExceptionCode.get(oException.uCode);
   if foAnalyzeException:
     oBugReport = foAnalyzeException(oBugReport, oCdbWrapper, oException);
     if not oCdbWrapper.bCdbRunning: return None;
     if not oBugReport:
       # This exception is not a bug, continue the application.
       return None;
   return oBugReport;
Esempio n. 2
0
 def foCreate(cBugReport, oCdbWrapper, sBugTypeId, sBugDescription, sSecurityImpact):
   uStackFramesCount = dxBugIdConfig["uMaxStackFramesCount"];
   oProcess = cProcess.foCreate(oCdbWrapper);
   if not oCdbWrapper.bCdbRunning: return None;
   oStack = cStack.foCreate(oCdbWrapper, uStackFramesCount);
   if not oCdbWrapper.bCdbRunning: return None;
   # Create a preliminary error report.
   oBugReport = cBugReport(
     oCdbWrapper = oCdbWrapper,
     sBugTypeId = sBugTypeId,
     sBugDescription = sBugDescription,
     sSecurityImpact = sSecurityImpact,
     oProcess = oProcess,
     oStack = oStack,
   );
   return oBugReport;
Esempio n. 3
0
 def __init__(oBugReport, oCdbWrapper, sBugTypeId, sBugDescription, sSecurityImpact, oStack):
   oBugReport.oCdbWrapper = oCdbWrapper;
   oBugReport.sBugTypeId = sBugTypeId;
   oBugReport.sBugDescription = sBugDescription;
   oBugReport.sSecurityImpact = sSecurityImpact;
   oBugReport.oProcess = cProcess.foCreate(oCdbWrapper);
   oBugReport.oStack = oStack;
   
   if oCdbWrapper.bGetDetailsHTML:
     oBugReport.sImportantOutputHTML = oCdbWrapper.sImportantOutputHTML;
   oBugReport.sProcessBinaryName = oBugReport.oProcess.sBinaryName;
   oBugReport.asExceptionSpecificBlocksHTML = [];
   # This information is gathered later, when it turns out this bug needs to be reported:
   oBugReport.sStackId = None;
   oBugReport.sId = None;
   oBugReport.oTopmostRelevantCodeFrame = None;
   oBugReport.sBugLocation = None;
   oBugReport.sBugSourceLocation = None;
def cBugReport_foAnalyzeException_STATUS_STOWED_EXCEPTION(
        oBugReport, oCdbWrapper, oException):
    # Parameter[0] = paStowedExceptionInformationArray;
    # Parameter[1] = uStowedExceptionInformationArrayLength;
    assert len(oException.auParameters) == 2, \
        "Unexpected number of WinRT language exception parameters (%d vs 2)" % len(oException.auParameters)
    pStowedExceptionsAddresses = oException.auParameters[0]
    uStowedExceptionsCount = oException.auParameters[1]
    assert uStowedExceptionsCount <= 1, \
        "Unexpected number of WinRT language exception stowed exceptions (%d vs 1)" % uStowedExceptionsCount
    # Get the stowed exception and replace information in the bug report:
    oStowedException = cStowedException.foCreate(oCdbWrapper,
                                                 pStowedExceptionsAddresses)
    oBugReport.sBugTypeId = oStowedException.sTypeId
    oBugReport.sBugDescription = oStowedException.sDescription
    oBugReport.sSecurityImpact = oStowedException.sSecurityImpact
    oBugReport.oProcess = cProcess.foCreate(oCdbWrapper)
    oBugReport.oStack = cStack.foCreateFromAddress(
        oCdbWrapper, oStowedException.pStackTrace,
        oStowedException.uStackTraceSize)
    return oBugReport
Esempio n. 5
0
    def __init__(oBugReport, oCdbWrapper, sBugTypeId, sBugDescription,
                 sSecurityImpact, oStack):
        oBugReport.oCdbWrapper = oCdbWrapper
        oBugReport.sBugTypeId = sBugTypeId
        oBugReport.sBugDescription = sBugDescription
        oBugReport.sSecurityImpact = sSecurityImpact
        oBugReport.oProcess = cProcess.foCreate(oCdbWrapper)
        oBugReport.oStack = oStack
        oBugReport.duRelevantAddress_by_sDescription = {}
        oBugReport.bRegistersRelevant = True
        # Set to false if register contents are not relevant to the crash

        if oCdbWrapper.bGetDetailsHTML:
            oBugReport.sImportantOutputHTML = oCdbWrapper.sImportantOutputHTML
        oBugReport.sProcessBinaryName = oBugReport.oProcess.sBinaryName
        oBugReport.asExceptionSpecificBlocksHTML = []
        # This information is gathered later, when it turns out this bug needs to be reported:
        oBugReport.sStackId = None
        oBugReport.sId = None
        oBugReport.sBugLocation = None
        oBugReport.sBugSourceLocation = None
Esempio n. 6
0
 def foCreate(cSelf, oCdbWrapper, uExceptionCode, sExceptionDescription, uBreakpointId):
   # Get current process details
   oProcess = cProcess.foCreate(oCdbWrapper);
   if not oCdbWrapper.bCdbRunning: return None;
   if uBreakpointId is not None:
     # Create exception details for a breakpoint:
     oException = cException(oProcess, STATUS_BREAKPOINT, "A BugId breakpoint");
     (sBugTypeId, sBugDescription, sSecurityImpact) = oCdbWrapper.xBugBreakpointInformation_by_uBreakpointId[uBreakpointId];
   else:
     # Get exception details from cdb.
     oException = cException.foCreate(oCdbWrapper, oProcess, uExceptionCode, sExceptionDescription);
     if not oCdbWrapper.bCdbRunning: return None;
     sBugTypeId = oException.sTypeId;
     sBugDescription = oException.sDescription;
     sSecurityImpact = oException.sSecurityImpact;
   
   # Get the stack based on the exception info and load symbols for all modules containing functions on the stack.
   oStack = oException.foGetStack(oCdbWrapper);
   if not oCdbWrapper.bCdbRunning: return None;
   
   # Hide some functions at the top of the stack that are merely helper functions and not relevant to the error:
   oStack.fHideTopFrames(asHiddenTopFrames);
   if oException.uCode == STATUS_BREAKPOINT and oException.oFunction and oException.oFunction.sName == "ntdll.dll!DbgBreakPoint":
     # This breakpoint most likely got inserted into the process by cdb. There will be no trace of it in the stack,
     # so do not try to check that exception information matches the first stack frame.
     return None;
   # Create a preliminary error report.
   oBugReport = cSelf(
     oCdbWrapper = oCdbWrapper,
     sBugTypeId = sBugTypeId,
     sBugDescription = sBugDescription,
     sSecurityImpact = sSecurityImpact,
     oException = oException,
     oStack = oStack,
   );
   
   if uBreakpointId is None:
     # Perform exception specific analysis:
     foAnalyzeException = dfoAnalyzeException_by_uExceptionCode.get(oException.uCode);
     if foAnalyzeException:
       oBugReport = foAnalyzeException(oBugReport, oCdbWrapper);
       if not oCdbWrapper.bCdbRunning: return None;
       if not oBugReport:
         # This exception is not a bug, continue the application.
         return None;
   
   # Calculate sStackId, determine sBugLocation and optionally create and return sStackHTML.
   sStackHTML = cBugReport_fsProcessStack(oBugReport, oCdbWrapper);
   oBugReport.sId = "%s %s" % (oBugReport.sBugTypeId, oBugReport.sStackId);
   if oCdbWrapper.bGetDetailsHTML: # Generate sDetailsHTML?
     # Create HTML details
     asBlocksHTML = [];
     # Create and add important output block if needed
     if oBugReport.sImportantOutputHTML:
       asBlocksHTML.append(sBlockHTMLTemplate % {"sName": "Potentially important application output", "sContent": oBugReport.sImportantOutputHTML});
     # Add stack block
     asBlocksHTML.append(sBlockHTMLTemplate % {"sName": "Stack", "sContent": sStackHTML});
     # Add exception specific blocks if needed:
     asBlocksHTML += oBugReport.asExceptionSpecificBlocksHTML;
     # Create and add disassembly block if possible
     sDisassemblyHTML = cBugReport_fsGetDisassemblyHTML(oBugReport, oCdbWrapper);
     if sDisassemblyHTML is None: return None;
     if sDisassemblyHTML:
       asBlocksHTML.append(sBlockHTMLTemplate % {"sName": "Disassembly", "sContent": sDisassemblyHTML});
     # Create and add registers block
     asRegisters = oCdbWrapper.fasSendCommandAndReadOutput("rM 0x%X" % (0x1 + 0x4 + 0x8 + 0x10 + 0x20 + 0x40));
     if not oCdbWrapper.bCdbRunning: return None;
     sRegistersHTML = "<br/>".join(['<span class="Registers">%s</span>' % oCdbWrapper.fsHTMLEncode(s) for s in asRegisters]);
     asBlocksHTML.append(sBlockHTMLTemplate % {"sName": "Registers", "sContent": sRegistersHTML});
     # Add referenced memory to memory block and add memory block if needed
     sReferencedMemoryHTML = cBugReport_fsGetReferencedMemoryHTML(oBugReport, oCdbWrapper)
     if sReferencedMemoryHTML is None: return None;
     if sReferencedMemoryHTML:
       asBlocksHTML.append(sBlockHTMLTemplate % {"sName": "Referenced memory", "sContent": sReferencedMemoryHTML});
     sBinaryInformationHTML = cBugReport_fsGetBinaryInformationHTML(oBugReport, oCdbWrapper);
     if sBinaryInformationHTML is None: return None;
     if sBinaryInformationHTML:
       asBlocksHTML.append(sBlockHTMLTemplate % {"sName": "Binary information", "sContent": sBinaryInformationHTML});
     # Convert saved cdb IO HTML into one string and delete everything but the last line to free up some memory.
     sCdbStdIOHTML = '<hr/>'.join(oBugReport.oCdbWrapper.asCdbStdIOBlocksHTML);
     oBugReport.oCdbWrapper.asCdbStdIOBlocksHTML = oBugReport.oCdbWrapper.asCdbStdIOBlocksHTML[-1:];
     # Stick everything together.
     oBugReport.sDetailsHTML = sDetailsHTMLTemplate % {
       "sId": oCdbWrapper.fsHTMLEncode(oBugReport.sId),
       "sBugDescription": oCdbWrapper.fsHTMLEncode(oBugReport.sBugDescription),
       "sBugLocation": oCdbWrapper.fsHTMLEncode(oBugReport.sBugLocation),
       "sSecurityImpact": oBugReport.sSecurityImpact and \
             '<span class="SecurityImpact">%s</span>' % oCdbWrapper.fsHTMLEncode(oBugReport.sSecurityImpact) or "Denial of Service",
       "sOptionalBlocks": "".join(asBlocksHTML),
       "sCdbStdIO": sCdbStdIOHTML,
     };
   
   return oBugReport;
Esempio n. 7
0
 def foCreate(cSelf, oCdbWrapper, uExceptionCode, sExceptionDescription):
   # Get current process details
   oProcess = cProcess.foCreate(oCdbWrapper);
   if not oCdbWrapper.bCdbRunning: return None;
   # Get exception details
   oException = cException.foCreate(oCdbWrapper, oProcess, uExceptionCode, sExceptionDescription);
   if not oCdbWrapper.bCdbRunning: return None;
   # Get the stack
   oStack = oException.foGetStack(oCdbWrapper);
   if not oCdbWrapper.bCdbRunning: return None;
   # Hide some functions at the top of the stack that are merely helper functions and not relevant to the error:
   oStack.fHideTopFrames(asHiddenTopFrames);
   # Create a preliminary error report.
   oErrorReport = cSelf(
     sErrorTypeId = oException.sTypeId,
     sErrorDescription = oException.sDescription,
     sSecurityImpact = oException.sSecurityImpact,
     oException = oException,
     oStack = oStack,
   );
   # Make exception specific changes to the error report:
   foSpecialErrorReport = dfoSpecialErrorReport_uExceptionCode.get(oException.uCode);
   if foSpecialErrorReport:
     oErrorReport = foSpecialErrorReport(oErrorReport, oCdbWrapper);
     if not oCdbWrapper.bCdbRunning: return None;
     if not oErrorReport:
       # This exception is not an error, continue the application.
       return None;
   
   # Find out which frame should be the "main" frame and get stack id.
   oTopmostRelevantFrame = None;          # topmost relevant frame
   oTopmostRelevantFunctionFrame = None;  # topmost relevant frame that has a function symbol
   oTopmostRelevantModuleFrame = None;    # topmost relevant frame that has no function symbol but a module
   uFramesHashed = 0;
   asHTMLStack = [];
   sStackId = "";
   for oStackFrame in oStack.aoFrames:
     if oStackFrame.bIsHidden:
       # This frame is hidden (because it is irrelevant to the crash)
       asHTMLStack.append("<s>%s</s><br/>" % fsHTMLEncode(oStackFrame.sAddress));
     else:
       oTopmostRelevantFrame = oTopmostRelevantFrame or oStackFrame;
       sHTMLAddress = fsHTMLEncode(oStackFrame.sAddress);
       # Make stack frames without a function symbol italic
       if not oStackFrame.oFunction:
         sHTMLAddress = "<i>%s</i>" % sHTMLAddress;
       # Hash frame address for id and output frame to html
       if uFramesHashed == oStack.uHashFramesCount:
         # no more hashing is needed: just output as is:
         asHTMLStack.append("%s<br/>" % sHTMLAddress);
       else:
         sStackId += oStackFrame.sId or "__";
         if oStackFrame.sId:
           # frame adds useful infoormation to the id: add hash and output bold
           uFramesHashed += 1;
           asHTMLStack.append("<b>%s</b> (%s in id)<br/>" % (sHTMLAddress, oStackFrame.sId));
           # Determine the top frame for the id:
           if oStackFrame.oFunction:
             oTopmostRelevantFunctionFrame = oTopmostRelevantFunctionFrame or oStackFrame;
           elif oStackFrame.oModule:
             oTopmostRelevantModuleFrame = oTopmostRelevantModuleFrame or oStackFrame;
         else:
           # This is not part of the id, but between frames that are: add "__" to id and output strike-through
           asHTMLStack.append("<s>%s</s><br/>" % sHTMLAddress);
   # If there are not enouogh id-able stack frames, there may be many trailing "_"-s; remove these. Also, if there
   # was not id, or nothing is left after removing the "_"-s, use the id "##".
   oErrorReport.sStackId = sStackId.rstrip("_") or "##";
   if oStack.bPartialStack:
     asHTMLStack.append("... (rest of the stack was ignored)<br/>");
   # Use a function for the id
   oCodeIdFrame = oTopmostRelevantFunctionFrame or oTopmostRelevantModuleFrame;
   oErrorReport.sCodeId = oCodeIdFrame and oCodeIdFrame.sSimplifiedAddress or "(unknown)";
   
   # Create the location description 
   oErrorReport.sCodeDescription = oTopmostRelevantFrame and oTopmostRelevantFrame.sAddress or "(unknown)";
   
   # Get the binary's cdb name for retreiving version information:
   asBinaryCdbNames = oCdbWrapper.fasGetCdbIdsForModuleFileNameInCurrentProcess(oErrorReport.sProcessBinaryName);
   if not oCdbWrapper.bCdbRunning: return None;
   assert len(asBinaryCdbNames) > 0, "Cannot find binary %s module" % oErrorReport.sProcessBinaryName;
   # If the binary is loaded as a module multiple times in the process, the first should be the binary that was
   # executed.
   dsGetVersionCdbId_by_sBinaryName = {oErrorReport.sProcessBinaryName: asBinaryCdbNames[0]};
   # Get the id frame's module cdb name for retreiving version information:
   if oCodeIdFrame:
     dsGetVersionCdbId_by_sBinaryName[oCodeIdFrame.oModule.sBinaryName] = oCodeIdFrame.oModule.sCdbId;
   asHTMLBinaryInformation = [];
   for sBinaryName, sCdbId in dsGetVersionCdbId_by_sBinaryName.items():
     asModuleInformationOutput = oCdbWrapper.fasSendCommandAndReadOutput("lmv m *%s" % sCdbId);
     if not oCdbWrapper.bCdbRunning: return None;
     # Sample output:
     # |0:004> lmv M firefox.exe
     # |start             end                 module name
     # |00000000`011b0000 00000000`0120f000   firefox    (deferred)             
     # |    Image path: firefox.exe
     # |    Image name: firefox.exe
     # |    Timestamp:        Thu Aug 13 03:23:30 2015 (55CBF192)
     # |    CheckSum:         0006133B
     # |    ImageSize:        0005F000
     # |    File version:     40.0.2.5702
     # |    Product version:  40.0.2.0
     # |    File flags:       0 (Mask 3F)
     # |    File OS:          4 Unknown Win32
     # |    File type:        2.0 Dll
     # |    File date:        00000000.00000000
     # |    Translations:     0000.04b0
     # |    CompanyName:      Mozilla Corporation
     # |    ProductName:      Firefox
     # |    InternalName:     Firefox
     # |    OriginalFilename: firefox.exe
     # |    ProductVersion:   40.0.2
     # |    FileVersion:      40.0.2
     # |    FileDescription:  Firefox
     # |    LegalCopyright:   (c)Firefox and Mozilla Developers; available under the MPL 2 license.
     # |    LegalTrademarks:  Firefox is a Trademark of The Mozilla Foundation.
     # |    Comments:         Firefox is a Trademark of The Mozilla Foundation.
     # The first two lines can be skipped.
     asHTMLBinaryInformation.append(sHTMLBinaryInformationTemplate % {
       "sName": fsHTMLEncode(sBinaryName),
       "sInformation": "".join(["%s<br/>" % fsHTMLEncode(x) for x in asModuleInformationOutput[2:]]),
     });
   
   # Turn cdb I/O into formatted HTML. It is separated into blocks, one for the initial cdb output and one for each
   # command executed.
   asHTMLBlocks = [];
   for asBlock in oCdbWrapper.aasCdbStdIO:
     asHTMLBlocks.append("".join(["%s<br/>" % fsHTMLEncode(sLine) for sLine in asBlock]));
   sHTMLCdbStdIO = "<hr/>".join(asHTMLBlocks);
   sHTMLCdbStdErr = "".join(["%s<br/>" % fsHTMLEncode(sLine) for sLine in oCdbWrapper.asCdbStdErr]);
   # Create HTML details
   oErrorReport.sHTMLDetails = sHTMLDetailsTemplate % {
     "sId": fsHTMLEncode(oErrorReport.sId),
     "sExceptionDescription": fsHTMLEncode(oErrorReport.sErrorDescription),
     "sProcessBinaryName": fsHTMLEncode(oErrorReport.sProcessBinaryName),
     "sCodeDescription": fsHTMLEncode(oErrorReport.sCodeDescription),
     "sSecurityImpact": oErrorReport.sSecurityImpact and "<b>%s</b>" % fsHTMLEncode(oErrorReport.sSecurityImpact) or "None",
     "sStack": "".join(asHTMLStack),
     "sBinaryInformation": "".join(asHTMLBinaryInformation),
     "sCdbStdErr": sHTMLCdbStdErr,
     "sCdbStdIO": sHTMLCdbStdIO,
   };
   return oErrorReport;
Esempio n. 8
0
 def foCreate(cSelf, oCrashInfo, uCode, sCodeDescription):
   oProcess = cProcess.foCreate(oCrashInfo);
   oSelf = cSelf(oProcess, uCode, sCodeDescription);
   # We do this twice to make sure symbols are loaded the first time, which may create additional symbal warnings and
   # errors that makes the output harder to parse. The second time, there will be no such output, so we can parse it
   # a lot easier.
   asExceptionRecord = oCrashInfo._fasSendCommandAndReadOutput(".exr -1");
   if asExceptionRecord is None: return None;
   asExceptionRecord = oCrashInfo._fasSendCommandAndReadOutput(".exr -1");
   if asExceptionRecord is None: return None;
   uParameterCount = None;
   uParameterIndex = None;
   for sLine in asExceptionRecord:
     oNameValueMatch = re.match(r"^\s*%s\s*$" % (
       r"(\w+)(?:\[(\d+)\])?\:\s+"     # (name) optional{ "[" (index) "]" } ":" whitespace
       r"([0-9A-F`]+)"                  # (value)
       r"(?:\s+\((.*)\))?"             # optional{ whitespace "(" (symbol || description) ")" }
     ), sLine, re.I);
     if oNameValueMatch:
       sName, sIndex, sValue, sDetails = oNameValueMatch.groups();
       uValue = int(sValue.replace("`", ""), 16);
       if sName == "ExceptionAddress":
         oSelf.uAddress = uValue;
         oSelf.sAddressSymbol = sDetails;
       elif sName == "ExceptionCode":
         assert uValue == uCode, \
             "Exception record has an unexpected ExceptionCode value (0x%08X vs 0x%08X)" % (uValue, uCode);
         assert sDetails is None or sDetails == sCodeDescription, \
             "Exception record has an unexpected ExceptionCode description (%s vs %s)" % \
                 (repr(sDetails), repr(sCodeDescription));
       elif sName == "ExceptionFlags":
         oSelf.uFlags = uValue;
       elif sName == "NumberParameters":
         uParameterCount = uValue;
         uParameterIndex = 0;
         oSelf.auParameters = [];
       elif sName == "Parameter":
         assert int(sIndex, 16) == uParameterIndex, \
             "Unexpected parameter #0x%s vs 0x%X" % (sIndex, uParameterIndex);
         oSelf.auParameters.append(uValue);
         uParameterIndex += 1;
       else:
         raise AssertionError("Unknown exception record value %s" % sLine);
     elif oSelf.sDetails is None:
       oSelf.sDetails = sLine;
     else:
       raise AssertionError("Superfluous exception record line %s" % sLine);
   assert oSelf.uAddress is not None, \
       "Exception record is missing an ExceptionAddress value";
   assert oSelf.uFlags is not None, \
       "Exception record is missing an ExceptionFlags value";
   assert uParameterCount is not None, \
       "Exception record is missing an NumberParameters value";
   assert uParameterCount == len(oSelf.auParameters), \
       "Unexpected number of parameters (%d vs %d)" % (len(oSelf.auParameters), uParameterCount);
   
   # Now handle the information in the exception record and perform additional tasks as needed. Create an exception
   # id that uniquely identifies the exception and a description of the exception.
   if uCode == 0xC000027B:
     # Parameter[0] = paStowedExceptionInformationArray;
     # Parameter[1] = uStowedExceptionInformationArrayLength;
     assert len(oSelf.auParameters) == 2, \
         "Unexpected number of WinRT language exception parameters (%d vs 2)" % len(oSelf.auParameters);
     pStowedExceptionsAddress = oSelf.auParameters[0];
     uStowedExceptionsCount = oSelf.auParameters[1];
     assert uStowedExceptionsCount == 1, \
         "Unexpected number of WinRT language exception stowed exceptions (%d vs 1)" % uStowedExceptionsCount;
     # The stowed exception replaces this exception:
     return cStowedException.foCreate(oCrashInfo, oProcess, pStowedExceptionsAddress);
   elif uCode == STATUS_ACCESS_VIOLATION:
     # Parameter[0] = access type (0 = read, 1 = write, 8 = execute)
     # Parameter[1] = address
     assert len(oSelf.auParameters) == 2, \
         "Unexpected number of access violation exception parameters (%d vs 2)" % len(oSelf.auParameters);
     # Access violation: add the type of operation and the location to the exception id.
     sViolationTypeId = "AV" + {0:"R", 1:"W", 8:"E"}.get(oSelf.auParameters[0], "?");
     sViolationTypeDescription = {0:"reading", 1:"writing", 8:"executing"}.get(oSelf.auParameters[0], "0x%X-ing" % oSelf.auParameters[0]);
     uAddress = oSelf.auParameters[1];
     sAddressId, sAddressDescription = ftsGetAddressIdAndDescription(uAddress);
     if sAddressId != "NULL":
       asPageHeapInformation = oCrashInfo._fasSendCommandAndReadOutput("!heap -p -a 0x%X" % uAddress);
       asPageHeapInformation = oCrashInfo._fasSendCommandAndReadOutput("!heap -p -a 0x%X" % uAddress);
       asPageHeapInformation = oCrashInfo._fasSendCommandAndReadOutput("!heap -p -a 0x%X" % (uAddress - 0x4));
       if asPageHeapInformation is None: return None;
       #if uAddress & 0xFFF < 0x8:
       #  # Assuming page heap is This may be a buffer overrun
     oSelf.sTypeId = "%s@%s" % (sViolationTypeId, sAddressId);
     oSelf.sDescription = "%s while %s memory at 0x%X (%s)" % \
         (sCodeDescription, sViolationTypeDescription, uAddress, sAddressDescription);
     uNULLMinusOffsetMinAddress = {"x64": 0xFFFFFFFFFFFF0000, "x86": 0xFFFF0000}[oProcess.sISA];
     oSelf.sSecurityImpact = ((uAddress > uNULLMinusOffsetMinAddress or uAddress < 0x10000)
       and "Not a security issue"
       or "Probably a security issue"
     );
   elif uCode == STATUS_STACK_BUFFER_OVERRUN:
     # Parameter[0] = fail fast code
     assert len(oSelf.auParameters) == 1, \
         "Unexpected number of fail fast exception parameters (%d vs 1)" % len(oSelf.auParameters);
     sCodeId, sCodeDescription, sSecurityImpact = \
         ftsGetFailFastErrorCodeIdDescriptionAndSecurityImpact(oSelf.auParameters[0]);
     oSelf.sTypeId = "FF@%s" % sCodeId;
     oSelf.sDescription = "A critical issue was detected (code %d: %s)" % (oSelf.auParameters[0], sCodeDescription);
     oSelf.sSecurityImpact = sSecurityImpact;
   else:
     oSelf.sTypeId = fsGetExceptionTypeId(uCode);
     oSelf.sDescription = "%s (code 0x%08X)" % (sCodeDescription, uCode);
     oSelf.sSecurityImpact = fsGetSecurityImpact(uCode);
   
   # Get the stack
   oSelf.oStack = cStack.foCreate(oCrashInfo, oSelf.oProcess);
   if oSelf.oStack is None: return None;
   
   return oSelf;
def cCrashInfo_foCdbRunApplicationAndGetErrorReport(oCrashInfo, asIntialOutput):
  # cdb can either start an application, or attach to paused processes; which is it?
  bCdbStartedAnApplication = len(oCrashInfo._auProcessIdsPendingAttach) == 0;
  bDebuggerIsAttachingToProcesses = not bCdbStartedAnApplication;
  # If cdb was asked to attach to a process, make sure it worked.
  if bDebuggerIsAttachingToProcesses:
    fDetectFailedAttach(asIntialOutput);
  # If the debugger started a process, we should set up exception handling now. Otherwise wait until the debugger has
  # attached to all the processes.
  bExceptionHandlersHaveBeenSet = False;
  # While no error has been reported:
  oErrorReport = None;
  while oErrorReport is None:
    # Find out what event caused the debugger break
    asLastEventOutput = oCrashInfo._fasSendCommandAndReadOutput(".lastevent");
    if not oCrashInfo._bCdbRunning: return None;
    # Sample output:
    # |Last event: 3d8.1348: Create process 3:3d8                
    # |  debugger time: Tue Aug 25 00:06:07.311 2015 (UTC + 2:00)
    # - or -
    # |Last event: c74.10e8: Exit process 4:c74, code 0          
    # |  debugger time: Tue Aug 25 00:06:07.311 2015 (UTC + 2:00)
    bValidLastEventOutput = len(asLastEventOutput) == 2 and re.match(r"^\s*debugger time: .*$", asLastEventOutput[1]);
    oEventMatch = bValidLastEventOutput and re.match(
      "".join([
        r"^Last event: ([0-9a-f]+)\.[0-9a-f]+: ",
        r"(?:",
          r"(Create|Exit) process [0-9a-f]+\:([0-9a-f]+)(?:, code [0-9a-f]+)?",
        r"|",
          r"(.*?) \- code ([0-9a-f]+) \(!*\s*(?:first|second) chance\s*!*\)",
        r")\s*$",
      ]),
      asLastEventOutput[0],
      re.I
    );
    assert oEventMatch, "Invalid .lastevent output:\r\n%s" % "\r\n".join(asLastEventOutput);
    (
      sProcessIdHex,
        sCreateExitProcess, sCreateExitProcessIdHex,
        sExceptionDescription, sExceptionCode
    ) = oEventMatch.groups();
    uProcessId = long(sProcessIdHex, 16);
    if sCreateExitProcess:
      # Make sure the created/exited process is the current process.
      assert sProcessIdHex == sCreateExitProcessIdHex, "%s vs %s" % (sProcessIdHex, sCreateExitProcessIdHex);
      oCrashInfo.fHandleCreateExitProcess(sCreateExitProcess, uProcessId);
      if len(oCrashInfo._auProcessIds) == 0:
        break; # The last process was terminated.
    else:
      uExceptionCode = int(sExceptionCode, 16);
      if uExceptionCode == STATUS_BREAKPOINT and uProcessId not in oCrashInfo._auProcessIds:
        # This is assumed to be the initial breakpoint after starting/attaching to the first process or after a new
        # process was created by the application. This assumption may not be correct, in which case the code needs to
        # be modifed to check the stack to determine if this really is the initial breakpoint. But that comes at a
        # performance cost, so until proven otherwise, the code is based on this assumption.
        oCrashInfo.fHandleCreateExitProcess("Create", uProcessId);
      else:
        # Report that analysis is starting...
        oCrashInfo._fExceptionDetectedCallback(uExceptionCode, sExceptionDescription);
        # Turn off noizy symbol loading; it can mess up the output of commands, making it unparsable.
        asOutput = oCrashInfo._fasSendCommandAndReadOutput("!sym quiet");
        if not oCrashInfo._bCdbRunning: return None;
        # Gather relevant information...
        oProcess = cProcess.foCreate(oCrashInfo);
        oException = cException.foCreate(oCrashInfo, oProcess, uExceptionCode, sExceptionDescription);
        if not oCrashInfo._bCdbRunning: return None;
        # Save the exception report for returning when we're finished.
        oErrorReport = cErrorReport.foCreateFromException(oCrashInfo, oException);
        if not oCrashInfo._bCdbRunning: return None;
        # Stop the debugger if there was a fatal error that needs to be reported.
        if oErrorReport is not None:
          break;
        # Turn noizy symbol loading back on if it was enabled.
        if dxCrashInfoConfig["bDebugSymbolLoading"]:
          asOutput = oCrashInfo._fasSendCommandAndReadOutput("!sym noizy");
          if not oCrashInfo._bCdbRunning: return None;
    # If there are more processes to attach to, do so:
    if len(oCrashInfo._auProcessIdsPendingAttach) > 0:
      asAttachToProcess = oCrashInfo._fasSendCommandAndReadOutput(".attach 0n%d" % oCrashInfo._auProcessIdsPendingAttach[0]);
      if not oCrashInfo._bCdbRunning: return;
    else:
      # The debugger has started the process or attached to all processes.
      # Set up exception handling if this has not beenm done yet.
      if not bExceptionHandlersHaveBeenSet:
        # Note to self: when rewriting the code, make sure not to set up exception handling before the debugger has
        # attached to all processes. But do so before resuming the threads. Otherwise one or more of the processes can
        # end up having only one thread that has a suspend count of 2 and no amount of resuming will cause the process
        # to run. The reason for this is unknown, but if things are done in the correct order, this problem is avoided.
        bExceptionHandlersHaveBeenSet = False;
        oCrashInfo._fasSendCommandAndReadOutput(sExceptionHandlingCommands);
        if not oCrashInfo._bCdbRunning: return;
      # If the debugger attached to processes, mark that as done and resume threads in all processes.
      if bDebuggerIsAttachingToProcesses:
        bDebuggerIsAttachingToProcesses = False;
        for uProcessId in oCrashInfo._auProcessIds:
          oCrashInfo._fasSendCommandAndReadOutput("|~[0n%d]s;~*m;~" % uProcessId);
          if not oCrashInfo._bCdbRunning: return;
    # Run the application
    asRunApplicationOutput = oCrashInfo._fasSendCommandAndReadOutput("g");
    if not oCrashInfo._bCdbRunning: return;
    # If cdb is attaching to a process, make sure it worked.
    if bDebuggerIsAttachingToProcesses:
      fDetectFailedAttach(asRunApplicationOutput);
  # Terminate cdb.
  oCrashInfo._bCdbTerminated = True;
  oCrashInfo._fasSendCommandAndReadOutput("q");
  assert not oCrashInfo._bCdbRunning, "Debugger did not terminate when requested";
  return oErrorReport;
Esempio n. 10
0
 def foCreate(cSelf, oCdbWrapper, uExceptionCode, sExceptionDescription):
   # Get current process details
   oProcess = cProcess.foCreate(oCdbWrapper);
   if not oCdbWrapper.bCdbRunning: return None;
   # Get exception details
   oException = cException.foCreate(oCdbWrapper, oProcess, uExceptionCode, sExceptionDescription);
   if not oCdbWrapper.bCdbRunning: return None;
   # Get registers. This information is not analyzed, but will end up in cdb output in the report, for potential
   # use by an analyst.
   oCdbWrapper.fasSendCommandAndReadOutput("r");
   if not oCdbWrapper.bCdbRunning: return None;
   # Similarly, try to get disassembly around code in which exception happened. This may not be possible if rip/eip
   # points to memeory that cannot be read.
   asDisassemblyOutput = oCdbWrapper.fasSendCommandAndReadOutput(".if ($vvalid(@$scopeip, 1)) { ub; }; .else { .echo Disassembly not possible };");
   if not oCdbWrapper.bCdbRunning: return None;
   if asDisassemblyOutput != ["Disassembly not possible"]:
     # rip/eip must be valid as disassembly before this address was returned: get disassembly after as well:
     oCdbWrapper.fasSendCommandAndReadOutput("u");
     if not oCdbWrapper.bCdbRunning: return None;
   # Get the stack
   oStack = oException.foGetStack(oCdbWrapper);
   if not oCdbWrapper.bCdbRunning: return None;
   # Compare stack with exception information
   if oException.sAddressSymbol:
     doModules_by_sCdbId = oCdbWrapper.fdoGetModulesByCdbIdForCurrentProcess();
     (
       uAddress,
       sUnloadedModuleFileName, oModule, uModuleOffset,
       oFunction, uFunctionOffset
     ) = oCdbWrapper.ftxSplitSymbolOrAddress(oException.sAddressSymbol, doModules_by_sCdbId);
     sCdbSource = oException.sAddressSymbol;
   else:
     sCdbSource = "%X" % oException.uAddress; # Kinda faking it here :)
     uAddress = oException.uAddress;
     sUnloadedModuleFileName, oModule, uModuleOffset = None, None, None;
     oFunction, uFunctionOffset = None, None;
   if not oStack.aoFrames:
     # Failed to get stack, use information from exception.
     uFrameNumber = 0;
     oStack.fCreateAndAddStackFrame(oCdbWrapper, uFrameNumber, sCdbSource, uAddress, sUnloadedModuleFileName, oModule, uModuleOffset, oFunction, uFunctionOffset);
   else:
     if oException.uCode in [STATUS_WX86_BREAKPOINT, STATUS_BREAKPOINT]:
       # A breakpoint happens at an int 3 instruction, and eip/rip may have been updated to the next instruction.
       # If the first stack frame is not the same as the exception address, fix this off-by-one:
       oFrame = oStack.aoFrames[0];
       if (
         oFrame.uAddress == uAddress
         and oFrame.sUnloadedModuleFileName == sUnloadedModuleFileName
         and oFrame.oModule == oModule
         and oFrame.uModuleOffset == uModuleOffset
         and oFrame.oFunction == oFunction
         and oFrame.uFunctionOffset == uFunctionOffset
       ):
         pass;
       else:
         if uAddress is not None:
           uAddress -= 1;
         elif uModuleOffset is not None:
           uModuleOffset -= 1;
         elif uFunctionOffset is not None:
           oFrame.uFunctionOffset -= 1;
         else:
           raise AssertionError("The first stack frame appears to have no address or offet to adjust.");
         assert (
           oFrame.uAddress == uAddress
           and oFrame.sUnloadedModuleFileName == sUnloadedModuleFileName
           and oFrame.oModule == oModule
           and oFrame.uModuleOffset == uModuleOffset
           and oFrame.oFunction == oFunction
           and oFrame.uFunctionOffset == uFunctionOffset
         ), "The first stack frame does not appear to match the exception address";
     else:
       # Check that the address where the exception happened is on the stack and hide any frames that appear above it,
       # as these are not interesting (e.g. ntdll!RaiseException).
       for oFrame in oStack.aoFrames:
         if (
           oFrame.uAddress == uAddress
           and oFrame.sUnloadedModuleFileName == sUnloadedModuleFileName
           and oFrame.oModule == oModule
           and oFrame.uModuleOffset == uModuleOffset
           and oFrame.oFunction == oFunction
           and oFrame.uFunctionOffset == uFunctionOffset
         ):
           break;
         oFrame.bIsHidden = True;
       else:
         raise AssertionError("The exception address %s was not found on the stack" % sCdbSource);
     
   # Hide some functions at the top of the stack that are merely helper functions and not relevant to the error:
   oStack.fHideTopFrames(asHiddenTopFrames);
   # Create a preliminary error report.
   oErrorReport = cSelf(
     oCdbWrapper = oCdbWrapper,
     sErrorTypeId = oException.sTypeId,
     sErrorDescription = oException.sDescription,
     sSecurityImpact = oException.sSecurityImpact,
     oException = oException,
     oStack = oStack,
     asImportantStdErrLines = oCdbWrapper.asImportantStdErrLines,
   );
   # Make exception specific changes to the error report:
   foSpecialErrorReport = dfoSpecialErrorReport_uExceptionCode.get(oException.uCode);
   if foSpecialErrorReport:
     oErrorReport = foSpecialErrorReport(oErrorReport, oCdbWrapper);
     if not oCdbWrapper.bCdbRunning: return None;
     if not oErrorReport:
       # This exception is not an error, continue the application.
       return None;
   
   # Find out which frame should be the "main" frame and get stack id.
   oTopmostRelevantFrame = None;          # topmost relevant frame
   oTopmostRelevantFunctionFrame = None;  # topmost relevant frame that has a function symbol
   oTopmostRelevantModuleFrame = None;    # topmost relevant frame that has no function symbol but a module
   uFramesHashed = 0;
   bStackShowsNoSignOfCorruption = True;
   asHTMLStack = [];
   sStackId = "";
   for oStackFrame in oStack.aoFrames:
     if oStackFrame.bIsHidden:
       # This frame is hidden (because it is irrelevant to the crash)
       asHTMLStack.append('<span class="StackIgnored">%s</span><br/>' % fsHTMLEncode(oStackFrame.sAddress));
     else:
       # Once a stack frame is encountered with no id, the stack can no longer be trusted to be correct.
       bStackShowsNoSignOfCorruption = bStackShowsNoSignOfCorruption and (oStackFrame.sId and True or False);
       oTopmostRelevantFrame = oTopmostRelevantFrame or oStackFrame;
       sHTMLAddress = fsHTMLEncode(oStackFrame.sAddress);
       # Make stack frames without a function symbol italic
       if not oStackFrame.oFunction:
         sHTMLAddress = '<span class="StackNoSymbol">%s</span>' % sHTMLAddress;
       # Hash frame address for id and output frame to html
       if not bStackShowsNoSignOfCorruption or uFramesHashed == oStack.uHashFramesCount:
         # no more hashing is needed: just output as is:
         asHTMLStack.append('<span class="Stack">%s</span><br/>' % sHTMLAddress);
       else:
         sStackId += oStackFrame.sId;
         # frame adds useful information to the id: add hash and output bold
         uFramesHashed += 1;
         asHTMLStack.append('<span class="StackHash">%s</span> (%s in id)<br/>' % (sHTMLAddress, oStackFrame.sId));
         # Determine the top frame for the id:
         if oStackFrame.oFunction:
           oTopmostRelevantFunctionFrame = oTopmostRelevantFunctionFrame or oStackFrame;
         elif oStackFrame.oModule:
           oTopmostRelevantModuleFrame = oTopmostRelevantModuleFrame or oStackFrame;
   # If there are not enouogh id-able stack frames, there may be many trailing "_"-s; remove these. Also, if there
   # was not id, or nothing is left after removing the "_"-s, use the id "##".
   oErrorReport.sStackId = sStackId.rstrip("_") or "##";
   if oStack.bPartialStack:
     asHTMLStack.append("... (rest of the stack was ignored)<br/>");
   oErrorReport.sHTMLStack = "".join(asHTMLStack);
   # Use a function for the id
   oCodeIdFrame = oTopmostRelevantFunctionFrame or oTopmostRelevantModuleFrame;
   oErrorReport.sCodeId = oCodeIdFrame and oCodeIdFrame.sSimplifiedAddress or "(unknown)";
   
   # Create the location description 
   oErrorReport.sCodeDescription = oTopmostRelevantFrame and oTopmostRelevantFrame.sAddress or "(unknown)";
   
   # Get the binary's cdb name for retreiving version information:
   asBinaryCdbNames = oCdbWrapper.fasGetCdbIdsForModuleFileNameInCurrentProcess(oErrorReport.sProcessBinaryName);
   if not oCdbWrapper.bCdbRunning: return None;
   assert len(asBinaryCdbNames) > 0, "Cannot find binary %s module" % oErrorReport.sProcessBinaryName;
   # If the binary is loaded as a module multiple times in the process, the first should be the binary that was
   # executed.
   # If this turns out to be wrong, this code should be switch to use "u @$exentry L1" to determine the cdb id of the
   # module in which the process's entry point is found.
   dsGetVersionCdbId_by_sBinaryName = {oErrorReport.sProcessBinaryName: asBinaryCdbNames[0]};
   # Get the id frame's module cdb name for retreiving version information:
   if oCodeIdFrame:
     dsGetVersionCdbId_by_sBinaryName[oCodeIdFrame.oModule.sBinaryName] = oCodeIdFrame.oModule.sCdbId;
   asHTMLBinaryInformation = [];
   for sBinaryName, sCdbId in dsGetVersionCdbId_by_sBinaryName.items():
     asModuleInformationOutput = oCdbWrapper.fasSendCommandAndReadOutput("lmv m *%s" % sCdbId);
     if not oCdbWrapper.bCdbRunning: return None;
     # Sample output:
     # |0:004> lmv M firefox.exe
     # |start             end                 module name
     # |00000000`011b0000 00000000`0120f000   firefox    (deferred)             
     # |    Image path: firefox.exe
     # |    Image name: firefox.exe
     # |    Timestamp:        Thu Aug 13 03:23:30 2015 (55CBF192)
     # |    CheckSum:         0006133B
     # |    ImageSize:        0005F000
     # |    File version:     40.0.2.5702
     # |    Product version:  40.0.2.0
     # |    File flags:       0 (Mask 3F)
     # |    File OS:          4 Unknown Win32
     # |    File type:        2.0 Dll
     # |    File date:        00000000.00000000
     # |    Translations:     0000.04b0
     # |    CompanyName:      Mozilla Corporation
     # |    ProductName:      Firefox
     # |    InternalName:     Firefox
     # |    OriginalFilename: firefox.exe
     # |    ProductVersion:   40.0.2
     # |    FileVersion:      40.0.2
     # |    FileDescription:  Firefox
     # |    LegalCopyright:   (c)Firefox and Mozilla Developers; available under the MPL 2 license.
     # |    LegalTrademarks:  Firefox is a Trademark of The Mozilla Foundation.
     # |    Comments:         Firefox is a Trademark of The Mozilla Foundation.
     # The first two lines can be skipped.
     asHTMLBinaryInformation.append(sHTMLBinaryInformationTemplate % {
       "sName": fsHTMLEncode(sBinaryName),
       "sInformation": "".join(["%s<br/>" % fsHTMLEncode(x) for x in asModuleInformationOutput[2:]]),
     });
   oErrorReport.sHTMLBinaryInformation = "".join(asHTMLBinaryInformation);
   # TODO: At some point the instruction that cause the exception could be added. Use "u @$eventip L1" to retreive it.
   
   return oErrorReport;
Esempio n. 11
0
    def foCreate(cSelf, oCdbWrapper, uExceptionCode, sExceptionDescription):
        # Get current process details
        oProcess = cProcess.foCreate(oCdbWrapper)
        if not oCdbWrapper.bCdbRunning: return None
        # Get exception details
        oException = cException.foCreate(oCdbWrapper, oProcess, uExceptionCode,
                                         sExceptionDescription)
        if not oCdbWrapper.bCdbRunning: return None
        # Get the stack
        oStack = oException.foGetStack(oCdbWrapper)
        if not oCdbWrapper.bCdbRunning: return None
        # Hide some functions at the top of the stack that are merely helper functions and not relevant to the error:
        oStack.fHideTopFrames(asHiddenTopFrames)
        # Create a preliminary error report.
        oErrorReport = cSelf(
            oCdbWrapper=oCdbWrapper,
            sErrorTypeId=oException.sTypeId,
            sErrorDescription=oException.sDescription,
            sSecurityImpact=oException.sSecurityImpact,
            oException=oException,
            oStack=oStack,
        )
        # Make exception specific changes to the error report:
        foSpecialErrorReport = dfoSpecialErrorReport_uExceptionCode.get(
            oException.uCode)
        if foSpecialErrorReport:
            oErrorReport = foSpecialErrorReport(oErrorReport, oCdbWrapper)
            if not oCdbWrapper.bCdbRunning: return None
            if not oErrorReport:
                # This exception is not an error, continue the application.
                return None

        # Find out which frame should be the "main" frame and get stack id.
        oTopmostRelevantFrame = None
        # topmost relevant frame
        oTopmostRelevantFunctionFrame = None
        # topmost relevant frame that has a function symbol
        oTopmostRelevantModuleFrame = None
        # topmost relevant frame that has no function symbol but a module
        uFramesHashed = 0
        asHTMLStack = []
        sStackId = ""
        for oStackFrame in oStack.aoFrames:
            if oStackFrame.bIsHidden:
                # This frame is hidden (because it is irrelevant to the crash)
                asHTMLStack.append(
                    '<span class="StackIgnored">%s</span><br/>' %
                    fsHTMLEncode(oStackFrame.sAddress))
            else:
                oTopmostRelevantFrame = oTopmostRelevantFrame or oStackFrame
                sHTMLAddress = fsHTMLEncode(oStackFrame.sAddress)
                # Make stack frames without a function symbol italic
                if not oStackFrame.oFunction:
                    sHTMLAddress = '<span class="StackNoSymbol">%s</span>' % sHTMLAddress
                # Hash frame address for id and output frame to html
                if uFramesHashed == oStack.uHashFramesCount:
                    # no more hashing is needed: just output as is:
                    asHTMLStack.append('<span class="Stack">%s</span><br/>' %
                                       sHTMLAddress)
                else:
                    sStackId += oStackFrame.sId or "__"
                    if oStackFrame.sId:
                        # frame adds useful infoormation to the id: add hash and output bold
                        uFramesHashed += 1
                        asHTMLStack.append(
                            '<span class="StackHash">%s</span> (%s in id)<br/>'
                            % (sHTMLAddress, oStackFrame.sId))
                        # Determine the top frame for the id:
                        if oStackFrame.oFunction:
                            oTopmostRelevantFunctionFrame = oTopmostRelevantFunctionFrame or oStackFrame
                        elif oStackFrame.oModule:
                            oTopmostRelevantModuleFrame = oTopmostRelevantModuleFrame or oStackFrame
                    else:
                        # This is not part of the id, but between frames that are: add "__" to id and output strike-through
                        asHTMLStack.append(
                            '<span class="StackHashIgnored">%s</span><br/>' %
                            sHTMLAddress)
        # If there are not enouogh id-able stack frames, there may be many trailing "_"-s; remove these. Also, if there
        # was not id, or nothing is left after removing the "_"-s, use the id "##".
        oErrorReport.sStackId = sStackId.rstrip("_") or "##"
        if oStack.bPartialStack:
            asHTMLStack.append("... (rest of the stack was ignored)<br/>")
        oErrorReport.sHTMLStack = "".join(asHTMLStack)
        # Use a function for the id
        oCodeIdFrame = oTopmostRelevantFunctionFrame or oTopmostRelevantModuleFrame
        oErrorReport.sCodeId = oCodeIdFrame and oCodeIdFrame.sSimplifiedAddress or "(unknown)"

        # Create the location description
        oErrorReport.sCodeDescription = oTopmostRelevantFrame and oTopmostRelevantFrame.sAddress or "(unknown)"

        # Get the binary's cdb name for retreiving version information:
        asBinaryCdbNames = oCdbWrapper.fasGetCdbIdsForModuleFileNameInCurrentProcess(
            oErrorReport.sProcessBinaryName)
        if not oCdbWrapper.bCdbRunning: return None
        assert len(
            asBinaryCdbNames
        ) > 0, "Cannot find binary %s module" % oErrorReport.sProcessBinaryName
        # If the binary is loaded as a module multiple times in the process, the first should be the binary that was
        # executed.
        # If this turns out to be wrong, this code should be switch to use "u @$exentry L1" to determine the cdb id of the
        # module in which the process's entry point is found.
        dsGetVersionCdbId_by_sBinaryName = {
            oErrorReport.sProcessBinaryName: asBinaryCdbNames[0]
        }
        # Get the id frame's module cdb name for retreiving version information:
        if oCodeIdFrame:
            dsGetVersionCdbId_by_sBinaryName[
                oCodeIdFrame.oModule.sBinaryName] = oCodeIdFrame.oModule.sCdbId
        asHTMLBinaryInformation = []
        for sBinaryName, sCdbId in dsGetVersionCdbId_by_sBinaryName.items():
            asModuleInformationOutput = oCdbWrapper.fasSendCommandAndReadOutput(
                "lmv m *%s" % sCdbId)
            if not oCdbWrapper.bCdbRunning: return None
            # Sample output:
            # |0:004> lmv M firefox.exe
            # |start             end                 module name
            # |00000000`011b0000 00000000`0120f000   firefox    (deferred)
            # |    Image path: firefox.exe
            # |    Image name: firefox.exe
            # |    Timestamp:        Thu Aug 13 03:23:30 2015 (55CBF192)
            # |    CheckSum:         0006133B
            # |    ImageSize:        0005F000
            # |    File version:     40.0.2.5702
            # |    Product version:  40.0.2.0
            # |    File flags:       0 (Mask 3F)
            # |    File OS:          4 Unknown Win32
            # |    File type:        2.0 Dll
            # |    File date:        00000000.00000000
            # |    Translations:     0000.04b0
            # |    CompanyName:      Mozilla Corporation
            # |    ProductName:      Firefox
            # |    InternalName:     Firefox
            # |    OriginalFilename: firefox.exe
            # |    ProductVersion:   40.0.2
            # |    FileVersion:      40.0.2
            # |    FileDescription:  Firefox
            # |    LegalCopyright:   (c)Firefox and Mozilla Developers; available under the MPL 2 license.
            # |    LegalTrademarks:  Firefox is a Trademark of The Mozilla Foundation.
            # |    Comments:         Firefox is a Trademark of The Mozilla Foundation.
            # The first two lines can be skipped.
            asHTMLBinaryInformation.append(
                sHTMLBinaryInformationTemplate % {
                    "sName":
                    fsHTMLEncode(sBinaryName),
                    "sInformation":
                    "".join([
                        "%s<br/>" % fsHTMLEncode(x)
                        for x in asModuleInformationOutput[2:]
                    ]),
                })
        oErrorReport.sHTMLBinaryInformation = "".join(asHTMLBinaryInformation)
        # TODO: At some point the instruction that cause the exception could be added. Use "u @$eventip L1" to retreive it.

        return oErrorReport
Esempio n. 12
0
    def foCreate(cSelf, oCrashInfo, uCode, sCodeDescription):
        oProcess = cProcess.foCreate(oCrashInfo)
        oSelf = cSelf(oProcess, uCode, sCodeDescription)
        # We do this twice to make sure symbols are loaded the first time, which may create additional symbal warnings and
        # errors that makes the output harder to parse. The second time, there will be no such output, so we can parse it
        # a lot easier.
        asExceptionRecord = oCrashInfo._fasSendCommandAndReadOutput(".exr -1")
        if asExceptionRecord is None: return None
        asExceptionRecord = oCrashInfo._fasSendCommandAndReadOutput(".exr -1")
        if asExceptionRecord is None: return None
        uParameterCount = None
        uParameterIndex = None
        for sLine in asExceptionRecord:
            oNameValueMatch = re.match(
                r"^\s*%s\s*$" % (
                    r"(\w+)(?:\[(\d+)\])?\:\s+"  # (name) optional{ "[" (index) "]" } ":" whitespace
                    r"([0-9A-F`]+)"  # (value)
                    r"(?:\s+\((.*)\))?"  # optional{ whitespace "(" (symbol || description) ")" }
                ),
                sLine,
                re.I)
            if oNameValueMatch:
                sName, sIndex, sValue, sDetails = oNameValueMatch.groups()
                uValue = int(sValue.replace("`", ""), 16)
                if sName == "ExceptionAddress":
                    oSelf.uAddress = uValue
                    oSelf.sAddressSymbol = sDetails
                elif sName == "ExceptionCode":
                    assert uValue == uCode, \
                        "Exception record has an unexpected ExceptionCode value (0x%08X vs 0x%08X)" % (uValue, uCode)
                    assert sDetails is None or sDetails == sCodeDescription, \
                        "Exception record has an unexpected ExceptionCode description (%s vs %s)" % \
                            (repr(sDetails), repr(sCodeDescription))
                elif sName == "ExceptionFlags":
                    oSelf.uFlags = uValue
                elif sName == "NumberParameters":
                    uParameterCount = uValue
                    uParameterIndex = 0
                    oSelf.auParameters = []
                elif sName == "Parameter":
                    assert int(sIndex, 16) == uParameterIndex, \
                        "Unexpected parameter #0x%s vs 0x%X" % (sIndex, uParameterIndex)
                    oSelf.auParameters.append(uValue)
                    uParameterIndex += 1
                else:
                    raise AssertionError("Unknown exception record value %s" %
                                         sLine)
            elif oSelf.sDetails is None:
                oSelf.sDetails = sLine
            else:
                raise AssertionError("Superfluous exception record line %s" %
                                     sLine)
        assert oSelf.uAddress is not None, \
            "Exception record is missing an ExceptionAddress value"
        assert oSelf.uFlags is not None, \
            "Exception record is missing an ExceptionFlags value"
        assert uParameterCount is not None, \
            "Exception record is missing an NumberParameters value"
        assert uParameterCount == len(oSelf.auParameters), \
            "Unexpected number of parameters (%d vs %d)" % (len(oSelf.auParameters), uParameterCount)

        # Now handle the information in the exception record and perform additional tasks as needed. Create an exception
        # id that uniquely identifies the exception and a description of the exception.
        if uCode == 0xC000027B:
            # Parameter[0] = paStowedExceptionInformationArray;
            # Parameter[1] = uStowedExceptionInformationArrayLength;
            assert len(oSelf.auParameters) == 2, \
                "Unexpected number of WinRT language exception parameters (%d vs 2)" % len(oSelf.auParameters)
            pStowedExceptionsAddress = oSelf.auParameters[0]
            uStowedExceptionsCount = oSelf.auParameters[1]
            assert uStowedExceptionsCount == 1, \
                "Unexpected number of WinRT language exception stowed exceptions (%d vs 1)" % uStowedExceptionsCount
            # The stowed exception replaces this exception:
            return cStowedException.foCreate(oCrashInfo, oProcess,
                                             pStowedExceptionsAddress)
        elif uCode == STATUS_ACCESS_VIOLATION:
            # Access violation: add the type of operation and the location to the exception id.
            sViolationTypeId = "AV" + {
                0: "R",
                1: "W",
                8: "E"
            }.get(oSelf.auParameters[0], "?")
            sViolationTypeDescription = {
                0: "reading",
                1: "writing",
                8: "executing"
            }.get(oSelf.auParameters[0], "?")
            uAddress = oSelf.auParameters[1]
            sAddressId = fsGetAddressId(uAddress)
            oSelf.sTypeId = "%s@%s" % (sViolationTypeId, sAddressId)
            oSelf.sDescription = "%s while %s memory at 0x%08X (%s)" % (
                sCodeDescription, sViolationTypeDescription, uAddress,
                sAddressId)
            oSelf.sSecurityImpact = (
                (uAddress > 0xFFFF0000 or uAddress < 0x10000)
                and "Not a security issue" or "Probably a security issue")
        else:
            oSelf.sTypeId = fsGetExceptionTypeId(uCode)
            oSelf.sDescription = "%s (code 0x%08X)" % (sCodeDescription, uCode)
            oSelf.sSecurityImpact = fsGetSecurityImpact(uCode)

        # Get the stack
        oSelf.oStack = cStack.foCreate(oCrashInfo, oSelf.oProcess)
        if oSelf.oStack is None: return None

        return oSelf