| # A script for analyzing the output of NPSPY and merging data about streams. | |
| import sys | |
| def ReadFile(filename, flags='rb'): | |
| """Returns the contents of a file.""" | |
| file = open(filename, flags) | |
| result = file.read() | |
| file.close() | |
| return result | |
| def WriteFile(filename, contents): | |
| """Overwrites the file with the given contents.""" | |
| file = open(filename, 'w') | |
| file.write(contents) | |
| file.close() | |
| # sample line: 'NPP_NewStream(0x645c898, 0x56ba900("application/x-shockwave-flash"), 0x64bb3b0 (http://weeklyad.target.com/target/flash/target/target.swf?ver=090326), TRUE, NP_NORMAL)' | |
| class Stream: | |
| def __init__(self, line): | |
| split = line.split(', ') | |
| self.mime_type = split[1].split('"')[1] | |
| self.url = split[2].split(' ')[1].strip('()') | |
| self.seekable = split[3] | |
| self.type = split[4].strip(')') | |
| self.size = 0 | |
| self.status = '' | |
| try: | |
| self.address = split[2].split(' ')[0] | |
| except: | |
| print 'parsing error on ' + line | |
| self.address = '' | |
| if self.type != 'NP_NORMAL': | |
| print 'line got unexpected type: ' + line | |
| def main(argv=None): | |
| if argv is None: | |
| argv = sys.argv | |
| streams = [] | |
| if len(argv) != 2: | |
| print 'need filename' | |
| return | |
| file = ReadFile(argv[1]) | |
| for line in file.splitlines(): | |
| if line.startswith('NPP_NewStream('): | |
| if line.count('(') < 3: | |
| print 'unknown format for line: ' + line | |
| continue | |
| s = Stream(line) | |
| streams.append(s) | |
| elif line.startswith('NPP_Write('): | |
| # sample: NPP_Write(0x645c898, 0x64bb3b0, 0, 16384, 0x56c1000("CW"))) | |
| split = line.split(', ') | |
| address = split[1] | |
| start = int(split[2]) | |
| size = int(split[3]) | |
| found = False | |
| for stream in streams: | |
| if stream.address == address: | |
| if stream.size != start: | |
| print 'error: starting at wrong place for write ' + stream.url + ' ' + str(stream.size) + ' ' + str(start) | |
| stream.size += size | |
| found = True | |
| break | |
| if not found: | |
| print "couldn't find stream to match NPP_Write " + line | |
| elif line.startswith('NPP_DestroyStream('): | |
| # sample: NPP_DestroyStream(0x645c898, 0x64bb3b0, NPRES_DONE) | |
| split = line.split(', ') | |
| address = split[1] | |
| status = split[2].strip(')') | |
| found = False | |
| for stream in streams: | |
| if stream.address == address: | |
| stream.status = status | |
| stream.address = '' # address can be reused | |
| found = True | |
| break | |
| if not found: | |
| print "couldn't find stream to match NPP_DestroyStream " + line | |
| output = [] | |
| for stream in streams: | |
| if stream.status != 'NPRES_DONE': | |
| print 'error: no NPP_DestroyStream with success for ' + stream.url + ' ' + stream.status + '.' | |
| output.append(', '.join([stream.url, stream.mime_type, str(stream.size), stream.seekable])) | |
| output_file = argv[1].replace('.', '_analyzed.') | |
| WriteFile(output_file, '\n'.join(output)) | |
| if __name__ == "__main__": | |
| sys.exit(main()) |