def save (self, filename): ''' Save a recording to the specified file. The contents of the recording are generated from our internal variables in sorted order. File format:: hit time:thread id:module name:mode base addr.:breakpoint function offset addr.:breakpoint offset addr. 002d97d0:00000a28:irc.dll:00401000:00009160:000092d1 @type filename: String @param filename: Filename @raise psx: An exception is raised if the specified file can not be opened for writing. ''' # open the file in write mode, create it if it does exist, overwrite it if it does. try: file = open(filename, "w+") except: raise psx("Unable to open file '%s' for writing." % filename) # initialize a list for storing the in-memory recording. recording = [] # construct an in-memory list from the internal lists. for i in xrange(self.num_entries()): recording.append("%08x:%08x:%s:%08x:%08x:%08x" % (self.times[i], self.threads[i], self.modules[i], \ self.bases[i], self.functions[i], self.nodes[i])) # sort the cross-reference list. recording.sort() # write data to disk. for entry in recording: file.write(entry + "\n")
def save (self, filename): ''' Save a cross-reference list to the specified file. The contents of the cross-reference are generated from our internal variables in sorted order. File format:: function offset address:source node offset address:destination node offset address 000000e0:0000011e:00015edc @type filename: String @param filename: Filename @raise psx: An exception is raised if the specified file can not be opened for writing. ''' # open the file in write mode, create it if it does exist, overwrite it if it does. try: file = open(filename, "w+") except: raise psx("Unable to open file '%s' for writing." % filename) # initialize a list for storing the in-memory cross-reference list. xrefs = [] # construct an in-memory list from the internal lists. for i in xrange(self.num_entries()): xrefs.append("%08x:%08x:%08x" % (self.functions[i], self.sources[i], self.destinations[i])) # sort the cross-reference list. xrefs.sort() # write data to disk. for entry in xrefs: file.write(entry + "\n")
def save (self, filename): ''' Save a breakpoint list to the specified file. The contents of the breakpoint list are generated from our internal variables in sorted order. Breakpoint list format:: module:function offset address:node offset address irc.dll:00000000:00000000 @type filename: String @param filename: Filename @raise psx: An exception is raised if the specified file can not be opened for writing. ''' # open the file in write mode, create it if it does exist, overwrite it if it does. try: file = open(filename, "w+") except: raise psx("Unable to open file '%s' for writing." % filename) # initialize a list for storing the in-memory breakpoint list. bpl = [] # construct an in-memory list from the internal lists. for i in xrange(self.num_entries()): bpl.append("%s:%08x:%08x" % (self.modules[i], self.functions[i], self.nodes[i])) # sort the breakpoint list. bpl.sort() # write data to disk. for entry in bpl: file.write(entry + "\n")
def parse (self, filename): ''' Open the specified *processed* recording and process the data into the internal lists. File format:: hit time:thread id:module name:mode base addr.:breakpoint function offset addr.:breakpoint offset addr. 002d97d0:00000a28:irc.dll:00401000:00009160:000092d1 @type filename: String @param filename: Filename @raise psx: An exception is raised if requested recording file can not be opened. ''' # open the file, read-only. try: file = open(filename, "r") except: raise psx("Unable to open file '%s' for reading." % filename) # clear the internal lists. self.times = [] self.threads = [] self.modules = [] self.bases = [] self.functions = [] self.nodes = [] # process the file line by line. for line in file.readlines(): line = line.rstrip(" \r\n") # parse out the line fields, ignore on error. try: (time, thread, module, base, function, node) = line.split(":") time = long(time, 16) thread = long(thread, 16) base = long(base, 16) function = long(function, 16) node = long(node, 16) module = module.lower() except: continue # add the successfully extracted fields to the internal lists. self.times.append(time) self.threads.append(thread) self.modules.append(module) self.bases.append(base) self.functions.append(function) self.nodes.append(node)
def parse (self, filename): ''' Open the specified Cross-reference list filename and process the data into the internal lists. File format:: function offset address:source node offset address:destination node offset address 000000e0:0000011e:00015edc @type filename: String @param filename: Filename @raise psx: An exception is raised if requested cross-reference file can not be opened. ''' # open the file, read-only. try: file = open(filename, "r") except: raise psx("Unable to open file '%s' for reading." % filename) # clear the internal lists. self.functions = [] self.sources = [] self.destinations = [] # process the file line by line. for line in file.readlines(): line = line.rstrip(" \r\n") # parse out the line fields, ignore on error. try: (function, source, destination) = line.split(":") function = long(function, 16) source = long(source, 16) destination = long(destination, 16) except: continue # re-base if required. if self.base_address: function = self.base_address + function source = self.base_address + source destination = self.base_address + destination # add the successfully extracted fields to the internal lists. self.functions.append(function) self.sources.append(source) self.destinations.append(destination)
def get_bp_entry (self, index): ''' Get the breakpoint entry at the specified index. @type index: Integer @param index: Breakpoint index @rtype: Tuple @return: BP module name, BP function offset address, BP node offset address @raise psx: An exception is raised if the requested index is out of range. ''' # ensure the requested index is within range. if index >= self.num_entries(): raise psx("Requested index is out of range.") return (self.modules[index], self.functions[index], self.nodes[index])
def get_xref_entry (self, index): ''' Get the cross-reference entry at the specified index. @type index: Integer @param index: Cross-reference index @rtype: Tuple @return: Function offset address, source node offset address, destination node offset address @raise psx: An exception is raised if the requested index is out of range. ''' # ensure the requested index is within range. if index >= self.num_entries(): raise psx("Requested index is out of range.") return (self.functions[index], self.sources[index], self.destinations[index])
def del_xref_entry (self, index): ''' Delete the cross-reference entry at the specified index. @type index: Integer @param index: Cross-reference index @raise psx: An exception is raised if the requested index is out of range. ''' # ensure the requested index is within range. if index >= self.num_entries(): raise psx("Requested index is out of range.") # remove the data at index from the internal lists. self.functions.pop(index) self.sources.pop(index) self.destinations.pop(index)
def del_bp_entry (self, index): ''' Delete the breakpoint entry at the specified index. @type index: Integer @param index: Breakpoint index @raise psx: An exception is raisd if the requested index is out of range. ''' # ensure the requested index is within range. if index >= self.num_entries(): raise psx("Requested index is out of range.") # remove the data at index from the internal lists. self.functions.pop(index) self.modules.pop(index) self.nodes.pop(index)
def get_recording_entry (self, index): ''' Get the recording entry at the specified index. @type index: Integer @param index: Recording index @rtype: Tuple @return: Time, module name, base, breakpoint offset address, register, register data location, register data @raise psx: An exception is raised if the requested index is out of range. ''' # ensure the requested index is within range. if index >= self.num_entries(): raise psx("Requested index is out of range.") return (self.times[index], self.modules[index], self.bases[index], self.addresses[index], self.registers[index], self.data_locations[index], self.data[index])
def get_recording_entry (self, index): ''' Get the recording entry at the specified index. @type index: Integer @param index: Recording index @rtype: Tuple @return: Time, thread ID, module name, module base address, function offset address, node offset address @raise psx: An exception is raised if the requested index is out of range. ''' # ensure the requested index is within range. if index >= self.num_entries(): raise psx("Requested index is out of range.") return (self.times[index], self.threads[index], self.modules[index], \ self.bases[index], self.functions[index], self.nodes[index])
def parse (self, filename): ''' Open the specified breakpoint list filename and process the data into the internal lists. Breakpoint list format:: module:function offset address:node offset address irc.dll:00000000:00000000 @type filename: String @param filename: Filename @raise psx: An exception is raised if requested breakpoint list can not be opened. ''' # open the file, read-only. try: file = open(filename, "r") except: raise psx("Unable to open file '%s' for reading." % filename) # clear the internal lists. self.functions = [] self.modules = [] self.nodes = [] # process the file line by line. for line in file.readlines(): line = line.rstrip(" \r\n") # parse out the line fields, ignore on error. try: (module, function, node) = line.split(":") function = long(function, 16) node = long(node, 16) module = module.lower() except: continue # add the successfully extracted fields to the internal lists. self.functions.append(function) self.modules.append(module) self.nodes.append(node)
def add_xref_entry (self, function, source, destination, dupe_check=False): ''' Add a cross-reference entry to the internal lists. @type function: DWORD @param function: Source function offset address @type source: DWORD @param source: Source node offset address @type destination: DWORD @param destination: Destination node offset address @type dupe_check: Boolean @param dupe_check: Optional flag specifying whether or not to check for duplicates before adding entry (slow). @raise psx: An exception is raised if the entry to add already exists. ''' if dupe_check: for i in xrange(self.num_entries()): if self.functions[i] == function and self.sources[i] == source and self.destinations[i] == destination: raise psx("Cross-reference entry already exists.") self.functions.append(function) self.sources.append(source) self.destinations.append(destination)
def add_bp_entry (self, module, function, node, dupe_check=False): ''' Add a breakpoint entry to the internal lists. @type module: String @param module: Module name @type function: DWORD @param function: Function offset address @type node: DWORD @param node: Node offset address @type dupe_check: Boolean @param dupe_check: Optional flag specifying whether or not to check for duplicates before adding entry (slow). @raise psx: An exception is raised if the entry to add already exists. ''' if dupe_check: for i in xrange(self.num_entries()): if self.modules[i] == module and self.functions[i] == function and self.nodes[i] == node: raise psx("Breakpoint entry already exists.") self.functions.append(function) self.modules.append(module) self.nodes.append(node)
def parse (self, filename): ''' Open and parse the specified register recording file. Register recordings are stored in the following format:: hit time:module name:base addr:breakpoint offset address:register name:register data location:register data 0096e63c:msn.dll:0001000:022ede10:EAX::DEADBEEF 0096e63c:msn.dll:0001000:022ede10:*EAX:heap:8405 0000 0000 0000 0000 0000 0100 0000 @type filename: String @param filename: Filename @raise psx: An exception is raised if requested recording file can not be opened. ''' # open the file, read-only. try: file = open(filename, "r") except: raise psx("Unable to open file '%s' for reading." % filename) # clear the internal lists. self.times = [] self.modules = [] self.bases = [] self.addresses = [] self.registers = [] self.data_locations = [] self.data = [] # process the file line by line. for line in file.readlines(): line = line.rstrip(" \r\n") # parse out the line fields, ignore on error. try: (time, module, base, address, register, data_location, data) = line.split(":") time = long(time, 16) base = long(base, 16) address = long(address, 16) module = module.lower() # if a data location wasn't specified, then this line specifies a direct register value. if not data_location: data = long(data, 16) # if a rebase address was provided, then over ride the read-in base address. if self.base_address: base = self.base_address except: continue # add the successfully extracted fields to the internal lists. self.times.append(time) self.modules.append(module) self.bases.append(base) self.addresses.append(address) self.registers.append(register) self.data_locations.append(data_location) self.data.append(data) # add this address->index map to the cache. key = "%08x" % (base + address) if not self.address_map.has_key(key): self.address_map[key] = [] self.address_map[key].append(len(self.bases) - 1)
def pre_process (self, filename, rebase=0): ''' Open the specified recording and process the data into the internal lists. File format:: hit time:thread id:module name:mode base addr.:breakpoint function offset addr.:breakpoint offset addr. 002d97d0:00000a28:irc.dll:00401000:00009160:000092d1 The second to final field, 'function offset address, is added in the processed output. Processed recorder files will be generated for each thread found within the pre-processed recording. @type filename: String @param filename: Filename @type rebase: DWORD @param rebase: Optional module rebase address @raise psx: An exception is raised if requested recording file can not be opened. ''' # open the file, read-only. try: file = open(filename, "r") except: raise psx("Unable to open file '%s' for reading." % filename) # process the file line by line. for line in file.readlines(): line = line.rstrip(" \r\n") # parse out the line fields, ignore on error. try: (time, thread, module, base, node) = line.split(":") time = long(time, 16) thread = long(thread, 16) base = long(base, 16) node = long(node, 16) module = module.lower() # override the read-in base if the rebase option is specified. if rebase: base = rebase except: continue # if the breakpoint list dictionary doesn't contain this module, then load it. if not self.bp_lists.has_key(module): self.bp_lists[module] = {} try: bpl = open(module + ".bpl") except: raise psx("Breakpoint list for module %s not found." % module) # process each line in this breakpoint list into the internal dictionary. for bp in bpl.readlines(): bp = bp.rstrip(" \r\n") # parse out the line fields, ignore on error. try: (_module, _function, _node) = bp.split(":") _function = long(_function, 16) _node = long(_node, 16) _module = _module.lower() except: continue self.bp_lists[_module][_node] = _function # load the function address for the current recording address from the breakpoint list dictionary. function = self.bp_lists[module][node] # create an output file for the current thread if it doesn't exist. if not self.thread_fhs.has_key(thread): self.thread_fhs[thread] = open(filename + ".%08x-processed" % thread, "w+") # output the processed line to the thread file. self.thread_fhs[thread].write("%08x:%08x:%s:%08x:%08x:%08x\n" % (time, thread, module, \ base, function, node)) # close the output file handles. for thread_fh in self.thread_fhs: self.thread_fhs[thread_fh].close() # close the input file handle. file.close()