Package Libs ::
Module libanalyze
|
|
1
2
3 """
4 (c) Immunity, Inc. 2004-2007
5
6
7 U{Immunity Inc.<http://www.immunityinc.com>}
8
9
10 """
11
12 __VERSION__ = '1.3'
13
14 import UserList
15 import debugger
16
17
18 RST_INVALID = 0
19 RST_VALUE = 1
20 RST_VFIXUP = 2
21 RST_INDIRECT = 3
22
23
24
25 DISASM_SIZE = 0
26 DISASM_DATA = 1
27 DISASM_TRACE = 2
28 DISASM_FILE = 3
29 DISASM_CODE = 4
30 DISASM_ALL = 5
31 DISASM_RTRACE = 6
32
33
34 C_TYPEMASK = 0xF0
35 C_CMD = 0x00
36 C_PSH = 0x10
37 C_POP = 0x20
38 C_MMX = 0x30
39 C_FLT = 0x40
40 C_JMP = 0x50
41 C_JMC = 0x60
42 C_CAL = 0x70
43 C_RET = 0x80
44 C_FLG = 0x90
45 C_RTF = 0xA0
46 C_REP = 0xB0
47 C_PRI = 0xC0
48 C_SSE = 0xD0
49 C_NOW = 0xE0
50 C_BAD = 0xF0
51
52
53 DEC_TYPEMASK = 0x1F
54 DEC_UNKNOWN = 0x00
55 DEC_BYTE = 0x01
56 DEC_WORD = 0x02
57 DEC_NEXTDATA = 0x03
58 DEC_DWORD = 0x04
59 DEC_FLOAT4 = 0x05
60 DEC_FWORD = 0x06
61 DEC_FLOAT8 = 0x07
62 DEC_QWORD = 0x08
63 DEC_FLOAT10 = 0x09
64 DEC_TBYTE = 0x0A
65 DEC_STRING = 0x0B
66 DEC_UNICODE = 0x0C
67 DEC_3DNOW = 0x0D
68 DEC_SSE = 0x0E
69 DEC_TEXT = 0x10
70 DEC_BYTESW = 0x11
71 DEC_NEXTCODE = 0x13
72 DEC_COMMAND = 0x1D
73 DEC_JMPDEST = 0x1E
74 DEC_CALLDEST = 0x1F
75
76 DEC_PROCMASK = 0x60
77 DEC_PROC = 0x20
78 DEC_PBODY = 0x40
79 DEC_PEND = 0x60
80
81 DEC_CHECKED = 0x80
82 DEC_SIGNED = 0x100
83
84 DECR_TYPEMASK = 0x3F
85 DECR_BYTE = 0x21
86 DECR_WORD = 0x22
87 DECR_DWORD = 0x24
88 DECR_QWORD = 0x28
89 DECR_FLOAT10 = 0x29
90 DECR_SEG = 0x2A
91 DECR_3DNOW = 0x2D
92 DECR_SSE = 0x2E
93
94 DECR_ISREG = 0x20
95 DEC_CONST = 0x40
96
97 Registers32BitsOrder = [ "EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI" ]
98 Registers16BitsOrder = [ "AX", "CX", "DX", "BX", "SP", "BP", "SI", "DI" ]
99 Registers8BitsOrder = [ "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH" ]
100
101 RegisterName = { (0,0,0,0,0,0,0,0):"", (1,0,0,0,0,0,0,0):"EAX",(0,1,0,0,0,0,0,0):"ECX",\
102 (0,0,1,0,0,0,0,0):"EDX", (0,0,0,1,0,0,0,0):"EBX",(0,0,0,0,1,0,0,0):"ESP",\
103 (0,0,0,0,0,1,0,0):"EBP", (0,0,0,0,0,0,1,0):"ESI", (0,0,0,0,0,0,0,1):"EDI"}
104
105 COUNT = 100
108 self.imm = imm
109 self.address = addr
110 self.operand = []
111
112
114 self.ip=opcode[0]
115 self.dump=opcode[1]
116 self.result=opcode[2]
117 self.comment=opcode[3]
118 self.opinfo=opcode[4]
119 self.cmdtype=opcode[5]
120 self.memtype=opcode[6]
121 self.nprefix=opcode[7]
122 self.indexed=opcode[8]
123 self.jmpconst=opcode[9]
124 self.jmptable=opcode[10]
125 self.adrconst=opcode[11]
126 self.immconst=opcode[12]
127 self.zeroconst=opcode[13]
128 self.fixupoffset=opcode[14]
129 self.fixupsize=opcode[15]
130 self.jmpaddr=opcode[16]
131 self.condition=opcode[17]
132 self.error=opcode[18]
133 self.warnings=opcode[19]
134 self.optype=opcode[20]
135 self.operandsize=opcode[21]
136 self.opsize=opcode[22]
137 self.opgood=opcode[23]
138 self.opaddr=opcode[24]
139 self.opdata=opcode[25]
140 self.operand=opcode[26]
141
142
143
144
145
146
147
148
149
150 self.regdata=opcode[27]
151 self.addrdata=opcode[28]
152 self.addrstatus=opcode[29]
153 self.regstack=opcode[30]
154
155
156
157
159 try:
160 return RegisterName[ self.operand[num][2] ]
161 except KeyError:
162 return "[]"
163
166
169
172
175
178
181
184
187
190
193
196
199
202
205
208
211
215
218
221
224
227
230
233
236
238 return self.zeroconst
239
241 return self.fixupoffset
242
244 return self.fixupsize
245
248
250 return self.condition
251
254
257
260
263
266
269
272
275
278
281
284
286 return self.addrstatus
287
290
293
296
297
298
299
301 return debugger.get_info_panel()
302
304 return debugger.get_variable( self.address )
305
307 return debugger.set_variable( self.address, variable_name )
308
309 -class Decode(UserList.UserList):
311 """
312 Internal Information of the Analyzed Code
313
314 @type address: DWORD
315 @param address: Address in the range of the analized code you want to retrieve
316 """
317 UserList.UserList.__init__(self)
318 self.address = address
319 self.data = debugger.find_decode( address )
320
322 try:
323 return ord( self.data[ i - self.address ] )
324 except IndexError:
325 raise IndexError, "Address 0x%08x not in this Decode" % i
326
328 self.data[ i - self.address ] = item
329
331 """
332 Check Whether or not the provided address is a destination for a jmp instruction
333
334 @type i: DWORD
335 @param i: Address to check
336
337 @rtype: BOOLEAN
338 @return: Whether or not the provided address is a destination for a jmp instruction
339 """
340 return ( self.__getitem__( i ) & DEC_TYPEMASK ) == DEC_JMPDEST
341
343 """
344 Check Whether or not the provided address is a destination for a call instruction
345
346 @type i: DWORD
347 @param i: Address to check
348
349 @rtype: BOOLEAN
350 @return: Whether or not the provided address is a destination for a call instruction
351 """
352 return ( self.__getitem__( i ) & DEC_TYPEMASK ) == DEC_CALLDEST
353
355 """
356 Check Whether or not the provided address has a command (regular opcode)
357
358 @type i: DWORD
359 @param i: Address to check
360
361 @rtype: BOOLEAN
362 @return: Whether or not the provided address a command (regular opcode)
363 """
364 return ( self.__getitem__( i ) & DEC_TYPEMASK ) == DEC_COMMAND
365
367 """
368 Check Whether or not the provided address is the begging of a Function
369
370 @type i: DWORD
371 @param i: Address to check
372
373 @rtype: BOOLEAN
374 @return: Whether or not the provided address is the begging of a Function
375 """
376 return ( self.__getitem__( i ) & DEC_PROCMASK ) == DEC_PROC
377
378 - def isFunctionBody(self, i):
379 """
380 Check Whether or not the provided address is part of a Function
381
382 @type i: DWORD
383 @param i: Address to check
384
385 @rtype: BOOLEAN
386 @return: Check Whether or not the provided address is part of a Function
387 """
388 return ( self.__getitem__( i ) & DEC_PROCMASK ) == DEC_PBODY
389
390
392 """
393 Class that contains information about a Function
394 """
396 """
397 Class that contains information about a Function
398
399 @type imm: Debbuger OBJECT
400 @param imm: Debbuger
401
402 @type start: DWORD
403 @param start: Address of the begging of the function
404 """
405 if not start:
406 raise Exception, "Wrong Function Address: 0x%08x" % start
407
408 self.start = start
409 self.imm = imm
410 self.bb = []
411 self.bbhash = {}
412
414 """
415 Change the start of a Function
416
417 @type address: DWORD
418 @param address: New address of the function
419 """
420 self.start = address
421
422
424 """
425 Get the Address of the Function
426
427 @rtype: DWORD
428 @return: Address of the function
429 """
430 return self.start
431
433 """
434 Get the name of the Function
435
436 @rtype: STRING
437 @return: Name of the Function
438 """
439 return self.imm.decodeAddress(self.start)
440
448
450 """
451 Get the end of the Function (Understanding end as the Basic Block with a ret inside)
452
453 @rtype: LIST of BasicBlock
454 @return: A list of all the basic block that end the function
455 """
456 ret = []
457 bb = self.getBasicBlocks()
458 for a in bb:
459 if a.isRet():
460 ret.append( a )
461 return ret
462
464 """
465 Find all the possible ret values on a function (Beta)
466 Note: This function only check the modifiers on a Ret BasicBlock, so the result might not be precise.
467
468 @type start: LIST OF OPCODE
469 @param start: Return all the possible modifiers of EAX
470 """
471 ret = []
472 endblocks = self.getEnd()
473 for bb in endblocks:
474 opcodes = bb.getInstructions(self.imm)
475
476
477 for a in range( len(opcodes)-1, 0, -1):
478 op = opcodes[a]
479 if op.getOperandRegister(0) == "EAX" and op.optype[0] == 36:
480 ret.append( op )
481 break
482 return ret
483
484
486 """
487 Check if the given address is part of the Function
488
489 @type address: DWORD
490 @param force: Address of the instruction to check
491
492 @rtype: BasicBlock object
493 @return: If true, returns the corresponding Basic block else returns None
494 """
495 bb = self.getBasicBlocks()
496 for b in bb:
497 if address >= b.start and address <= b.end:
498 return b
499 return None
500
502 """
503 Get basic block from the current Function
504
505 @type force: BOOLEAN
506 @param force: (Optional, Def: False) Force to Function to reparse the basic blocks
507
508 @rtype: LIST of BasicBlock objects
509 @return: Basic blocks of the current function
510
511
512 TODO: Recursion here is bad - we need to make this an iterative process with a work queue
513 """
514 if self.bb and not force:
515 return self.bb
516
517 op = None
518 if not self.imm.isAnalysed( self.start ):
519 self.imm.analyseCode( self.start )
520
521
522
523
524
525 self._getBB(self.start)
526
527 return self.bb
528
529
530
531
627
628
629
632 """
633 Basic Block class
634
635 @type start: DWORD
636 @param start: Address of the begging of the Basic Block
637
638 @type end: DWORD
639 @param end: Address of the end of the Basic Block
640 """
641 self.edgeamount = 0
642 self.start = start
643 self.end = end
644 self.calls = []
645
646 self.Function = None
647
648
649
652
655
658
661
663 """
664 Comparision by the start address of the BB
665 """
666 return cmp(self.start, other.start)
667
669 """
670 Change the start of a Basic Block
671
672 @type address: DWORD
673 @param address: New address of the Basic Block
674 """
675 self.start = address
676
679
681 self.falseedge = addr
682
684 if not self.edgeamount:
685 return (0,0)
686 elif self.edgeamount == 1:
687 if self.trueedge == 0:
688 return (0,0)
689 else:
690 return (self.trueedge,0)
691 else:
692 return ( self.trueedge, self.falseedge )
693
695 """
696 Get the 'true' Edge
697
698 @rtype: DWORD
699 @return: 'True' Edge of the Basic Block
700 """
701 if not self.edgeamount:
702 return None
703 elif self.edgeamount != 1:
704 return self.trueedge
705
707 """
708 Get the 'false' Edge
709
710 @rtype: DWORD
711 @return: 'False' Edge of the Basic Block (The 'false' edge, is not always present. Depends of the Basic Block)
712 """
713 if not self.edgeamount:
714 return None
715 elif self.edgeamount != 1:
716 return self.falseedge
717
719 """
720 Get the Edges of a Basic Block
721
722 @rtype: TUPLE of DWORD
723 @return: The Edge of the Basic Block (Might change depending of the basic block type)
724 """
725 if not self.edgeamount:
726 return ()
727 elif self.edgeamount == 1:
728 if self.trueedge == 0:
729 return ()
730 else:
731 return self.trueedge
732
734 """
735 Return the Size of the Basic Block
736
737 @rtype: DWORD
738 @return: Size of the Basic Block
739 """
740 return self.end - self.start
741
743 """
744 Change the end of a Basic Block
745
746 @type address: DWORD
747 @param address: New address of the Basic Block end
748 """
749
750 self.end = address
752 """
753 Get the limits of the basic block
754
755 @rtype: TUPLE OF DWORD
756 @return: (Beginning of BB, End of BB)
757 """
758 return ( self.start,self.end )
759
761 """
762 Get the begging of a Basic Block
763
764 @rtype: DWORD
765 @return: Beginning of the Basic Block
766 """
767 return self.start
768
770 """
771 Get the End of a Basic Block
772
773 @rtype: DWORD
774 @return: End of the Basic Block
775 """
776 return self.end
777
778
780 """
781 Get the disassembled instructions from a Basic Block
782
783 @type imm: Debugger OBJECT
784 @param imm: Debugger
785
786 @rtype: LIST of opCode OBJECT
787 @return: List of disassembled instructions
788 """
789 addr = self.start
790 instructions = []
791
792 while addr < self.end:
793 op = imm.disasm( addr )
794 instructions.append( op )
795 addr += op.getSize()
796
797 return instructions
798
800 """
801 Check if a Basic Block was created from an XREF
802
803 @rtype: BOOLEAN
804 @return: Whether the Basic Block was created from an XREF
805 """
806 return isinstance(self, XREFBasicBlock)
807
809 """
810 Check if a Basic Block was created from a Conditional Jump instruction
811
812 @rtype: BOOLEAN
813 @return: Whether the Basic Block was created from a Conditional Jump instruction
814 """
815 return isinstance(self, JMCBasicBlock)
816
818 """
819 Check if a Basic Block was created from a Jump instruction
820
821 @rtype: BOOLEAN
822 @return: Whether the Basic Block was created from a Jump instruction
823 """
824 return isinstance(self, JMPBasicBlock)
825
827 """
828 Check if a Basic Block was created from a RET instruction
829
830 @rtype: BOOLEAN
831 @return: Whether the Basic Block was created from a RET instruction
832 """
833 return isinstance(self, RETBasicBlock)
834
837 """
838 XREF Basic Block, Basic Block created from a code reference
839
840 @type start: DWORD
841 @param start: Address of the begging of the Basic Block
842
843 @type end: DWORD
844 @param end: Address of the end of the Basic Block
845 """
846 BasicBlock.__init__(self, start, end)
847 self.edgeamount = 1
848
851 """
852 Conditional Jump Basic Block, Basic Block created from a conditional jump instruction (branch node)
853
854 @type start: DWORD
855 @param start: Address of the begging of the Basic Block
856
857 @type end: DWORD
858 @param end: Address of the end of the Basic Block
859 """
860 BasicBlock.__init__(self, start, end)
861 self.edgeamount = 2
862
863
864
865
868 """
869 Jump Basic Block, Basic Block created from a jump instruction
870
871 @type start: DWORD
872 @param start: Address of the begging of the Basic Block
873
874 @type end: DWORD
875 @param end: Address of the end of the Basic Block
876 """
877 BasicBlock.__init__(self, start, end)
878 self.edgeamount = 1
879
882 """
883 RET Basic Block, Basic Block created from a RET instruction (exit node)
884
885 @type start: DWORD
886 @param start: Address of the begging of the Basic Block
887
888 @type end: DWORD
889 @param end: Address of the end of the Basic Block
890 """
891 BasicBlock.__init__(self, start, end)
892 self.edgeamount = 0
893
895 - def __init__(self, imm, func_address, tracedarg, shownonusersupplied = False):
896 self.imm = imm
897 self.func_address = func_address
898 self.tracedarg = tracedarg
899 self.shownonusersupplied = shownonusersupplied
900
902 idx = 0
903 stack =[]
904 address = self.func_address
905
906
907 while idx < COUNT:
908 op = self.imm.disasmBackward( address )
909 if op.isPush():
910 stack.append(1)
911 if len(stack) == self.tracedarg:
912 break
913 elif op.isPop():
914 if len(stack):
915 stack.pop(0)
916 else:
917 return
918 address = op.getAddress()
919 del op
920 idx += 1
921
922
923 if idx < COUNT:
924
925 dotraceback = True
926 if not op.isPush():
927
928 return ()
929
930
931
932 if op.getOperandRegister(0) == "":
933 if not self.shownonusersupplied:
934 return ()
935 else:
936 return (op, [])
937
938
939
940
941
942 elif op.getOperandRegister(0) == "EBP" and op.operand[0][3]:
943 dotraceback = False
944
945
946 show = []
947
948
949 if dotraceback:
950 self.modarg = []
951 self.visited = []
952
953 try:
954 self.traceArgBackWithDecode( op.getAddress(), op.operand[0][2] )
955 except IndexError:
956 op = self.traceArgBack( op.getAddress(), op.operand[0][2])
957 if op:
958 self.modarg.append(op)
959
960 newop = None
961
962 type = ""
963 for newop in self.modarg:
964 newop.type = ""
965
966
967 if newop.getOperandRegister(1) == "":
968 if self.shownonusersupplied or newop.isCall():
969 show.append( newop )
970 else:
971 return ()
972 else:
973 type = ""
974
975 if newop.getOperandRegister(1) == "EBP":
976 if newop.operand[1][3] < 0x80000000:
977 newop.type = "VARS"
978 else:
979 newop.type = "ARGS"
980
981 show.append( newop )
982
983 op.type = ""
984
985
986 if op.getOperandRegister(0) == "EBP":
987 if op.operand[0][3] < 0x80000000 and op.operand[0][3] != 0:
988 op.type = "<VARS>"
989 elif op.operand[0][3] > 0x80000000:
990 op.type = "<ARGS>"
991
992
993
994
995
996
997 return (op, show)
998
999 return ()
1000
1001
1002
1003
1004
1006 idx = 0
1007 decode = self.imm.findDecode( address )
1008
1009 while idx < COUNT:
1010 if address in self.visited:
1011 return 0
1012 op = self.imm.disasmBackward( address )
1013
1014 self.visited.append( address )
1015 if op.isJmp():
1016 return 0
1017 if op.getResult()[:3] in ("MOV", "XOR"):
1018
1019
1020 if op.operand[0][2] == register:
1021 self.modarg.append( op )
1022 return 0
1023
1024
1025
1026 elif register == (1,0,0,0,0,0,0,0) and op.isCall():
1027 self.modarg.append( op )
1028 return 0
1029
1030 if decode.isJmpDestination(address):
1031 for ref in self.imm.getXrefFrom( address ):
1032 self.traceArgBackWithDecode(ref[0], register)
1033
1034 address = op.getAddress()
1035 idx += 1
1036 if decode:
1037
1038 if decode.isFunctionStart( address ):
1039 del decode
1040 return None
1041 del op
1042
1043 del decode
1044 return None
1045
1046
1047
1048
1049
1050
1052 idx = 0
1053 decode = self.imm.findDecode( address )
1054
1055 while idx < COUNT:
1056 op = self.imm.disasmBackward( address )
1057 if op.getResult()[:3] == "MOV":
1058
1059
1060 if op.operand[0][2] == register:
1061 return op
1062
1063
1064
1065 elif register == (1,0,0,0,0,0,0,0) and op.isCall():
1066 return op
1067
1068 address = op.getAddress()
1069 idx += 1
1070 if decode:
1071
1072 if decode.isFunctionStart( address ):
1073 del decode
1074 return None
1075 del op
1076
1077 del decode
1078 return None
1079