Package Libs :: Module immlib
[hide private]
[frames] | no frames]

Source Code for Module Libs.immlib

   1  #!/usr/bin/env python 
   2  """ 
   3      Immunity Debugger API for python 
   4   
   5      (c) Immunity, Inc. 2004-2007 
   6   
   7   
   8      U{Immunity Inc.<http://www.immunityinc.com>} Debugger API for python 
   9   
  10   
  11      """ 
  12   
  13  __VERSION__ = '1.3' 
  14   
  15   
  16  import debugger 
  17  import immutils 
  18  import string 
  19  import time 
  20  import struct 
  21  import pickle 
  22  import cPickle 
  23  import libheap 
  24  import sys 
  25   
  26  from libhook    import * 
  27  from libevent   import * 
  28  from debugtypes import * 
  29  from libanalyze import * 
  30  from librecognition import FunctionRecognition 
  31  from libcontrolflow import ControlFlowAnalysis 
  32   
  33  # CONSTANT 
  34  BpKeys        =  {"VK_F2": 0x71, "VK_F4" : 0x73} 
  35  BpFlags       = {"TY_STOPAN": 0x80L, "TY_SET": 0x100L, "TY_ACTIVE": 0x200L, "TY_DISABLED":0x400,\ 
  36                   "TY_ONESHOT": 0x800L, "TY_TEMP":0x1000L, "TY_KEEPCODE":0x2000L, "TY_KEEPCOND": 0x4000L,\ 
  37                   "TY_NOUPDATE":0x8000, "TY_RTRACE": 0x10000} 
  38   
  39  # Hardware breakpoint type flags 
  40   
  41  HB_FREE=0      # Breakpoint is not used 
  42  HB_CODE=1      # Active on command execution 
  43  HB_ACCESS=2    # Active on read/write access 
  44  HB_WRITE=3     # Active on write access 
  45  HB_IO=4        # Active on port I/O 
  46  HB_ONESHOT=5   # One-shot on command execution 
  47  HB_STOPAN=6    # One-shot on command and stop 
  48  HB_TEMP=7      # Temporary on command execution 
  49   
  50  DebugerStatus = { "NONE":0, "STOPPED":1, "EVENT":2, "RUNNING": 3, "FINISHED":4, "CLOSING":5 } 
  51   
  52  Register      = { "EAX" : 0 , "ECX" : 1, "EDX": 2, "EBX": 3, "ESP": 4, "EBP": 5, "ESI": 6, "EDI": 7, "EIP":8} 
  53   
  54  PageFlags     = {0x1 : "   ",0x2: "R  ", 0x4:"RW ", 0x8: "RW  COW", 0x10: "  E",\ 
  55                   0x20: "R E", 0x40: "RWE", 0x80: "RWE  COW"} 
  56   
  57  ImmFonts      =   {"fixed": 0, "terminal6": 1, "fixedsys":2, "courier":3, "lucida":4, "font5": 5,\ 
  58                     "font6": 6, "font7":7, "main": 8, "sys": 9, "info": 10} 
  59   
  60   
  61   
  62  BpMemFlags    = {"R": 0x1, "W":0x2, "S":0x1000L} 
  63   
  64  MemoryProtection = { "PAGE_EXECUTE" :0x10, "PAGE_EXECUTE_READ" :0x20 , "PAGE_EXECUTE_READWRITE": 0x40,\ 
  65                       "PAGE_EXECUTE_WRITECOPY":0x80,  "PAGE_NOACCESS":0x01, "PAGE_READONLY":0x02,\ 
  66                       "PAGE_READWRITE":0x04, "PAGE_WRITECOPY": 0x08 } 
  67   
  68   
  69   
  70  IgnoreSingleStep = {"DISABLE" : 0 , "FORCE" : 1 , "CONTINUE" : 2} 
  71   
  72   
  73   
  74  #define JT_JUMP        0               // Unconditional jump 
  75  #define JT_COND        1               // Conditional jump 
  76  #define JT_SWITCH      2               // Jump via switch table 
  77  #define JT_CALL        3               // Local (intramodular) call 
  78  #define CALL_INTER     4               // intermodular call 
  79  jmpTypeFlags = {"JUMP":0,\ 
  80                  "JUMP_COND":1,\ 
  81                  "JUMP_SWITCH":2,\ 
  82                  "CALL":3,\ 
  83                  "CALL_INTER":4} 
  84   
  85   
  86  NM_NONAME=0x00            # Undefined name 
  87  NM_MODSEARCH=0xFD 
  88  NM_ANYNAME=0xFF           # Name of any type 
  89  #Names saved in the data file of module they appear. 
  90  NM_PLUGCMD=0x30           # Plugin commands to execute at break 
  91  NM_LABEL=0x31             # User-defined label 
  92  NM_EXPORT=0x32            # Exported (global) name 
  93  NM_IMPORT=0x33            # Imported name 
  94  NM_LIBRARY=0x34           # Name from library or object file 
  95  NM_CONST=0x35             # User-defined constant 
  96  NM_COMMENT=0x36           # User-defined comment 
  97  NM_LIBCOMM=0x37           # Comment from library or object file 
  98  NM_BREAK=0x38             # Condition related with breakpoint 
  99  NM_ARG=0x39               # Arguments decoded by analyzer 
 100  NM_ANALYSE=0x3A           # Comment added by analyzer 
 101  NM_BREAKEXPR=0x3B         # Expression related with breakpoint 
 102  NM_BREAKEXPL=0x3C         # Explanation related with breakpoint 
 103  NM_ASSUME=0x3D            # Assume function with known arguments 
 104  NM_STRUCT=0x3E            # Code structure decoded by analyzer 
 105  NM_CASE=0x3F              # Case description decoded by analyzer 
 106  #Names saved in the data file of main module. 
 107  NM_INSPECT=0x40           # Several last inspect expressions 
 108  NM_WATCH=0x41             # Watch expressions 
 109  NM_ASM=0x42               # Several last assembled strings 
 110  NM_FINDASM=0x43           # Several last find assembler strings 
 111  NM_LASTWATCH=0x48         # Several last watch expressions 
 112  NM_SOURCE=0x49            # Several last source search strings 
 113  NM_REFTXT=0x4A            # Several last ref text search strings 
 114  NM_GOTO=0x4B              # Several last expressions to follow 
 115  NM_GOTODUMP=0x4C          # Several expressions to follow in Dump 
 116  NM_TRPAUSE=0x4D           # Several expressions to pause trace 
 117  #Names saved in the data file of debugged DLL. 
 118  NM_DLLPARMS=0x50          # (10 parms + 6 regs) x 10-line history 
 119  #Names that are not saved in the data file. 
 120  NM_DEBUG=0x80             # Names from debug data 
 121  NM_IMPLIB=0x81            # Names of import library files 
 122  NM_IMPNAME=0x82           # Names of import library entries 
 123  NM_FONT=0x83              # Names of fonts 
 124  NM_SCHEME=0x84            # Names of colour schemes 
 125  NM_GOTOSTACK=0x85         # Several expressions to follow in Stack 
 126  NM_HILITE=0x86            # Names of highlighting schemes 
 127  #Pseudonames. 
 128  NM_IMCALL=0xFE            # Intermodular call 
 129   
 130   
 131  import UserDict 
 132   
 133  # Dict that returns classess 
