| Home | Trees | Indices | Help |
|
|---|
|
|
1
2 '''
3 Contains generators that use a set of data (dictionaries) such as files, lists,
4 etc.
5
6 @author: Michael Eddington
7 @version: $Id: Peach.Generators.dictionary-pysrc.html 1138 2008-08-16 19:39:03Z meddingt $
8 '''
9
10 #
11 # Copyright (c) 2005-2007 Michael Eddington
12 # Copyright (c) 2004-2005 IOActive Inc.
13 #
14 # Permission is hereby granted, free of charge, to any person obtaining a copy
15 # of this software and associated documentation files (the "Software"), to deal
16 # in the Software without restriction, including without limitation the rights
17 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18 # copies of the Software, and to permit persons to whom the Software is
19 # furnished to do so, subject to the following conditions:
20 #
21 # The above copyright notice and this permission notice shall be included in
22 # all copies or substantial portions of the Software.
23 #
24 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 # SOFTWARE.
31 #
32
33 # Authors:
34 # Michael Eddington (mike@phed.org)
35
36 # $Id: Peach.Generators.dictionary-pysrc.html 1138 2008-08-16 19:39:03Z meddingt $
37
38 import types, static, sys, struct
39 sys.path.append("c:/projects/peach")
40 from Peach import generator, group
41 from Peach.group import GroupSequence
42 from Peach.generator import *
43 from Peach.Generators.block import Block3
44 from Peach.Generators.static import *
45
46 #__all__ = ['Dictionary', 'GeneratorList', 'GeneratorList2', 'List', 'BinaryList']
47
49 '''
50 DEPRICATED -- Use Flags2, it works better. This class is still around
51 for backwards compatability.
52 '''
55 '''
56 @type group: Group
57 @param group: Group to assign this generator to
58 @type flagSpecs: Array of integers
59 @param flagSpecs: Array of bit offset for corresponding flag
60 @type flagGenerators: Array of Generators
61 @param flagGenerators: Generators in this array produce flag values
62 @type flagBase: Number
63 @param flagBase: [optional] Base of flag (defaults to 0x0)
64 '''
65 Generator.__init__(self)
66 self.setGroup(group)
67
68 if flagSpecs == None:
69 flagSpecs = []
70 if flagGenerators == None:
71 flagGenerators = []
72
73 if len(flagSpecs) != len(flagGenerators):
74 raise Exception("Count of flagSpecs does not match flagGenerators")
75
76 self._flagSpecs = flagSpecs
77 self._flagGenerators = flagGenerators
78 self._flagBase = flagBase
79 self.flag = 0x00000000000000000000
80
81 self._calcFlag()
82
84
85 # Are we done? Only done if everyone is done
86
87 stop = True
88 for i in range(len(self._flagSpecs)):
89 try:
90 self._flagGenerators[i].next()
91 stop = False
92 except GeneratorCompleted:
93 pass
94
95 if stop == True:
96 raise GeneratorCompleted("Flags is done sir!")
97
98 # Otherwise figure out next flag varianet
99 self._calcFlag
100
102 self._flag = self._flagBase
103 for i in range(len(self._flagSpecs)):
104 self._flag |= int(self._flagGenerators[i].getValue()) << int(self._flagSpecs[i])
105
108
109
111 '''
112 Define the layout of flags and provide a generator for each. Each flag
113 has a position, length, and generator. The Flag itself also has a total
114 length and byte order (litte or big). If values generated for each field in
115 the flag are masked such as they always fit and do not affect other fields
116 in the flag.
117
118 Example:
119
120 >>> gen = Flags2(None, 8, [ [0, 1, Bit()], [4, 1, Bit()], [6, 2, List(None, [0, 1, 2])] ])
121 >>> print gen.getValue()
122 0
123 >>> gen.next()
124 >>> print gen.getValue()
125 81
126 >>> gen.next()
127 >>> print gen.getValue()
128 145
129 >>> gen.next()
130 >>> print gen.getValue()
131 209
132
133 '''
134
136 '''
137 @type group: Group
138 @param group: Group for this Generator
139 @type length: Integer
140 @type length: Length of flag field, must be 8, 16, 32, or 64.
141 @type flags: Array of Arrays
142 @param flags: Each sub-array must contain a position (zero based),
143 length (in bits), and a generator.
144 '''
145 SimpleGenerator.__init__(self, group)
146
147 if length % 2 != 0:
148 raise Exception("Invalid length argument. Length must be multiple of 2!")
149
150 for flag in flags:
151 if flag[0] > length:
152 raise Exception("Flag position larger then length")
153 if (flag[0] + flag[1]) > length:
154 raise Exception("Flag position + flag length larger then length")
155
156 self.length = length
157 self.flags = flags
158
159 # flags needs to contain position and length
160
162 done = True
163
164 for flag in self.flags:
165 try:
166 flag[2].next()
167 done = False
168 except GeneratorCompleted:
169 pass
170
171 if done:
172 raise GeneratorCompleted("Flags are done")
173
175 ret = 0
176
177 for flag in self.flags:
178 mask = 0x00 << self.length - (flag[0] + flag[1])
179
180 cnt = flag[0] + flag[1] - 1
181 for i in range(flag[1]):
182 #print "<< %d" % cnt
183 mask |= 1 << cnt
184 cnt -= 1
185
186 #print "Mask:",repr(mask)
187 flagValue = flag[2].getValue()
188 if flagValue == None or flagValue == 'None':
189 flagValue = 0
190
191 ret |= mask & (int(flagValue) << flag[0])
192
193 return ret
194
195
197 '''
198 Iterates through a collection of values stored in a file.
199 Possible uses could be to brute force passwords or try a set of
200 known bad values.
201 '''
202
203 _fileName = None
204 _fd = None
205 _currentValue = None
206
208 '''
209 @type group: Group
210 @param group: Group this Generator belongs to
211 @type fileName: string
212 @param fileName: Name of file use
213 '''
214 Generator.__init__(self)
215 self._fileName = fileName
216 self.setGroup(group)
217
219 '''
220 Get name of file.
221
222 @rtype: string
223 @return: name of file
224 '''
225 return self._fileName
226
228 '''
229 Set filename.
230
231 @type filename: string
232 @param filename: Filename to use
233 '''
234 self._fileName = filename
235
237 if self._fd == None:
238 self._fd = open(self._fileName, 'rb')
239 if self._fd == None:
240 raise Exception('Unable to open', self._fileName)
241
242 oldValue = self._currentValue
243 self._currentValue = self._fd.readline()
244 if self._currentValue == None or len(self._currentValue) == 0:
245 self._currentValue = oldValue
246 raise generator.GeneratorCompleted("Dictionary completed for file [%s]" % self._fileName)
247
248 self._currentValue = self._currentValue.rstrip("\r\n")
249
251 if self._fd == None:
252 self._fd = open(self._fileName, 'rb')
253 if self._fd == None:
254 raise Exception('Unable to open', self._fileName)
255
256 if self._currentValue == None:
257 self._currentValue = self._fd.readline()
258 self._currentValue = self._currentValue.rstrip("\r\n")
259
260 return self._currentValue
261
265
267 g = group.Group()
268 dict = Dictionary(g, 'samples/dict.txt')
269
270 try:
271 while g.next():
272 print dict.getValue()
273 except group.GroupCompleted:
274 pass
275
276 g.reset()
277
278 try:
279 while g.next():
280 print dict.getValue()
281 except group.GroupCompleted:
282 pass
283 unittest = staticmethod(unittest)
284
285
287 '''
288 Iterates through a specified list of values. When the end of the list is
289 reached a generator.GeneratorCompleted exceoption is raised. Last item
290 will be returned until reset is called.
291
292 Example:
293
294 >>> list = List(None, ['1', '2', '3'])
295 >>> list.getValue()
296 1
297 >>> list.next()
298 >>> list.getValue()
299 2
300 >>> list.next()
301 >>> list.getValue()
302 3
303
304 '''
305
306 _list = None
307 _curPos = 0
308
310 '''
311 @type group: Group
312 @param group: Group this Generator belongs to
313 @type list: list
314 @param list: List of values to iterate through
315 '''
316 Generator.__init__(self)
317 self.setGroup(group)
318 self._list = list
319 self._curPos = 0
320
321 if self._list == None:
322 self._list = []
323
325 self._curPos = 0
326
328 self._curPos += 1
329 if self._curPos >= len(self._list):
330 self._curPos -= 1
331 raise generator.GeneratorCompleted("List")
332
335
337 '''
338 Get current list of values.
339
340 @rtype: list
341 @return: Current list of values
342 '''
343 return self._list
344
346 '''
347 Set list of values.
348
349 @type list: list
350 @param list: List of values
351 '''
352 self._list = list
353
354 if self._list == None:
355 self._list = []
356
358 g = group.Group()
359 list = List(g, ['A', 'B', 'C', 'D'])
360
361 if list.getValue() != 'A':
362 raise Exception("List unittest failed 1")
363 g.next()
364 if list.getValue() != 'B':
365 raise Exception("List unittest failed 2")
366 g.next()
367 if list.getValue() != 'C':
368 raise Exception("List unittest failed 3")
369 g.next()
370 if list.getValue() != 'D':
371 raise Exception("List unittest failed 4")
372
373 try:
374 g.next()
375 raise Exception("List unittest failed 5")
376 except group.GroupCompleted:
377 pass
378
379 try:
380 g.next()
381 raise Exception("List unittest failed 5")
382 except group.GroupCompleted:
383 pass
384
385 if list.getValue() != 'D':
386 raise Exception("List unittest failed 6")
387
388 list = List(g, [1, 2, 3, 4, 5])
389
390 try:
391 while g.next():
392 print list.getValue()
393 except group.GroupCompleted:
394 pass
395 unittest = staticmethod(unittest)
396
397
399 '''
400 Iterates through a specified list of binary values. When the end
401 of the list is reached a generator.GeneratorCompleted exceoption
402 is raised.
403 '''
404
405 _packString = 'b'
406
408 '''
409 @type group: Group
410 @param group: Group this Generator belongs to
411 @type list: list
412 @param list: List of values to iterate through
413 @type packString: string
414 @param packString: Defaults to 'b'
415 '''
416 Generator.__init__(self)
417 List.__init__(self, group, list)
418 self._packString = packString
419
421 out = self._list[self._curPos]
422 if self._packString != None:
423 return struct.pack(self._packString, out)
424
425 return out
426
428 g = group.Group()
429 list = BinaryList(g, [0, 1, 2, 3], '>B')
430
431 try:
432 while g.next():
433 print list.getValue()
434 except group.GroupCompleted:
435 pass
436 unittest = staticmethod(unittest)
437
438
440 '''Internal helper class'''
441
443 self._listOfLists = listOfLists
444 self._pos = 0
445 self._block
446 self._block = Block(self._listOfLists[self._pos])
447
450
452 if (self._pos + 1) >= len(self._listOfLists):
453 raise generator.GeneratorCompleted("ArrayList")
454
455 self._pos += 1
456 self._block = Block(self._listOfLists[self._pos])
457
460
461 import random
462
464 '''
465 Will choose from a list of Generators. See use cases below for
466 further description of operation:
467
468 Case 1 - minOccurs and maxOccurs are 1. In this case a single
469 generator is selected N times.
470 Case 2 - minOccurs is 1 and maxOccurs is 100. In this case
471 N sets of random items are chosen.
472 Case 3 - minOccurs is 0 and maxOccurs is 1. You will always
473 get 1 case were 0 items are chosen and 1 case of
474 other items chosen
475
476 Currently N == 10.
477
478 '''
479
481 '''
482 @type group: Group
483 @param group: Group this Generator belongs to
484 @type list: list
485 @param list: List of Generators to choose frome
486 @type name: string
487 @type name: Name of generator
488 '''
489
490 generator.Generator.__init__(self)
491
492 self.n = n
493 self.minOccurs = minOccurs
494 self.maxOccurs = maxOccurs
495 self._curPos = 0
496 self.setName(name)
497
498 if group != None:
499 self.setGroup(group)
500
501 self._groups = groups
502 self._list = list
503
504 if self._list == None or self._groups == None:
505 raise Exception("groups and list cannot be None.")
506
507 if len(self._list) != len(self._groups):
508 raise Exception("groups and list must have same number of items!")
509
510 if len(self._list) < self.maxOccurs:
511 self.maxOccurs = len(self._list)
512
513 # handle case 1 - minOccurs == 1 and maxOccurs == 1
514 if self.minOccurs == 1 and self.maxOccurs == 1:
515
516 theGroups = []
517 theItems = []
518
519 # select a single generator
520 if len(self._list) <= self.n:
521 sample = xrange(len(self._list))
522 else:
523 sample = random.sample(xrange(len(self._list)), self.n)
524
525 for n in sample:
526 theGroups.append(self._groups[n])
527 theItems.append(self._list[n])
528
529 self.generator = GeneratorList2(None, theGroups, theItems)
530
531 # handle case 3 -- minOccurs == 0, maxOccurs == 1
532 elif self.minOccurs == 0 and self.maxOccurs == 1:
533 theGroups = []
534 theItems = []
535
536 if self.maxOccurs - self.minOccurs <= self.n:
537 sample = xrange(self.maxOccurs - self.minOccurs)
538
539 else:
540 sample = random.sample(xrange(len(self._list)), self.n)
541
542 for n in sample:
543 theGroups.append(self._groups[n])
544 theItems.append(self._list[n])
545
546 self.generator = GeneratorList(None, [
547 Static(''),
548 GeneratorList2(None, theGroups, theItems)
549 ])
550
551 # handle case 2 - minOccurs == 1, maxOccurs == 100
552 else:
553
554 theGeneratorLists = []
555 sample = None
556
557 if self.maxOccurs - self.minOccurs <= self.n:
558 sample = xrange(self.maxOccurs - self.minOccurs)
559
560 else:
561 sample = random.sample(xrange(self.minOccurs, self.maxOccurs), self.n)
562
563 for n in sample:
564
565 theGroups = []
566 theItems = []
567
568 subSample = random.sample(xrange(len(self._list)), n)
569 subSample.sort()
570
571 # remove dups
572 old = -1
573 newSample = []
574 for x in subSample:
575 if x != old:
576 old = x
577 newSample.append(x)
578
579 subSample = newSample
580 for x in subSample:
581 theGroups.append(self._groups[x])
582 theItems.append(self._list[x])
583
584 theGeneratorLists.append(Block3(GroupSequence(theGroups), theItems))
585
586 self.generator = GeneratorList(None, theGeneratorLists)
587
590
593
596
597
598
600 '''
601 Iterates through a specified list of generators. When the end of the list is
602 reached a generator.GeneratorCompleted exceoption is raised.
603
604 NOTE: Generators are incremented by this object so DON'T SET A GROUP ON THEM!
605
606 NOTE: We only increment to next generator in list when the GeneratorCompleted
607 exception has been thrown from current generator. This allows one todo kewl
608 things like have 2 static generators, then a dictionary, then a repeater.
609
610 Example:
611
612 >>> gen = GeneratorList(None, [
613 ... Static('1'),
614 ... Static('2'),
615 ... Static('3')
616 ... ])
617 >>> print gen.getValue()
618 1
619 >>> gen.next()
620 >>> print gen.getValue()
621 2
622 >>> gen.next()
623 >>> print gen.getValue()
624 3
625 >>> try:
626 ... gen.next() # Will raise GeneraterCompleted exception
627 ... except:
628 ... pass
629 >>> print gen.getValue() # notice we get last value again.
630 3
631
632 Example:
633
634 >>> gen = GeneratorList(None, [
635 ... Repeater(None, Static('Peach'), 1, 2),
636 ... Static('Hello World')
637 ... ])
638 >>> print gen.getValue()
639 Peach
640 >>> gen.next()
641 >>> print gen.getValue()
642 PeachPeach
643 >>> gen.next()
644 >>> print gen.getValue()
645 Hello World
646 >>> try:
647 ... gen.next() # Will raise GeneraterCompleted exception
648 ... except:
649 ... pass
650 >>> print gen.getValue() # notice we get last value again.
651 Hello World
652
653 Bad Example, group set on Generator in list:
654
655 >>> group = Group()
656 >>> gen = GeneratorList(group, [
657 ... Repeater(group, Static('Peach'), 1, 2),
658 ... Static('Hello World')
659 ... ])
660 >>> print gen.getValue()
661 Peach
662 >>> group.next()
663 >>> print gen.getValue()
664 Hello World
665 >>> try:
666 ... gen.next() # Will raise GeneraterCompleted exception
667 ... except:
668 ... pass
669 >>> print gen.getValue() # notice we get last value again.
670 Hello World
671
672 '''
673
675 '''
676 @type group: Group
677 @param group: Group this Generator belongs to
678 @type list: list
679 @param list: List of Generators to iterate through
680 @type name: string
681 @type name: Name of generator
682 '''
683
684 Generator.__init__(self)
685
686 self._curPos = 0
687
688 self.setName(name)
689
690 if group != None:
691 self.setGroup(group)
692
693 self._list = list
694
695 if self._list == None:
696 self._list = []
697
699 try:
700 self._list[self._curPos].next()
701 except generator.GeneratorCompleted:
702 #print "Peach.dictionary.GeneratorList2.next(): caught GeneratorCompleted"
703 self._curPos += 1
704
705 if self._curPos >= len(self._list):
706 self._curPos -= 1
707 #print "Peach.dictionary.GeneratorList2.next(): throwing complete exceptions"
708 raise generator.GeneratorCompleted("Peach.dictionary.GeneratorList")
709
715
717 # Use .getValue to make sure we
718 # pick up any transformers
719 value = self._list[self._curPos].getValue()
720 if value is None:
721 print "Peach.dictionary.GeneratorList.getRawValue(): getValue() was None"
722 print "Peach.dictionary.GeneratorList.getRawValue(): Name is %s" % self._list[self._curPos].getName()
723 print "Peach.dictionary.GeneratorList.getRawValue(): Type is %s" % self._list[self._curPos]
724
725 return value
726
728 '''
729 Get list of Generators.
730
731 @rtype: list
732 @return: list of Generators
733 '''
734 return self._list
735
737 '''
738 Set list of Generators.
739
740 @type list: list
741 @param list: List of Generators
742 '''
743 self._list = list
744
745 if self._list == None:
746 self._list = []
747
749 g = group.Group()
750 list = GeneratorList(g, [static.Static('A'), static.Static('B'), static.Static('C')])
751
752 try:
753 while g.next():
754 print list.getValue()
755 except group.GroupCompleted:
756 pass
757 unittest = staticmethod(unittest)
758
759
761 '''
762 Iterates through a specified list of generators (different group control).
763 When the end of the list is reached a generator.GeneratorCompleted exceoption
764 is raised.
765
766 This generator differs from GeneratorList by allowing one group to
767 drive the rounds, but associating different sub groups to each generator.
768 When the master group is incremented the group for the current generator is
769 also incremented. This allows more complex control of how generators
770 create data.
771
772 NOTE: We only increment to next generator in list when the GeneratorCompleted
773 exception has been thrown from current generator. This allows one todo kewl
774 things like have 2 static generators, then a dictionary, then a repeater.
775
776 Example:
777
778 >>> groupA = Group()
779 >>> groupBA = Group()
780 >>> groupBB = Group()
781 >>> groupB = GroupForeachDo(groupBA, groupBB)
782 >>>
783 >>> gen = GeneratorList2(None, [groupA, groupB], [
784 ... Repeater(groupA, Static('A'), 1, 1, 3),
785 ... Block([
786 ... List(groupBA, [':', '\\', '/']),
787 ... Repeater(groupBB, Static('B'), 1, 1, 3)
788 ... ])
789 ... ])
790 >>>
791 >>> print gen.getValue()
792 A
793 >>> gen.next()
794 >>> gen.getValue()
795 AA
796 >>> gen.next()
797 >>> gen.getValue()
798 AAA
799 >>> gen.next()
800 >>> gen.getValue()
801 :B
802 >>> gen.next()
803 >>> gen.getValue()
804 :BB
805 >>> gen.next()
806 >>> gen.getValue()
807 :BBB
808 >>> gen.next()
809 >>> gen.getValue()
810 \B
811 >>> gen.next()
812 >>> gen.getValue()
813 \BB
814 >>> gen.next()
815 >>> gen.getValue()
816 \BBB
817 >>> gen.next()
818 >>> gen.getValue()
819 /B
820 >>> gen.next()
821 >>> gen.getValue()
822 /BB
823 >>> gen.next()
824 >>> gen.getValue()
825 /BBB
826
827 @see: L{GeneratorList}
828 '''
829
830 #_groupList = None
831
833 '''
834 @type group: Group
835 @param group: Group this Generator belongs to
836 @type groupList: list
837 @param groupList: List of Groups to use on generators
838 @type list: list
839 @param list: List of Generators to iterate through
840 @type name: String
841 @param name: [optional] Name for this Generator. Used for debugging.
842 '''
843 Generator.__init__(self)
844 self.setGroup(group)
845 self.generators = self._list = list
846 self.groups = self._groupList = groupList
847 self.setName(name)
848 self._curPos = 0
849
850 if self._list == None:
851 self._list = []
852 if self._groupList == None:
853 self._groupList = []
854
855 self.reset()
856
858 try:
859 self._groupList[self._curPos].next()
860 #print "GeneratorList2.next(): ..."
861 except group.GroupCompleted:
862 #print "GeneratorList2.next(): Next pos [%d]" % self._curPos
863 #print "GeneratorList2.next(): %d items in our list" % len(self._list)
864 self._curPos += 1
865 if self._curPos < len(self._list):
866 self._groupList[self._curPos].reset()
867 #except:
868 # print "GeneratorList2.next(): Caught some other exception"
869
870 if self._curPos >= len(self._list):
871 self._curPos -= 1
872 #print "%s: GeneratorList2.next() Completed" % name
873 raise generator.GeneratorCompleted("Peach.dictionary.GeneratorList2")
874
876 '''
877 Set list of Groups.
878
879 @type list: list
880 @param list: List of Groups
881 '''
882 self._groupList = list
883
884 if self._groupList == None:
885 self._groupList = []
886
888 self._curPos = 0
889
890 for i in self._list:
891 i.reset()
892
893 for i in self._groupList:
894 i.reset()
895
897 g = group.Group()
898 list = GeneratorList2(g, [static.Static('A'), static.Static('B'), static.Static('C')])
899
900 try:
901 while g.next():
902 print list.getValue()
903 except group.GroupCompleted:
904 pass
905 unittest = staticmethod(unittest)
906
907
909 '''
910 Provides a mechanism to create in effect a group of GeneratorList2's that
911 will progress and increment together drivin by the master of the group. This
912 Generator is the Group Master generator and controls the slaves of the
913 group.
914
915 This generator comes in handy when you have two bits of data that are
916 logically linked but in separate places. An example would be a length of
917 data being generated. Both values are parameters and generated separaetly