1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 """
32 Crash dump support.
33
34 @group Crash reporting:
35 Crash, CrashDictionary
36
37 @group Warnings:
38 CrashWarning
39
40 @group Deprecated classes:
41 CrashContainer, CrashTable, CrashTableMSSQL,
42 VolatileCrashContainer, DummyCrashContainer
43 """
44
45 __revision__ = "$Id: crash.py 1299 2013-12-20 09:30:55Z qvasimodo $"
46
47 __all__ = [
48
49
50 'Crash',
51
52
53 'CrashDictionary',
54
55
56 'CrashWarning',
57
58
59 'CrashContainer',
60 'CrashTable',
61 'CrashTableMSSQL',
62 'VolatileCrashContainer',
63 'DummyCrashContainer',
64 ]
65
66 import win32
67 from system import System
68 from textio import HexDump, CrashDump
69 from util import StaticClass, MemoryAddresses, PathOperations
70
71 import os
72 import time
73 import zlib
74 import warnings
75
76
77 sql = None
78 anydbm = None
79
80
81
82
83 try:
84 import cerealizer
85 pickle = cerealizer
90
91
92 HIGHEST_PROTOCOL = 0
93
94
95
96
97
98
99
100
101
102 except ImportError:
103
104
105 try:
106 import cPickle as pickle
107
108
109 except ImportError:
110 import pickle
111
112
113 HIGHEST_PROTOCOL = pickle.HIGHEST_PROTOCOL
114
115
116 try:
117 from pickletools import optimize
118 except ImportError:
121
123 """
124 Custom pickler for L{Crash} objects. Optimizes the pickled data when using
125 the standard C{pickle} (or C{cPickle}) module. The pickled data is then
126 compressed using zlib.
127 """
128
129 @staticmethod
131 return zlib.compress(optimize(pickle.dumps(obj)), 9)
132
133 @staticmethod
135 return pickle.loads(zlib.decompress(data))
136
140 """
141 An error occurred while gathering crash data.
142 Some data may be incomplete or missing.
143 """
144
145
146
147
148 -class Crash (object):
149 """
150 Represents a crash, bug, or another interesting event in the debugee.
151
152 @group Basic information:
153 timeStamp, signature, eventCode, eventName, pid, tid, arch, os, bits,
154 registers, labelPC, pc, sp, fp
155
156 @group Optional information:
157 debugString,
158 modFileName,
159 lpBaseOfDll,
160 exceptionCode,
161 exceptionName,
162 exceptionDescription,
163 exceptionAddress,
164 exceptionLabel,
165 firstChance,
166 faultType,
167 faultAddress,
168 faultLabel,
169 isOurBreakpoint,
170 isSystemBreakpoint,
171 stackTrace,
172 stackTracePC,
173 stackTraceLabels,
174 stackTracePretty
175
176 @group Extra information:
177 commandLine,
178 environment,
179 environmentData,
180 registersPeek,
181 stackRange,
182 stackFrame,
183 stackPeek,
184 faultCode,
185 faultMem,
186 faultPeek,
187 faultDisasm,
188 memoryMap
189
190 @group Report:
191 briefReport, fullReport, notesReport, environmentReport, isExploitable
192
193 @group Notes:
194 addNote, getNotes, iterNotes, hasNotes, clearNotes, notes
195
196 @group Miscellaneous:
197 fetch_extra_data
198
199 @type timeStamp: float
200 @ivar timeStamp: Timestamp as returned by time.time().
201
202 @type signature: object
203 @ivar signature: Approximately unique signature for the Crash object.
204
205 This signature can be used as an heuristic to determine if two crashes
206 were caused by the same software error. Ideally it should be treated as
207 as opaque serializable object that can be tested for equality.
208
209 @type notes: list( str )
210 @ivar notes: List of strings, each string is a note.
211
212 @type eventCode: int
213 @ivar eventCode: Event code as defined by the Win32 API.
214
215 @type eventName: str
216 @ivar eventName: Event code user-friendly name.
217
218 @type pid: int
219 @ivar pid: Process global ID.
220
221 @type tid: int
222 @ivar tid: Thread global ID.
223
224 @type arch: str
225 @ivar arch: Processor architecture.
226
227 @type os: str
228 @ivar os: Operating system version.
229
230 May indicate a 64 bit version even if L{arch} and L{bits} indicate 32
231 bits. This means the crash occurred inside a WOW64 process.
232
233 @type bits: int
234 @ivar bits: C{32} or C{64} bits.
235
236 @type commandLine: None or str
237 @ivar commandLine: Command line for the target process.
238
239 C{None} if unapplicable or unable to retrieve.
240
241 @type environmentData: None or list of str
242 @ivar environmentData: Environment data for the target process.
243
244 C{None} if unapplicable or unable to retrieve.
245
246 @type environment: None or dict( str S{->} str )
247 @ivar environment: Environment variables for the target process.
248
249 C{None} if unapplicable or unable to retrieve.
250
251 @type registers: dict( str S{->} int )
252 @ivar registers: Dictionary mapping register names to their values.
253
254 @type registersPeek: None or dict( str S{->} str )
255 @ivar registersPeek: Dictionary mapping register names to the data they point to.
256
257 C{None} if unapplicable or unable to retrieve.
258
259 @type labelPC: None or str
260 @ivar labelPC: Label pointing to the program counter.
261
262 C{None} or invalid if unapplicable or unable to retrieve.
263
264 @type debugString: None or str
265 @ivar debugString: Debug string sent by the debugee.
266
267 C{None} if unapplicable or unable to retrieve.
268
269 @type exceptionCode: None or int
270 @ivar exceptionCode: Exception code as defined by the Win32 API.
271
272 C{None} if unapplicable or unable to retrieve.
273
274 @type exceptionName: None or str
275 @ivar exceptionName: Exception code user-friendly name.
276
277 C{None} if unapplicable or unable to retrieve.
278
279 @type exceptionDescription: None or str
280 @ivar exceptionDescription: Exception description.
281
282 C{None} if unapplicable or unable to retrieve.
283
284 @type exceptionAddress: None or int
285 @ivar exceptionAddress: Memory address where the exception occured.
286
287 C{None} if unapplicable or unable to retrieve.
288
289 @type exceptionLabel: None or str
290 @ivar exceptionLabel: Label pointing to the exception address.
291
292 C{None} or invalid if unapplicable or unable to retrieve.
293
294 @type faultType: None or int
295 @ivar faultType: Access violation type.
296 Only applicable to memory faults.
297 Should be one of the following constants:
298
299 - L{win32.ACCESS_VIOLATION_TYPE_READ}
300 - L{win32.ACCESS_VIOLATION_TYPE_WRITE}
301 - L{win32.ACCESS_VIOLATION_TYPE_DEP}
302
303 C{None} if unapplicable or unable to retrieve.
304
305 @type faultAddress: None or int
306 @ivar faultAddress: Access violation memory address.
307 Only applicable to memory faults.
308
309 C{None} if unapplicable or unable to retrieve.
310
311 @type faultLabel: None or str
312 @ivar faultLabel: Label pointing to the access violation memory address.
313 Only applicable to memory faults.
314
315 C{None} if unapplicable or unable to retrieve.
316
317 @type firstChance: None or bool
318 @ivar firstChance:
319 C{True} for first chance exceptions, C{False} for second chance.
320
321 C{None} if unapplicable or unable to retrieve.
322
323 @type isOurBreakpoint: bool
324 @ivar isOurBreakpoint:
325 C{True} for breakpoints defined by the L{Debug} class,
326 C{False} otherwise.
327
328 C{None} if unapplicable.
329
330 @type isSystemBreakpoint: bool
331 @ivar isSystemBreakpoint:
332 C{True} for known system-defined breakpoints,
333 C{False} otherwise.
334
335 C{None} if unapplicable.
336
337 @type modFileName: None or str
338 @ivar modFileName: File name of module where the program counter points to.
339
340 C{None} or invalid if unapplicable or unable to retrieve.
341
342 @type lpBaseOfDll: None or int
343 @ivar lpBaseOfDll: Base of module where the program counter points to.
344
345 C{None} if unapplicable or unable to retrieve.
346
347 @type stackTrace: None or tuple of tuple( int, int, str )
348 @ivar stackTrace:
349 Stack trace of the current thread as a tuple of
350 ( frame pointer, return address, module filename ).
351
352 C{None} or empty if unapplicable or unable to retrieve.
353
354 @type stackTracePretty: None or tuple of tuple( int, str )
355 @ivar stackTracePretty:
356 Stack trace of the current thread as a tuple of
357 ( frame pointer, return location ).
358
359 C{None} or empty if unapplicable or unable to retrieve.
360
361 @type stackTracePC: None or tuple( int... )
362 @ivar stackTracePC: Tuple of return addresses in the stack trace.
363
364 C{None} or empty if unapplicable or unable to retrieve.
365
366 @type stackTraceLabels: None or tuple( str... )
367 @ivar stackTraceLabels:
368 Tuple of labels pointing to the return addresses in the stack trace.
369
370 C{None} or empty if unapplicable or unable to retrieve.
371
372 @type stackRange: tuple( int, int )
373 @ivar stackRange:
374 Stack beginning and end pointers, in memory addresses order.
375
376 C{None} if unapplicable or unable to retrieve.
377
378 @type stackFrame: None or str
379 @ivar stackFrame: Data pointed to by the stack pointer.
380
381 C{None} or empty if unapplicable or unable to retrieve.
382
383 @type stackPeek: None or dict( int S{->} str )
384 @ivar stackPeek: Dictionary mapping stack offsets to the data they point to.
385
386 C{None} or empty if unapplicable or unable to retrieve.
387
388 @type faultCode: None or str
389 @ivar faultCode: Data pointed to by the program counter.
390
391 C{None} or empty if unapplicable or unable to retrieve.
392
393 @type faultMem: None or str
394 @ivar faultMem: Data pointed to by the exception address.
395
396 C{None} or empty if unapplicable or unable to retrieve.
397
398 @type faultPeek: None or dict( intS{->} str )
399 @ivar faultPeek: Dictionary mapping guessed pointers at L{faultMem} to the data they point to.
400
401 C{None} or empty if unapplicable or unable to retrieve.
402
403 @type faultDisasm: None or tuple of tuple( long, int, str, str )
404 @ivar faultDisasm: Dissassembly around the program counter.
405
406 C{None} or empty if unapplicable or unable to retrieve.
407
408 @type memoryMap: None or list of L{win32.MemoryBasicInformation} objects.
409 @ivar memoryMap: Memory snapshot of the program. May contain the actual
410 data from the entire process memory if requested.
411 See L{fetch_extra_data} for more details.
412
413 C{None} or empty if unapplicable or unable to retrieve.
414
415 @type _rowid: int
416 @ivar _rowid: Row ID in the database. Internally used by the DAO layer.
417 Only present in crash dumps retrieved from the database. Do not rely
418 on this property to be present in future versions of WinAppDbg.
419 """
420
422 """
423 @type event: L{Event}
424 @param event: Event object for crash.
425 """
426
427
428 self.timeStamp = time.time()
429
430
431 self.notes = list()
432
433
434 process = event.get_process()
435 thread = event.get_thread()
436
437
438 self.os = System.os
439 self.arch = process.get_arch()
440 self.bits = process.get_bits()
441
442
443 self.eventCode = event.get_event_code()
444 self.eventName = event.get_event_name()
445 self.pid = event.get_pid()
446 self.tid = event.get_tid()
447 self.registers = dict(thread.get_context())
448 self.labelPC = process.get_label_at_address(self.pc)
449
450
451 self.commandLine = None
452 self.environment = None
453 self.environmentData = None
454 self.registersPeek = None
455 self.debugString = None
456 self.modFileName = None
457 self.lpBaseOfDll = None
458 self.exceptionCode = None
459 self.exceptionName = None
460 self.exceptionDescription = None
461 self.exceptionAddress = None
462 self.exceptionLabel = None
463 self.firstChance = None
464 self.faultType = None
465 self.faultAddress = None
466 self.faultLabel = None
467 self.isOurBreakpoint = None
468 self.isSystemBreakpoint = None
469 self.stackTrace = None
470 self.stackTracePC = None
471 self.stackTraceLabels = None
472 self.stackTracePretty = None
473 self.stackRange = None
474 self.stackFrame = None
475 self.stackPeek = None
476 self.faultCode = None
477 self.faultMem = None
478 self.faultPeek = None
479 self.faultDisasm = None
480 self.memoryMap = None
481
482
483 if self.eventCode == win32.OUTPUT_DEBUG_STRING_EVENT:
484 self.debugString = event.get_debug_string()
485
486
487
488
489 elif self.eventCode in (win32.CREATE_PROCESS_DEBUG_EVENT,
490 win32.EXIT_PROCESS_DEBUG_EVENT,
491 win32.LOAD_DLL_DEBUG_EVENT,
492 win32.UNLOAD_DLL_DEBUG_EVENT):
493 aModule = event.get_module()
494 self.modFileName = event.get_filename()
495 if not self.modFileName:
496 self.modFileName = aModule.get_filename()
497 self.lpBaseOfDll = event.get_module_base()
498 if not self.lpBaseOfDll:
499 self.lpBaseOfDll = aModule.get_base()
500
501
502
503 elif self.eventCode == win32.EXCEPTION_DEBUG_EVENT:
504
505
506 self.exceptionCode = event.get_exception_code()
507 self.exceptionName = event.get_exception_name()
508 self.exceptionDescription = event.get_exception_description()
509 self.exceptionAddress = event.get_exception_address()
510 self.firstChance = event.is_first_chance()
511 self.exceptionLabel = process.get_label_at_address(
512 self.exceptionAddress)
513 if self.exceptionCode in (win32.EXCEPTION_ACCESS_VIOLATION,
514 win32.EXCEPTION_GUARD_PAGE,
515 win32.EXCEPTION_IN_PAGE_ERROR):
516 self.faultType = event.get_fault_type()
517 self.faultAddress = event.get_fault_address()
518 self.faultLabel = process.get_label_at_address(
519 self.faultAddress)
520 elif self.exceptionCode in (win32.EXCEPTION_BREAKPOINT,
521 win32.EXCEPTION_SINGLE_STEP):
522 self.isOurBreakpoint = hasattr(event, 'breakpoint') \
523 and event.breakpoint
524 self.isSystemBreakpoint = \
525 process.is_system_defined_breakpoint(self.exceptionAddress)
526
527
528 try:
529 self.stackTracePretty = thread.get_stack_trace_with_labels()
530 except Exception, e:
531 warnings.warn(
532 "Cannot get stack trace with labels, reason: %s" % str(e),
533 CrashWarning)
534 try:
535 self.stackTrace = thread.get_stack_trace()
536 stackTracePC = [ ra for (_,ra,_) in self.stackTrace ]
537 self.stackTracePC = tuple(stackTracePC)
538 stackTraceLabels = [ process.get_label_at_address(ra) \
539 for ra in self.stackTracePC ]
540 self.stackTraceLabels = tuple(stackTraceLabels)
541 except Exception, e:
542 warnings.warn("Cannot get stack trace, reason: %s" % str(e),
543 CrashWarning)
544
546 """
547 Fetch extra data from the L{Event} object.
548
549 @note: Since this method may take a little longer to run, it's best to
550 call it only after you've determined the crash is interesting and
551 you want to save it.
552
553 @type event: L{Event}
554 @param event: Event object for crash.
555
556 @type takeMemorySnapshot: int
557 @param takeMemorySnapshot:
558 Memory snapshot behavior:
559 - C{0} to take no memory information (default).
560 - C{1} to take only the memory map.
561 See L{Process.get_memory_map}.
562 - C{2} to take a full memory snapshot.
563 See L{Process.take_memory_snapshot}.
564 - C{3} to take a live memory snapshot.
565 See L{Process.generate_memory_snapshot}.
566 """
567
568
569 process = event.get_process()
570 thread = event.get_thread()
571
572
573 try:
574 self.commandLine = process.get_command_line()
575 except Exception, e:
576 warnings.warn("Cannot get command line, reason: %s" % str(e),
577 CrashWarning)
578
579
580 try:
581 self.environmentData = process.get_environment_data()
582 self.environment = process.parse_environment_data(
583 self.environmentData)
584 except Exception, e:
585 warnings.warn("Cannot get environment, reason: %s" % str(e),
586 CrashWarning)
587
588
589 self.registersPeek = thread.peek_pointers_in_registers()
590
591
592 aModule = process.get_module_at_address(self.pc)
593 if aModule is not None:
594 self.modFileName = aModule.get_filename()
595 self.lpBaseOfDll = aModule.get_base()
596
597
598 try:
599 self.stackRange = thread.get_stack_range()
600 except Exception, e:
601 warnings.warn("Cannot get stack range, reason: %s" % str(e),
602 CrashWarning)
603 try:
604 self.stackFrame = thread.get_stack_frame()
605 stackFrame = self.stackFrame
606 except Exception, e:
607 self.stackFrame = thread.peek_stack_data()
608 stackFrame = self.stackFrame[:64]
609 if stackFrame:
610 self.stackPeek = process.peek_pointers_in_data(stackFrame)
611
612
613 self.faultCode = thread.peek_code_bytes()
614 try:
615 self.faultDisasm = thread.disassemble_around_pc(32)
616 except Exception, e:
617 warnings.warn("Cannot disassemble, reason: %s" % str(e),
618 CrashWarning)
619
620
621
622 if self.eventCode == win32.EXCEPTION_DEBUG_EVENT:
623 if self.pc != self.exceptionAddress and self.exceptionCode in (
624 win32.EXCEPTION_ACCESS_VIOLATION,
625 win32.EXCEPTION_ARRAY_BOUNDS_EXCEEDED,
626 win32.EXCEPTION_DATATYPE_MISALIGNMENT,
627 win32.EXCEPTION_IN_PAGE_ERROR,
628 win32.EXCEPTION_STACK_OVERFLOW,
629 win32.EXCEPTION_GUARD_PAGE,
630 ):
631 self.faultMem = process.peek(self.exceptionAddress, 64)
632 if self.faultMem:
633 self.faultPeek = process.peek_pointers_in_data(
634 self.faultMem)
635
636
637
638
639
640 if takeMemorySnapshot == 1:
641 self.memoryMap = process.get_memory_map()
642 mappedFilenames = process.get_mapped_filenames(self.memoryMap)
643 for mbi in self.memoryMap:
644 mbi.filename = mappedFilenames.get(mbi.BaseAddress, None)
645 mbi.content = None
646 elif takeMemorySnapshot == 2:
647 self.memoryMap = process.take_memory_snapshot()
648 elif takeMemorySnapshot == 3:
649 self.memoryMap = process.generate_memory_snapshot()
650
651 @property
653 """
654 Value of the program counter register.
655
656 @rtype: int
657 """
658 try:
659 return self.registers['Eip']
660 except KeyError:
661 return self.registers['Rip']
662
663 @property
665 """
666 Value of the stack pointer register.
667
668 @rtype: int
669 """
670 try:
671 return self.registers['Esp']
672 except KeyError:
673 return self.registers['Rsp']
674
675 @property
677 """
678 Value of the frame pointer register.
679
680 @rtype: int
681 """
682 try:
683 return self.registers['Ebp']
684 except KeyError:
685 return self.registers['Rbp']
686
689
691 """
692 Alias of L{signature}. Deprecated since WinAppDbg 1.5.
693 """
694 warnings.warn("Crash.key() method was deprecated in WinAppDbg 1.5",
695 DeprecationWarning)
696 return self.signature
697
698 @property
700 if self.labelPC:
701 pc = self.labelPC
702 else:
703 pc = self.pc
704 if self.stackTraceLabels:
705 trace = self.stackTraceLabels
706 else:
707 trace = self.stackTracePC
708 return (
709 self.arch,
710 self.eventCode,
711 self.exceptionCode,
712 pc,
713 trace,
714 self.debugString,
715 )
716
717
718
720 """
721 Guess how likely is it that the bug causing the crash can be leveraged
722 into an exploitable vulnerability.
723
724 @note: Don't take this as an equivalent of a real exploitability
725 analysis, that can only be done by a human being! This is only
726 a guideline, useful for example to sort crashes - placing the most
727 interesting ones at the top.
728
729 @see: The heuristics are similar to those of the B{!exploitable}
730 extension for I{WinDBG}, which can be downloaded from here:
731
732 U{http://www.codeplex.com/msecdbg}
733
734 @rtype: tuple( str, str, str )
735 @return: The first element of the tuple is the result of the analysis,
736 being one of the following:
737
738 - Not an exception
739 - Not exploitable
740 - Not likely exploitable
741 - Unknown
742 - Probably exploitable
743 - Exploitable
744
745 The second element of the tuple is a code to identify the matched
746 heuristic rule.
747
748 The third element of the tuple is a description string of the
749 reason behind the result.
750 """
751
752
753
754 if self.eventCode != win32.EXCEPTION_DEBUG_EVENT:
755 return ("Not an exception", "NotAnException", "The event is not an exception.")
756
757 if self.stackRange and self.pc is not None and self.stackRange[0] <= self.pc < self.stackRange[1]:
758 return ("Exploitable", "StackCodeExecution", "Code execution from the stack is considered exploitable.")
759
760
761 if self.stackRange and self.sp is not None and not (self.stackRange[0] <= self.sp < self.stackRange[1]):
762 return ("Exploitable", "StackPointerCorruption", "Stack pointer corruption is considered exploitable.")
763
764 if self.exceptionCode == win32.EXCEPTION_ILLEGAL_INSTRUCTION:
765 return ("Exploitable", "IllegalInstruction", "An illegal instruction exception indicates that the attacker controls execution flow.")
766
767 if self.exceptionCode == win32.EXCEPTION_PRIV_INSTRUCTION:
768 return ("Exploitable", "PrivilegedInstruction", "A privileged instruction exception indicates that the attacker controls execution flow.")
769
770 if self.exceptionCode == win32.EXCEPTION_GUARD_PAGE:
771 return ("Exploitable", "GuardPage", "A guard page violation indicates a stack overflow has occured, and the stack of another thread was reached (possibly the overflow length is not controlled by the attacker).")
772
773 if self.exceptionCode == win32.STATUS_STACK_BUFFER_OVERRUN:
774 return ("Exploitable", "GSViolation", "An overrun of a protected stack buffer has been detected. This is considered exploitable, and must be fixed.")
775
776 if self.exceptionCode == win32.STATUS_HEAP_CORRUPTION:
777 return ("Exploitable", "HeapCorruption", "Heap Corruption has been detected. This is considered exploitable, and must be fixed.")
778
779 if self.exceptionCode == win32.EXCEPTION_ACCESS_VIOLATION:
780 nearNull = self.faultAddress is None or MemoryAddresses.align_address_to_page_start(self.faultAddress) == 0
781 controlFlow = self.__is_control_flow()
782 blockDataMove = self.__is_block_data_move()
783 if self.faultType == win32.EXCEPTION_EXECUTE_FAULT:
784 if nearNull:
785 return ("Probably exploitable", "DEPViolation", "User mode DEP access violations are probably exploitable if near NULL.")
786 else:
787 return ("Exploitable", "DEPViolation", "User mode DEP access violations are exploitable.")
788 elif self.faultType == win32.EXCEPTION_WRITE_FAULT:
789 if nearNull:
790 return ("Probably exploitable", "WriteAV", "User mode write access violations that are near NULL are probably exploitable.")
791 else:
792 return ("Exploitable", "WriteAV", "User mode write access violations that are not near NULL are exploitable.")
793 elif self.faultType == win32.EXCEPTION_READ_FAULT:
794 if self.faultAddress == self.pc:
795 if nearNull:
796 return ("Probably exploitable", "ReadAVonIP", "Access violations at the instruction pointer are probably exploitable if near NULL.")
797 else:
798 return ("Exploitable", "ReadAVonIP", "Access violations at the instruction pointer are exploitable if not near NULL.")
799 if controlFlow:
800 if nearNull:
801 return ("Probably exploitable", "ReadAVonControlFlow", "Access violations near null in control flow instructions are considered probably exploitable.")
802 else:
803 return ("Exploitable", "ReadAVonControlFlow", "Access violations not near null in control flow instructions are considered exploitable.")
804 if blockDataMove:
805 return ("Probably exploitable", "ReadAVonBlockMove", "This is a read access violation in a block data move, and is therefore classified as probably exploitable.")
806
807
808
809
810
811
812
813
814
815
816 result = ("Unknown", "Unknown", "Exploitability unknown.")
817
818 if self.exceptionCode == win32.EXCEPTION_ACCESS_VIOLATION:
819 if self.faultType == win32.EXCEPTION_READ_FAULT:
820 if nearNull:
821 result = ("Not likely exploitable", "ReadAVNearNull", "This is a user mode read access violation near null, and is probably not exploitable.")
822
823 elif self.exceptionCode == win32.EXCEPTION_INT_DIVIDE_BY_ZERO:
824 result = ("Not likely exploitable", "DivideByZero", "This is an integer divide by zero, and is probably not exploitable.")
825
826 elif self.exceptionCode == win32.EXCEPTION_FLT_DIVIDE_BY_ZERO:
827 result = ("Not likely exploitable", "DivideByZero", "This is a floating point divide by zero, and is probably not exploitable.")
828
829 elif self.exceptionCode in (win32.EXCEPTION_BREAKPOINT, win32.STATUS_WX86_BREAKPOINT):
830 result = ("Unknown", "Breakpoint", "While a breakpoint itself is probably not exploitable, it may also be an indication that an attacker is testing a target. In either case breakpoints should not exist in production code.")
831
832
833
834
835
836
837 return result
838
840 """
841 Private method to tell if the instruction pointed to by the program
842 counter is a control flow instruction.
843
844 Currently only works for x86 and amd64 architectures.
845 """
846 jump_instructions = (
847 'jmp', 'jecxz', 'jcxz',
848 'ja', 'jnbe', 'jae', 'jnb', 'jb', 'jnae', 'jbe', 'jna', 'jc', 'je',
849 'jz', 'jnc', 'jne', 'jnz', 'jnp', 'jpo', 'jp', 'jpe', 'jg', 'jnle',
850 'jge', 'jnl', 'jl', 'jnge', 'jle', 'jng', 'jno', 'jns', 'jo', 'js'
851 )
852 call_instructions = ( 'call', 'ret', 'retn' )
853 loop_instructions = ( 'loop', 'loopz', 'loopnz', 'loope', 'loopne' )
854 control_flow_instructions = call_instructions + loop_instructions + \
855 jump_instructions
856 isControlFlow = False
857 instruction = None
858 if self.pc is not None and self.faultDisasm:
859 for disasm in self.faultDisasm:
860 if disasm[0] == self.pc:
861 instruction = disasm[2].lower().strip()
862 break
863 if instruction:
864 for x in control_flow_instructions:
865 if x in instruction:
866 isControlFlow = True
867 break
868 return isControlFlow
869
871 """
872 Private method to tell if the instruction pointed to by the program
873 counter is a block data move instruction.
874
875 Currently only works for x86 and amd64 architectures.
876 """
877 block_data_move_instructions = ('movs', 'stos', 'lods')
878 isBlockDataMove = False
879 instruction = None
880 if self.pc is not None and self.faultDisasm:
881 for disasm in self.faultDisasm:
882 if disasm[0] == self.pc:
883 instruction = disasm[2].lower().strip()
884 break
885 if instruction:
886 for x in block_data_move_instructions:
887 if x in instruction:
888 isBlockDataMove = True
889 break
890 return isBlockDataMove
891
893 """
894 @rtype: str
895 @return: Short description of the event.
896 """
897 if self.exceptionCode is not None:
898 if self.exceptionCode == win32.EXCEPTION_BREAKPOINT:
899 if self.isOurBreakpoint:
900 what = "Breakpoint hit"
901 elif self.isSystemBreakpoint:
902 what = "System breakpoint hit"
903 else:
904 what = "Assertion failed"
905 elif self.exceptionDescription:
906 what = self.exceptionDescription
907 elif self.exceptionName:
908 what = self.exceptionName
909 else:
910 what = "Exception %s" % \
911 HexDump.integer(self.exceptionCode, self.bits)
912 if self.firstChance:
913 chance = 'first'
914 else:
915 chance = 'second'
916 if self.exceptionLabel:
917 where = self.exceptionLabel
918 elif self.exceptionAddress:
919 where = HexDump.address(self.exceptionAddress, self.bits)
920 elif self.labelPC:
921 where = self.labelPC
922 else:
923 where = HexDump.address(self.pc, self.bits)
924 msg = "%s (%s chance) at %s" % (what, chance, where)
925 elif self.debugString is not None:
926 if self.labelPC:
927 where = self.labelPC
928 else:
929 where = HexDump.address(self.pc, self.bits)
930 msg = "Debug string from %s: %r" % (where, self.debugString)
931 else:
932 if self.labelPC:
933 where = self.labelPC
934 else:
935 where = HexDump.address(self.pc, self.bits)
936 msg = "%s (%s) at %s" % (
937 self.eventName,
938 HexDump.integer(self.eventCode, self.bits),
939 where
940 )
941 return msg
942
944 """
945 @type bShowNotes: bool
946 @param bShowNotes: C{True} to show the user notes, C{False} otherwise.
947
948 @rtype: str
949 @return: Long description of the event.
950 """
951 msg = self.briefReport()
952 msg += '\n'
953
954 if self.bits == 32:
955 width = 16
956 else:
957 width = 8
958
959 if self.eventCode == win32.EXCEPTION_DEBUG_EVENT:
960 (exploitability, expcode, expdescription) = self.isExploitable()
961 msg += '\nSecurity risk level: %s\n' % exploitability
962 msg += ' %s\n' % expdescription
963
964 if bShowNotes and self.notes:
965 msg += '\nNotes:\n'
966 msg += self.notesReport()
967
968 if self.commandLine:
969 msg += '\nCommand line: %s\n' % self.commandLine
970
971 if self.environment:
972 msg += '\nEnvironment:\n'
973 msg += self.environmentReport()
974
975 if not self.labelPC:
976 base = HexDump.address(self.lpBaseOfDll, self.bits)
977 if self.modFileName:
978 fn = PathOperations.pathname_to_filename(self.modFileName)
979 msg += '\nRunning in %s (%s)\n' % (fn, base)
980 else:
981 msg += '\nRunning in module at %s\n' % base
982
983 if self.registers:
984 msg += '\nRegisters:\n'
985 msg += CrashDump.dump_registers(self.registers)
986 if self.registersPeek:
987 msg += '\n'
988 msg += CrashDump.dump_registers_peek(self.registers,
989 self.registersPeek,
990 width = width)
991
992 if self.faultDisasm:
993 msg += '\nCode disassembly:\n'
994 msg += CrashDump.dump_code(self.faultDisasm, self.pc,
995 bits = self.bits)
996
997 if self.stackTrace:
998 msg += '\nStack trace:\n'
999 if self.stackTracePretty:
1000 msg += CrashDump.dump_stack_trace_with_labels(
1001 self.stackTracePretty,
1002 bits = self.bits)
1003 else:
1004 msg += CrashDump.dump_stack_trace(self.stackTrace,
1005 bits = self.bits)
1006
1007 if self.stackFrame:
1008 if self.stackPeek:
1009 msg += '\nStack pointers:\n'
1010 msg += CrashDump.dump_stack_peek(self.stackPeek, width = width)
1011 msg += '\nStack dump:\n'
1012 msg += HexDump.hexblock(self.stackFrame, self.sp,
1013 bits = self.bits, width = width)
1014
1015 if self.faultCode and not self.modFileName:
1016 msg += '\nCode dump:\n'
1017 msg += HexDump.hexblock(self.faultCode, self.pc,
1018 bits = self.bits, width = width)
1019
1020 if self.faultMem:
1021 if self.faultPeek:
1022 msg += '\nException address pointers:\n'
1023 msg += CrashDump.dump_data_peek(self.faultPeek,
1024 self.exceptionAddress,
1025 bits = self.bits,
1026 width = width)
1027 msg += '\nException address dump:\n'
1028 msg += HexDump.hexblock(self.faultMem, self.exceptionAddress,
1029 bits = self.bits, width = width)
1030
1031 if self.memoryMap:
1032 msg += '\nMemory map:\n'
1033 mappedFileNames = dict()
1034 for mbi in self.memoryMap:
1035 if hasattr(mbi, 'filename') and mbi.filename:
1036 mappedFileNames[mbi.BaseAddress] = mbi.filename
1037 msg += CrashDump.dump_memory_map(self.memoryMap, mappedFileNames,
1038 bits = self.bits)
1039
1040 if not msg.endswith('\n\n'):
1041 if not msg.endswith('\n'):
1042 msg += '\n'
1043 msg += '\n'
1044 return msg
1045
1047 """
1048 @rtype: str
1049 @return: The process environment variables,
1050 merged and formatted for a report.
1051 """
1052 msg = ''
1053 if self.environment:
1054 for key, value in self.environment.iteritems():
1055 msg += ' %s=%s\n' % (key, value)
1056 return msg
1057
1059 """
1060 @rtype: str
1061 @return: All notes, merged and formatted for a report.
1062 """
1063 msg = ''
1064 if self.notes:
1065 for n in self.notes:
1066 n = n.strip('\n')
1067 if '\n' in n:
1068 n = n.strip('\n')
1069 msg += ' * %s\n' % n.pop(0)
1070 for x in n:
1071 msg += ' %s\n' % x
1072 else:
1073 msg += ' * %s\n' % n
1074 return msg
1075
1077 """
1078 Add a note to the crash event.
1079
1080 @type msg: str
1081 @param msg: Note text.
1082 """
1083 self.notes.append(msg)
1084
1086 """
1087 Clear the notes of this crash event.
1088 """
1089 self.notes = list()
1090
1092 """
1093 Get the list of notes of this crash event.
1094
1095 @rtype: list( str )
1096 @return: List of notes.
1097 """
1098 return self.notes
1099
1101 """
1102 Iterate the notes of this crash event.
1103
1104 @rtype: listiterator
1105 @return: Iterator of the list of notes.
1106 """
1107 return self.notes.__iter__()
1108
1110 """
1111 @rtype: bool
1112 @return: C{True} if there are notes for this crash event.
1113 """
1114 return bool( self.notes )
1115
1119 """
1120 Old crash dump persistencer using a DBM database.
1121 Doesn't support duplicate crashes.
1122
1123 @warning:
1124 DBM database support is provided for backwards compatibility with older
1125 versions of WinAppDbg. New applications should not use this class.
1126 Also, DBM databases in Python suffer from multiple problems that can
1127 easily be avoided by switching to a SQL database.
1128
1129 @see: If you really must use a DBM database, try the standard C{shelve}
1130 module instead: U{http://docs.python.org/library/shelve.html}
1131
1132 @group Marshalling configuration:
1133 optimizeKeys, optimizeValues, compressKeys, compressValues, escapeKeys,
1134 escapeValues, binaryKeys, binaryValues
1135
1136 @type optimizeKeys: bool
1137 @cvar optimizeKeys: Ignored by the current implementation.
1138
1139 Up to WinAppDbg 1.4 this setting caused the database keys to be
1140 optimized when pickled with the standard C{pickle} module.
1141
1142 But with a DBM database backend that causes inconsistencies, since the
1143 same key can be serialized into multiple optimized pickles, thus losing
1144 uniqueness.
1145
1146 @type optimizeValues: bool
1147 @cvar optimizeValues: C{True} to optimize the marshalling of keys, C{False}
1148 otherwise. Only used with the C{pickle} module, ignored when using the
1149 more secure C{cerealizer} module.
1150
1151 @type compressKeys: bool
1152 @cvar compressKeys: C{True} to compress keys when marshalling, C{False}
1153 to leave them uncompressed.
1154
1155 @type compressValues: bool
1156 @cvar compressValues: C{True} to compress values when marshalling, C{False}
1157 to leave them uncompressed.
1158
1159 @type escapeKeys: bool
1160 @cvar escapeKeys: C{True} to escape keys when marshalling, C{False}
1161 to leave them uncompressed.
1162
1163 @type escapeValues: bool
1164 @cvar escapeValues: C{True} to escape values when marshalling, C{False}
1165 to leave them uncompressed.
1166
1167 @type binaryKeys: bool
1168 @cvar binaryKeys: C{True} to marshall keys to binary format (the Python
1169 C{buffer} type), C{False} to use text marshalled keys (C{str} type).
1170
1171 @type binaryValues: bool
1172 @cvar binaryValues: C{True} to marshall values to binary format (the Python
1173 C{buffer} type), C{False} to use text marshalled values (C{str} type).
1174 """
1175
1176 optimizeKeys = False
1177 optimizeValues = True
1178 compressKeys = False
1179 compressValues = True
1180 escapeKeys = False
1181 escapeValues = False
1182 binaryKeys = False
1183 binaryValues = False
1184
1185 - def __init__(self, filename = None, allowRepeatedKeys = False):
1186 """
1187 @type filename: str
1188 @param filename: (Optional) File name for crash database.
1189 If no filename is specified, the container is volatile.
1190
1191 Volatile containers are stored only in memory and
1192 destroyed when they go out of scope.
1193
1194 @type allowRepeatedKeys: bool
1195 @param allowRepeatedKeys:
1196 Currently not supported, always use C{False}.
1197 """
1198 if allowRepeatedKeys:
1199 raise NotImplementedError()
1200 self.__filename = filename
1201 if filename:
1202 global anydbm
1203 if not anydbm:
1204 import anydbm
1205 self.__db = anydbm.open(filename, 'c')
1206 self.__keys = dict([ (self.unmarshall_key(mk), mk)
1207 for mk in self.__db.keys() ])
1208 else:
1209 self.__db = dict()
1210 self.__keys = dict()
1211
1213 """
1214 Removes the given key from the set of known keys.
1215
1216 @type key: L{Crash} key.
1217 @param key: Key to remove.
1218 """
1219 del self.__keys[key]
1220
1222 """
1223 Marshalls a Crash key to be used in the database.
1224
1225 @see: L{__init__}
1226
1227 @type key: L{Crash} key.
1228 @param key: Key to convert.
1229
1230 @rtype: str or buffer
1231 @return: Converted key.
1232 """
1233 if key in self.__keys:
1234 return self.__keys[key]
1235 skey = pickle.dumps(key, protocol = 0)
1236 if self.compressKeys:
1237 skey = zlib.compress(skey, zlib.Z_BEST_COMPRESSION)
1238 if self.escapeKeys:
1239 skey = skey.encode('hex')
1240 if self.binaryKeys:
1241 skey = buffer(skey)
1242 self.__keys[key] = skey
1243 return skey
1244
1246 """
1247 Unmarshalls a Crash key read from the database.
1248
1249 @type key: str or buffer
1250 @param key: Key to convert.
1251
1252 @rtype: L{Crash} key.
1253 @return: Converted key.
1254 """
1255 key = str(key)
1256 if self.escapeKeys:
1257 key = key.decode('hex')
1258 if self.compressKeys:
1259 key = zlib.decompress(key)
1260 key = pickle.loads(key)
1261 return key
1262
1264 """
1265 Marshalls a Crash object to be used in the database.
1266 By default the C{memoryMap} member is B{NOT} stored here.
1267
1268 @warning: Setting the C{storeMemoryMap} argument to C{True} can lead to
1269 a severe performance penalty!
1270
1271 @type value: L{Crash}
1272 @param value: Object to convert.
1273
1274 @type storeMemoryMap: bool
1275 @param storeMemoryMap: C{True} to store the memory map, C{False}
1276 otherwise.
1277
1278 @rtype: str
1279 @return: Converted object.
1280 """
1281 if hasattr(value, 'memoryMap'):
1282 crash = value
1283 memoryMap = crash.memoryMap
1284 try:
1285 crash.memoryMap = None
1286 if storeMemoryMap and memoryMap is not None:
1287
1288 crash.memoryMap = list(memoryMap)
1289 if self.optimizeValues:
1290 value = pickle.dumps(crash, protocol = HIGHEST_PROTOCOL)
1291 value = optimize(value)
1292 else:
1293 value = pickle.dumps(crash, protocol = 0)
1294 finally:
1295 crash.memoryMap = memoryMap
1296 del memoryMap
1297 del crash
1298 if self.compressValues:
1299 value = zlib.compress(value, zlib.Z_BEST_COMPRESSION)
1300 if self.escapeValues:
1301 value = value.encode('hex')
1302 if self.binaryValues:
1303 value = buffer(value)
1304 return value
1305
1323
1324
1325
1326
1327
1328
1330 """
1331 @rtype: int
1332 @return: Count of known keys.
1333 """
1334 return len(self.__keys)
1335
1337 """
1338 @rtype: bool
1339 @return: C{False} if there are no known keys.
1340 """
1341 return bool(self.__keys)
1342
1344 """
1345 @type crash: L{Crash}
1346 @param crash: Crash object.
1347
1348 @rtype: bool
1349 @return:
1350 C{True} if a Crash object with the same key is in the container.
1351 """
1352 return self.has_key( crash.key() )
1353
1355 """
1356 @type key: L{Crash} key.
1357 @param key: Key to find.
1358
1359 @rtype: bool
1360 @return: C{True} if the key is present in the set of known keys.
1361 """
1362 return key in self.__keys
1363
1365 """
1366 @rtype: iterator
1367 @return: Iterator of known L{Crash} keys.
1368 """
1369 return self.__keys.iterkeys()
1370
1372 """
1373 Iterator of Crash objects. Returned by L{CrashContainer.__iter__}.
1374 """
1375
1377 """
1378 @type container: L{CrashContainer}
1379 @param container: Crash set to iterate.
1380 """
1381
1382
1383
1384
1385
1386
1387
1388 self.__container = container
1389 self.__keys_iter = container.iterkeys()
1390
1392 """
1393 @rtype: L{Crash}
1394 @return: A B{copy} of a Crash object in the L{CrashContainer}.
1395 @raise StopIteration: No more items left.
1396 """
1397 key = self.__keys_iter.next()
1398 return self.__container.get(key)
1399
1401 "Class destructor. Closes the database when this object is destroyed."
1402 try:
1403 if self.__filename:
1404 self.__db.close()
1405 except:
1406 pass
1407
1409 """
1410 @see: L{itervalues}
1411 @rtype: iterator
1412 @return: Iterator of the contained L{Crash} objects.
1413 """
1414 return self.itervalues()
1415
1417 """
1418 @rtype: iterator
1419 @return: Iterator of the contained L{Crash} objects.
1420
1421 @warning: A B{copy} of each object is returned,
1422 so any changes made to them will be lost.
1423
1424 To preserve changes do the following:
1425 1. Keep a reference to the object.
1426 2. Delete the object from the set.
1427 3. Modify the object and add it again.
1428 """
1429 return self.__CrashContainerIterator(self)
1430
1431 - def add(self, crash):
1432 """
1433 Adds a new crash to the container.
1434 If the crash appears to be already known, it's ignored.
1435
1436 @see: L{Crash.key}
1437
1438 @type crash: L{Crash}
1439 @param crash: Crash object to add.
1440 """
1441 if crash not in self:
1442 key = crash.key()
1443 skey = self.marshall_key(key)
1444 data = self.marshall_value(crash, storeMemoryMap = True)
1445 self.__db[skey] = data
1446
1448 """
1449 Removes a crash from the container.
1450
1451 @type key: L{Crash} unique key.
1452 @param key: Key of the crash to get.
1453 """
1454 skey = self.marshall_key(key)
1455 del self.__db[skey]
1456 self.remove_key(key)
1457
1459 """
1460 Removes a crash from the container.
1461
1462 @type crash: L{Crash}
1463 @param crash: Crash object to remove.
1464 """
1465 del self[ crash.key() ]
1466
1467 - def get(self, key):
1468 """
1469 Retrieves a crash from the container.
1470
1471 @type key: L{Crash} unique key.
1472 @param key: Key of the crash to get.
1473
1474 @rtype: L{Crash} object.
1475 @return: Crash matching the given key.
1476
1477 @see: L{iterkeys}
1478 @warning: A B{copy} of each object is returned,
1479 so any changes made to them will be lost.
1480
1481 To preserve changes do the following:
1482 1. Keep a reference to the object.
1483 2. Delete the object from the set.
1484 3. Modify the object and add it again.
1485 """
1486 skey = self.marshall_key(key)
1487 data = self.__db[skey]
1488 crash = self.unmarshall_value(data)
1489 return crash
1490
1492 """
1493 Retrieves a crash from the container.
1494
1495 @type key: L{Crash} unique key.
1496 @param key: Key of the crash to get.
1497
1498 @rtype: L{Crash} object.
1499 @return: Crash matching the given key.
1500
1501 @see: L{iterkeys}
1502 @warning: A B{copy} of each object is returned,
1503 so any changes made to them will be lost.
1504
1505 To preserve changes do the following:
1506 1. Keep a reference to the object.
1507 2. Delete the object from the set.
1508 3. Modify the object and add it again.
1509 """
1510 return self.get(key)
1511
1515 """
1516 Dictionary-like persistence interface for L{Crash} objects.
1517
1518 Currently the only implementation is through L{sql.CrashDAO}.
1519 """
1520
1521 - def __init__(self, url, creator = None, allowRepeatedKeys = True):
1522 """
1523 @type url: str
1524 @param url: Connection URL of the crash database.
1525 See L{sql.CrashDAO.__init__} for more details.
1526
1527 @type creator: callable
1528 @param creator: (Optional) Callback function that creates the SQL
1529 database connection.
1530
1531 Normally it's not necessary to use this argument. However in some
1532 odd cases you may need to customize the database connection, for
1533 example when using the integrated authentication in MSSQL.
1534
1535 @type allowRepeatedKeys: bool
1536 @param allowRepeatedKeys:
1537 If C{True} all L{Crash} objects are stored.
1538
1539 If C{False} any L{Crash} object with the same signature as a
1540 previously existing object will be ignored.
1541 """
1542 global sql
1543 if sql is None:
1544 import sql
1545 self._allowRepeatedKeys = allowRepeatedKeys
1546 self._dao = sql.CrashDAO(url, creator)
1547
1548 - def add(self, crash):
1549 """
1550 Adds a new crash to the container.
1551
1552 @note:
1553 When the C{allowRepeatedKeys} parameter of the constructor
1554 is set to C{False}, duplicated crashes are ignored.
1555
1556 @see: L{Crash.key}
1557
1558 @type crash: L{Crash}
1559 @param crash: Crash object to add.
1560 """
1561 self._dao.add(crash, self._allowRepeatedKeys)
1562
1563 - def get(self, key):
1564 """
1565 Retrieves a crash from the container.
1566
1567 @type key: L{Crash} signature.
1568 @param key: Heuristic signature of the crash to get.
1569
1570 @rtype: L{Crash} object.
1571 @return: Crash matching the given signature. If more than one is found,
1572 retrieve the newest one.
1573
1574 @see: L{iterkeys}
1575 @warning: A B{copy} of each object is returned,
1576 so any changes made to them will be lost.
1577
1578 To preserve changes do the following:
1579 1. Keep a reference to the object.
1580 2. Delete the object from the set.
1581 3. Modify the object and add it again.
1582 """
1583 found = self._dao.find(signature=key, limit=1, order=-1)
1584 if not found:
1585 raise KeyError(key)
1586 return found[0]
1587
1589 """
1590 @rtype: iterator
1591 @return: Iterator of the contained L{Crash} objects.
1592 """
1593 offset = 0
1594 limit = 10
1595 while 1:
1596 found = self._dao.find(offset=offset, limit=limit)
1597 if not found:
1598 break
1599 offset += len(found)
1600 for crash in found:
1601 yield crash
1602
1604 """
1605 @rtype: iterator
1606 @return: Iterator of the contained L{Crash} objects.
1607 """
1608 return self.__iter__()
1609
1611 """
1612 @rtype: iterator
1613 @return: Iterator of the contained L{Crash} heuristic signatures.
1614 """
1615 for crash in self:
1616 yield crash.signature
1617
1619 """
1620 @type crash: L{Crash}
1621 @param crash: Crash object.
1622
1623 @rtype: bool
1624 @return: C{True} if the Crash object is in the container.
1625 """
1626 return self._dao.count(signature=crash.signature) > 0
1627
1629 """
1630 @type key: L{Crash} signature.
1631 @param key: Heuristic signature of the crash to get.
1632
1633 @rtype: bool
1634 @return: C{True} if a matching L{Crash} object is in the container.
1635 """
1636 return self._dao.count(signature=key) > 0
1637
1639 """
1640 @rtype: int
1641 @return: Count of L{Crash} elements in the container.
1642 """
1643 return self._dao.count()
1644
1646 """
1647 @rtype: bool
1648 @return: C{False} if the container is empty.
1649 """
1650 return bool( len(self) )
1651
1653 """
1654 Old crash dump persistencer using a SQLite database.
1655
1656 @warning:
1657 Superceded by L{CrashDictionary} since WinAppDbg 1.5.
1658 New applications should not use this class.
1659 """
1660
1661 - def __init__(self, location = None, allowRepeatedKeys = True):
1662 """
1663 @type location: str
1664 @param location: (Optional) Location of the crash database.
1665 If the location is a filename, it's an SQLite database file.
1666
1667 If no location is specified, the container is volatile.
1668 Volatile containers are stored only in memory and
1669 destroyed when they go out of scope.
1670
1671 @type allowRepeatedKeys: bool
1672 @param allowRepeatedKeys:
1673 If C{True} all L{Crash} objects are stored.
1674
1675 If C{False} any L{Crash} object with the same signature as a
1676 previously existing object will be ignored.
1677 """
1678 warnings.warn(
1679 "The %s class is deprecated since WinAppDbg 1.5." % self.__class__,
1680 DeprecationWarning)
1681 if location:
1682 url = "sqlite:///%s" % location
1683 else:
1684 url = "sqlite://"
1685 super(CrashTable, self).__init__(url, allowRepeatedKeys)
1686
1688 """
1689 Old crash dump persistencer using a Microsoft SQL Server database.
1690
1691 @warning:
1692 Superceded by L{CrashDictionary} since WinAppDbg 1.5.
1693 New applications should not use this class.
1694 """
1695
1696 - def __init__(self, location = None, allowRepeatedKeys = True):
1697 """
1698 @type location: str
1699 @param location: Location of the crash database.
1700 It must be an ODBC connection string.
1701
1702 @type allowRepeatedKeys: bool
1703 @param allowRepeatedKeys:
1704 If C{True} all L{Crash} objects are stored.
1705
1706 If C{False} any L{Crash} object with the same signature as a
1707 previously existing object will be ignored.
1708 """
1709 warnings.warn(
1710 "The %s class is deprecated since WinAppDbg 1.5." % self.__class__,
1711 DeprecationWarning)
1712 import urllib
1713 url = "mssql+pyodbc:///?odbc_connect=" + urllib.quote_plus(location)
1714 super(CrashTableMSSQL, self).__init__(url, allowRepeatedKeys)
1715
1717 """
1718 Old in-memory crash dump storage.
1719
1720 @warning:
1721 Superceded by L{CrashDictionary} since WinAppDbg 1.5.
1722 New applications should not use this class.
1723 """
1724
1725 - def __init__(self, allowRepeatedKeys = True):
1726 """
1727 Volatile containers are stored only in memory and
1728 destroyed when they go out of scope.
1729
1730 @type allowRepeatedKeys: bool
1731 @param allowRepeatedKeys:
1732 If C{True} all L{Crash} objects are stored.
1733
1734 If C{False} any L{Crash} object with the same key as a
1735 previously existing object will be ignored.
1736 """
1737 super(VolatileCrashContainer, self).__init__(
1738 allowRepeatedKeys=allowRepeatedKeys)
1739
1741 """
1742 Fakes a database of volatile Crash objects,
1743 trying to mimic part of it's interface, but
1744 doesn't actually store anything.
1745
1746 Normally applications don't need to use this.
1747
1748 @see: L{CrashDictionary}
1749 """
1750
1751 - def __init__(self, allowRepeatedKeys = True):
1752 """
1753 Fake containers don't store L{Crash} objects, but they implement the
1754 interface properly.
1755
1756 @type allowRepeatedKeys: bool
1757 @param allowRepeatedKeys:
1758 Mimics the duplicate filter behavior found in real containers.
1759 """
1760 self.__keys = set()
1761 self.__count = 0
1762 self.__allowRepeatedKeys = allowRepeatedKeys
1763
1765 """
1766 @type crash: L{Crash}
1767 @param crash: Crash object.
1768
1769 @rtype: bool
1770 @return: C{True} if the Crash object is in the container.
1771 """
1772 return crash.signature in self.__keys
1773
1775 """
1776 @rtype: int
1777 @return: Count of L{Crash} elements in the container.
1778 """
1779 if self.__allowRepeatedKeys:
1780 return self.__count
1781 return len( self.__keys )
1782
1784 """
1785 @rtype: bool
1786 @return: C{False} if the container is empty.
1787 """
1788 return bool( len(self) )
1789
1790 - def add(self, crash):
1791 """
1792 Adds a new crash to the container.
1793
1794 @note:
1795 When the C{allowRepeatedKeys} parameter of the constructor
1796 is set to C{False}, duplicated crashes are ignored.
1797
1798 @see: L{Crash.key}
1799
1800 @type crash: L{Crash}
1801 @param crash: Crash object to add.
1802 """
1803 self.__keys.add( crash.signature )
1804 self.__count += 1
1805
1806 - def get(self, key):
1807 """
1808 This method is not supported.
1809 """
1810 raise NotImplementedError()
1811
1813 """
1814 @type key: L{Crash} signature.
1815 @param key: Heuristic signature of the crash to get.
1816
1817 @rtype: bool
1818 @return: C{True} if a matching L{Crash} object is in the container.
1819 """
1820 return self.__keys.has_key( key )
1821
1823 """
1824 @rtype: iterator
1825 @return: Iterator of the contained L{Crash} object keys.
1826
1827 @see: L{get}
1828 @warning: A B{copy} of each object is returned,
1829 so any changes made to them will be lost.
1830
1831 To preserve changes do the following:
1832 1. Keep a reference to the object.
1833 2. Delete the object from the set.
1834 3. Modify the object and add it again.
1835 """
1836 return iter(self.__keys)
1837
1838
1839
1840
1841 try:
1842 cerealizer.register(Crash)
1843 cerealizer.register(win32.MemoryBasicInformation)
1844 except NameError:
1845 pass
1846