134 -class DictTypes(UserDict.IterableUserDict):
135 - def __init__(self):
136 UserDict.IterableUserDict.__init__(self)
137 - def __iter__(self):
138 for k in self.data.keys(): 139 yield self.data[k]
140 141 142 ImmDrawColors = {"Black":0,"Maroon":128,"Green":32768,"Olive":32896,"Navy":8388608,"Purple":8388736,"Teal":8421376,\ 143 "Gray":8421504,"Silver":12632256,"Red":255,"Lime":65280,"Yellow":65535,"Blue":16711680,"Fuchsia":16711935,\ 144 "Aqua":16776960,"LightGray":12632256,"DarkGray":8421504,"White":16777215,"MoneyGreen":12639424,\ 145 "SkyBlue":15780518,"Cream":15793151,"MedGray":10789024,"red":255,"darkgreen":32768} 146 147 ########################### 148 ########################### 149 ### Debugger main class ### 150 ########################### 151 ###########################
152 -class Debugger(object):
153 - def __init__(self):
154 """ Initialize the Immunity Debugger API""" 155 self.threadid = 0 156 os = self.getOsInformation() 157 self.ossystem = os[ 0 ].lower() 158 self.osversion = os[ 1 ].lower() 159 self.osrelease = os[ 2 ].lower() 160 self.isWin7 = False 161 162 # we want to distinguish Vista and Win7 over other Windows. 163 self.isVista = self.getOsRelease()[0] == '6' 164 if self.isVista: 165 tmprelease = self.getOsRelease() 166 if len(tmprelease) > 3: 167 if tmprelease[2] == '1': 168 self.isWin7 = True 169 self.isVista = False 170 171 self.Eventndx = { debugger.CREATE_PROCESS_DEBUG_EVENT : CreateProcessEvent, 172 debugger.CREATE_THREAD_DEBUG_EVENT : CreateThreadEvent, 173 debugger.EXCEPTION_DEBUG_EVENT : ExceptionEvent, 174 debugger.EXIT_PROCESS_DEBUG_EVENT : ExitProcessEvent, 175 debugger.EXIT_THREAD_DEBUG_EVENT : ExitThreadEvent, 176 debugger.LOAD_DLL_DEBUG_EVENT : LoadDLLEvent, 177 debugger.OUTPUT_DEBUG_STRING_EVENT : OutputDebugEvent, 178 debugger.UNLOAD_DLL_DEBUG_EVENT : UnloadDLLEvent, 179 debugger.RIP_EVENT : RIPEvent } 180 181 self.clearState()
182
183 - def clearState(self):
184 self.Symbols = DictTypes() 185 self.Handles = DictTypes() 186 self.Threads = DictTypes() 187 self.MemoryPages = DictTypes() 188 self.Modules = DictTypes() 189 self.BackTrace = [] 190 self.HeapsAddr = [] 191 self.Heaps = {}
192 193 194 ### Get the ultimate solution ###
196 return self.error("%d" % (0x15 * 2))
197 198 199 ### Immunity Debugger Knowledge ### 200 # Sharing information between scripts 201
202 - def addKnowledge(self, id, object, force_add = 0x0):
203 """ 204 This function add a python object to the knowledge database. 205 206 @type id: STRING 207 @param id: unique name tag of the object 208 209 @type object: Python object 210 @param object: Object to be saved in the knowledge database 211 """ 212 213 pickled_object=pickle.dumps(object) 214 return debugger.add_knowledge(pickled_object,id, force_add)
215
216 - def getKnowledge(self,id):
217 """ 218 Gets python object from the knowledge database. 219 220 @type id: STRING 221 @param id: unique name tag of the object 222 223 @rtype: PYTHON OBJECT 224 @return: Object retrieved from the knowledge database 225 """ 226 pickled_object=debugger.get_knowledge(id) 227 #try: 228 if not pickled_object: 229 return None 230 return pickle.loads(pickled_object)
231
232 - def listKnowledge(self):
233 """ 234 Gets the list of saved objects in the knowledge database. 235 236 @rtype: TUPLE 237 @return: List of String ids currently saved 238 """ 239 return debugger.list_knowledge()
240
241 - def findPacker(self, name, OnMemory = True):
242 """ 243 Find possible Packer/Cryptors/etc on a Module 244 245 @type name: STRING 246 @param name: Module name 247 248 @type OnMemory: (Optional, Def: True) BOOLEAN 249 @param OnMemory: Whether to look in memory or on a file. 250 251 @rtype: LIST of TUPLES in the form of (DWORD, LIST OF STRING) 252 @return: A list of the Packer founded (Offset, List of Packer found in that address) 253 """ 254 if OnMemory: 255 mem = self.getMemoryPageByOwner(name) 256 if not mem: 257 raise Exception, "Coudln't find a Memory Page belonging to %s" % name 258 data = "" 259 for a in mem: 260 data+= a.getMemory() 261 else: 262 mod = self.getModule( name ) 263 if not mod: 264 raise Exception, "Coudln't find the correct Module belonging to %s" % name 265 data = mod.getPath() 266 267 import pefile 268 import peutils 269 if OnMemory: 270 pe = pefile.PE( data = data ) 271 else: 272 pe = pefile.PE( name = data ) 273 274 sig_db = peutils.SignatureDatabase('Data/UserDB.TXT') 275 return sig_db.match( pe )
276
277 - def forgetKnowledge(self,id):
278 """ 279 Remove python object from knowledge database. 280 281 @type id: STRING 282 @param id: unique name tag of the object 283 """ 284 return debugger.forget_knowledge(id)
285
286 - def cleanKnowledge(self):
287 """ Clean ID memory from known objects 288 """ 289 for ke in self.listKnowledge(): 290 self.forgetKnowledge(ke)
291 292
293 - def addGenHook(self,object):
294 """ 295 Add a hook to Immunity Debugger 296 """ 297 298 import pickle 299 try: 300 rtype=object.type 301 except: 302 rtype=0 303 try: 304 label=object.label 305 except: 306 label="No Label specified for this hook" 307 pickled_object=pickle.dumps(object) 308 debugger.add_hook(pickled_object,label,rtype)
309 310
311 - def cleanHooks(self):
312 """ 313 Clean ID memory from hook objects 314 """ 315 for hk in self.listHooks(): 316 debugger.remove_hook(hk)
317 318 319
320 - def cleanUp(self):
321 """ 322 Clean ID memory for every kind of object saved in it 323 """ 324 self.cleanHooks() 325 self.cleanKnowledge()
326 327
328 - def getPEBAddress(self):
329 """ 330 Gets PEB. 331 @rtype: DWORD 332 @return: PEB address 333 """ 334 return debugger.get_PEB()
335 336 337 338 ### Disassembling / Analyzing Functions / etc ### 339
340 - def analyseCode(self,address):
341 """ 342 Analyse module's code 343 344 @type Address: DWORD 345 @param Address: Address from module to be analysed 346 """ 347 debugger.analyse_code(address)
348
349 - def isAnalysed(self,address):
350 """ 351 Check if module is already analysed 352 353 @type Address: DWORD 354 @param Address: Address from module 355 356 @rtype: DWORD 357 @return: 1 if module already analysed 358 """ 359 ret = debugger.is_analysed(address) 360 361 if ret == -1: 362 return 0 363 else: 364 return ret
365
366 - def setVariable(self,address,string):
367 """ 368 Set Variable name to specified address. 369 370 @type Address: DWORD 371 @param Address: Address from assembly line 372 373 @type String: STRING 374 @param String: Variable name to be set 375 376 """ 377 return debugger.set_variable(address,string)
378
379 - def getVariable(self,address):
380 """ 381 Get Variable name from specified address 382 383 @type Address: DWORD 384 @param Address: Address from assembly line 385 386 @rtype: STRING 387 @return: Variable name for given address. 388 389 """ 390 return debugger.get_variable(address)
391 392
393 - def validateAddress(self, address, perm):
394 """ 395 It validates if a given address has the permissions provided in <perm>. 396 perm = RWXNC (N=No Access, C=Write Copy) 397 """ 398 399 mem = self.getMemoryPageByAddress(address) 400 if not mem: 401 return False 402 403 access = mem.getAccess() 404 ret = True 405 406 if "X" in perm: 407 ret = ret and access >= 0x10 408 if "R" in perm: 409 ret = ret and (access >= 0x20 or (access >= 0x2 and access <= 0x8)) 410 if "W" in perm: 411 ret = ret and (access >= 0x40 or (access >= 0x4 and access <= 0x8)) 412 if "C" in perm: 413 ret = ret and (access == 0x80 or access == 0x8) 414 if "N" in perm: 415 ret = ret and access == 0x1 416 417 return ret
418
419 - def getCurrentTEBAddress(self):
420 tid=self.getThreadId() 421 if not self.Threads.has_key(tid): #avoid refreshing the threads list on every call 422 self.getAllThreads() 423 return self.Threads[tid].getTEB()
424 425
426 - def disasm(self, address, mode = DISASM_ALL):
427 """ 428 disasm address 429 430 @type Address: DWORD 431 @param Address: Address to disasm 432 433 @type Mode: (Optional, Def: DISASM_ALL) 434 @param Mode: disasm mode 435 436 @rtype: opCode Object (Check libanalyze.py) 437 @return: Disassmbled Opcode 438 """ 439 440 op= opCode( self, address ) 441 op._getfromtuple( debugger.disasm( address, mode) ) 442 return op
443 444 445 # disasmSize 0.00007515 usec/pass
446 - def disasmSizeOnly(self, address):
447 """ 448 Determine command size only 449 450 @type Address: DWORD 451 @param Address: Address to disasm 452 453 @rtype: opCode Object (Check libanalyze.py) 454 @return: Disassmbled Opcode 455 """ 456 return self.disasm(address, DISASM_SIZE)
457 458 # disasmData 0.00007375 usec/pass
459 - def disasmData(self, address):
460 """ 461 Determine size and analysis data 462 463 @type Address: DWORD 464 @param Address: Address to disasm 465 466 @rtype: opCode Object (Check libanalyze.py) 467 @return: Disassmbled Opcode 468 """ 469 return self.disasm(address, DISASM_DATA)
470
471 - def disasmTrace(self, address):
472 """ 473 Trace integer registers 474 475 @type Address: DWORD 476 @param Address: Address to disasm 477 478 @rtype: opCode Object (Check libanalyze.py) 479 @return: Disassmbled Opcode 480 """ 481 return self.disasm(address, DISASM_TRACE)
482 483 # disasmFile 0.00007934 usec/pass
484 - def disasmFile(self, address):
485 """ 486 Disassembly, no symbols/registers 487 488 @type Address: DWORD 489 @param Address: Address to disasm 490 491 @rtype: opCode Object (Check libanalyze.py) 492 @return: Disassmbled Opcode 493 """ 494 return self.disasm(address, DISASM_FILE)
495 496 # disasmCode 0.00008549 usec/pass
497 - def disasmCode(self, address):
498 """ 499 Disassembly, registers undefined 500 501 @type Address: DWORD 502 @param Address: Address to disasm 503 504 @rtype: opCode Object (Check libanalyze.py) 505 @return: Disassmbled Opcode 506 """ 507 return self.disasm(address, DISASM_CODE)
508
509 - def disasmRTrace(self, address):
510 """ 511 Disassemble with run-trace registers 512 513 @type Address: DWORD 514 @param Address: Address to disasm 515 516 @rtype: opCode Object (Check libanalyze.py) 517 @return: Disassmbled Opcode 518 """ 519 return self.disasm(address, DISASM_RTRACE)
520 521
522 - def disasmForward( self, address, nlines=1, mode = DISASM_ALL):
523 """ 524 disasm nlines forward of given address 525 526 @type Address: DWORD 527 @param Address: Address to disasm 528 529 @type nlines: DWORD 530 @param nlines: (Optional, Def: 1) Number of lines to disassemble forward 531 532 @type Mode: (Optional, Def: DISASM_ALL) 533 @param Mode: disasm mode 534 535 @rtype: opCode Object (Check libanalyze.py) 536 @return: Disassmbled Opcode 537 """ 538 forward_address = debugger.disasm_forward( address, nlines ) 539 op=opCode( self, forward_address ) 540 op._getfromtuple( debugger.disasm( forward_address, mode ) ) 541 return op
542 543 544
545 - def disasmForwardAddressOnly(self, address, nlines=1):
546 """ 547 disasm nlines forward to the given address 548 549 @type Address: DWORD 550 @param Address: Address to disasm 551 552 @type nlines: DWORD 553 @param nlines: (Optional, Def: 1) Number of lines to disassemble forward 554 555 @type Mode: (Optional, Def: DISASM_ALL) 556 @param Mode: disasm mode 557 558 @rtype: DWORD 559 @return: Address of the opcode 560 """ 561 return debugger.disasm_forward(address,nlines)
562
563 - def disasmForwardSizeOnly(self, address, nlines=1):
564 """ 565 Determine command size only 566 567 @type Address: DWORD 568 @param Address: Address to disasm 569 570 @type nlines: DWORD 571 @param nlines: (Optional, Def: 1) Number of lines to disassemble forward 572 573 @rtype: opCode Object (Check libanalyze.py) 574 @return: Disassmbled Opcode 575 """ 576 return self.disasmForward(address, nlines, DISASM_SIZE)
577
578 - def disasmForwardData(self, address, nlines=1):
579 """ 580 Determine size and analysis data 581 582 @type Address: DWORD 583 @param Address: Address to disasm 584 585 @type nlines: DWORD 586 @param nlines: (Optional, Def: 1) Number of lines to disassemble forward 587 588 @rtype: opCode Object (Check libanalyze.py) 589 @return: Disassmbled Opcode 590 591 """ 592 return self.disasmForward(address, nlines, DISASM_DATA)
593
594 - def disasmForwardTrace(self, address, nlines=1):
595 """ 596 Trace integer registers 597 598 @type Address: DWORD 599 @param Address: Address to disasm 600 601 @type nlines: DWORD 602 @param nlines: (Optional, Def: 1) Number of lines to disassemble forward 603 604 @rtype: opCode Object (Check libanalyze.py) 605 @return: Disassmbled Opcode 606 """ 607 return self.disasmForward(address, nlines, DISASM_TRACE)
608
609 - def disasmForwardFile(self, address, nlines=1):
610 """ 611 Disassembly, no symbols/registers 612 613 @type Address: DWORD 614 @param Address: Address to disasm 615 616 @type nlines: DWORD 617 @param nlines: (Optional, Def: 1) Number of lines to disassemble forward 618 619 @rtype: opCode Object (Check libanalyze.py) 620 @return: Disassmbled Opcode 621 """ 622 return self.disasmForward(address, nlines, DISASM_FILE)
623
624 - def disasmForwardCode(self, address, nlines=1):
625 """ 626 Disassembly, registers undefined 627 628 @type Address: DWORD 629 @param Address: Address to disasm 630 631 @type nlines: DWORD 632 @param nlines: (Optional, Def: 1) Number of lines to disassemble forward 633 634 @rtype: opCode Object (Check libanalyze.py) 635 @return: Disassmbled Opcode 636 """ 637 return self.disasmForward(address, DISASM_CODE)
638
639 - def disasmForwardRTrace(self, address, nlines=1):
640 """ 641 Disassemble with run-trace registers 642 643 @type Address: DWORD 644 @param Address: Address to disasm 645 646 @type nlines: DWORD 647 @param nlines: (Optional, Def: 1) Number of lines to disassemble forward 648 649 @rtype: opCode Object (Check libanalyze.py) 650 @return: Disassmbled Opcode 651 """ 652 return self.disasmForward(address, nlines, DISASM_RTRACE)
653
654 - def disasmBackward( self, address, nlines = 1, mode = DISASM_ALL):
655 """ 656 disasm nlines backward from the given address 657 658 @type Address: DWORD 659 @param Address: Address to disasm 660 661 @type nlines: DWORD 662 @param nlines: (Optional, Def: 1) Number of lines to disassemble forward 663 664 @rtype: opCode Object (Check libanalyze.py) 665 @return: Disassmbled Opcode 666 """ 667 backward_address = debugger.disasm_backward( address, nlines ) 668 op = opCode( self, backward_address ) 669 op._getfromtuple( debugger.disasm( backward_address, mode ) ) 670 return op
671
672 - def disasmBackwardAddressOnly(self,address,nlines=1):
673 """ 674 disasm nlines backward of given address 675 676 @type Address: DWORD 677 @param Address: Address to disasm 678 679 @type nlines: DWORD 680 @param nlines: (Optional, Def: 1) Number of lines to disassemble forward 681 682 @rtype: DWORD 683 @return: Address of the Opcode""" 684 return debugger.disasm_backward(address,nlines)
685 686 687
688 - def disasmBackwardSizeOnly(self, address, nlines = 1):
689 """ 690 Determine command size only 691 692 @type Address: DWORD 693 @param Address: Address to disasm 694 695 @type nlines: DWORD 696 @param nlines: (Optional, Def: 1) Number of lines to disassemble forward 697 698 @rtype: opCode Object (Check libanalyze.py) 699 @return: Disassmbled Opcode 700 """ 701 return self.disasmBackward(address, nlines, DISASM_SIZE)
702
703 - def disasmBackwardData(self, address, nlines = 1):
704 """ 705 Determine size and analysis data 706 707 @type Address: DWORD 708 @param Address: Address to disasm 709 710 @type nlines: DWORD 711 @param nlines: (Optional, Def: 1) Number of lines to disassemble forward 712 713 @rtype: opCode Object (Check libanalyze.py) 714 @return: Disassmbled Opcode 715 """ 716 return self.disasmBackward(address, nlines, DISASM_DATA)
717
718 - def disasmBackwardTrace(self, address, nlines = 1):
719 """ 720 Trace integer registers 721 722 @type Address: DWORD 723 @param Address: Address to disasm 724 725 @type nlines: DWORD 726 @param nlines: (Optional, Def: 1) Number of lines to disassemble forward 727 728 @rtype: opCode Object (Check libanalyze.py) 729 @return: Disassmbled Opcode 730 """ 731 return self.disasmBackward(address, nlines, DISASM_TRACE)
732
733 - def disasmBackwardFile(self, address, nlines = 1):
734 """ 735 Disassembly, no symbols/registers 736 737 @type Address: DWORD 738 @param Address: Address to disasm 739 740 @type nlines: DWORD 741 @param nlines: (Optional, Def: 1) Number of lines to disassemble forward 742 743 @rtype: opCode Object (Check libanalyze.py) 744 @return: Disassmbled Opcode 745 """ 746 return self.disasmBackward(address, nlines, DISASM_FILE)
747
748 - def disasmBackwardCode(self, address, nlines = 1):
749 """ 750 Disassembly, registers undefined 751 752 @type Address: DWORD 753 @param Address: Address to disasm 754 755 @type nlines: DWORD 756 @param nlines: (Optional, Def: 1) Number of lines to disassemble forward 757 758 @rtype: opCode Object (Check libanalyze.py) 759 @return: Disassmbled Opcode 760 """ 761 return self.disasmBackward(address, nlines, DISASM_CODE)
762
763 - def disasmBackwardRTrace(self, address, nlines = 1):
764 """ 765 Disassemble with run-trace registers 766 767 @type Address: DWORD 768 @param Address: Address to disasm 769 770 @type nlines: DWORD 771 @param nlines: (Optional, Def: 1) Number of lines to disassemble forward 772 773 @rtype: opCode Object (Check libanalyze.py) 774 @return: Disassmbled Opcode 775 """ 776 return self.disasmBackward(address, nlines, DISASM_RTRACE)
777
778 - def findDecode(self, address):
779 """ 780 Get the internal decode information from an analysed module 781 782 @type Address: DWORD 783 @param Address: Address in the range of the module page 784 785 @rtype: Decode OBJECT 786 @return: Decode Object containing the analized information 787 """ 788 return Decode( address )
789 #return debugger.find_decode( address ) 790
791 - def goNextProcedure(self):
792 """ 793 Go to next procedure 794 795 @rtype: DWORD 796 @return: Address of next procedure 797 """ 798 return debugger.go_next_procedure()
799
800 - def goPreviousProcedure(self):
801 """ 802 Go to previous procedure 803 804 @rtype: DWORD 805 @return: Address of previous procedure 806 """ 807 return debugger.go_previous_procedure()
808
809 - def getOpcode(self,address):
810 """ 811 Get address's Opcode 812 813 @type Address: DWORD 814 @param Address: Address to disasm 815 816 @rtype: opCode Object (Check libanalyze.py) 817 @return: Disassmbled Opcode 818 """ 819 op=opCode(self, address) 820 op._getfromtuple(debugger.disasm(address)) 821 return op
822
823 - def assemble(self, code,address=0x0):
824 """ 825 assemble code. 826 827 @type code: STRING 828 @param code: Code to be assembled 829 830 @rtype: STRING 831 @return: Opcodes of the assembled code 832 """ 833 opcode = [] 834 for line in code.split("\n"): 835 line = line.strip() 836 if line: 837 opcode.append( debugger.assemble(line,address) ) 838 return string.joinfields( opcode, "")
839
840 - def decodeAddress(self,address):
841 """ 842 Decode given address 843 844 @rtype: STRING 845 @return: decoded value 846 """ 847 return debugger.decode_address(address)
848
849 - def undecorateName(self,decorated):
850 """ 851 Undecorate given name 852 853 @type decorated: STRING 854 @param decorated: decorated name 855 @rtype: STRING 856 @return: undecorated name 857 """ 858 return debugger.undecorate_name(decorated)
859
860 - def getTraceArgs(self, address, tracedarg, shownonusersupplied = False):
861 """ 862 Trace Parameters of a function, return only when is user-supplied 863 864 @type Address: DWORD 865 @param Address: Address of the function call 866 867 @type Tracedarg: DWORD 868 @param Tracedarg: Parameter to trace 869 870 @type Shownonusersupplied: BOOLEAN 871 @param Shownonusersupplied: (Optional, Def: False) Flag whether or not show user supplied param 872 873 @rtype: TUPLES 874 @return: Returns a tuple of (Push Opcode, TABLE of OPCODES setting the PUSH) 875 """ 876 t = TraceArgs( self, address, tracedarg, shownonusersupplied ) 877 return t.get()
878
879 - def getAllFunctions(self,address):
880 """ 881 Gets all function of given module's address 882 883 @rtype: LIST 884 @return: Function start address 885 """ 886 return debugger.get_all_functions(address)
887
888 - def getFunction(self, address):
889 """ 890 Get the Function information 891 892 @type Address: DWORD 893 @param Address: Address of the function 894 895 @rtype: Function Object 896 @return: Function Object containing information of the requested function 897 898 """ 899 return Function(self, address)
900
901 - def getFunctionBegin(self,address):
902 """ 903 Find start address of funcion 904 905 @rtype: DWORD 906 @return: Start Address""" 907 return debugger.get_func_begin(address)
908
909 - def getFunctionEnd(self, function_address):
910 """ 911 Get all the possible ends of a Function 912 913 @type function_address: DWORD 914 @param function_address: Address of the function 915 916 @rtype: LIST 917 @return: List of Address of all the possible ret address 918 """ 919 if type(function_address) in (type(1), type(1L)): 920 func = self.getFunction( function_address ) 921 return func.getFunctionEnd() 922 elif isinstance(function_address, Function): 923 return function_address.getFunctionEnd() 924 else: 925 raise Exception, "Function type not recognized"
926 927 #def getFunctionEnd(self,address): 928 #""" 929 #Find end address of funcion (Deprecated, use Function) 930 931 #@rtype: DWORD 932 #@return: End address 933 #""" 934 #return debugger.get_func_end(address) 935
936 - def getAllBasicBlocks(self,address):
937 """ 938 Gets all basic blocks of given procedure (Deprecated, use Function) 939 940 @rtype: LIST 941 @return: (start,end) addresses of basic blocks 942 """ 943 bblocks = debugger.get_all_basic_blocks(address) 944 basicblocks = [] 945 if bblocks: 946 for block in bblocks: 947 basicblocks.append(basicBlock(self,block[0],block[1])) 948 return basicblocks
949
950 - def findDataRef(self,address):
951 """ 952 Find data references to given address 953 954 @rtype: LIST 955 @return: Table with found references 956 """ 957 return debugger.find_data_ref(address)
958
959 - def getXrefFrom(self, address):
960 """ 961 Get X Reference from a given address 962 963 @type Address: DWORD 964 @param Address: Address 965 966 @rtype: LIST 967 @return: List of X reference from the given address 968 """ 969 for mod in self.getAllModules(): 970 xref = mod.getXrefFrom(address) 971 972 if xref: return xref 973 return []
974
975 - def getXrefTo(self, address):
976 """ 977 Get X Reference to a given address 978 979 @type Address: DWORD 980 @param Address: Address 981 982 @rtype: LIST 983 @return: List of X reference to the given address 984 """ 985 for mod in self.getAllModules(): 986 xref = mod.getXrefTo(address) 987 988 if xref: return xref 989 return []
990
991 - def getInterCalls(self,address):
992 """ 993 Get intermodular calls 994 995 @type Address: DWORD 996 @param Address: Address 997 998 @rtype: DICTIONARY 999 @return: Dict of intermodular calls to the given address 1000 """ 1001 self.gotoDisasmWindow(address) 1002 return debugger.get_inter_calls(address)
1003 1004 1005 ### Gathering Information for the debugged process ### 1006 # All kind of information that can be gathered for the process (PEB, Heap, Events, Modules, etc) 1007
1008 - def getRegs(self):
1009 """ 1010 Get CPU Context values. 1011 1012 @rtype: DICTIONARY 1013 @return: x86 Registers 1014 """ 1015 return debugger.get_regs()
1016
1017 - def getRegsRepr(self):
1018 """ 1019 We have to do this to handle the Long integers, which XML-RPC cannot do 1020 1021 @rtype: DICTIONARY 1022 @return: x86 registers in string format (repr) 1023 """ 1024 regs=self.getRegs() 1025 1026 for r in regs: 1027 regs[r]=repr(regs[r]) 1028 return regs
1029
1030 - def setReg(self,reg,value):
1031 """ 1032 Set REG value 1033 1034 @type reg: STRING 1035 @param reg: Register name 1036 1037 @type value: DWORD 1038 @param vale: Value to set the register 1039 """ 1040 return debugger.set_reg(Register[reg],value)
1041
1042 - def getPEB(self):
1043 """ 1044 Get the PEB information of the debugged process 1045 1046 @rtype: PEB OBJECT 1047 @return: PEB """ 1048 1049 return PEB(self)
1050 1051
1052 - def getHeap(self, addr, restore = False):
1053 """ 1054 Get Heap Information 1055 1056 @type addr: DWORD 1057 @param addr: Address of the heap 1058 1059 @type restore: BOOLEAN 1060 @param restore: (Optional, Def: False) Flag whether or not use a restore heap 1061 1062 @rtype: PHeap OBJECT 1063 @return: Heap 1064 """ 1065 if self.Heaps.has_key(addr): 1066 return self.Heaps[addr] 1067 1068 if self.isVista or self.isWin7: 1069 pheap = libheap.VistaPHeap( self, addr, restore ) 1070 else: 1071 pheap = libheap.PHeap( self, addr, restore ) 1072 1073 if pheap: 1074 self.Heaps[addr] = pheap 1075 return pheap
1076
1077 - def getDebuggedName(self):
1078 """ 1079 Get debugged name 1080 1081 @rtype: STRING 1082 @return: Name of the Process been debugged 1083 """ 1084 return debugger.get_debugged_name()
1085
1086 - def getDebuggedPid(self):
1087 """ 1088 Get debugged pid 1089 1090 @rtype: DWORD 1091 @return: Process ID 1092 """ 1093 return debugger.get_PID()
1094
1095 - def isAdmin(self):
1096 """ 1097 Is debugger running as admin? 1098 @rtype: INTEGER 1099 @return: 1 if running as admin 1100 """ 1101 return debugger.is_admin()
1102
1103 - def getInfoPanel(self):
1104 """ 1105 Get information displayed on Info Panel 1106 1107 @rtype: TUPLE 1108 @return: Python Tuple with the 3 lines from InfoPanel 1109 """ 1110 return debugger.get_info_panel()
1111
1112 - def getCurrentAddress(self):
1113 """ 1114 Get the current address been focus on the disasm window 1115 1116 @rtype: DWORD 1117 @return: Address 1118 """ 1119 return debugger.get_current_address()
1120 1121
1122 - def getAllModules(self):
1123 """ 1124 Get all loaded modules. 1125 1126 @rtype: DICTIONARY 1127 @return: Dict of Modules 1128 """ 1129 1130 if self.Modules: 1131 return self.Modules 1132 1133 modulos = debugger.get_all_modules() 1134 symbol = 1 1135 for mod in modulos.keys(): 1136 if not self.Modules.has_key(mod): 1137 # Modules are stable 1138 m = Module(mod, modulos[mod][0], modulos[mod][1], modulos[mod][2]) 1139 mod_dict = self._getmoduleinfo(modulos[mod][0]) 1140 m.setModuleExtension(mod_dict) 1141 if symbol: 1142 self.getAllSymbols() #_getsymbols() 1143 symbol = 0 1144 1145 try: 1146 m.setSymbols( self.Symbols[ mod.lower() ] ) 1147 except KeyError: 1148 pass 1149 self.Modules[mod] = m 1150 # XXX TODO: Here we must check between the modules that are loaded and the catched one on self.Modules 1151 # so we know if a module is not there anymore 1152 1153 return self.Modules
1154
1155 - def getModuleByAddress(self, address):
1156 1157 modulos = debugger.get_all_modules() 1158 1159 for name in modulos.keys(): 1160 total_range = modulos[name][0] + modulos[name][1] 1161 if address > modulos[name][0] and address < total_range: 1162 if not self.Modules.has_key(name): 1163 m = Module(name, modulos[name][0], modulos[name][1], modulos[name][2]) 1164 mod_dict = self._getmoduleinfo(modulos[name][0]) 1165 m.setModuleExtension(mod_dict) 1166 self.Modules[name] = m 1167 return m 1168 else: 1169 return self.Modules[name]
1170
1171 - def getModule(self, name):
1172 """ 1173 Get Module Information 1174 1175 @type name: STRING 1176 @param name: Name of the module 1177 1178 @rtype: Module OBJECT 1179 @return: A Module object 1180 """ 1181 1182 #self.getAllModules() 1183 1184 modulos = debugger.get_all_modules() 1185 if modulos.has_key(name): 1186 if not self.Modules.has_key(name): 1187 # Modules are stable 1188 m = Module(name, modulos[name][0], modulos[name][1], modulos[name][2]) 1189 mod_dict = self._getmoduleinfo(modulos[name][0]) 1190 m.setModuleExtension(mod_dict) 1191 #if symbol: 1192 # self.getAllSymbols() #_getsymbols() 1193 # symbol = 0 1194 1195 #try: 1196 # m.setSymbols( self.Symbols[ mod.lower() ] ) 1197 #except KeyError: 1198 # pass 1199 self.Modules[name] = m 1200 return m 1201 else: 1202 return self.Modules[name] 1203 1204 #if type(name) == type(''): 1205 # try: 1206 # return self.Modules[ name ] 1207 # except KeyError: 1208 # return None 1209 #else: 1210 # for mod in self.Modules.keys(): 1211 # if self.Modules[ mod ].baseaddress == name: 1212 # return self.Modules[ mod ] 1213 return None
1214
1215 - def _getmoduleinfo(self,base_address):
1216 return debugger.get_mod_info(base_address)
1217
1218 - def getReferencedStrings(self,code_base):
1219 """ 1220 Get all referenced string from module 1221 1222 @type name: DWORD 1223 @param name: Code Base Address 1224 @rtype: LIST 1225 @return: A list of tuples with referenced strings (address, string, comment) 1226 """ 1227 return debugger.get_referenced_strings(code_base)
1228
1229 - def ps(self):
1230 """ 1231 List all active processes. 1232 1233 @rtype: LIST 1234 @return: A list of tuples with process information (pid, name, path, services, tcp list, udp list) 1235 """ 1236 return debugger.ps()
1237
1238 - def getSehChain(self):
1239 """ 1240 Get the SEH chain. 1241 1242 @rtype: LIST 1243 @return: A list of tuples with SEH information (seh, handler) 1244 """ 1245 return debugger.get_seh_chain()
1246
1247 - def getEvent(self):
1248 """ 1249 Get the current Event 1250 1251 @rtype: Event Object 1252 @return: Event 1253 """ 1254 event = debugger.get_event() 1255 EventCode = event[0][0] 1256 try: 1257 return self.Eventndx[ EventCode ]( event ) 1258 except KeyError: # We cannot handle this event 1259 return None
1260
1261 - def getPage(self, addr):
1262 """ 1263 Get a memory page. 1264 1265 @type addr: DWORD 1266 @param addr: Address of a beginning of the Page 1267 1268 @rtype: Page OBJECT 1269 @return: Memory Page 1270 """ 1271 self.getMemoryPages() 1272 try: 1273 return self.MemoryPages[addr] 1274 except KeyError: 1275 return None
1276
1277 - def getMemoryPageByOwner(self, owner):
1278 """ 1279 Get the Memory Pages belonging to the given dll. 1280 1281 @type owner: STRING 1282 @param owner: Name of the dll 1283 1284 @rtype: LIST 1285 @return: LIST of Memory Pages belonging to the given dll 1286 """ 1287 self.getMemoryPages() 1288 1289 pages = [] 1290 for a in self.MemoryPages.keys(): 1291 mem = self.MemoryPages[a] 1292 if mem.getOwner().lower() == owner.lower(): 1293 pages.append( mem ) 1294 1295 return pages
1296
1297 - def getMemoryPageByOwnerAddress(self, owner_addr):
1298 """ 1299 Get the Memory Pages belonging to the given dll by its base address. 1300 1301 @type owner: STRING 1302 @param owner: Name of the dll 1303 1304 @rtype: LIST 1305 @return: LIST of Memory Pages belonging to the given dll 1306 """ 1307 self.getMemoryPages() 1308 1309 pages = [] 1310 for a in self.MemoryPages.keys(): 1311 mem = self.MemoryPages[a] 1312 if mem.owner == owner_addr: 1313 pages.append( mem ) 1314 1315 return pages
1316
1317 - def getMemoryPageByAddress(self, address):
1318 """ 1319 Get a memory page. 1320 1321 @type address: DWORD 1322 @param address: Address in the range of the Page 1323 1324 @rtype: Page OBJECT 1325 @return: Memory Page 1326 """ 1327 1328 self.getMemoryPages() 1329 for a in self.MemoryPages.keys(): 1330 mem = self.MemoryPages[a] 1331 if mem.baseaddress <= address and (mem.getBaseAddress() + mem.size) > address : 1332 return mem 1333 return None
1334
1335 - def getMemoryPages(self):
1336 """ 1337 Get All memory pages. 1338 1339 @rtype: DICTIONARY 1340 @return: List of all memory pages 1341 """ 1342 if self.MemoryPages: 1343 return self.MemoryPages 1344 1345 pages = debugger.get_memory_pages() 1346 1347 for addr in pages.keys(): 1348 m = MemoryPage(addr, self) 1349 m._getfromtuple(pages[addr]) 1350 self.MemoryPages[addr] = m 1351 return self.MemoryPages
1352
1353 - def vmQuery(self,address):
1354 """ 1355 Query Memory Page 1356 1357 @type address: DWORD 1358 @param address: Base Address of memory page 1359 1360 @rtype: Python List 1361 @return: List with memory page structure 1362 """ 1363 return debugger.vm_query(address)
1364 1365
1366 - def getAllHandles(self):
1367 """ 1368 Get all handles. 1369 1370 @rtype: DICTIONARY 1371 @return: All the process handles 1372 """ 1373 if self.Handles: 1374 return self.Handles 1375 1376 handles = debugger.get_all_handles() 1377 for h in handles.keys(): 1378 H = Handle( h ) 1379 H._getfromtuple( handles[h] ) 1380 self.Handles[ h ] = H 1381 return self.Handles
1382
1383 - def getAllThreads(self):
1384 """ 1385 Get all threads. 1386 @rtype: LIST 1387 @return: All process threads 1388 """ 1389 1390 self.Threads = DictTypes() #clean the dict first 1391 threads = debugger.get_all_threads() 1392 for thread in threads: 1393 T = Thread() 1394 T._getfromtuple(thread) 1395 self.Threads[T.getId()] = T 1396 return self.Threads
1397 1398 1399 1400
1401 - def getAllSymbols(self):
1402 """ 1403 Get All Symbols. 1404 1405 @rtype: DICTIONARY 1406 @return: All the symbols of the process 1407 """ 1408 if self.Symbols: 1409 return self.Symbols 1410 1411 names = debugger.get_all_names() 1412 current = self.getDebuggedName().rsplit(".", 1)[0] 1413 # reorder it a little bit 1414 for a in names.keys(): 1415 s=Symbol(a) 1416 s._getfromtuple( names[a] ) 1417 if current.lower() != s.getModule().lower(): 1418 module = s.getModule() + ".dll" 1419 else: 1420 module = s.getModule() + ".exe" 1421 1422 if self.Symbols.has_key( module ): 1423 self.Symbols[ module ][ a ] = s 1424 else: 1425 self.Symbols[ module ] = { a : s } 1426 1427 return self.Symbols
1428
1429 - def getAllSymbolsFromModule(self,address):
1430 """ 1431 Get Symbols from module. 1432 @type Address: DWORD 1433 @param Address: Address from module. 1434 1435 @rtype: DICTIONARY 1436 @return: All the symbols of the module 1437 """ 1438 1439 names = debugger.get_all_names(address) 1440 return names
1441 1442 1443
1444 - def callStack(self):
1445 """ 1446 Get a Back Trace (Call stack). 1447 1448 @rtype: LIST of Stack OBJECT 1449 @return: list of all the stack trace 1450 """ 1451 if self.BackTrace: 1452 return self.BackTrace 1453 1454 callstack = debugger.get_call_stack() 1455 for a in callstack: 1456 s = Stack() 1457 s._setfromtuple(a) 1458 self.BackTrace.append(s) 1459 return self.BackTrace
1460
1461 - def getCallTree(self,address=0):
1462 """ 1463 Get the call tree of given address. 1464 @rtype: LIST of Call tuples 1465 @return: list of all the call tree 1466 ulong line; // Line number in column 1467 ulong dummy; // Must be 1 1468 ulong type; // Type, set of TY_xxx 1469 ulong entry; // Address of function 1470 ulong from; // Address of calling instruction 1471 ulong calls; // Address of called subfunction 1472 """ 1473 1474 return debugger.get_call_tree(address)
1475 1476
1477 - def findModule(self, address):
1478 """ 1479 Find which module an address belongs to. 1480 1481 @type address: DWORD 1482 @param address: Address 1483 1484 @rtype: LIST 1485 @return: Tuple of module information (name, base address) 1486 1487 """ 1488 mod = debugger.find_module( address ) 1489 if mod == -1: 1490 mod = () 1491 return mod
1492
1493 - def findModuleByName(self, modname):
1494 """ 1495 Find a module by name (case insensitive). 1496 1497 @type modname: STRING 1498 @param modname: Module Name 1499 1500 @rtype: OBJECT|BOOLEAN 1501 @return: a Module object matching the given name or False if it's not found or name is ambiguous 1502 1503 """ 1504 1505 found=False 1506 for name,mod in self.getAllModules().iteritems(): 1507 if modname.lower() in name.lower(): 1508 if found != False: #name is ambiguous 1509 return False 1510 found=mod 1511 1512 return found
1513
1514 - def getHeapsAddress(self):
1515 """ 1516 Get a the process heaps 1517 1518 @rtype: LIST of DWORD 1519 @return: List of Heap Address 1520 """ 1521 self.HeapsAddr = [] 1522 1523 peb = self.getPEB() 1524 addr = peb.ProcessHeaps 1525 for ndx in range(0, peb.NumberOfHeaps): 1526 l = self.readLong( addr + ndx * 4 ) 1527 if l: 1528 self.HeapsAddr.append( l ) 1529 1530 return self.HeapsAddr
1531
1532 - def getAddressOfExpression(self, expression):
1533 """ 1534 Get the address from an expression as ntdll.RtlAllocateHeap 1535 1536 @type expression: STRING 1537 @param expression: Expression to translate into an address 1538 1539 @rtype: DWORD 1540 @return: Address of the Expression 1541 """ 1542 return debugger.get_addr_from_exp(expression)
1543 1544
1545 - def getAddress(self, expression):
1546 """ 1547 Get the address from an expression as ntdll.RtlAllocateHeap 1548 1549 @type expression: STRING 1550 @param expression: Expression to translate into an address 1551 1552 @rtype: DWORD 1553 @return: Address of the Expression 1554 1555 """ 1556 return debugger.get_addr_from_exp(expression)
1557 1558 ### Displaying information ### 1559 # Error, Log, Creating new windows, etc 1560
1561 - def error(self, msg):
1562 """ 1563 This function shows an Error dialog with a custom message. 1564 1565 @type msg: STRING 1566 @param msg: Message 1567 """ 1568 return debugger.error( msg )
1569
1570 - def openTextFile(self,path=""):
1571 """ 1572 Opens text file in MDI windows. ( if no path is specified browsefile dialog will pop up ) 1573 1574 @type: STRING 1575 @param: (Optional, Def= "") Path to file 1576 """ 1577 if (len(path) > 0): 1578 return debugger.open_text_file(path) 1579 else: 1580 return debugger.open_text_file()
1581
1582 - def setStatusBar(self, msg):
1583 """ 1584 Sets the status bar message. 1585 1586 @type msg: STRING 1587 @param msg: Message 1588 """ 1589 return debugger.info_line(msg)
1590
1591 - def clearStatusBar(self):
1592 """ 1593 Removes the current status bar message. 1594 """ 1595 return debugger.info_line()
1596
1597 - def logLines(self, data, address = 0, highlight = False, gray = False , focus = 0):
1598 """ 1599 Adds multiple lines of ASCII text to the log window. 1600 1601 @type msg: LIST of STRING 1602 @param msg: List of Message to add (max size of msg is 255 bytes) 1603 1604 @type address: DWORD 1605 @param address: Address associated with the message 1606 1607 @type highlight: BOOLEAN 1608 @param highlight: Set highlight text 1609 1610 @type gray: BOOLEAN 1611 @param gray: Set gray text 1612 """ 1613 return [ self.log(d, address, highlight, gray, focus) for d in data.split("\n") ]
1614
1615 - def log(self, msg, address = 0xbadf00d ,highlight = False, gray = False , focus = 0):
1616 """ 1617 Adds a single line of ASCII text to the log window. 1618 1619 @type msg: STRING 1620 @param msg: Message (max size is 255 bytes) 1621 1622 @type address: DWORD 1623 @param address: Address associated with the message 1624 1625 @type highlight: BOOLEAN 1626 @param highlight: Set highlight text 1627 1628 @type gray: BOOLEAN 1629 @param gray: Set gray text 1630 """ 1631 if gray and not highlight: 1632 highlight = -1 1633 return debugger.add_to_list( address, int(highlight), msg[:255],focus)
1634
1635 - def updateLog(self):
1636 """ 1637 Forces an immediate update of the log window. 1638 """ 1639 debugger.update_list()
1640
1641 - def createLogWindow(self):
1642 """ 1643 Creates or restores the log window. 1644 """ 1645 return debugger.create_list_window()
1646
1647 - def createWindow(self, title, col_titles):
1648 """ 1649 Creates a custom window. 1650 1651 @type title: STRING 1652 @param title: Window title 1653 1654 @type col_titles: LIST OF STRING 1655 @param col_titles: Column titles list 1656 1657 @return HWND: Handler of created table 1658 """ 1659 return self.createTable( title, col_titles )
1660
1661 - def createTable(self,title,col_titles):
1662 """ 1663 Creates a custom window. 1664 1665 @type title: STRING 1666 @param title: Window title 1667 1668 @type col_titles: LIST OF STRING 1669 @param col_titles: Column titles list 1670 1671 """ 1672 return Table(self,title,col_titles)
1673
1674 - def setFocus(self,handler):
1675 """ 1676 Set focus on window. 1677 1678 @type handler: ULONG 1679 @param handler: Windows Handler 1680 1681 @return phandler: Handle to the window that previously had the focus. 1682 """ 1683 return debugger.set_focus(handler)
1684
1685 - def isValidHandle(self,handler):
1686 """ 1687 Does a window still exist? 1688 1689 @type handler: ULONG 1690 @param handler: Windows to check handle 1691 1692 @return: INT : 1 Exists, 0 Doesnt exist 1693 """ 1694 return debugger.is_valid_handle(handler)
1695
1696 - def setStatusBarAndLog(self, addr, msg):
1697 """ 1698 Sets and logs a status bar message. 1699 1700 @type addr: DWORD 1701 @param addr: Address related with the message 1702 1703 @type msg: STRING 1704 @param msg: Message 1705 """ 1706 return debugger.message(addr, msg)
1707
1708 - def flashMessage(self, msg):
1709 """ 1710 Flashes a message at status bar. 1711 1712 @type msg: STRING 1713 @param msg: Message 1714 """ 1715 return debugger.flash(msg)
1716
1717 - def setProgressBar(self, message, promille=100):
1718 """ 1719 Displays a progress bar which can contain formatted text and a progress percentage. 1720 If the formatted text contains a dollar sign ('$') it will be replaced by the current progress percentage. 1721 1722 @type msg: STRING 1723 @param msg: Message 1724 1725 @type promille: DWORD 1726 @param promille: Progress. At 0 the progress bar is closed and the previous message restored. 1727 """ 1728 return debugger.progress(promille, message)
1729
1730 - def closeProgressBar(self):
1731 """ 1732 Close Progress Bar. 1733 """ 1734 return debugger.progress(0, "")
1735
1736 - def getComment(self, address,type=0xFD):
1737 """ 1738 Get the comment of the opcode line. 1739 1740 @type address: DWORD 1741 @param address: Address of the requested comment 1742 1743 @rtype: STRING 1744 @return: Requested comment 1745 """ 1746 comment=None 1747 #First, try to fetch any comment 1748 if type == 0xFD: 1749 #alway look for user defined comments first 1750 comment=debugger.get_comment(address,NM_COMMENT) 1751 if not comment: 1752 #try argument comment 1753 comment=debugger.get_comment(address,NM_ARG) 1754 if not comment: 1755 #try library comment 1756 comment=debugger.get_comment(address,NM_LIBCOMM) 1757 if not comment: 1758 #try Analyse comment 1759 comment=debugger.get_comment(address,NM_ANALYSE) 1760 else: 1761 #Let the user pick the comment type 1762 comment=debugger.get_comment(address,type) 1763 1764 return comment
1765 1766 1767 #If you are unsure about what kind of comment are you looking for, 1768 #dont use this methods, and go for the automatic one "getComment(address)" 1769
1770 - def getUserComment(self,address):
1771 return debugger.get_comment(address,NM_COMMENT)
1772
1773 - def getArgumentsComment(self,address):
1774 return debugger.get_comment(address,NM_ARG)
1775
1776 - def getAnalyseComment(self,address):
1777 return debugger.get_comment(address,NM_ANALYSE)
1778
1779 - def getLibraryComment(self,address):
1780 return debugger.get_comment(address,NM_LIBCOMM)
1781 1782
1783 - def setComment(self, address, comment):
1784 """ 1785 Set a comment. 1786 1787 @type address: DWORD 1788 @param address: Address of the Comment 1789 1790 @type comment: STRING 1791 @param comment: Comment to add 1792 """ 1793 return debugger.set_comment(address, comment)
1794
1795 - def setLabel(self, address, label):
1796 """ 1797 Set a label. 1798 1799 @type adresss: DWORD 1800 @param address: Address to the new label 1801 1802 @type label: STRING 1803 @param label: Label to add 1804 """ 1805 return debugger.set_label(address, label)
1806
1807 - def markBegin(self):
1808 """ 1809 Place a start mark for timming your script 1810 """ 1811 self.timer=time.clock()
1812
1813 - def markEnd(self):
1814 """ 1815 Place an End mark for timming your script 1816 1817 @rtype time: DWORD 1818 @return time: time in seconds 1819 """ 1820 if self.timer >0: 1821 return time.clock() - self.timer 1822 else: 1823 return 0
1824
1825 - def findDependecies(self, lookfor):
1826 """ 1827 Find exported function on the loaded dlls. 1828 1829 @type lookfor: TABLE of DWORD 1830 @param lookfor: Table of functions to search 1831 1832 @rtype: DICTIONARY 1833 @return: Dictionary 1834 """ 1835 #lookfor = ["rpcrt4.rpcserveruseprotseq","rpcrt4.rpcserveruseprotseqex","rpcrt4.rpcserveruseprotseqw", "rpcrt4.rpcserveruseprotseqEp", "rpcrt4.rpcserveruseprotseqif",\ 1836 # "rpcrt4.rpcserveruseallprotseqs", "rpcrt4.rpcserveruseallprotseqsif", "rpcrt4.rpcserveruseprotseqepw",\ 1837 # "rpcrt4.rpcserveruseprotseqepexw", "rpcrt4.rpcserveruseallprotseqsifw"] 1838 symbol = self.getAllSymbols() 1839 1840 result = {} 1841 for modname in symbol.keys(): 1842 modsym = symbol[modname] 1843 for modaddr in modsym.keys(): 1844 mod = modsym[modaddr] 1845 if mod.name.lower() in lookfor: 1846 if mod.type == "Import": 1847 if result.has_key(modname): 1848 result[modname].append(mod) 1849 else: 1850 result[modname] = [mod] 1851 return result
1852 1853 1854
1855 - def isVmWare(self):
1856 """ 1857 Check if debugger is running under a vmware machine 1858 1859 @rtype: DWORD 1860 @return: 1 if vmware machine exists 1861 """ 1862 return debugger.check_vmware()
1863 1864 ### Breakpoint Functions ### 1865 # All kind of breakpoint functions 1866 1867 # For manual breakpoints: 1868 # key shiftkey Action 1869 # VK_F2 0 Toggle unconditional breakpoint 1870 # VK_F2 Pressed (not 0) Set conditional breakpoint 1871 # VK_F4 Pressed (not 0) Set logging breakpoint 1872
1873 - def manualBreakpoint(self, address, key, shiftkey, font):
1874 """ 1875 Set a Manual Breakpoint. 1876 1877 @type address: DWORD 1878 @param address: Address of the breakpoint 1879 1880 @type key: DWORD 1881 @param key: VK_F2 (Conditional Breakpoint) or VK_F4 (Logging Breakpoint) 1882 1883 @type shiftkey: DWORD 1884 @param shiftkey: State of the shiftkey 1885 1886 @type font: STRING 1887 @param font: See ImmFonts 1888 """ 1889 if not ImmFonts.has_key( font.lower() ): 1890 font = ImmFonts[ "fixed" ] 1891 else: 1892 font = ImmFonts[ font.lower() ] 1893 1894 return debugger.manual_breakpoint(address, key, int(shiftkey), font)
1895
1896 - def setUnconditionalBreakpoint(self, address, font="fixed"):
1897 """ 1898 Set an Unconditional Breakpoint. 1899 1900 @type address: DWORD 1901 @param address: Address for the breakpoint 1902 1903 @type font: STRING 1904 @param font: (Optional, Def: fixed) Font for the breakpoint 1905 """ 1906 return self.manualBreakpoint(address, BpKeys["VK_F2"], False, font)
1907
1908 - def setConditionalBreakpoint(self, address, font="fixed"):
1909 """ 1910 Set a Conditional Breakpoint. 1911 1912 @type address: DWORD 1913 @param address: Address for the breakpoint 1914 1915 @type font: STRING 1916 @param font: (Optional, Def: fixed) Font for the breakpoint 1917 """ 1918 return self.manualBreakpoint(address, BpKeys["VK_F2"], True, font)
1919
1920 - def setLoggingBreakpoint(self, address):
1921 """ 1922 Set a Logging Breakpoint. (This breakpoint will not puase the execution, it will just act as a Watch point" 1923 1924 @type address: DWORD 1925 @param address: Address for the breakpoint 1926 """ 1927 return debugger.set_logging_breakpoint(address)
1928
1929 - def setWatchPoint(self,address):
1930 """ 1931 Set a watching Breakpoint. 1932 1933 @type address: DWORD 1934 @param address: Address for the watchpoint 1935 """ 1936 return debugger.set_logging_breakpoint(address)
1937 1938 1939 #define TY_SET 0x00000100 // Code INT3 is in memory 1940 #define TY_ACTIVE 0x00000200 // Permanent breakpoint 1941 #define TY_DISABLED 0x00000400 // Permanent disabled breakpoint 1942 #define TY_ONESHOT 0x00000800 // Temporary stop 1943 #define TY_TEMP 0x00001000 // Temporary breakpoint 1944 #define TY_KEEPCODE 0x00002000 // Set and keep command code 1945 #define TY_KEEPCOND 0x00004000 // Keep condition unchanged (0: remove) 1946 #define TY_NOUPDATE 0x00008000 // Don't redraw breakpoint window 1947 #define TY_RTRACE 0x00010000 // Pseudotype of run trace breakpoint 1948
1949 - def setTemporaryBreakpoint(self, address, continue_execution = False, stoptrace = False):
1950 """ 1951 Set a Temporary Breakpoint. 1952 1953 @type address: DWORD 1954 @param address: Address for the breakpoint 1955 1956 @type continue_execution: BOOLEAN 1957 @param continue_execution: Automatically removes temporary breakpoint when hit and continue execution 1958 1959 @type stoptrace: BOOLEAN 1960 @param stoptrace: Stop any kind of trace or animation when hit 1961 """ 1962 if continue_execution: 1963 flags = BpFlags["TY_TEMP"] | BpFlags["TY_KEEPCOND"] 1964 else: 1965 flags = BpFlags["TY_ONESHOT"] | BpFlags["TY_KEEPCOND"] 1966 if stoptrace: 1967 flags |= BpFlags["TY_STOPAN"] 1968 1969 return debugger.temp_breakpoint(address, flags)
1970
1971 - def setBreakpoint(self, address):
1972 """ 1973 Set a Breakpoint. 1974 1975 @type address: DWORD 1976 @param address: Address for the breakpoint 1977 """ 1978 flags = BpFlags["TY_ACTIVE"] 1979 return debugger.set_breakpoint(address, flags, "")
1980
1981 - def setBreakpointOnName(self,name):
1982 """ 1983 Set a Breakpoint. 1984 1985 @type Name: STRING 1986 @param Name: name of the function to bp 1987 1988 @rtype: DWORD 1989 @return: Address of name 1990 """ 1991 return debugger.set_breakpoint_on_name(name)
1992
1993 - def disableBreakpoint(self, address):
1994 """ 1995 Disable Breakpoint. 1996 1997 @type address: DWORD 1998 @param address: Address for the breakpoint 1999 """ 2000 flags = BpFlags["TY_DISABLED"] 2001 return debugger.set_breakpoint(address, flags, "")
2002
2003 - def deleteBreakpoint(self,address,address2=0):
2004 """ 2005 Delete Breakpoint. 2006 2007 @type address: DWORD 2008 @param address: Start range of addresses to delete breakpoints 2009 @type address2: DWORD 2010 @param Address: End range of addresses to delete breakpoints 2011 """ 2012 return debugger.delete_breakpoints(address,address2)
2013 2014
2015 - def getBreakpointType(self, address):
2016 """ 2017 Get the Breakpoint type. 2018 2019 @type address: DWORD 2020 @param address: Address for the breakpoint 2021 2022 @rtype: STRING 2023 @return: Breakpoint type 2024 """ 2025 2026 type = debugger.get_breakpoint_type_count(address) 2027 for a in BpFlags.keys(): 2028 if BpFlags[a] == type: 2029 return a 2030 return ""
2031
2032 - def setMemBreakpoint(self,addr, type, size=4):
2033 """ 2034 Modifies or removes a memory breakpoint. 2035 2036 @type address: DWORD 2037 @param address: Address for the breakpoint 2038 2039 @type type: DWORD 2040 @param type: Type of Memory Breakpoint (READ/WRITE/SFX) 2041 2042 @type size: DWORD 2043 @param size: (Optional, Def: 4) Size of Memory Breakpoint 2044 """ 2045 ty = type.strip().split("|") 2046 flags = 0 2047 for a in ty: 2048 try: 2049 flags |= BpMemFlags[a] 2050 except KeyError: 2051 raise Exception("Bad Flags for setMembreakpoint: %s" % type) 2052 2053 return debugger.set_mem_breakpoint(flags, addr, size)
2054
2055 - def disableMemBreakpoint(self, addr):
2056 """ 2057 Disable Memory Breakpoint. 2058 """ 2059 return debugger.set_mem_breakpoint(0, addr,0)
2060 2061
2062 - def setHardwareBreakpoint(self,addr,type=HB_CODE,size=1):
2063 """ 2064 Sets Hardware breakpoint 2065 """ 2066 return debugger.set_hardware_breakpoint(type,addr,size)
2067 2068 2069 ### Read/Write/Search ### 2070 # Read/Write from process memory 2071
2072 - def writeLong(self, address, dword):
2073 """ 2074 Write long to memory address. 2075 2076 @type address: DWORD 2077 @param address: Address 2078 2079 @type dword: DWORD 2080 @param dword: long to write 2081 """ 2082 return debugger.write_memory( immutils.intel_order( dword ), address, 4, 0x2 )
2083
2084 - def writeMemory(self, address, buf):
2085 """ 2086 Write buffer to memory address. 2087 2088 @type address: DWORD 2089 @param address: Address 2090 2091 @type buf: BUFFER 2092 @param buf: Buffer 2093 """ 2094 return debugger.write_memory(buf, address, len(buf), 0x2)
2095
2096 - def readMemory(self, address, size):
2097 """ 2098 Read block of memory. 2099 2100 @type address: DWORD 2101 @param address: Address 2102 2103 @type size: DWORD 2104 @param size: Size 2105 2106 @rtype: BUFFER 2107 @return: Process memory 2108 """ 2109 return debugger.read_memory(address, size, 0x01|0x02)
2110
2111 - def readLong(self, address):
2112 """ 2113 Read a Long from the debugged process 2114 2115 @type address: DWORD 2116 @param address: Address 2117 2118 @rtype: DWORD 2119 @return: Long 2120 """ 2121 long = self.readMemory(address, 0x4) 2122 if len(long) == 4: 2123 try: 2124 return immutils.str2int32_swapped(long) 2125 except ValueError: 2126 raise Exception, "readLong failed to gather a long at 0x%08x" % address 2127 else: 2128 raise Exception, "readLong failed to gather a long at 0x%08x" % address
2129
2130 - def readString(self, address):
2131 """ 2132 Read a string from the remote process 2133 2134 @type address: DWORD 2135 @param address: Address of the string 2136 2137 @rtype: String 2138 @return: String 2139 """ 2140 return self.readUntil(address, '\x00')
2141
2142 - def readWString(self,address):
2143 """ 2144 Read a unicode string from the remote process 2145 2146 @type address: DWORD 2147 @param address: Address of the unicode string 2148 2149 @rtype: Unicode String 2150 @return: Unicode String 2151 """ 2152 wstring = self.readUntil(address, "\x00\x00") 2153 2154 if not wstring.endswith("\x00"): 2155 wstring = wstring + "\x00" 2156 2157 return wstring
2158
2159 - def readUntil(self, address, ending):
2160 """ 2161 Read string until ending starting at given address 2162 2163 @param Address: Start address 2164 @return Readed String 2165 """ 2166 readed=[] 2167 while(1): 2168 read = self.readMemory( address, 16 ) 2169 address += 16 2170 ndx = read.find(ending) 2171 if ndx != -1: 2172 readed.append( read[0:ndx] ) 2173 break 2174 else: 2175 readed.append( read ) 2176 2177 return string.joinfields(readed, "")
2178
2179 - def readShort(self, address):
2180 """ 2181 Read a short integer from the remote process 2182 2183 @type address: DWORD 2184 @param address: Address of the short 2185 2186 @rtype: Short Integer 2187 @return: Short 2188 """ 2189 short = self.readMemory(address, 0x2) 2190 return immutils.str2int16_swapped(short)
2191
2192 - def searchShort(self, short , flag=None):
2193 """ 2194 Search a short integer on the remote process memory 2195 2196 @type short: SHORT 2197 @param short: Short integer to search for 2198 2199 @type flag: STRING 2200 @param flag: Memory Protection String Flag 2201 2202 @rtype: List 2203 @return: List of address of the short integer founded 2204 """ 2205 return self.search(immutils.int2str16_swapped(short),flag)
2206
2207 - def searchLong(self, long, flag=None):
2208 """ 2209 Search a short integer on the remote process memory 2210 2211 @type long: DWORD 2212 @param long: integer to search for 2213 @type flag: STRING 2214 @param flag: Memory Protection String Flag 2215 2216 @rtype: List 2217 @return: List of address of the integer founded 2218 """ 2219 return self.search( immutils.int2str32_swapped(long),flag) 2220
2221 - def searchOnExecute(self,buf):
2222 """ 2223 Search string in executable memory. 2224 2225 @param buf: Buffer to search for 2226 @return: A list of address where the string was found on memory 2227 """ 2228 if not buf: 2229 return [] 2230 self.getMemoryPages() 2231 find = [] 2232 buf_size = len(buf) 2233 for a in self.MemoryPages.keys(): 2234 if (MemoryProtection["PAGE_EXECUTE"] == self.MemoryPages[a].access\ 2235 or MemoryProtection["PAGE_EXECUTE_READ"] == self.MemoryPages[a].access\ 2236 or MemoryProtection["PAGE_EXECUTE_READWRITE"] == self.MemoryPages[a].access\ 2237 or MemoryProtection["PAGE_EXECUTE_WRITECOPY"] == self.MemoryPages[a].access): 2238 mem = self.MemoryPages[a].getMemory() 2239 if not mem: 2240 continue 2241 ndx = 0 2242 while 1: 2243 f = mem[ndx:].find( buf ) 2244 if f == -1 : break 2245 find.append( ndx + f + a ) 2246 ndx += f + buf_size 2247 return find
2248
2249 - def searchOnWrite(self,buf):
2250 """ 2251 Search string in writable memory. 2252 2253 @param buf: Buffer to search for 2254 @return: A list of address where the string was found on memory 2255 """ 2256 if not buf: 2257 return [] 2258 self.getMemoryPages() 2259 find = [] 2260 buf_size = len(buf) 2261 for a in self.MemoryPages.keys(): 2262 if (MemoryProtection["PAGE_READWRITE"] == self.MemoryPages[a].access\ 2263 or MemoryProtection["PAGE_WRITECOPY"] == self.MemoryPages[a].access\ 2264 or MemoryProtection["PAGE_EXECUTE_READWRITE"] == self.MemoryPages[a].access\ 2265 or MemoryProtection["PAGE_EXECUTE_WRITECOPY"] == self.MemoryPages[a].access): 2266 mem = self.MemoryPages[a].getMemory() 2267 if not mem: 2268 continue 2269 ndx = 0 2270 while 1: 2271 f = mem[ndx:].find( buf ) 2272 if f == -1 : break 2273 find.append( ndx + f + a ) 2274 ndx += f + buf_size 2275 return find
2276
2277 - def searchOnRead(self,buf):
2278 """ 2279 Search string in readable memory. 2280 2281 @param buf: Buffer to search for 2282 @return: A list of address where the string was found on memory 2283 """ 2284 if not buf: 2285 return [] 2286 self.getMemoryPages() 2287 find = [] 2288 buf_size = len(buf) 2289 for a in self.MemoryPages.keys(): 2290 if (MemoryProtection["PAGE_READONLY"] == self.MemoryPages[a].access\ 2291 or MemoryProtection["PAGE_EXECUTE_READ"] == self.MemoryPages[a].access): 2292 mem = self.MemoryPages[a].getMemory() 2293 if not mem: 2294 continue 2295 ndx = 0 2296 while 1: 2297 f = mem[ndx:].find( buf ) 2298 if f == -1 : break 2299 find.append( ndx + f + a ) 2300 ndx += f + buf_size 2301 return find
2302
2303 - def search( self, buf, flag = None ):
2304 if not buf: 2305 return [] 2306 2307 self.getMemoryPages() 2308 find = [] 2309 buf_len = len(buf) 2310 2311 for a in self.MemoryPages.keys(): 2312 if flag: 2313 if (MemoryProtection[flag] == self.MemoryPages[a].access): 2314 mem = self.MemoryPages[a].getMemory() 2315 if not mem: 2316 continue 2317 2318 mem_list = mem.split( buf ) 2319 total_length = buf_len * -1 2320 recur_find = [] 2321 for i in mem_list: 2322 2323 total_length = total_length + len(i) + buf_len 2324 recur_find.append( a + total_length ) 2325 2326 # The last one is the remaining slice from the split 2327 # so remove it from the list 2328 del recur_find[ len(recur_find) - 1 ] 2329 find += recur_find 2330 2331 else: 2332 mem = self.MemoryPages[a].getMemory() 2333 if not mem: 2334 continue 2335 mem_list = mem.split( buf ) 2336 total_length = buf_len * -1 2337 recur_find = [] 2338 for i in mem_list: 2339 2340 total_length = total_length + len(i) + buf_len 2341 recur_find.append( a + total_length ) 2342 2343 # The last one is the remaining slice from the split 2344 # so remove it from the list 2345 del recur_find[ len(recur_find) - 1 ] 2346 find += recur_find 2347 2348 return find
2349 2350
2351 - def oldSearch(self, buf,flag=None):
2352 """ 2353 Search string in memory. 2354 2355 @param buf: Buffer to search for 2356 @param flag: Memory Protection String Flag 2357 @return: A list of address where the string was found on memory 2358 2359 2360 """ 2361 if not buf: 2362 return [] 2363 2364 self.getMemoryPages() 2365 find = [] 2366 buf_size = len(buf) 2367 for a in self.MemoryPages.keys(): 2368 if flag: 2369 if (MemoryProtection[flag] == self.MemoryPages[a].access): 2370 mem = self.MemoryPages[a].getMemory() 2371 if not mem: 2372 continue 2373 ndx = 0 2374 while 1: 2375 f = mem[ndx:].find( buf ) 2376 if f == -1 : break 2377 find.append( ndx + f + a ) 2378 ndx += f + buf_size 2379 else: 2380 mem = self.MemoryPages[a].getMemory() 2381 if not mem: 2382 continue 2383 ndx = 0 2384 while 1: 2385 f = mem[ndx:].find( buf ) 2386 if f == -1 : break 2387 find.append( ndx + f + a ) 2388 ndx += f + buf_size 2389 return find
2390
2391 - def searchCommands(self, cmd):
2392 """ 2393 Search for a sequence of commands in all executable modules loaded. 2394 @type cmd: STRING 2395 @param cmd: Assembly code to search for (Search using regexp is available. See Documentation) 2396 2397 @rtype: List 2398 @return: List of address of the command found 2399 2400 NOTE: Since ImmunityDebugger 1.2 , the returning tuple[1] value is deprecated, 2401 if you need the opcode string of the resulted address, you'll have to do a immlib.disasm(tuple[0]). 2402 2403 """ 2404 address=0 # all loaded modules 2405 return debugger.search_regexp(address,cmd)
2406
2407 - def searchCommandsOnModule(self,address,cmd):
2408 """ 2409 Search for a sequence of commands in given executable module. 2410 @type cmd: STRING 2411 @param cmd: Assembly code to search for (Search using regexp is available. See Documentation) 2412 2413 @rtype: List 2414 @return: List of address of the command found 2415 2416 NOTE: Since ImmunityDebugger 1.2 , the returning tuple[1] value is deprecated, 2417 if you need the opcode string of the resulted address, you'll have to do a immlib.disasm(tuple[0]). 2418 2419 """ 2420 return debugger.search_regexp(address,cmd)
2421 2422 ### Execution control ### 2423 # All kind of functions that interact with code execution 2424
2425 - def run(self, address=0):
2426 """Run Process untill address. 2427 @param address: Address""" 2428 self.clearState() 2429 return debugger.run(address)
2430
2431 - def runTillRet(self):
2432 """Run Process till ret. 2433 """ 2434 self.clearState() 2435 return debugger.run_until_ret()
2436 2437
2438 - def pause(self):
2439 """Pause process""" 2440 return debugger.pause()
2441
2442 - def stepOver(self, address=0):
2443 """ 2444 Step-Over Process untill address. 2445 2446 @type address: DWORD 2447 @param address: (Optional, Def = 0) Address 2448 """ 2449 self.clearState() 2450 return debugger.step_over(address)
2451
2452 - def stepIn(self, address=0):
2453 """ 2454 Step-in Process untill address. 2455 2456 @type address: DWORD 2457 @param address: (Optional, Def = 0) Address 2458 """ 2459 self.clearState() 2460 return debugger.step_in(address)
2461
2462 - def quitDebugger(self):
2463 """ 2464 Quits debugger 2465 """ 2466 return debugger.exit_ID()
2467 2468
2469 - def ignoreSingleStep(self,flag="CONTINUE"):
2470 """ 2471 Ignore Single Step events 2472 @type flag: STRING 2473 @param flag: How to continue after a single event is catched 2474 flag = DISABLE : Disable ignoring 2475 flag = FORCE : Conventional Force continue method 2476 flag = CONTINUE : Transparent continue method 2477 2478 CAUTION: This method overrides GUI option 'single-step break' 2479 """ 2480 return debugger.ignore_single_step(IgnoreSingleStep[flag])
2481 2482 #Consider the following three methods of experimental nature.
2483 - def openProcess(self, path,mode=0):
2484 """ 2485 Open process for debugging 2486 @type path: STRING 2487 @param path: Path to file to debug 2488 @type mode: INTEGER 2489 @param mode: How to start: -2 SILENT, 0 NORMAL 2490 """ 2491 return debugger.open(path,mode)
2492
2493 - def restartProcess(self,mode=-1):
2494 """ 2495 Restart debuggee 2496 @type mode: INTEGER 2497 @param mode: How to restart : -2 SILENT, -1 MSGBOX 2498 2499 """ 2500 return debugger.open("",mode)
2501 2502
2503 - def Attach(self, pid):
2504 """ 2505 Attach to an active process 2506 @type pid: INTEGER 2507 @param pid: Process Id. 2508 """ 2509 return debugger.attach(pid)
2510
2511 - def Detach(self):
2512 """ 2513 Detach from active process 2514 """ 2515 #this methos is still very experimental 2516 return debugger.detach()
2517 2518
2519 - def prepareForNewProcess(self):
2520 """ 2521 Prepare Debugger for fresh debugging session 2522 NOTE: be sure to know what you are doing when 2523 calling this method 2524 """ 2525 return debugger.prepare_for_new_ps()
2526 2527 ### GUI interaction ### 2528 # Whatever interaction on the gui 2529
2530 - def goSilent(self,silent):
2531 """ Set/Unset silent debugging flag 2532 @type silent: INTEGER 2533 @param silent: 1 to set silent, 0 to unset 2534 """ 2535 return debugger.go_silent(silent)
2536
2537 - def addHeader(self,address,header,color="Black"):
2538 """ 2539 Add a header to given row. 2540 @type address: DWORD 2541 @param address: Address to add the header into 2542 @type header: STRING 2543 @param header: Header string to add into row 2544 @type color: STRING 2545 @param color: Color of text 2546 """ 2547 return debugger.add_header_to_row(address,header,ImmDrawColors[color])
2548
2549 - def removeHeader(self,address):
2550 """ 2551 Removes header from row. 2552 @type address: DWORD 2553 @param address: Address to remove the header from 2554 """ 2555 return debugger.remove_header_from_row(address)
2556
2557 - def removeLine(self,address):
2558 """ 2559 Removes header from row. 2560 @type address: DWORD 2561 @param address: Address to remove the header from 2562 """ 2563 return debugger.remove_header_from_row(address)
2564
2565 - def getHeader(self,address):
2566 """ 2567 Get Header from row. 2568 @type address: DWORD 2569 @param address: Address to get the headers from 2570 @return PYLIST: List of strings 2571 """ 2572 return debugger.get_header_from_row(address)
2573
2574 - def addLine(self,address,header,color="Black"):
2575 """ 2576 Add a line to cpu window. 2577 @type address: DWORD 2578 @param address: Address to add line 2579 @type header: STRING 2580 @param header: Header string to add into row 2581 @type color: STRING 2582 @param color: Color of text 2583 """ 2584 return debugger.add_header_to_row(address,header,ImmDrawColors[color])
2585
2586 - def gotoDisasmWindow(self, addr):
2587 """ 2588 GoTo the Disassembler Window. 2589 2590 @type addr: DWORD 2591 @param addr: Address to show on the Disassembler Window 2592 """ 2593 return debugger.set_cpu( self.threadid, addr, 0, 0, 0x8000L) # redraw
2594
2595 - def gotoDumpWindow(self, addr):
2596 """ 2597 GoTo Dump Window. 2598 2599 @type addr: DWORD 2600 @param addr: Address to show on the Dump Window 2601 """ 2602 return debugger.set_cpu( self.threadid, 0, addr, 0, 0x8000L) # redraw
2603
2604 - def gotoStackWindow(self, addr):
2605 """ 2606 GoTo the Stack Window. 2607 @type addr: DWORD 2608 @param addr: Address to show on the Stack Window 2609 """ 2610 return debugger.set_cpu( self.threadid, 0, 0, addr, 0x8000L) # redraw
2611
2612 - def inputBox(self,title):
2613 """ 2614 Creates Dialog with an input_box. 2615 2616 @type title: STRING 2617 @param title: Title for the input_box dialog 2618 2619 @return: String from the inputbox 2620 """ 2621 return debugger.input_box(title)
2622
2623 - def comboBox(self,title,combolist):
2624 """ 2625 Creates Dialog with a combo_box. 2626 2627 @type title: STRING 2628 @param title: Title for the dialog 2629 2630 @type combolist: LIST 2631 @param combolist: List of items to add to combo dialog 2632 2633 @return: Selected item 2634 """ 2635 return debugger.combo_box(title,combolist,len(combolist))
2636 2637 ### Debugger State ### 2638 # The state of the debugger 2639
2640 - def getStatus(self):
2641 """ 2642 Get the status of the debugged process. 2643 2644 @return: Status of the debugged process 2645 """ 2646 return debugger.get_status()
2647
2648 - def isStopped(self):
2649 """ 2650 Is the debugged process stopped? 2651 2652 @rtype: BOOL 2653 @return: Boolean (True/False) 2654 """ 2655 return DebugerStatus["STOPPED"] == self.getStatus()
2656
2657 - def isEvent(self):
2658 """ 2659 Is the debugged process in an event state? 2660 2661 @rtype: BOOL 2662 @return: Boolean (True/False) 2663 """ 2664 return DebugerStatus["EVENT"] == self.getStatus()
2665
2666 - def isRunning(self):
2667 """ 2668 Is the debugged process running? 2669 2670 @rtype: BOOL 2671 @return: Boolean (True/False) 2672 """ 2673 return DebugerStatus["RUNNING"] == self.getStatus()
2674
2675 - def isFinished(self):
2676 """ 2677 Is the debugged process finished? 2678 2679 @rtype: BOOL 2680 @return: Boolean (True/False) 2681 """ 2682 return DebugerStatus["FINISHED"] == self.getStatus()
2683
2684 - def isClosing(self):
2685 """ 2686 Is the debugged process closed? 2687 2688 @rtype: BOOL 2689 @return: Boolean (True/False) 2690 """ 2691 return DebugerStatus["CLOSING"] == self.getStatus()
2692 2693 ### Hooks ### 2694
2695 - def listHooks(self):
2696 """ 2697 List of active hooks 2698 2699 @rtype: LIST 2700 @return: List of active hooks 2701 """ 2702 return debugger.list_hook()
2703
2704 - def removeHook(self,hook_str):
2705 """Unhook from memory 2706 """ 2707 debugger.remove_hook(hook_str)
2708
2709 - def _getHookEntry(self, entry):
2710 tbl = [] 2711 # We need to use HOOK_REG, since some of the original register 2712 # are saved on the stack 2713 try: 2714 reg = HOOK_REG[ entry[0] ] 2715 tbl.append( "MOV EAX, %s" % reg ) 2716 except KeyError: 2717 if entry[0] == 'ESP': 2718 tbl.append("LEA EAX, [ESP+0x14]") 2719 elif type( entry[0] ) == type(0): 2720 tbl.append("MOV EAX, [0x%08x]" % entry[0] ) 2721 else: 2722 return [] 2723 2724 if len(entry) == 2: 2725 tbl.append( "MOV EAX, [EAX + 0x%x]" % entry[1] ) 2726 tbl.append( "STOSD" ) 2727 2728 return tbl
2729 2730 # afterHookAddr = hookAddr + idx 2731 # ndx = function num 2732 # table = [ (reg), (reg, offset) ]
2733 - def _createCodeforHook( self, memAddress, afterHookAddr, ndx, table, execute_prelude, alloc_size):
2734 # SAVING REGS, WE DONT WANT TO TOUCH ANYTHING! 2735 # XXX: Replace it with a PUSHA/POPA 2736 # Add a global deadlock 2737 alloc_stub = [ "PUSHAD" ] # Save all registers 2738 alloc_stub += [ "MOV EBX, 0x%08x" % memAddress ] # 2739 alloc_stub += [ "MOV EDI, [EBX]"] # GETTING A POINTER to top of data 2740 alloc_stub += [ "CMP DWORD DS:[EBX+4],1"] # Check the deadlock 2741 #alloc_stub += [ "JZ -0xC" ] # If its in use, loop 2742 alloc_stub += [ "MOV DWORD DS:[EBX+4],1"] # Turn deadlock on 2743 alloc_stub += [ "MOV EAX, EDI"] 2744 alloc_stub += [ "SUB EAX, EBX"] 2745 alloc_stub += [ "ADD EAX, 0x%08x" % (len(table) * 4 + 4) ] 2746 alloc_stub += [ "CMP EAX, 0x%08x" % alloc_size] # Did we reach the end of memory? 2747 # JE -> JMP TO THE END OF THE FUNCTION 2748 alloc_stub_reg = [ "MOV EAX, 0x%x" % ndx] 2749 alloc_stub_reg += [ "STOSD"] # SAVE IN MEMORY THE FUNCTION NUMBER 2750 for entry in table: 2751 alloc_stub_reg += self._getHookEntry( entry ) # Get all the regs/mem and save them in data 2752 alloc_stub_reg += [ "MOV [EBX], EDI"] # Save the top of the data 2753 alloc_stub_reg += [ "MOV DWORD DS:[EBX+4],0"] # Turn Lock OFF 2754 2755 alloc_stub_pos = [ "POPAD"] # Restore register 2756 # Right here is where the 'saved' instruction 2757 # of the hook are executed 2758 alloc_ret = "PUSH 0x%08x\nRET" % afterHookAddr # Back to the function 2759 2760 2761 code = self.assemble( "\n".join( alloc_stub ) ) 2762 reg_code = self.assemble( "\n".join( alloc_stub_reg ) ) 2763 code += "\x0f\x83" + struct.pack("L", len(reg_code) ) 2764 code += reg_code 2765 code += self.assemble( "\n".join( alloc_stub_pos ) ) 2766 2767 code += execute_prelude 2768 code += self.assemble( alloc_ret ) 2769 2770 return code
2771 2772
2773 - def addFastLogHook(self, hook, alloc_size = 0x100000):
2774 CODE_HOOK_START = 8 2775 flh = hook 2776 # Get the table of functions from the hook 2777 table = flh.get() 2778 # Allocate memory for the hook and the log 2779 memAddress = self.remoteVirtualAlloc( alloc_size ) 2780 self.log( "Logging at 0x%08x" % memAddress ) 2781 2782 # MEMORY LOOKS LIKE: 2783 # mem [ ptr to data ] 2784 # mem + 4 [ deadlock ] 2785 # mem + 8 [ start of hook code ] 2786 # mem + n [ ... ] 2787 # mem + n [ start of data ] 2788 2789 ptr = memAddress + CODE_HOOK_START 2790 2791 fn_restore = [] 2792 2793 for fn_ndx in range( 0, len(table) ): 2794 hookAddress = table[ fn_ndx ][0] 2795 entry = table[ fn_ndx ][1] 2796 2797 idx = 0 2798 #patch_code = self.assemble( "PUSH 0x%08x\nRET" % ptr ) 2799 patch_code = self.assemble( "JMP 0x%08x" % ptr, address = hookAddress) 2800 2801 while idx < len(patch_code): 2802 op = self.disasm( hookAddress + idx ) 2803 if op.isCall() or op.isJmp(): 2804 op = None 2805 break 2806 2807 idx += op.getOpSize() 2808 if not op: 2809 continue 2810 2811 2812 ex_prelude = self.readMemory( hookAddress, idx ) 2813 2814 code = self._createCodeforHook( memAddress, hookAddress + idx,\ 2815 fn_ndx + 1, entry, ex_prelude, alloc_size) 2816 2817 self.writeMemory( ptr , code ) 2818 ptr+= len(code) 2819 self.writeMemory( hookAddress, patch_code ) 2820 2821 fn_restore.append( ex_prelude ) # Correspond in index with function address 2822 2823 if ptr % 4: 2824 ptr = 4 + ptr & ~(4-1) 2825 hook.setMem( ptr ) 2826 self.writeLong( memAddress, ptr ) 2827 2828 hook.setRestore( fn_restore ) 2829 2830 2831 2832 ### Remote Allocation/Deallocation ### 2833
2834 - def rVirtualAlloc(self, lpAddress, dwSize, flAllocationType, flProtect):
2835 """ 2836 Virtual Allocation on the Debugged Process 2837 2838 @type lpAddress: DWORD 2839 @param lpAddress: Desired starting Address 2840 2841 @type dwSize: DWORD 2842 @param dwSize: Size of the memory to be allocated (in bytes) 2843 2844 @type flAllocationType: DWORD 2845 @param flAllocationType: Type of Memory Allocation (MEM_COMMIT, MEM_RESERVED, MEM_RESET, etc) 2846 2847 @type flProtect: DWORD 2848 @param flProtect: Flag protection of the memory allocated 2849 2850 @rtype: DWORD 2851 @return: Address of the memory allocated 2852 """ 2853 return debugger.pVirtualAllocEx( lpAddress, dwSize, flAllocationType, flProtect )
2854 2855 # default dwFreetype == MEM_RELEASE
2856 - def rVirtualFree(self, lpAddress, dwSize = 0x0, dwFreeType = 0x8000):
2857 """ 2858 Virtual Free of memory on the Debugged Process 2859 2860 @type size: DWORD 2861 @param size: (Optional, Def: 0) Size of the memory to free 2862 2863 @type dwFreeType: DWORD 2864 @param dwFreeType: (Optional, Def: MEM_RELEASE) Type of Free operation 2865 2866 @rtype: DWORD 2867 @return: On Successful, returns a non zero value 2868 """ 2869 return debugger.pVirtualFreeEx( lpAddress, dwSize, dwFreeType )
2870
2871 - def remoteVirtualAlloc(self, size = 0x10000, interactive = True):
2872 """ 2873 Virtual Allocation on the Debugged Process 2874 2875 @type size: DWORD 2876 @param size: (Optional, Def: 0x10000) Size of the memory to allocated, in bytes 2877 2878 @rtype: DWORD 2879 @return: Address of the memory allocated 2880 """ 2881 2882 return self.rVirtualAlloc( 0x0, size, 0x1000, 0x40)
2883 2884 ### OS information ###
2885 - def getOsVersion(self):
2886 return self.osversion
2887
2888 - def getOsRelease(self):
2889 return self.osrelease
2890
2891 - def getOsInformation(self):
2892 """ 2893 Get OS information 2894 2895 @rtype: TUPLE 2896 @return: List with ( system, release, version) 2897 """ 2898 import platform 2899 return (platform.system(),platform.release(),platform.version())
2900
2901 - def getThreadId(self):
2902 """ 2903 Return current debuggee thread id 2904 2905 @trype: LONG 2906 @return: Thread ID 2907 """ 2908 return debugger.get_thread_id()
2909 2910 2911 ### Accessing Recognition Routines ### 2912
2913 - def searchFunctionByName(self, name, heuristic = 90, module = None, version = None, data=""):
2914 """ 2915 Look up into our dictionaries to find a function match. 2916 2917 @type name: STRING 2918 @param name: Name of the function to search 2919 2920 @type module: STRING 2921 @param module: name of a module to restrict the search 2922 2923 @type version: STRING 2924 @param version: restrict the search to the given version 2925 2926 @type heuristic: INTEGER 2927 @param heuristic: heuristic threasold to consider a real function match 2928 2929 @type data: STRING|LIST 2930 @param data: Name (or list of names) of the .dat file inside the Data folder, where're stored the function 2931 patterns. Use an empty string to use all the files in the Data folder. 2932 2933 @rtype: DWORD|None 2934 @return: the address of the function or None if we can't find it 2935 """ 2936 recon = FunctionRecognition(self, data) 2937 return recon.searchFunctionByName(name, heuristic , module, version )
2938
2939 - def searchFunctionByHeuristic(self, csvline, heuristic = 90, module = None, data=""):
2940 """ 2941 Search memory to find a function that fullfit the options. 2942 2943 @type csvline: STRING 2944 @param csvline: A line of a Data CSV file. This's a simple support for copy 'n paste from a CSV file. 2945 2946 @type heuristic: INTEGER 2947 @param heuristic: heuristic threasold to consider a real function match 2948 2949 @type module: STRING 2950 @param module: name of a module to restrict the search 2951 2952 @type data: STRING|LIST 2953 @param data: Name (or list of names) of the .dat file inside the Data folder, where're stored the function 2954 patterns. Use an empty string to use all the files in the Data folder. 2955 2956 @rtype: DWORD|None 2957 @return: the address of the function or None if we can't find it 2958 """ 2959 2960 recon = FunctionRecognition(self, data) 2961 return recon.searchFunctionByHeuristic(csvline, heuristic , module )
2962
2963 - def resolvFunctionByAddress(self, address, heuristic=90,data=""):
2964 """ 2965 Look up into our dictionaries to find a function match. 2966 2967 @type address: DWORD 2968 @param address: Address of the function to search 2969 2970 @type heuristic: INTEGER 2971 @param heuristic: heuristic threasold to consider a real function match 2972 2973 @type data: STRING|LIST 2974 @param data: Name (or list of names) of the .dat file inside the Data folder, where're stored the function 2975 patterns. Use an empty string to use all the files in the Data folder. 2976 2977 @rtype: STRING 2978 @return: a STRING with the function's real name or the given address if there's no match 2979 """ 2980 recon = FunctionRecognition(self,data) 2981 return recon.resolvFunctionByAddress(address, heuristic,data)
2982
2983 - def makeFunctionHashHeuristic(self, address, compressed = False, followCalls = True, data=""):
2984 """ 2985 @type address: DWORD 2986 @param address: address of the function to hash 2987 2988 @type compressed: Boolean 2989 @param compressed: return a compressed base64 representation or the raw data 2990 2991 @type followCalls: Boolean 2992 @param followCalls: follow the first call in a single basic block function 2993 2994 @type data: STRING|LIST 2995 @param data: Name (or list of names) of the .dat file inside the Data folder, where're stored the function 2996 patterns. Use an empty string to use all the files in the Data folder. 2997 2998 @rtype: LIST 2999 @return: the first element is described below and the second is the result of this same function but over the first 3000 call of a single basic block function (if applies), each element is like this: 3001 a base64 representation of the compressed version of each bb hash: 3002 [4 bytes BB(i) start][4 bytes BB(i) 1st edge][4 bytes BB(i) 2nd edge] 3003 0 <= i < BB count 3004 or the same but like a LIST with raw data. 3005 """ 3006 recon = FunctionRecognition(self, data) 3007 return FunctionRecognition.makeFunctionHashHeuristic(address, compressed, followCalls)
3008
3009 - def makeFunctionHashExact(self, address,data=""):
3010 """ 3011 Return a SHA-1 hash of the function, taking the raw bytes as data. 3012 3013 @type address: DWORD 3014 @param address: address of the function to hash 3015 3016 @type data: STRING|LIST 3017 @param data: Name (or list of names) of the .dat file inside the Data folder, where're stored the function 3018 patterns. Use an empty string to use all the files in the Data folder. 3019 3020 @rtype: STRING 3021 @return: SHA-1 hash of the function 3022 """ 3023 3024 recon = FunctionRecognition(self,data) 3025 return recon.makeFunctionHashExact(address)
3026
3027 - def makeFunctionHash(self, address, compressed = False,data=""):
3028 """ 3029 Return a list with the best BB to use for a search and the heuristic hash 3030 of the function. This two components are the function hash. 3031 3032 @type address: DWORD 3033 @param address: address of the function to hash 3034 3035 @type compressed: Boolean 3036 @param compressed: return a compressed base64 representation or the raw data 3037 3038 @type data: STRING|LIST 3039 @param data: Name (or list of names) of the .dat file inside the Data folder, where're stored the function 3040 patterns. Use an empty string to use all the files in the Data folder. 3041 3042 @rtype: LIST 3043 @return: 1st element is the generalized instructions to use with searchCommand 3044 2nd element is the heuristic function hash (makeFunctionHashHeuristic) 3045 3rd element is an exact hash of the function (makeFunctionHashExact) 3046 """ 3047 recon = FunctionRecognition(self,data) 3048 return recon.makeFunctionHash(address, compressed)
3049 3050 3051 ### Accessing Control Flow Analysis Routines ### 3052
3053 - def findLoops(self, address):
3054 """ 3055 This function finds Natural Loops inside a function. 3056 3057 Each loop item has the following structure: 3058 [ start, end, nodes ] 3059 start: address of node receiving the back edge. 3060 end: address of node which has the back edge. 3061 node: list of node's addresses involved in this loop. 3062 3063 @type address: DWORD 3064 @param address: function start address 3065 3066 @rtype: LIST 3067 @return: A list of loops 3068 """ 3069 3070 cfa = ControlFlowAnalysis(self, address) 3071 return cfa.findNaturalLoops()
3072
3073 - def sleepTillStopped(self, timeout):
3074 """ 3075 timeout is in seconds. this function will sleep 1 second at a time until timeout is reached 3076 or the debugger has stopped (probably due to AV) 3077 returns True if we were stopped before timeout happened 3078 """ 3079 for i in xrange(timeout): 3080 #sleep 1 second at a time 3081 if self.isStopped(): 3082 return True 3083 if self.isEvent(): 3084 return True 3085 3086 time.sleep(1) 3087 return False
3088
3089 - def injectDll( self, dll_path ):
3090 """ 3091 This function loads a DLL into the debugged process. 3092 3093 @type dll_path: STRING 3094 @param dll_path: The full path to the DLL. ie C:\\WINDOWS\\system32\\kernel32.dll 3095 3096 @rtype: DWORD 3097 @return: The thread ID of the DLL loading thread. 3098 """ 3099 3100 return debugger.inject_dll( dll_path )
3101
3102 -class HookOutput:
3103
3104 - def __init__(self):
3105 raise Exception(' '.join(['Only instantiate subclasses of this ', 3106 'class that define an __init__ function', 3107 'that hooks an output stream']))
3108 - def write(self, out):
3109 for line in out.split('\n'): 3110 if len(line) == 0: 3111 continue 3112 3113 self.imm.log(line) 3114 self.orig.write(line)
3115
3116 - def __getattr__(self, name):
3117 return self.orig.__getattr__(name)
3118
3119 -class StderrToLog(HookOutput):
3120
3121 - def __init__(self):
3122 sys.stderr = self 3123 self.orig = sys.__stderr__ 3124 3125 self.imm = Debugger()
3126
3127 -class StdoutToLog(HookOutput):
3128
3129 - def __init__(self):
3130 sys.stdout = self 3131 self.orig = sys.__stdout__ 3132 3133 self.imm = Debugger()
3134