| Trees | Indices | Help |
|
|---|
|
|
1 #!/usr/bin/env python
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 # REGISTER STATUS
18 RST_INVALID = 0 # Register undefined
19 RST_VALUE = 1 # Register contains regdata
20 RST_VFIXUP = 2 # Reg contains regdata that is fixup
21 RST_INDIRECT = 3 # Register contains [regdata]
22
23
24 # DISASM MODE
25 DISASM_SIZE = 0 # Determine command size only
26 DISASM_DATA = 1 # Determine size and analysis data
27 DISASM_TRACE = 2 # Trace integer registers
28 DISASM_FILE = 3 # Disassembly, no symbols/registers
29 DISASM_CODE = 4 # Disassembly, registers undefined
30 DISASM_ALL = 5 # Completely disassembly
31 DISASM_RTRACE = 6 # Disassemble with run-trace registers
32
33 # Types for Opcode
34 C_TYPEMASK = 0xF0 # Mask for command type
35 C_CMD = 0x00 # Ordinary instruction
36 C_PSH = 0x10 # PUSH instruction
37 C_POP = 0x20 # POP instruction
38 C_MMX = 0x30 # MMX instruction
39 C_FLT = 0x40 # FPU instruction
40 C_JMP = 0x50 # JUMP instruction
41 C_JMC = 0x60 # Conditional JUMP instruction
42 C_CAL = 0x70 # CALL instruction
43 C_RET = 0x80 # RET instruction
44 C_FLG = 0x90 # Changes system flags
45 C_RTF = 0xA0 # C_JMP and C_FLG simultaneously
46 C_REP = 0xB0 # Instruction with REPxx prefix
47 C_PRI = 0xC0 # Privileged instruction
48 C_SSE = 0xD0 # SSE instruction
49 C_NOW = 0xE0 # 3DNow! instruction
50 C_BAD = 0xF0 # Unrecognized command
51
52 # Decode type
53 DEC_TYPEMASK = 0x1F # Type of memory byte
54 DEC_UNKNOWN = 0x00 # Unknown type
55 DEC_BYTE = 0x01 # Accessed as byte
56 DEC_WORD = 0x02 # Accessed as short
57 DEC_NEXTDATA = 0x03 # Subsequent byte of data
58 DEC_DWORD = 0x04 # Accessed as long
59 DEC_FLOAT4 = 0x05 # Accessed as float
60 DEC_FWORD = 0x06 # Accessed as descriptor/long pointer
61 DEC_FLOAT8 = 0x07 # Accessed as double
62 DEC_QWORD = 0x08 # Accessed as 8-byte integer
63 DEC_FLOAT10 = 0x09 # Accessed as long double
64 DEC_TBYTE = 0x0A # Accessed as 10-byte integer
65 DEC_STRING = 0x0B # Zero-terminated ASCII string
66 DEC_UNICODE = 0x0C # Zero-terminated UNICODE string
67 DEC_3DNOW = 0x0D # Accessed as 3Dnow operand
68 DEC_SSE = 0x0E # Accessed as SSE operand
69 DEC_TEXT = 0x10 # For use in t_result only
70 DEC_BYTESW = 0x11 # Accessed as byte index to switch
71 DEC_NEXTCODE = 0x13 # Subsequent byte of command
72 DEC_COMMAND = 0x1D # First byte of command
73 DEC_JMPDEST = 0x1E # Jump destination
74 DEC_CALLDEST = 0x1F # Call (and maybe jump) destination
75
76 DEC_PROCMASK = 0x60 # Procedure analysis
77 DEC_PROC = 0x20 # Start of procedure
78 DEC_PBODY = 0x40 # Body of procedure
79 DEC_PEND = 0x60 # End of procedure
80
81 DEC_CHECKED = 0x80 # Byte was analysed
82 DEC_SIGNED = 0x100 # For use in t_result only
83
84 DECR_TYPEMASK = 0x3F # Type of register or memory
85 DECR_BYTE = 0x21 # Byte register
86 DECR_WORD = 0x22 # Short integer register
87 DECR_DWORD = 0x24 # Long integer register
88 DECR_QWORD = 0x28 # MMX register
89 DECR_FLOAT10 = 0x29 # Floating-point register
90 DECR_SEG = 0x2A # Segment register
91 DECR_3DNOW = 0x2D # 3Dnow! register
92 DECR_SSE = 0x2E # SSE register
93
94 DECR_ISREG = 0x20 # Mask to check that operand is register
95 DEC_CONST = 0x40 # Immediate constant, used by Analyser
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
111
112
114 self.ip=opcode[0] # Instruction pointer
115 self.dump=opcode[1] # Hexadecimal dump of the command
116 self.result=opcode[2] # Disassembled command
117 self.comment=opcode[3] # Brief comment
118 self.opinfo=opcode[4] # Comments to command's operands (tuple[3])
119 self.cmdtype=opcode[5] # One of C_xxx
120 self.memtype=opcode[6] # Type of addressed variable in memory
121 self.nprefix=opcode[7] # Number of prefixes
122 self.indexed=opcode[8] # Address contains register(s)
123 self.jmpconst=opcode[9] # Constant jump address
124 self.jmptable=opcode[10] # Possible address of switch table
125 self.adrconst=opcode[11] # Constant part of address
126 self.immconst=opcode[12] # Immediate constant
127 self.zeroconst=opcode[13] # Whether contains zero constant
128 self.fixupoffset=opcode[14] # Possible offset of 32-bit fixups
129 self.fixupsize=opcode[15] # Possible total size of fixups or 0
130 self.jmpaddr=opcode[16] # Destination of jump/call/return
131 self.condition=opcode[17] # 0xFF:unconditional, 0:false, 1:true
132 self.error=opcode[18] # Error while disassembling command
133 self.warnings=opcode[19] # Combination of DAW_xxx
134 self.optype=opcode[20] # Type of operand (extended set DEC_xxx) (tuple[3])
135 self.operandsize=opcode[21] # Size of operand, bytes (tuple[3])
136 self.opsize=opcode[22] #common opsize in bytes (this is the one you want, almost sure)
137 self.opgood=opcode[23] # Whether address and data valid (tuple[3])
138 self.opaddr=opcode[24] # Address if memory, index if register (tuple[3])
139 self.opdata=opcode[25] # Actual value (only integer operands) (tuple[3])
140 self.operand=opcode[26] # Full description of operand (tuple[3])
141 #NOTE ABOUT self.operand:
142 #self.operand[n][0] = operand type DEC_xxx (mem), DECR_xxx (reg) or DEC_CONST (const)
143 #self.operand[n][1] = operand size (in bytes)
144 #self.operand[n][2][x] = registers scale
145 # (use Registers32BitsOrder,Registers16BitsOrder,Registers8BitsOrder depending on operand size)
146 # Note: more than one register could be used in some memory addressing modes.
147 #self.operand[n][3] = constant
148
149
150 self.regdata=opcode[27] # Registers after command is executed / status of registers list[(reg,status)]
151 self.addrdata=opcode[28] # Traced memory address
152 self.addrstatus=opcode[29] # Status of addrdata, one of RST_xxx
153 self.regstack=opcode[30] # Stack tracing buffer / status of stack items list[(stack,status)]
154 #self.nregstack=opcode[32] # Number of items in stack trace buffer
155
156 # We need to include more than one register
157 # ex: [EAX+EDI+2]
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
239
242
245
248
251
253 return self.error
254
257
260
263
266
269
272
275
278
281
284
287
290
293
296
297 #NOTE: info panel is runtime information, no matter which opcode you use to fetch it
298 # you'll have the info IP linked.
299
302
305
308
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
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
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 = {} # Hash that contains the visited Blocks
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
442 ret = []
443 endblocks = self.getEnd()
444 for bb in endblocks:
445 op = self.imm.disasmBackward( bb.getEnd() )
446 ret.append( op.getAddress() )
447 return ret
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() # Grab all the Blocks with "Ret" on it.
473 for bb in endblocks:
474 opcodes = bb.getInstructions(self.imm)
475 # We are gonna loop over the instruction on the block backwardly, in order to
476 # find who is modifying eax before the ret.
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 #self.decode = self.imm.findDecode( self.start )
522 #self.imm.log("Decode Len: %d" % len(self.decode))
523 #if not self.decode:
524 # raise Exception, "Couldn't find a proper Decode"
525 self._getBB(self.start)
526
527 return self.bb
528
529 # Depth First construction of Basic block
530 # This is the real recursive function that iterates over the function code flow creating basic block.
531 # The function iterate over every assembly code always following first the jmp/jmc
533 decode = self.imm.findDecode( address )
534 if not decode:
535 raise Exception, "Couldn't find a proper Decode for address 0x%08x" % address
536 start = address
537 calls = []
538 while 1:
539 # XREF BASIC BLOCK:
540 # If we find our address has an xref, we know is the end the basic block
541 if decode.isJmpDestination( address ) and start != address:
542
543 if self.bbhash.has_key(start):
544 return
545 #self.imm.log("BB created (xref): %08x %08x" % ( start, address ) )
546 op = self.imm.disasm( address )
547 bb = XREFBasicBlock( start, address )
548 bb.setFunction( self )
549 bb.addTrueEdge( address )
550 bb.setCalls( calls )
551 if calls:
552 bb.setCalls( calls )
553 calls = [] # cleaning calls
554 self.bb.append( bb )
555 self.bbhash[ start ] = 1
556 start = address
557 if self.bbhash.has_key( address ):
558 return
559
560 #op = self.imm.disasmData( address ) XXX: change it for this one
561 op = self.imm.disasm( address )
562 #self.imm.log( op.getResult(), address = address)
563
564 # JMC Basic block:
565 # If we find a conditional jmp, its the end of a basic block. We recursively follow the jmp
566 if op.isConditionalJmp():
567 #self.imm.log("BB conditional (JMC): %08x %08x" % ( start, address ) )
568 self.bbhash[ start ] = 1
569 bb = JMCBasicBlock( start, address + op.getSize() )
570 if calls:
571 bb.setCalls( calls )
572 calls = [] # cleaning calls
573 start = address + op.getSize()
574 bb.setFunction( self )
575 bb.addTrueEdge( op.getJmpConst() )
576 bb.addFalseEdge( start ) # the next instruction
577 self.bb.append( bb )
578
579 # if the jmp address is not on our current basic block list, we follow that leaf
580 if not self.bbhash.has_key( op.getJmpConst() ):
581 self._getBB( op.getJmpConst() )
582 op = self.imm.disasm( address )
583
584 if self.bbhash.has_key( start ) :
585 return
586
587 # JMP Basic Block:
588 # If we find a jmp, we create a new basic block.
589 elif op.isJmp():
590 if not self.bbhash.has_key( address):
591 #self.imm.log("BB conditional (JMP): %08x %08x" % ( start, address ) )
592 self.bbhash[ start ] = 1
593 bb = JMPBasicBlock( start, address + op.getSize() )
594 bb.setFunction( self )
595 bb.addTrueEdge( op.getJmpConst() )
596 if calls:
597 bb.setCalls( calls )
598 calls = [] # cleaning calls
599 self.bb.append( bb )
600 start = address + op.getSize()
601 if not self.bbhash.has_key( op.getJmpConst() ):
602 # We limit the jmp only on a decode we control.
603 # That means, it has to jmp into our own dll
604 try:
605 decode[op.getJmpConst()]
606 self._getBB( op.getJmpConst() )
607 except Exception:
608 pass
609 return
610
611 # RET Basic Block
612 # Whenever we find a ret, its the end of the tree. We create a Basic Block and return
613 elif op.isRet():
614 #self.imm.log("BB conditional (RET): %08x %08x\n" % ( start, address ) )
615 self.bbhash[ start ] = 1
616 bb = RETBasicBlock( start, address + op.getSize() )
617 bb.setFunction( self )
618 if calls:
619 bb.setCalls( calls )
620 calls = [] # cleaning calls
621 self.bb.append( bb )
622 return
623 elif op.isCall():
624 calls.append( address )
625
626 address += op.getSize()
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 #self.Function is a pointer to our parent so we always have it available
646 self.Function = None
647 #TODO: Flesh this out - let's store as much information as possible in the basic blocks
648 #for example, if we write to the stack or heap or if we have various macros in us, etc
649
651 self.Function = function
652
654 return self.Function
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
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 # Important Note:
864 # Keep in mind, that the Edge of a JMP Basic block could be 0x0
865 # (For example, in case like jmp [...]), we still don't take care of this special cases
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
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 # Find the corresponding PUSH
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 # Is this a PUSH?
923 if idx < COUNT:
924 # Double check, just in case
925 dotraceback = True
926 if not op.isPush():
927 #imm.log("XXX: Error, Opcode should be a Push")
928 return ()
929
930 # If the PUSH has no register, its a PUSH CONSTANT
931 # PUSH 0x400
932 if op.getOperandRegister(0) == "":
933 if not self.shownonusersupplied:
934 return ()
935 else:
936 return (op, [])
937
938 # If the Operand of the push is EBP, no need to get the traceback.
939 # Cause is probably a PUSH of arguments or a local variable.
940 # (At least, not now)
941 # PUSH [EBP+C]
942 elif op.getOperandRegister(0) == "EBP" and op.operand[0][3]:
943 dotraceback = False
944 #return (op, [])
945
946 show = []
947
948 # DOING THE TRACEBACK
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 # If the second argument is a constant, then is not user-supplied
966 # MOV ESI, 0x200
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 # op.operand[1][3] constante
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 # op.operand[1][3] constant
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 #imm.log("Found user-supplied for arg_%d in %s" % ( tracedarg, imm.disasm(ref[0]).result) , address = ref[0])
993 #imm.log( "%s %s" % (op.getDisasm(), type), address = op.getAddress() )
994 #for msg in show:
995 # imm.log( msg[0], address = msg[1] )
996 #imm.log("------")
997 return (op, show)
998
999 return ()
1000
1001 # Note:
1002 # We just trace for MOV (We skip arymethic and lea opcodes)
1003 # This function search backward linearly, we should change it into changing using
1004 # xrefs and probably detecting more than one traceBack
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 #imm.log("> %s" % op.result, address = op.getAddress())
1014 self.visited.append( address )
1015 if op.isJmp():
1016 return 0
1017 if op.getResult()[:3] in ("MOV", "XOR"):
1018 # Register is the source
1019 # ex: MOV EAX, ...
1020 if op.operand[0][2] == register:
1021 self.modarg.append( op )
1022 return 0
1023 # If the register we are looking for is EAX, a CALL would be the one
1024 # the modifier
1025 # CALL ntdll.67225328
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 # Finish looking if we reach the begging of the address
1038 if decode.isFunctionStart( address ):
1039 del decode
1040 return None
1041 del op
1042
1043 del decode
1044 return None
1045
1046
1047 # Note:
1048 # We just trace for MOV (We skip arymethic and lea opcodes)
1049 # This function search backward linearly, we should change it into changing using
1050 # xrefs and probably detecting more than one traceBack
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 # Register is the source
1059 # ex: MOV EAX, ...
1060 if op.operand[0][2] == register:
1061 return op
1062 # If the register we are looking for is EAX, a CALL would be the one
1063 # the modifier
1064 # CALL ntdll.67225328
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 # Finish looking if we reach the begging of the address
1072 if decode.isFunctionStart( address ):
1073 del decode
1074 return None
1075 del op
1076
1077 del decode
1078 return None
1079
| Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Thu Mar 17 18:43:03 2011 | http://epydoc.sourceforge.net |