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 Functions for text input, logging or text output.
33
34 @group Helpers:
35 HexDump,
36 HexInput,
37 HexOutput,
38 Color,
39 Table,
40 Logger
41 DebugLog
42 CrashDump
43 """
44
45 __revision__ = "$Id: textio.py 1299 2013-12-20 09:30:55Z qvasimodo $"
46
47 __all__ = [
48 'HexDump',
49 'HexInput',
50 'HexOutput',
51 'Color',
52 'Table',
53 'CrashDump',
54 'DebugLog',
55 'Logger',
56 ]
57
58 import win32
59 from util import StaticClass
60
61 import re
62 import time
63 import struct
64 import traceback
302
306 """
307 Static functions for user output parsing.
308 The counterparts for each method are in the L{HexInput} class.
309
310 @type integer_size: int
311 @cvar integer_size: Default size in characters of an outputted integer.
312 This value is platform dependent.
313
314 @type address_size: int
315 @cvar address_size: Default Number of bits of the target architecture.
316 This value is platform dependent.
317 """
318
319 integer_size = (win32.SIZEOF(win32.DWORD) * 2) + 2
320 address_size = (win32.SIZEOF(win32.SIZE_T) * 2) + 2
321
322 @classmethod
323 - def integer(cls, integer, bits = None):
324 """
325 @type integer: int
326 @param integer: Integer.
327
328 @type bits: int
329 @param bits:
330 (Optional) Number of bits of the target architecture.
331 The default is platform dependent. See: L{HexOutput.integer_size}
332
333 @rtype: str
334 @return: Text output.
335 """
336 if bits is None:
337 integer_size = cls.integer_size
338 else:
339 integer_size = (bits / 4) + 2
340 if integer >= 0:
341 return ('0x%%.%dx' % (integer_size - 2)) % integer
342 return ('-0x%%.%dx' % (integer_size - 2)) % -integer
343
344 @classmethod
345 - def address(cls, address, bits = None):
346 """
347 @type address: int
348 @param address: Memory address.
349
350 @type bits: int
351 @param bits:
352 (Optional) Number of bits of the target architecture.
353 The default is platform dependent. See: L{HexOutput.address_size}
354
355 @rtype: str
356 @return: Text output.
357 """
358 if bits is None:
359 address_size = cls.address_size
360 bits = win32.bits
361 else:
362 address_size = (bits / 4) + 2
363 if address < 0:
364 address = ((2 ** bits) - 1) ^ ~address
365 return ('0x%%.%dx' % (address_size - 2)) % address
366
367 @staticmethod
369 """
370 Convert binary data to a string of hexadecimal numbers.
371
372 @type data: str
373 @param data: Binary data.
374
375 @rtype: str
376 @return: Hexadecimal representation.
377 """
378 return HexDump.hexadecimal(data, separator = '')
379
380 @classmethod
382 """
383 Write a list of integers to a file.
384 If a file of the same name exists, it's contents are replaced.
385
386 See L{HexInput.integer_list_file} for a description of the file format.
387
388 @type filename: str
389 @param filename: Name of the file to write.
390
391 @type values: list( int )
392 @param values: List of integers to write to the file.
393
394 @type bits: int
395 @param bits:
396 (Optional) Number of bits of the target architecture.
397 The default is platform dependent. See: L{HexOutput.integer_size}
398 """
399 fd = open(filename, 'w')
400 for integer in values:
401 print >> fd, cls.integer(integer, bits)
402 fd.close()
403
404 @classmethod
406 """
407 Write a list of strings to a file.
408 If a file of the same name exists, it's contents are replaced.
409
410 See L{HexInput.string_list_file} for a description of the file format.
411
412 @type filename: str
413 @param filename: Name of the file to write.
414
415 @type values: list( int )
416 @param values: List of strings to write to the file.
417 """
418 fd = open(filename, 'w')
419 for string in values:
420 print >> fd, string
421 fd.close()
422
423 @classmethod
425 """
426 Write a list of mixed values to a file.
427 If a file of the same name exists, it's contents are replaced.
428
429 See L{HexInput.mixed_list_file} for a description of the file format.
430
431 @type filename: str
432 @param filename: Name of the file to write.
433
434 @type values: list( int )
435 @param values: List of mixed values to write to the file.
436
437 @type bits: int
438 @param bits:
439 (Optional) Number of bits of the target architecture.
440 The default is platform dependent. See: L{HexOutput.integer_size}
441 """
442 fd = open(filename, 'w')
443 for original in values:
444 try:
445 parsed = cls.integer(original, bits)
446 except TypeError:
447 parsed = repr(original)
448 print >> fd, parsed
449 fd.close()
450
451
452
453 -class HexDump (StaticClass):
454 """
455 Static functions for hexadecimal dumps.
456
457 @type integer_size: int
458 @cvar integer_size: Size in characters of an outputted integer.
459 This value is platform dependent.
460
461 @type address_size: int
462 @cvar address_size: Size in characters of an outputted address.
463 This value is platform dependent.
464 """
465
466 integer_size = (win32.SIZEOF(win32.DWORD) * 2)
467 address_size = (win32.SIZEOF(win32.SIZE_T) * 2)
468
469 @classmethod
470 - def integer(cls, integer, bits = None):
471 """
472 @type integer: int
473 @param integer: Integer.
474
475 @type bits: int
476 @param bits:
477 (Optional) Number of bits of the target architecture.
478 The default is platform dependent. See: L{HexDump.integer_size}
479
480 @rtype: str
481 @return: Text output.
482 """
483 if bits is None:
484 integer_size = cls.integer_size
485 else:
486 integer_size = bits / 4
487 return ('%%.%dX' % integer_size) % integer
488
489 @classmethod
490 - def address(cls, address, bits = None):
491 """
492 @type address: int
493 @param address: Memory address.
494
495 @type bits: int
496 @param bits:
497 (Optional) Number of bits of the target architecture.
498 The default is platform dependent. See: L{HexDump.address_size}
499
500 @rtype: str
501 @return: Text output.
502 """
503 if bits is None:
504 address_size = cls.address_size
505 bits = win32.bits
506 else:
507 address_size = bits / 4
508 if address < 0:
509 address = ((2 ** bits) - 1) ^ ~address
510 return ('%%.%dX' % address_size) % address
511
512 @staticmethod
514 """
515 Replace unprintable characters with dots.
516
517 @type data: str
518 @param data: Binary data.
519
520 @rtype: str
521 @return: Printable text.
522 """
523 result = ''
524 for c in data:
525 if 32 < ord(c) < 128:
526 result += c
527 else:
528 result += '.'
529 return result
530
531 @staticmethod
533 """
534 Convert binary data to a string of hexadecimal numbers.
535
536 @type data: str
537 @param data: Binary data.
538
539 @type separator: str
540 @param separator:
541 Separator between the hexadecimal representation of each character.
542
543 @rtype: str
544 @return: Hexadecimal representation.
545 """
546 return separator.join( [ '%.2x' % ord(c) for c in data ] )
547
548 @staticmethod
550 """
551 Convert binary data to a string of hexadecimal WORDs.
552
553 @type data: str
554 @param data: Binary data.
555
556 @type separator: str
557 @param separator:
558 Separator between the hexadecimal representation of each WORD.
559
560 @rtype: str
561 @return: Hexadecimal representation.
562 """
563 if len(data) & 1 != 0:
564 data += '\0'
565 return separator.join( [ '%.4x' % struct.unpack('<H', data[i:i+2])[0] \
566 for i in xrange(0, len(data), 2) ] )
567
568 @staticmethod
570 """
571 Convert binary data to a string of hexadecimal DWORDs.
572
573 @type data: str
574 @param data: Binary data.
575
576 @type separator: str
577 @param separator:
578 Separator between the hexadecimal representation of each DWORD.
579
580 @rtype: str
581 @return: Hexadecimal representation.
582 """
583 if len(data) & 3 != 0:
584 data += '\0' * (4 - (len(data) & 3))
585 return separator.join( [ '%.8x' % struct.unpack('<L', data[i:i+4])[0] \
586 for i in xrange(0, len(data), 4) ] )
587
588 @staticmethod
590 """
591 Convert binary data to a string of hexadecimal QWORDs.
592
593 @type data: str
594 @param data: Binary data.
595
596 @type separator: str
597 @param separator:
598 Separator between the hexadecimal representation of each QWORD.
599
600 @rtype: str
601 @return: Hexadecimal representation.
602 """
603 if len(data) & 7 != 0:
604 data += '\0' * (8 - (len(data) & 7))
605 return separator.join( [ '%.16x' % struct.unpack('<Q', data[i:i+8])[0]\
606 for i in xrange(0, len(data), 8) ] )
607
608 @classmethod
609 - def hexline(cls, data, separator = ' ', width = None):
610 """
611 Dump a line of hexadecimal numbers from binary data.
612
613 @type data: str
614 @param data: Binary data.
615
616 @type separator: str
617 @param separator:
618 Separator between the hexadecimal representation of each character.
619
620 @type width: int
621 @param width:
622 (Optional) Maximum number of characters to convert per text line.
623 This value is also used for padding.
624
625 @rtype: str
626 @return: Multiline output text.
627 """
628 if width is None:
629 fmt = '%s %s'
630 else:
631 fmt = '%%-%ds %%-%ds' % ((len(separator)+2)*width-1, width)
632 return fmt % (cls.hexadecimal(data, separator), cls.printable(data))
633
634 @classmethod
635 - def hexblock(cls, data, address = None,
636 bits = None,
637 separator = ' ',
638 width = 8):
639 """
640 Dump a block of hexadecimal numbers from binary data.
641 Also show a printable text version of the data.
642
643 @type data: str
644 @param data: Binary data.
645
646 @type address: str
647 @param address: Memory address where the data was read from.
648
649 @type bits: int
650 @param bits:
651 (Optional) Number of bits of the target architecture.
652 The default is platform dependent. See: L{HexDump.address_size}
653
654 @type separator: str
655 @param separator:
656 Separator between the hexadecimal representation of each character.
657
658 @type width: int
659 @param width:
660 (Optional) Maximum number of characters to convert per text line.
661
662 @rtype: str
663 @return: Multiline output text.
664 """
665 return cls.hexblock_cb(cls.hexline, data, address, bits, width,
666 cb_kwargs = {'width' : width, 'separator' : separator})
667
668 @classmethod
669 - def hexblock_cb(cls, callback, data, address = None,
670 bits = None,
671 width = 16,
672 cb_args = (),
673 cb_kwargs = {}):
674 """
675 Dump a block of binary data using a callback function to convert each
676 line of text.
677
678 @type callback: function
679 @param callback: Callback function to convert each line of data.
680
681 @type data: str
682 @param data: Binary data.
683
684 @type address: str
685 @param address:
686 (Optional) Memory address where the data was read from.
687
688 @type bits: int
689 @param bits:
690 (Optional) Number of bits of the target architecture.
691 The default is platform dependent. See: L{HexDump.address_size}
692
693 @type cb_args: str
694 @param cb_args:
695 (Optional) Arguments to pass to the callback function.
696
697 @type cb_kwargs: str
698 @param cb_kwargs:
699 (Optional) Keyword arguments to pass to the callback function.
700
701 @type width: int
702 @param width:
703 (Optional) Maximum number of bytes to convert per text line.
704
705 @rtype: str
706 @return: Multiline output text.
707 """
708 result = ''
709 if address is None:
710 for i in xrange(0, len(data), width):
711 result = '%s%s\n' % ( result, \
712 callback(data[i:i+width], *cb_args, **cb_kwargs) )
713 else:
714 for i in xrange(0, len(data), width):
715 result = '%s%s: %s\n' % (
716 result,
717 cls.address(address, bits),
718 callback(data[i:i+width], *cb_args, **cb_kwargs)
719 )
720 address += width
721 return result
722
723 @classmethod
724 - def hexblock_byte(cls, data, address = None,
725 bits = None,
726 separator = ' ',
727 width = 16):
728 """
729 Dump a block of hexadecimal BYTEs from binary data.
730
731 @type data: str
732 @param data: Binary data.
733
734 @type address: str
735 @param address: Memory address where the data was read from.
736
737 @type bits: int
738 @param bits:
739 (Optional) Number of bits of the target architecture.
740 The default is platform dependent. See: L{HexDump.address_size}
741
742 @type separator: str
743 @param separator:
744 Separator between the hexadecimal representation of each BYTE.
745
746 @type width: int
747 @param width:
748 (Optional) Maximum number of BYTEs to convert per text line.
749
750 @rtype: str
751 @return: Multiline output text.
752 """
753 return cls.hexblock_cb(cls.hexadecimal, data,
754 address, bits, width,
755 cb_kwargs = {'separator': separator})
756
757 @classmethod
758 - def hexblock_word(cls, data, address = None,
759 bits = None,
760 separator = ' ',
761 width = 8):
762 """
763 Dump a block of hexadecimal WORDs from binary data.
764
765 @type data: str
766 @param data: Binary data.
767
768 @type address: str
769 @param address: Memory address where the data was read from.
770
771 @type bits: int
772 @param bits:
773 (Optional) Number of bits of the target architecture.
774 The default is platform dependent. See: L{HexDump.address_size}
775
776 @type separator: str
777 @param separator:
778 Separator between the hexadecimal representation of each WORD.
779
780 @type width: int
781 @param width:
782 (Optional) Maximum number of WORDs to convert per text line.
783
784 @rtype: str
785 @return: Multiline output text.
786 """
787 return cls.hexblock_cb(cls.hexa_word, data,
788 address, bits, width * 2,
789 cb_kwargs = {'separator': separator})
790
791 @classmethod
792 - def hexblock_dword(cls, data, address = None,
793 bits = None,
794 separator = ' ',
795 width = 4):
796 """
797 Dump a block of hexadecimal DWORDs from binary data.
798
799 @type data: str
800 @param data: Binary data.
801
802 @type address: str
803 @param address: Memory address where the data was read from.
804
805 @type bits: int
806 @param bits:
807 (Optional) Number of bits of the target architecture.
808 The default is platform dependent. See: L{HexDump.address_size}
809
810 @type separator: str
811 @param separator:
812 Separator between the hexadecimal representation of each DWORD.
813
814 @type width: int
815 @param width:
816 (Optional) Maximum number of DWORDs to convert per text line.
817
818 @rtype: str
819 @return: Multiline output text.
820 """
821 return cls.hexblock_cb(cls.hexa_dword, data,
822 address, bits, width * 4,
823 cb_kwargs = {'separator': separator})
824
825 @classmethod
826 - def hexblock_qword(cls, data, address = None,
827 bits = None,
828 separator = ' ',
829 width = 2):
830 """
831 Dump a block of hexadecimal QWORDs from binary data.
832
833 @type data: str
834 @param data: Binary data.
835
836 @type address: str
837 @param address: Memory address where the data was read from.
838
839 @type bits: int
840 @param bits:
841 (Optional) Number of bits of the target architecture.
842 The default is platform dependent. See: L{HexDump.address_size}
843
844 @type separator: str
845 @param separator:
846 Separator between the hexadecimal representation of each QWORD.
847
848 @type width: int
849 @param width:
850 (Optional) Maximum number of QWORDs to convert per text line.
851
852 @rtype: str
853 @return: Multiline output text.
854 """
855 return cls.hexblock_cb(cls.hexa_qword, data,
856 address, bits, width * 8,
857 cb_kwargs = {'separator': separator})
858
859
860
861
862
863 -class Color (object):
864 """
865 Colored console output.
866 """
867
868 @staticmethod
871
872 @staticmethod
873 - def _set_text_attributes(wAttributes):
875
876
877
878 @classmethod
880 """
881 Determine if we can use colors.
882
883 Colored output only works when the output is a real console, and fails
884 when redirected to a file or pipe. Call this method before issuing a
885 call to any other method of this class to make sure it's actually
886 possible to use colors.
887
888 @rtype: bool
889 @return: C{True} if it's possible to output text with color,
890 C{False} otherwise.
891 """
892 try:
893 cls._get_text_attributes()
894 return True
895 except Exception:
896 return False
897
898 @classmethod
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916 @classmethod
924
925 @classmethod
931
932 @classmethod
938
939 @classmethod
946
947 @classmethod
954
955 @classmethod
962
963 @classmethod
970
971 @classmethod
978
979 @classmethod
986
987 @classmethod
994
995 @classmethod
1002
1003
1004
1005 @classmethod
1013
1014 @classmethod
1020
1021 @classmethod
1027
1028 @classmethod
1035
1036 @classmethod
1043
1044 @classmethod
1051
1052 @classmethod
1059
1060 @classmethod
1067
1068 @classmethod
1075
1076 @classmethod
1083
1084 @classmethod
1091
1092
1093
1094
1095
1096 -class Table (object):
1097 """
1098 Text based table. The number of columns and the width of each column
1099 is automatically calculated.
1100 """
1101
1103 """
1104 @type sep: str
1105 @param sep: Separator between cells in each row.
1106 """
1107 self.__cols = list()
1108 self.__width = list()
1109 self.__sep = sep
1110
1112 """
1113 Add a row to the table. All items are converted to strings.
1114
1115 @type row: tuple
1116 @keyword row: Each argument is a cell in the table.
1117 """
1118 row = [ str(item) for item in row ]
1119 len_row = [ len(item) for item in row ]
1120 width = self.__width
1121 len_old = len(width)
1122 len_new = len(row)
1123 known = min(len_old, len_new)
1124 missing = len_new - len_old
1125 if missing > 0:
1126 width.extend( len_row[ -missing : ] )
1127 elif missing < 0:
1128 len_row.extend( [0] * (-missing) )
1129 self.__width = [ max( width[i], len_row[i] ) for i in xrange(len(len_row)) ]
1130 self.__cols.append(row)
1131
1132 - def justify(self, column, direction):
1133 """
1134 Make the text in a column left or right justified.
1135
1136 @type column: int
1137 @param column: Index of the column.
1138
1139 @type direction: int
1140 @param direction:
1141 C{-1} to justify left,
1142 C{1} to justify right.
1143
1144 @raise IndexError: Bad column index.
1145 @raise ValueError: Bad direction value.
1146 """
1147 if direction == -1:
1148 self.__width[column] = abs(self.__width[column])
1149 elif direction == 1:
1150 self.__width[column] = - abs(self.__width[column])
1151 else:
1152 raise ValueError("Bad direction value.")
1153
1155 """
1156 Get the width of the text output for the table.
1157
1158 @rtype: int
1159 @return: Width in characters for the text output,
1160 including the newline character.
1161 """
1162 width = 0
1163 if self.__width:
1164 width = sum( abs(x) for x in self.__width )
1165 width = width + len(self.__width) * len(self.__sep) + 1
1166 return width
1167
1169 """
1170 Get the text output for the table.
1171
1172 @rtype: str
1173 @return: Text output.
1174 """
1175 return '%s\n' % '\n'.join( self.yieldOutput() )
1176
1178 """
1179 Generate the text output for the table.
1180
1181 @rtype: generator of str
1182 @return: Text output.
1183 """
1184 width = self.__width
1185 if width:
1186 num_cols = len(width)
1187 fmt = ['%%%ds' % -w for w in width]
1188 if width[-1] > 0:
1189 fmt[-1] = '%s'
1190 fmt = self.__sep.join(fmt)
1191 for row in self.__cols:
1192 row.extend( [''] * (num_cols - len(row)) )
1193 yield fmt % tuple(row)
1194
1196 """
1197 Print the text output for the table.
1198 """
1199 print self.getOutput()
1200
1204 """
1205 Static functions for crash dumps.
1206
1207 @type reg_template: str
1208 @cvar reg_template: Template for the L{dump_registers} method.
1209 """
1210
1211
1212 reg_template = {
1213 win32.ARCH_I386 : (
1214 'eax=%(Eax).8x ebx=%(Ebx).8x ecx=%(Ecx).8x edx=%(Edx).8x esi=%(Esi).8x edi=%(Edi).8x\n'
1215 'eip=%(Eip).8x esp=%(Esp).8x ebp=%(Ebp).8x %(efl_dump)s\n'
1216 'cs=%(SegCs).4x ss=%(SegSs).4x ds=%(SegDs).4x es=%(SegEs).4x fs=%(SegFs).4x gs=%(SegGs).4x efl=%(EFlags).8x\n'
1217 ),
1218 win32.ARCH_AMD64 : (
1219 'rax=%(Rax).16x rbx=%(Rbx).16x rcx=%(Rcx).16x\n'
1220 'rdx=%(Rdx).16x rsi=%(Rsi).16x rdi=%(Rdi).16x\n'
1221 'rip=%(Rip).16x rsp=%(Rsp).16x rbp=%(Rbp).16x\n'
1222 ' r8=%(R8).16x r9=%(R9).16x r10=%(R10).16x\n'
1223 'r11=%(R11).16x r12=%(R12).16x r13=%(R13).16x\n'
1224 'r14=%(R14).16x r15=%(R15).16x\n'
1225 '%(efl_dump)s\n'
1226 'cs=%(SegCs).4x ss=%(SegSs).4x ds=%(SegDs).4x es=%(SegEs).4x fs=%(SegFs).4x gs=%(SegGs).4x efl=%(EFlags).8x\n'
1227 ),
1228 }
1229
1230 @staticmethod
1232 """
1233 Dump the x86 processor flags.
1234 The output mimics that of the WinDBG debugger.
1235 Used by L{dump_registers}.
1236
1237 @type efl: int
1238 @param efl: Value of the eFlags register.
1239
1240 @rtype: str
1241 @return: Text suitable for logging.
1242 """
1243 if efl is None:
1244 return ''
1245 efl_dump = 'iopl=%1d' % ((efl & 0x3000) >> 12)
1246 if efl & 0x100000:
1247 efl_dump += ' vip'
1248 else:
1249 efl_dump += ' '
1250 if efl & 0x80000:
1251 efl_dump += ' vif'
1252 else:
1253 efl_dump += ' '
1254
1255 if efl & 0x800:
1256 efl_dump += ' ov'
1257 else:
1258 efl_dump += ' no'
1259 if efl & 0x400:
1260 efl_dump += ' dn'
1261 else:
1262 efl_dump += ' up'
1263 if efl & 0x200:
1264 efl_dump += ' ei'
1265 else:
1266 efl_dump += ' di'
1267
1268 if efl & 0x80:
1269 efl_dump += ' ng'
1270 else:
1271 efl_dump += ' pl'
1272 if efl & 0x40:
1273 efl_dump += ' zr'
1274 else:
1275 efl_dump += ' nz'
1276 if efl & 0x10:
1277 efl_dump += ' ac'
1278 else:
1279 efl_dump += ' na'
1280
1281 if efl & 0x4:
1282 efl_dump += ' pe'
1283 else:
1284 efl_dump += ' po'
1285
1286 if efl & 0x1:
1287 efl_dump += ' cy'
1288 else:
1289 efl_dump += ' nc'
1290 return efl_dump
1291
1292 @classmethod
1294 """
1295 Dump the x86/x64 processor register values.
1296 The output mimics that of the WinDBG debugger.
1297
1298 @type registers: dict( str S{->} int )
1299 @param registers: Dictionary mapping register names to their values.
1300
1301 @type arch: str
1302 @param arch: Architecture of the machine whose registers were dumped.
1303 Defaults to the current architecture.
1304 Currently only the following architectures are supported:
1305 - L{win32.ARCH_I386}
1306 - L{win32.ARCH_AMD64}
1307
1308 @rtype: str
1309 @return: Text suitable for logging.
1310 """
1311 if registers is None:
1312 return ''
1313 if arch is None:
1314 if 'Eax' in registers:
1315 arch = win32.ARCH_I386
1316 elif 'Rax' in registers:
1317 arch = win32.ARCH_AMD64
1318 else:
1319 arch = 'Unknown'
1320 if arch not in cls.reg_template:
1321 msg = "Don't know how to dump the registers for architecture: %s"
1322 raise NotImplementedError(msg % arch)
1323 registers = registers.copy()
1324 registers['efl_dump'] = cls.dump_flags( registers['EFlags'] )
1325 return cls.reg_template[arch] % registers
1326
1327 @staticmethod
1329 """
1330 Dump data pointed to by the given registers, if any.
1331
1332 @type registers: dict( str S{->} int )
1333 @param registers: Dictionary mapping register names to their values.
1334 This value is returned by L{Thread.get_context}.
1335
1336 @type data: dict( str S{->} str )
1337 @param data: Dictionary mapping register names to the data they point to.
1338 This value is returned by L{Thread.peek_pointers_in_registers}.
1339
1340 @rtype: str
1341 @return: Text suitable for logging.
1342 """
1343 if None in (registers, data):
1344 return ''
1345 names = data.keys()
1346 names.sort()
1347 result = ''
1348 for reg_name in names:
1349 tag = reg_name.lower()
1350 dumped = HexDump.hexline(data[reg_name], separator, width)
1351 result += '%s -> %s\n' % (tag, dumped)
1352 return result
1353
1354 @staticmethod
1355 - def dump_data_peek(data, base = 0,
1356 separator = ' ',
1357 width = 16,
1358 bits = None):
1359 """
1360 Dump data from pointers guessed within the given binary data.
1361
1362 @type data: str
1363 @param data: Dictionary mapping offsets to the data they point to.
1364
1365 @type base: int
1366 @param base: Base offset.
1367
1368 @type bits: int
1369 @param bits:
1370 (Optional) Number of bits of the target architecture.
1371 The default is platform dependent. See: L{HexDump.address_size}
1372
1373 @rtype: str
1374 @return: Text suitable for logging.
1375 """
1376 if data is None:
1377 return ''
1378 pointers = data.keys()
1379 pointers.sort()
1380 result = ''
1381 for offset in pointers:
1382 dumped = HexDump.hexline(data[offset], separator, width)
1383 address = HexDump.address(base + offset, bits)
1384 result += '%s -> %s\n' % (address, dumped)
1385 return result
1386
1387 @staticmethod
1389 """
1390 Dump data from pointers guessed within the given stack dump.
1391
1392 @type data: str
1393 @param data: Dictionary mapping stack offsets to the data they point to.
1394
1395 @type separator: str
1396 @param separator:
1397 Separator between the hexadecimal representation of each character.
1398
1399 @type width: int
1400 @param width:
1401 (Optional) Maximum number of characters to convert per text line.
1402 This value is also used for padding.
1403
1404 @type arch: str
1405 @param arch: Architecture of the machine whose registers were dumped.
1406 Defaults to the current architecture.
1407
1408 @rtype: str
1409 @return: Text suitable for logging.
1410 """
1411 if data is None:
1412 return ''
1413 if arch is None:
1414 arch = win32.arch
1415 pointers = data.keys()
1416 pointers.sort()
1417 result = ''
1418 if pointers:
1419 if arch == win32.ARCH_I386:
1420 spreg = 'esp'
1421 elif arch == win32.ARCH_AMD64:
1422 spreg = 'rsp'
1423 else:
1424 spreg = 'STACK'
1425 tag_fmt = '[%s+0x%%.%dx]' % (spreg, len( '%x' % pointers[-1] ) )
1426 for offset in pointers:
1427 dumped = HexDump.hexline(data[offset], separator, width)
1428 tag = tag_fmt % offset
1429 result += '%s -> %s\n' % (tag, dumped)
1430 return result
1431
1432 @staticmethod
1434 """
1435 Dump a stack trace, as returned by L{Thread.get_stack_trace} with the
1436 C{bUseLabels} parameter set to C{False}.
1437
1438 @type stack_trace: list( int, int, str )
1439 @param stack_trace: Stack trace as a list of tuples of
1440 ( return address, frame pointer, module filename )
1441
1442 @type bits: int
1443 @param bits:
1444 (Optional) Number of bits of the target architecture.
1445 The default is platform dependent. See: L{HexDump.address_size}
1446
1447 @rtype: str
1448 @return: Text suitable for logging.
1449 """
1450 if not stack_trace:
1451 return ''
1452 table = Table()
1453 table.addRow('Frame', 'Origin', 'Module')
1454 for (fp, ra, mod) in stack_trace:
1455 fp_d = HexDump.address(fp, bits)
1456 ra_d = HexDump.address(ra, bits)
1457 table.addRow(fp_d, ra_d, mod)
1458 return table.getOutput()
1459
1460 @staticmethod
1462 """
1463 Dump a stack trace,
1464 as returned by L{Thread.get_stack_trace_with_labels}.
1465
1466 @type stack_trace: list( int, int, str )
1467 @param stack_trace: Stack trace as a list of tuples of
1468 ( return address, frame pointer, module filename )
1469
1470 @type bits: int
1471 @param bits:
1472 (Optional) Number of bits of the target architecture.
1473 The default is platform dependent. See: L{HexDump.address_size}
1474
1475 @rtype: str
1476 @return: Text suitable for logging.
1477 """
1478 if not stack_trace:
1479 return ''
1480 table = Table()
1481 table.addRow('Frame', 'Origin')
1482 for (fp, label) in stack_trace:
1483 table.addRow( HexDump.address(fp, bits), label )
1484 return table.getOutput()
1485
1486
1487
1488
1489
1490
1491
1492 @staticmethod
1493 - def dump_code(disassembly, pc = None,
1494 bLowercase = True,
1495 bits = None):
1496 """
1497 Dump a disassembly. Optionally mark where the program counter is.
1498
1499 @type disassembly: list of tuple( int, int, str, str )
1500 @param disassembly: Disassembly dump as returned by
1501 L{Process.disassemble} or L{Thread.disassemble_around_pc}.
1502
1503 @type pc: int
1504 @param pc: (Optional) Program counter.
1505
1506 @type bLowercase: bool
1507 @param bLowercase: (Optional) If C{True} convert the code to lowercase.
1508
1509 @type bits: int
1510 @param bits:
1511 (Optional) Number of bits of the target architecture.
1512 The default is platform dependent. See: L{HexDump.address_size}
1513
1514 @rtype: str
1515 @return: Text suitable for logging.
1516 """
1517 if not disassembly:
1518 return ''
1519 table = Table(sep = ' | ')
1520 for (addr, size, code, dump) in disassembly:
1521 if bLowercase:
1522 code = code.lower()
1523 if addr == pc:
1524 addr = ' * %s' % HexDump.address(addr, bits)
1525 else:
1526 addr = ' %s' % HexDump.address(addr, bits)
1527 table.addRow(addr, dump, code)
1528 table.justify(1, 1)
1529 return table.getOutput()
1530
1531 @staticmethod
1532 - def dump_code_line(disassembly_line, bShowAddress = True,
1533 bShowDump = True,
1534 bLowercase = True,
1535 dwDumpWidth = None,
1536 dwCodeWidth = None,
1537 bits = None):
1538 """
1539 Dump a single line of code. To dump a block of code use L{dump_code}.
1540
1541 @type disassembly_line: tuple( int, int, str, str )
1542 @param disassembly_line: Single item of the list returned by
1543 L{Process.disassemble} or L{Thread.disassemble_around_pc}.
1544
1545 @type bShowAddress: bool
1546 @param bShowAddress: (Optional) If C{True} show the memory address.
1547
1548 @type bShowDump: bool
1549 @param bShowDump: (Optional) If C{True} show the hexadecimal dump.
1550
1551 @type bLowercase: bool
1552 @param bLowercase: (Optional) If C{True} convert the code to lowercase.
1553
1554 @type dwDumpWidth: int or None
1555 @param dwDumpWidth: (Optional) Width in characters of the hex dump.
1556
1557 @type dwCodeWidth: int or None
1558 @param dwCodeWidth: (Optional) Width in characters of the code.
1559
1560 @type bits: int
1561 @param bits:
1562 (Optional) Number of bits of the target architecture.
1563 The default is platform dependent. See: L{HexDump.address_size}
1564
1565 @rtype: str
1566 @return: Text suitable for logging.
1567 """
1568 if bits is None:
1569 address_size = HexDump.address_size
1570 else:
1571 address_size = bits / 4
1572 (addr, size, code, dump) = disassembly_line
1573 dump = dump.replace(' ', '')
1574 result = list()
1575 fmt = ''
1576 if bShowAddress:
1577 result.append( HexDump.address(addr, bits) )
1578 fmt += '%%%ds:' % address_size
1579 if bShowDump:
1580 result.append(dump)
1581 if dwDumpWidth:
1582 fmt += ' %%-%ds' % dwDumpWidth
1583 else:
1584 fmt += ' %s'
1585 if bLowercase:
1586 code = code.lower()
1587 result.append(code)
1588 if dwCodeWidth:
1589 fmt += ' %%-%ds' % dwCodeWidth
1590 else:
1591 fmt += ' %s'
1592 return fmt % tuple(result)
1593
1594 @staticmethod
1596 """
1597 Dump the memory map of a process. Optionally show the filenames for
1598 memory mapped files as well.
1599
1600 @type memoryMap: list( L{win32.MemoryBasicInformation} )
1601 @param memoryMap: Memory map returned by L{Process.get_memory_map}.
1602
1603 @type mappedFilenames: dict( int S{->} str )
1604 @param mappedFilenames: (Optional) Memory mapped filenames
1605 returned by L{Process.get_mapped_filenames}.
1606
1607 @type bits: int
1608 @param bits:
1609 (Optional) Number of bits of the target architecture.
1610 The default is platform dependent. See: L{HexDump.address_size}
1611
1612 @rtype: str
1613 @return: Text suitable for logging.
1614 """
1615 if not memoryMap:
1616 return ''
1617
1618 table = Table()
1619 if mappedFilenames:
1620 table.addRow("Address", "Size", "State", "Access", "Type", "File")
1621 else:
1622 table.addRow("Address", "Size", "State", "Access", "Type")
1623
1624
1625 for mbi in memoryMap:
1626
1627
1628 BaseAddress = HexDump.address(mbi.BaseAddress, bits)
1629 RegionSize = HexDump.address(mbi.RegionSize, bits)
1630
1631
1632 mbiState = mbi.State
1633 if mbiState == win32.MEM_RESERVE:
1634 State = "Reserved"
1635 elif mbiState == win32.MEM_COMMIT:
1636 State = "Commited"
1637 elif mbiState == win32.MEM_FREE:
1638 State = "Free"
1639 else:
1640 State = "Unknown"
1641
1642
1643 if mbiState != win32.MEM_COMMIT:
1644 Protect = ""
1645 else:
1646 mbiProtect = mbi.Protect
1647 if mbiProtect & win32.PAGE_NOACCESS:
1648 Protect = "--- "
1649 elif mbiProtect & win32.PAGE_READONLY:
1650 Protect = "R-- "
1651 elif mbiProtect & win32.PAGE_READWRITE:
1652 Protect = "RW- "
1653 elif mbiProtect & win32.PAGE_WRITECOPY:
1654 Protect = "RC- "
1655 elif mbiProtect & win32.PAGE_EXECUTE:
1656 Protect = "--X "
1657 elif mbiProtect & win32.PAGE_EXECUTE_READ:
1658 Protect = "R-X "
1659 elif mbiProtect & win32.PAGE_EXECUTE_READWRITE:
1660 Protect = "RWX "
1661 elif mbiProtect & win32.PAGE_EXECUTE_WRITECOPY:
1662 Protect = "RCX "
1663 else:
1664 Protect = "??? "
1665 if mbiProtect & win32.PAGE_GUARD:
1666 Protect += "G"
1667 else:
1668 Protect += "-"
1669 if mbiProtect & win32.PAGE_NOCACHE:
1670 Protect += "N"
1671 else:
1672 Protect += "-"
1673 if mbiProtect & win32.PAGE_WRITECOMBINE:
1674 Protect += "W"
1675 else:
1676 Protect += "-"
1677
1678
1679 mbiType = mbi.Type
1680 if mbiType == win32.MEM_IMAGE:
1681 Type = "Image"
1682 elif mbiType == win32.MEM_MAPPED:
1683 Type = "Mapped"
1684 elif mbiType == win32.MEM_PRIVATE:
1685 Type = "Private"
1686 elif mbiType == 0:
1687 Type = ""
1688 else:
1689 Type = "Unknown"
1690
1691
1692 if mappedFilenames:
1693 FileName = mappedFilenames.get(mbi.BaseAddress, '')
1694 table.addRow( BaseAddress, RegionSize, State, Protect, Type, FileName )
1695 else:
1696 table.addRow( BaseAddress, RegionSize, State, Protect, Type )
1697
1698
1699 return table.getOutput()
1700
1701
1702
1703 -class DebugLog (StaticClass):
1704 'Static functions for debug logging.'
1705
1706 @staticmethod
1707 - def log_text(text):
1708 """
1709 Log lines of text, inserting a timestamp.
1710
1711 @type text: str
1712 @param text: Text to log.
1713
1714 @rtype: str
1715 @return: Log line.
1716 """
1717 if text.endswith('\n'):
1718 text = text[:-len('\n')]
1719
1720 ltime = time.strftime("%X")
1721 msecs = (time.time() % 1) * 1000
1722 return '[%s.%04d] %s' % (ltime, msecs, text)
1723
1724
1725 @classmethod
1765
1766
1767
1768 -class Logger(object):
1769 """
1770 Logs text to standard output and/or a text file.
1771
1772 @type logfile: str or None
1773 @ivar logfile: Append messages to this text file.
1774
1775 @type verbose: bool
1776 @ivar verbose: C{True} to print messages to standard output.
1777
1778 @type fd: file
1779 @ivar fd: File object where log messages are printed to.
1780 C{None} if no log file is used.
1781 """
1782
1783 - def __init__(self, logfile = None, verbose = True):
1784 """
1785 @type logfile: str or None
1786 @param logfile: Append messages to this text file.
1787
1788 @type verbose: bool
1789 @param verbose: C{True} to print messages to standard output.
1790 """
1791 self.verbose = verbose
1792 self.logfile = logfile
1793 if self.logfile:
1794 self.fd = open(self.logfile, 'a+')
1795
1797 """
1798 Shows an error message to standard error
1799 if the log file can't be written to.
1800
1801 Used internally.
1802
1803 @type e: Exception
1804 @param e: Exception raised when trying to write to the log file.
1805 """
1806 from sys import stderr
1807 msg = "Warning, error writing log file %s: %s\n"
1808 msg = msg % (self.logfile, str(e))
1809 stderr.write(DebugLog.log_text(msg))
1810 self.logfile = None
1811 self.fd = None
1812
1814 """
1815 Writes the given text verbatim into the log file (if any)
1816 and/or standard input (if the verbose flag is turned on).
1817
1818 Used internally.
1819
1820 @type text: str
1821 @param text: Text to print.
1822 """
1823 if isinstance(text, unicode):
1824 text = text.encode('cp1252')
1825 if self.verbose:
1826 print text
1827 if self.logfile:
1828 try:
1829 self.fd.writelines('%s\n' % text)
1830 except IOError, e:
1831 self.__logfile_error(e)
1832
1833 - def log_text(self, text):
1834 """
1835 Log lines of text, inserting a timestamp.
1836
1837 @type text: str
1838 @param text: Text to log.
1839 """
1840 self.__do_log( DebugLog.log_text(text) )
1841
1843 """
1844 Log lines of text associated with a debug event.
1845
1846 @type event: L{Event}
1847 @param event: Event object.
1848
1849 @type text: str
1850 @param text: (Optional) Text to log. If no text is provided the default
1851 is to show a description of the event itself.
1852 """
1853 self.__do_log( DebugLog.log_event(event, text) )
1854
1856 """
1857 Log lines of text associated with the last Python exception.
1858 """
1859 self.__do_log( 'Exception raised: %s' % traceback.format_exc() )
1860
1862 """
1863 Determines if the logger will actually print anything when the log_*
1864 methods are called.
1865
1866 This may save some processing if the log text requires a lengthy
1867 calculation to prepare. If no log file is set and stdout logging
1868 is disabled, there's no point in preparing a log text that won't
1869 be shown to anyone.
1870
1871 @rtype: bool
1872 @return: C{True} if a log file was set and/or standard output logging
1873 is enabled, or C{False} otherwise.
1874 """
1875 return self.verbose or self.logfile
1876