|
Package Libs ::
Module libanalize
|
|
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 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",\
98 (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",\
99 (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"}
100
101 COUNT = 100
104 self.imm = imm
105 self.address = addr
106 self.operand = []
107
108
110 self.ip=opcode[0]
111 self.dump=opcode[1]
112 self.result=opcode[2]
113 self.comment=opcode[3]
114 self.opinfo=opcode[4]
115 self.cmdtype=opcode[5]
116 self.memtype=opcode[6]
117 self.nprefix=opcode[7]
118 self.indexed=opcode[8]
119 self.jmpconst=opcode[9]
120 self.jmptable=opcode[10]
121 self.adrconst=opcode[11]
122 self.immconst=opcode[12]
123 self.zeroconst=opcode[13]
124 self.fixupoffset=opcode[14]
125 self.fixupsize=opcode[15]
126 self.jmpaddr=opcode[16]
127 self.condition=opcode[17]
128 self.error=opcode[18]
129 self.warnings=opcode[19]
130 self.optype=opcode[20]
131 self.operandsize=opcode[21]
132 self.opsize=opcode[22]
133 self.opgood=opcode[23]
134 self.opaddr=opcode[24]
135 self.opdata=opcode[25]
136
137
138
139
140
141
142 self.operand=opcode[26]
143
144
145 self.regdata=opcode[27]
146 self.addrdata=opcode[28]
147 self.addrstatus=opcode[29]
148 self.regstack=opcode[30]
149
150
151
152
154 try:
155 return RegisterName[ self.operand[num][2] ]
156 except KeyError:
157 return "[]"
158
160 return self.ip
161
163 return self.address
164
166 return self.dump
167
169 return self.result
170
172 return self.result
173
175 return self.comment
176
178 return self.opinfo
179
182
185
188
191
194
197
200
203
205 return self.cmdtype
206
210
212 return self.memtype
213
215 return self.nprefix
216
218 return self.indexed
219
221 return self.jmpconst
222
224 return self.jmptable
225
227 return self.adrconst
228
230 return self.immconst
231
233 return self.zeroconst
234
236 return self.fixupoffset
237
239 return self.fixupsize
240
242 return self.jmpaddr
243
245 return self.condition
246
249
251 return self.warnings
252
254 return self.optype
255
257 return self.opsize
258
260 return self.opsize
261
263 return self.opgood
264
266 return self.opaddr
267
269 return self.opdata
270
272 return self.regdata
273
275 return self.regdata
276
278 return self.addrdata
279
281 return self.addrstatus
282
284 return self.regstack
285
287 return self.regstack
288
290 return "deprecated"
291
292
293
294
296 return debugger.Getinfopanel()
297
298 -class Decode(UserList.UserList):
300 """
301 Internal Information of the Analyzed Code
302
303 @type address: DWORD
304 @param address: Address in the range of the analized code you want to retrieve
305 """
306 UserList.UserList.__init__(self)
307 self.address = address
308 self.data = debugger.FindDecode( address )
309
311 try:
312 return ord( self.data[ i - self.address ] )
313 except IndexError:
314 raise IndexError, "Address 0x%08x not in this Decode" % i
315
317 self.data[ i - self.address ] = item
318
320 """
321 Check Whether or not the provided address is a destination for a jmp instruction
322
323 @type i: DWORD
324 @param i: Address to check
325
326 @rtype: BOOLEAN
327 @return: Whether or not the provided address is a destination for a jmp instruction
328 """
329 return ( self.__getitem__( i ) & DEC_TYPEMASK ) == DEC_JMPDEST
330
332 """
333 Check Whether or not the provided address is a destination for a call instruction
334
335 @type i: DWORD
336 @param i: Address to check
337
338 @rtype: BOOLEAN
339 @return: Whether or not the provided address is a destination for a call instruction
340 """
341 return ( self.__getitem__( i ) & DEC_TYPEMASK ) == DEC_CALLDEST
342
344 """
345 Check Whether or not the provided address has a command (regular opcode)
346
347 @type i: DWORD
348 @param i: Address to check
349
350 @rtype: BOOLEAN
351 @return: Whether or not the provided address a command (regular opcode)
352 """
353 return ( self.__getitem__( i ) & DEC_TYPEMASK ) == DEC_COMMAND
354
356 """
357 Check Whether or not the provided address is the begging of a Function
358
359 @type i: DWORD
360 @param i: Address to check
361
362 @rtype: BOOLEAN
363 @return: Whether or not the provided address is the begging of a Function
364 """
365 return ( self.__getitem__( i ) & DEC_PROCMASK ) == DEC_PROC
366
367 - def isFunctionBody(self, i):
368 """
369 Check Whether or not the provided address is part of a Function
370
371 @type i: DWORD
372 @param i: Address to check
373
374 @rtype: BOOLEAN
375 @return: Check Whether or not the provided address is part of a Function
376 """
377 return ( self.__getitem__( i ) & DEC_PROCMASK ) == DEC_PBODY
378
379
381 """
382 Class that contains information about a Function
383 """
385 """
386 Class that contains information about a Function
387
388 @type imm: Debbuger OBJECT
389 @param imm: Debbuger
390
391 @type start: DWORD
392 @param start: Address of the begging of the function
393 """
394 if not start:
395 raise Exception, "Wrong Function Address: 0x%08x" % start
396
397 self.start = start
398 self.imm = imm
399 self.bb = []
400 self.bbhash = {}
401
403 """
404 Change the start of a Function
405
406 @type address: DWORD
407 @param address: New address of the function
408 """
409 self.start = address
410
411
413 """
414 Get the Address of the Function
415
416 @rtype: DWORD
417 @return: Address of the function
418 """
419 return self.start
420
422 """
423 Get the name of the Function
424
425 @rtype: STRING
426 @return: Name of the Function
427 """
428 return self.imm.decodeAddress(self.start)
429
437
439 """
440 Get the end of the Function (Understanding end as the Basic Block with a ret inside)
441
442 @rtype: LIST of BasicBlock
443 @return: A list of all the basic block that end the function
444 """
445 ret = []
446 bb = self.getBasicBlocks()
447 for a in bb:
448 if a.isRet():
449 ret.append( a )
450 return ret
451
453 """
454 Find all the possible ret values on a function (Beta)
455 Note: This function only check the modifiers on a Ret BasicBlock, so the result might not be precise.
456
457 @type start: LIST OF OPCODE
458 @param start: Return all the possible modifiers of EAX
459 """
460 ret = []
461 endblocks = self.getEnd()
462 for bb in endblocks:
463 opcodes = bb.getInstructions(self.imm)
464
465
466 for a in range( len(opcodes)-1, 0, -1):
467 op = opcodes[a]
468 if op.getOperandRegister(0) == "EAX" and op.optype[0] == 36:
469 ret.append( op )
470 break
471 return ret
472
473
475 """
476 Check if the given address is part of the Function
477
478 @type address: DWORD
479 @param force: Address of the instruction to check
480
481 @rtype: BasicBlock object
482 @return: If true, returns the corresponding Basic block else returns None
483 """
484 bb = self.getBasicBlocks()
485 for b in bb:
486 if address >= b.start and address <= b.end:
487 return b
488 return None
489
491 """
492 Get basic block from the current Function
493
494 @type force: BOOLEAN
495 @param force: (Optional, Def: False) Force to Function to reparse the basic blocks
496
497 @rtype: LIST of BasicBlock objects
498 @return: Basic blocks of the current function
499
500
501 TODO: Recursion here is bad - we need to make this an iterative process with a work queue
502 """
503 if self.bb and not force:
504 return self.bb
505
506 op = None
507 if not self.imm.isAnalysed( self.start ):
508 self.imm.analyseCode( self.start )
509
510
511
512
513
514 self._getBB(self.start)
515
516 return self.bb
517
518
519
520
616
617
618
621 """
622 Basic Block class
623
624 @type start: DWORD
625 @param start: Address of the begging of the Basic Block
626
627 @type end: DWORD
628 @param end: Address of the end of the Basic Block
629 """
630 self.edgeamount = 0
631 self.start = start
632 self.end = end
633 self.calls = []
634
635 self.Function = None
636
637
638
641
644
646 self.calls = calls
647
649 return self.calls
650
652 """
653 Comparision by the start address of the BB
654 """
655 return cmp(self.start, other.start)
656
658 """
659 Change the start of a Basic Block
660
661 @type address: DWORD
662 @param address: New address of the Basic Block
663 """
664 self.start = address
665
667 self.trueedge = addr
668
670 self.falseedge = addr
671
673 if not self.edgeamount:
674 return (0,0)
675 elif self.edgeamount == 1:
676 if self.trueedge == 0:
677 return (0,0)
678 else:
679 return (self.trueedge,0)
680 else:
681 return ( self.trueedge, self.falseedge )
682
684 """
685 Get the 'true' Edge
686
687 @rtype: DWORD
688 @return: 'True' Edge of the Basic Block
689 """
690 if not self.edgeamount:
691 return None
692 elif self.edgeamount != 1:
693 return self.trueedge
694
696 """
697 Get the 'false' Edge
698
699 @rtype: DWORD
700 @return: 'False' Edge of the Basic Block (The 'false' edge, is not always present. Depends of the Basic Block)
701 """
702 if not self.edgeamount:
703 return None
704 elif self.edgeamount != 1:
705 return self.falseedge
706
708 """
709 Get the Edges of a Basic Block
710
711 @rtype: TUPLE of DWORD
712 @return: The Edge of the Basic Block (Might change depending of the basic block type)
713 """
714 if not self.edgeamount:
715 return ()
716 elif self.edgeamount == 1:
717 if self.trueedge == 0:
718 return ()
719 else:
720 return self.trueedge
721
723 """
724 Return the Size of the Basic Block
725
726 @rtype: DWORD
727 @return: Size of the Basic Block
728 """
729 return self.end - self.start
730
732 """
733 Change the end of a Basic Block
734
735 @type address: DWORD
736 @param address: New address of the Basic Block end
737 """
738
739 self.end = address
741 """
742 Get the limits of the basic block
743
744 @rtype: TUPLE OF DWORD
745 @return: (Beginning of BB, End of BB)
746 """
747 return ( self.start,self.end )
748
750 """
751 Get the begging of a Basic Block
752
753 @rtype: DWORD
754 @return: Beginning of the Basic Block
755 """
756 return self.start
757
759 """
760 Get the End of a Basic Block
761
762 @rtype: DWORD
763 @return: End of the Basic Block
764 """
765 return self.end
766
767
769 """
770 Get the disassembled instructions from a Basic Block
771
772 @type imm: Debugger OBJECT
773 @param imm: Debugger
774
775 @rtype: LIST of opCode OBJECT
776 @return: List of disassembled instructions
777 """
778 addr = self.start
779 instructions = []
780
781 while addr < self.end:
782 op = imm.Disasm( addr )
783 instructions.append( op )
784 addr += op.getSize()
785
786 return instructions
787
789 """
790 Check if a Basic Block was created from an XREF
791
792 @rtype: BOOLEAN
793 @return: Whether the Basic Block was created from an XREF
794 """
795 return isinstance(self, XREFBasicBlock)
796
798 """
799 Check if a Basic Block was created from a Conditional Jump instruction
800
801 @rtype: BOOLEAN
802 @return: Whether the Basic Block was created from a Conditional Jump instruction
803 """
804 return isinstance(self, JMCBasicBlock)
805
807 """
808 Check if a Basic Block was created from a Jump instruction
809
810 @rtype: BOOLEAN
811 @return: Whether the Basic Block was created from a Jump instruction
812 """
813 return isinstance(self, JMPBasicBlock)
814
816 """
817 Check if a Basic Block was created from a RET instruction
818
819 @rtype: BOOLEAN
820 @return: Whether the Basic Block was created from a RET instruction
821 """
822 return isinstance(self, RETBasicBlock)
823
826 """
827 XREF Basic Block, Basic Block created from a code reference
828
829 @type start: DWORD
830 @param start: Address of the begging of the Basic Block
831
832 @type end: DWORD
833 @param end: Address of the end of the Basic Block
834 """
835 BasicBlock.__init__(self, start, end)
836 self.edgeamount = 1
837
840 """
841 Conditional Jump Basic Block, Basic Block created from a conditional jump instruction (branch node)
842
843 @type start: DWORD
844 @param start: Address of the begging of the Basic Block
845
846 @type end: DWORD
847 @param end: Address of the end of the Basic Block
848 """
849 BasicBlock.__init__(self, start, end)
850 self.edgeamount = 2
851
852
853
854
857 """
858 Jump Basic Block, Basic Block created from a jump instruction
859
860 @type start: DWORD
861 @param start: Address of the begging of the Basic Block
862
863 @type end: DWORD
864 @param end: Address of the end of the Basic Block
865 """
866 BasicBlock.__init__(self, start, end)
867 self.edgeamount = 1
868
871 """
872 RET Basic Block, Basic Block created from a RET instruction (exit node)
873
874 @type start: DWORD
875 @param start: Address of the begging of the Basic Block
876
877 @type end: DWORD
878 @param end: Address of the end of the Basic Block
879 """
880 BasicBlock.__init__(self, start, end)
881 self.edgeamount = 0
882
884 - def __init__(self, imm, func_address, tracedarg, shownonusersupplied = False):
885 self.imm = imm
886 self.func_address = func_address
887 self.tracedarg = tracedarg
888 self.shownonusersupplied = shownonusersupplied
889
891 idx = 0
892 stack =[]
893 address = self.func_address
894
895
896 while idx < COUNT:
897 op = self.imm.disasmBackward( address )
898 if op.isPush():
899 stack.append(1)
900 if len(stack) == self.tracedarg:
901 break
902 elif op.isPop():
903 if len(stack):
904 stack.pop(0)
905 else:
906 return
907 address = op.getAddress()
908 del op
909 idx += 1
910
911
912 if idx < COUNT:
913
914 dotraceback = True
915 if not op.isPush():
916
917 return ()
918
919
920
921 if op.getOperandRegister(0) == "":
922 if not self.shownonusersupplied:
923 return ()
924 else:
925 return (op, [])
926
927
928
929
930
931 elif op.getOperandRegister(0) == "EBP" and op.operand[0][3]:
932 dotraceback = False
933
934
935 show = []
936
937
938 if dotraceback:
939 self.modarg = []
940 self.visited = []
941
942 try:
943 self.traceArgBackWithDecode( op.getAddress(), op.operand[0][2] )
944 except IndexError:
945 op = self.traceArgBack( op.getAddress(), op.operand[0][2])
946 if op:
947 self.modarg.append(op)
948
949 newop = None
950
951 type = ""
952 for newop in self.modarg:
953 newop.type = ""
954
955
956 if newop.getOperandRegister(1) == "":
957 if self.shownonusersupplied or newop.isCall():
958 show.append( newop )
959 else:
960 return ()
961 else:
962 type = ""
963
964 if newop.getOperandRegister(1) == "EBP":
965 if newop.operand[1][3] < 0x80000000:
966 newop.type = "VARS"
967 else:
968 newop.type = "ARGS"
969
970 show.append( newop )
971
972 op.type = ""
973
974
975 if op.getOperandRegister(0) == "EBP":
976 if op.operand[0][3] < 0x80000000 and op.operand[0][3] != 0:
977 op.type = "<VARS>"
978 elif op.operand[0][3] > 0x80000000:
979 op.type = "<ARGS>"
980
981
982
983
984
985
986 return (op, show)
987
988 return ()
989
990
991
992
993
995 idx = 0
996 decode = self.imm.findDecode( address )
997
998 while idx < COUNT:
999 if address in self.visited:
1000 return 0
1001 op = self.imm.disasmBackward( address )
1002
1003 self.visited.append( address )
1004 if op.isJmp():
1005 return 0
1006 if op.getResult()[:3] in ("MOV", "XOR"):
1007
1008
1009 if op.operand[0][2] == register:
1010 self.modarg.append( op )
1011 return 0
1012
1013
1014
1015 elif register == (1,0,0,0,0,0,0,0) and op.isCall():
1016 self.modarg.append( op )
1017 return 0
1018
1019 if decode.isJmpDestination(address):
1020 for ref in self.imm.getXrefFrom( address ):
1021 self.traceArgBackWithDecode(ref[0], register)
1022
1023 address = op.getAddress()
1024 idx += 1
1025 if decode:
1026
1027 if decode.isFunctionStart( address ):
1028 del decode
1029 return None
1030 del op
1031
1032 del decode
1033 return None
1034
1035
1036
1037
1038
1039
1041 idx = 0
1042 decode = self.imm.findDecode( address )
1043
1044 while idx < COUNT:
1045 op = self.imm.disasmBackward( address )
1046 if op.getResult()[:3] == "MOV":
1047
1048
1049 if op.operand[0][2] == register:
1050 return op
1051
1052
1053
1054 elif register == (1,0,0,0,0,0,0,0) and op.isCall():
1055 return op
1056
1057 address = op.getAddress()
1058 idx += 1
1059 if decode:
1060
1061 if decode.isFunctionStart( address ):
1062 del decode
1063 return None
1064 del op
1065
1066 del decode
1067 return None
1068