From 0592212a954d33ece963f36b6dee49945fe2e82f Mon Sep 17 00:00:00 2001 From: Sylvain Pelissier Date: Tue, 13 Jun 2017 15:18:34 +0200 Subject: [PATCH] First step to Python 3 compatibility --- JSAnalysis.py | 6 +- PDFConsole.py | 484 +++++++++++++++++++-------------------- PDFCore.py | 58 ++--- PDFCrypto.py | 10 +- PDFUtils.py | 19 +- ccitt.py | 24 +- lzw.py | 4 +- peepdf.py | 622 +++++++++++++++++++++++++------------------------- 8 files changed, 623 insertions(+), 604 deletions(-) diff --git a/JSAnalysis.py b/JSAnalysis.py index 79fce91..39ac277 100644 --- a/JSAnalysis.py +++ b/JSAnalysis.py @@ -251,8 +251,8 @@ def unescape(escapedBytes, unicode = True): else: unicodePadding = '' try: - if escapedBytes.lower().find('%u') != -1 or escapedBytes.lower().find('\u') != -1 or escapedBytes.find('%') != -1: - if escapedBytes.lower().find('\u') != -1: + if escapedBytes.lower().find('%u') != -1 or escapedBytes.lower().find(r'\u') != -1 or escapedBytes.find('%') != -1: + if escapedBytes.lower().find(r'\u') != -1: splitBytes = escapedBytes.split('\\') else: splitBytes = escapedBytes.split('%') @@ -279,4 +279,4 @@ def unescape(escapedBytes, unicode = True): unescapedBytes = escapedBytes except: return (-1, 'Error while unescaping the bytes') - return (0, unescapedBytes) \ No newline at end of file + return (0, unescapedBytes) diff --git a/PDFConsole.py b/PDFConsole.py index 5b9b3d9..3e0034e 100644 --- a/PDFConsole.py +++ b/PDFConsole.py @@ -144,7 +144,7 @@ def precmd(self, line): def postloop(self): if self.use_rawinput: - print newLine + 'Leaving the Peepdf interactive console...Bye! ;)' + newLine + print((newLine + 'Leaving the Peepdf interactive console...Bye! ;)' + newLine)) self.leaving = True def do_bytes(self, argv): @@ -177,8 +177,8 @@ def do_bytes(self, argv): self.help_bytes() def help_bytes(self): - print newLine + 'Usage: bytes $offset $num_bytes [$file]' - print newLine + 'Shows or stores in the specified file $num_bytes of the file beginning from $offset' + newLine + print((newLine + 'Usage: bytes $offset $num_bytes [$file]')) + print((newLine + 'Shows or stores in the specified file $num_bytes of the file beginning from $offset' + newLine)) def do_changelog(self, argv): if self.pdfFile is None: @@ -258,8 +258,8 @@ def do_changelog(self, argv): self.log_output('changelog ' + argv, output) def help_changelog(self): - print newLine + 'Usage: changelog [$version]' - print newLine + 'Shows the changelog of the document or version of the document' + newLine + print((newLine + 'Usage: changelog [$version]')) + print((newLine + 'Shows the changelog of the document or version of the document' + newLine)) def do_create(self, argv): message = '' @@ -378,10 +378,10 @@ def do_create(self, argv): self.log_output('create ' + argv, message) def help_create(self): - print newLine + 'Usage: create pdf simple|(open_action_js [$js_file])' - print newLine + 'Creates a new simple PDF file or one with Javascript code to be executed when opening the file. It\'s possible to specify the file where the Javascript code is stored or do it manually.' + newLine * 2 - print 'Usage: create object_stream [$version]' + newLine - print 'Creates an object stream choosing the objects to be compressed.' + newLine + print((newLine + 'Usage: create pdf simple|(open_action_js [$js_file])')) + print((newLine + 'Creates a new simple PDF file or one with Javascript code to be executed when opening the file. It\'s possible to specify the file where the Javascript code is stored or do it manually.' + newLine * 2)) + print(('Usage: create object_stream [$version]' + newLine)) + print(('Creates an object stream choosing the objects to be compressed.' + newLine)) def do_decode(self, argv): decodedContent = '' @@ -481,21 +481,21 @@ def do_decode(self, argv): self.log_output('decode ' + argv, decodedContent, [decodedContent], bytesOutput=True) def help_decode(self): - print newLine + 'Usage: decode variable $var_name $filter1 [$filter2 ...]' - print 'Usage: decode file $file_name $filter1 [$filter2 ...]' - print 'Usage: decode raw $offset $num_bytes $filter1 [$filter2 ...]' - print 'Usage: decode string $encoded_string $filter1 [$filter2 ...]' + newLine - print 'Decodes the content of the specified variable, file or raw bytes using the following filters or algorithms:' - print '\tbase64,b64: Base64' - print '\tasciihex,ahx: /ASCIIHexDecode' - print '\tascii85,a85: /ASCII85Decode' - print '\tlzw: /LZWDecode' - print '\tflatedecode,fl: /FlateDecode' - print '\trunlength,rl: /RunLengthDecode' - print '\tccittfax,ccf: /CCITTFaxDecode' - print '\tjbig2: /JBIG2Decode (Not implemented)' - print '\tdct: /DCTDecode (Not implemented)' - print '\tjpx: /JPXDecode (Not implemented)' + newLine + print((newLine + 'Usage: decode variable $var_name $filter1 [$filter2 ...]')) + print('Usage: decode file $file_name $filter1 [$filter2 ...]') + print('Usage: decode raw $offset $num_bytes $filter1 [$filter2 ...]') + print(('Usage: decode string $encoded_string $filter1 [$filter2 ...]' + newLine)) + print('Decodes the content of the specified variable, file or raw bytes using the following filters or algorithms:') + print('\tbase64,b64: Base64') + print('\tasciihex,ahx: /ASCIIHexDecode') + print('\tascii85,a85: /ASCII85Decode') + print('\tlzw: /LZWDecode') + print('\tflatedecode,fl: /FlateDecode') + print('\trunlength,rl: /RunLengthDecode') + print('\tccittfax,ccf: /CCITTFaxDecode') + print('\tjbig2: /JBIG2Decode (Not implemented)') + print('\tdct: /DCTDecode (Not implemented)') + print(('\tjpx: /JPXDecode (Not implemented)' + newLine)) def do_decrypt(self, argv): if self.pdfFile is None: @@ -521,8 +521,8 @@ def do_decrypt(self, argv): self.log_output('decrypt ' + argv, message) def help_decrypt(self): - print newLine + 'Usage: decrypt $password' - print newLine + 'Decrypts the file with the specified password' + newLine + print((newLine + 'Usage: decrypt $password')) + print((newLine + 'Decrypts the file with the specified password' + newLine)) def do_embed(self, argv): fileType = 'application#2Fpdf' @@ -783,10 +783,10 @@ def do_embed(self, argv): self.log_output('open ' + argv, message) def help_embed(self): - print newLine + 'Usage: embed [-x] $filename [$file_type]' - print newLine + 'Embeds the specified file in the actual PDF file. The default type is "application/pdf".' + newLine - print 'Options:' - print '\t-x: The file is executed when the actual PDF file is opened' + newLine + print((newLine + 'Usage: embed [-x] $filename [$file_type]')) + print((newLine + 'Embeds the specified file in the actual PDF file. The default type is "application/pdf".' + newLine)) + print('Options:') + print(('\t-x: The file is executed when the actual PDF file is opened' + newLine)) def do_encode(self, argv): encodedContent = '' @@ -881,21 +881,21 @@ def do_encode(self, argv): self.log_output('encode ' + argv, encodedContent, [encodedContent], bytesOutput=True) def help_encode(self): - print newLine + 'Usage: encode variable $var_name $filter1 [$filter2 ...]' - print 'Usage: encode file $file_name $filter1 [$filter2 ...]' - print 'Usage: encode raw $offset $num_bytes $filter1 [$filter2 ...]' - print 'Usage: encode string $my_string $filter1 [$filter2 ...]' + newLine - print 'Encodes the content of the specified variable, file or raw bytes using the following filters or algorithms:' - print '\tbase64,b64: Base64' - print '\tasciihex,ahx: /ASCIIHexDecode' - print '\tascii85,a85: /ASCII85Decode (Not implemented)' - print '\tlzw: /LZWDecode' - print '\tflatedecode,fl: /FlateDecode' - print '\trunlength,rl: /RunLengthDecode (Not implemented)' - print '\tccittfax,ccf: /CCITTFaxDecode (Not implemented)' - print '\tjbig2: /JBIG2Decode (Not implemented)' - print '\tdct: /DCTDecode (Not implemented)' - print '\tjpx: /JPXDecode (Not implemented)' + newLine + print((newLine + 'Usage: encode variable $var_name $filter1 [$filter2 ...]')) + print('Usage: encode file $file_name $filter1 [$filter2 ...]') + print('Usage: encode raw $offset $num_bytes $filter1 [$filter2 ...]') + print(('Usage: encode string $my_string $filter1 [$filter2 ...]' + newLine)) + print('Encodes the content of the specified variable, file or raw bytes using the following filters or algorithms:') + print('\tbase64,b64: Base64') + print('\tasciihex,ahx: /ASCIIHexDecode') + print('\tascii85,a85: /ASCII85Decode (Not implemented)') + print('\tlzw: /LZWDecode') + print('\tflatedecode,fl: /FlateDecode') + print('\trunlength,rl: /RunLengthDecode (Not implemented)') + print('\tccittfax,ccf: /CCITTFaxDecode (Not implemented)') + print('\tjbig2: /JBIG2Decode (Not implemented)') + print('\tdct: /DCTDecode (Not implemented)') + print(('\tjpx: /JPXDecode (Not implemented)' + newLine)) def do_encode_strings(self, argv): if self.pdfFile is None: @@ -975,8 +975,8 @@ def do_encode_strings(self, argv): self.log_output('encode_strings ' + argv, message) def help_encode_strings(self): - print newLine + 'Usage: encode_strings [$object_id|trailer [$version]]' - print newLine + 'Encodes the strings and names included in the file, object or trailer' + newLine + print((newLine + 'Usage: encode_strings [$object_id|trailer [$version]]')) + print((newLine + 'Encodes the strings and names included in the file, object or trailer' + newLine)) def do_encrypt(self, argv): if self.pdfFile is None: @@ -1004,8 +1004,8 @@ def do_encrypt(self, argv): self.log_output('encrypt ' + argv, message) def help_encrypt(self): - print newLine + 'Usage: encrypt [$password]' - print newLine + 'Encrypts the file with the default or specified password' + newLine + print((newLine + 'Usage: encrypt [$password]')) + print((newLine + 'Encrypts the file with the default or specified password' + newLine)) def do_errors(self, argv): if self.pdfFile is None: @@ -1090,15 +1090,15 @@ def do_errors(self, argv): self.log_output('errors ' + argv, errors) def help_errors(self): - print newLine + 'Usage: errors [$object_id|xref|trailer [$version]]' - print newLine + 'Shows the errors of the file or object (object_id, xref, trailer)' + newLine + print((newLine + 'Usage: errors [$object_id|xref|trailer [$version]]')) + print((newLine + 'Shows the errors of the file or object (object_id, xref, trailer)' + newLine)) def do_exit(self, argv): return True def help_exit(self): - print newLine + 'Usage: exit' - print newLine + 'Exits from the console' + newLine + print((newLine + 'Usage: exit')) + print((newLine + 'Exits from the console' + newLine)) def do_extract(self, argv): validTypes = ['uri', 'js'] @@ -1152,8 +1152,8 @@ def do_extract(self, argv): self.log_output('extract ' + argv, output) def help_extract(self): - print newLine + 'Usage: extract uri|js [$version]' - print newLine + 'Extracts all the given type elements of the specified version after being decoded and decrypted (if necessary)' + newLine + print(newLine + 'Usage: extract uri|js [$version]') + print(newLine + 'Extracts all the given type elements of the specified version after being decoded and decrypted (if necessary)' + newLine) def do_filters(self, argv): @@ -1273,18 +1273,18 @@ def do_filters(self, argv): self.log_output('filters ' + argv, message + value, [value], bytesOutput=True) def help_filters(self): - print newLine + 'Usage: filters $object_id [$version] [$filter1 [$filter2 ...]]' - print newLine + 'Shows the filters found in the stream object or set the filters in the object (first filter is used first). The valid values for filters are the following:' - print '\tnone: No filters' - print '\tasciihex,ahx: /ASCIIHexDecode' - print '\tascii85,a85: /ASCII85Decode (Not implemented)' - print '\tlzw: /LZWDecode' - print '\tflatedecode,fl: /FlateDecode' - print '\trunlength,rl: /RunLengthDecode (Not implemented)' - print '\tccittfax,ccf: /CCITTFaxDecode (Not implemented)' - print '\tjbig2: /JBIG2Decode (Not implemented)' - print '\tdct: /DCTDecode (Not implemented)' - print '\tjpx: /JPXDecode (Not implemented)' + newLine + print(newLine + 'Usage: filters $object_id [$version] [$filter1 [$filter2 ...]]') + print(newLine + 'Shows the filters found in the stream object or set the filters in the object (first filter is used first). The valid values for filters are the following:') + print('\tnone: No filters') + print('\tasciihex,ahx: /ASCIIHexDecode') + print('\tascii85,a85: /ASCII85Decode (Not implemented)') + print('\tlzw: /LZWDecode') + print('\tflatedecode,fl: /FlateDecode') + print('\trunlength,rl: /RunLengthDecode (Not implemented)') + print('\tccittfax,ccf: /CCITTFaxDecode (Not implemented)') + print('\tjbig2: /JBIG2Decode (Not implemented)') + print('\tdct: /DCTDecode (Not implemented)') + print('\tjpx: /JPXDecode (Not implemented)' + newLine) def do_hash(self, argv): content = '' @@ -1392,16 +1392,16 @@ def do_hash(self, argv): self.log_output('hash ' + argv, output) def help_hash(self): - print newLine + 'Usage: hash object|rawobject|stream|rawstream $object_id [$version]' - print 'Usage: hash raw $offset $num_bytes' - print 'Usage: hash file $file_name' - print 'Usage: hash variable $var_name' - print 'Usage: hash string $my_string' - print newLine + 'Generates the hash (MD5/SHA1/SHA256) of the specified source: raw bytes of the file, objects and streams, and the content of files or variables' + newLine + print(newLine + 'Usage: hash object|rawobject|stream|rawstream $object_id [$version]') + print('Usage: hash raw $offset $num_bytes') + print('Usage: hash file $file_name') + print('Usage: hash variable $var_name') + print('Usage: hash string $my_string') + print(newLine + 'Generates the hash (MD5/SHA1/SHA256) of the specified source: raw bytes of the file, objects and streams, and the content of files or variables' + newLine) def help_help(self): - print newLine + 'Usage: help [$command]' - print newLine + 'Shows the available commands or the usage of the specified command' + newLine + print(newLine + 'Usage: help [$command]') + print(newLine + 'Shows the available commands or the usage of the specified command' + newLine) def do_info(self, argv): if self.pdfFile is None: @@ -1710,8 +1710,8 @@ def do_info(self, argv): self.log_output('info ' + argv, stats) def help_info(self): - print newLine + 'Usage: info [$object_id|xref|trailer [$version]]' - print newLine + 'Shows information of the file or object ($object_id, xref, trailer)' + newLine + print(newLine + 'Usage: info [$object_id|xref|trailer [$version]]') + print(newLine + 'Shows information of the file or object ($object_id, xref, trailer)' + newLine) def do_js_analyse(self, argv): content = '' @@ -1752,7 +1752,7 @@ def do_js_analyse(self, argv): self.log_output('js_analyse ' + argv, message) return False else: - print 'Warning: the object may not contain Javascript code...' + newLine + print('Warning: the object may not contain Javascript code...' + newLine) elif type == 'file': if not os.path.exists(src): message = '*** Error: The file does not exist!!' @@ -1768,7 +1768,7 @@ def do_js_analyse(self, argv): self.log_output('js_analyse ' + argv, message) return False else: - print 'Warning: the object may not contain Javascript code...' + newLine + print('Warning: the object may not contain Javascript code...' + newLine) elif type == 'object': if self.pdfFile is None: message = '*** Error: You must open a file!!' @@ -1796,7 +1796,7 @@ def do_js_analyse(self, argv): self.log_output('js_analyse ' + argv, message) return False else: - print 'Warning: the object may not contain Javascript code...' + newLine + print('Warning: the object may not contain Javascript code...' + newLine) objectType = object.getType() if objectType == 'stream': content = object.getStream() @@ -1852,11 +1852,11 @@ def do_js_analyse(self, argv): self.log_output('js_analyse ' + argv, jsanalyseOutput, unescapedBytes) def help_js_analyse(self): - print newLine + 'Usage: js_analyse variable $var_name' - print 'Usage: js_analyse file $file_name' - print 'Usage: js_analyse object $object_id [$version]' - print 'Usage: js_analyse string $javascript_code' - print newLine + 'Analyses the Javascript code stored in the specified string, variable, file or object' + newLine + print(newLine + 'Usage: js_analyse variable $var_name') + print('Usage: js_analyse file $file_name') + print('Usage: js_analyse object $object_id [$version]') + print('Usage: js_analyse string $javascript_code') + print(newLine + 'Analyses the Javascript code stored in the specified string, variable, file or object' + newLine) def do_js_beautify(self, argv): content = '' @@ -1894,7 +1894,7 @@ def do_js_beautify(self, argv): self.log_output('js_beautify ' + argv, message) return False else: - print 'Warning: the object may not contain Javascript code...' + newLine + print('Warning: the object may not contain Javascript code...' + newLine) elif type == 'file': if not os.path.exists(src): message = '*** Error: The file does not exist!!' @@ -1910,7 +1910,7 @@ def do_js_beautify(self, argv): self.log_output('js_beautify ' + argv, message) return False else: - print 'Warning: the object may not contain Javascript code...' + newLine + print('Warning: the object may not contain Javascript code...' + newLine) elif type == 'string': content = src else: @@ -1940,7 +1940,7 @@ def do_js_beautify(self, argv): self.log_output('js_beautify ' + argv, message) return False else: - print 'Warning: the object may not contain Javascript code...' + newLine + print('Warning: the object may not contain Javascript code...' + newLine) objectType = object.getType() if objectType == 'stream': content = object.getStream() @@ -1967,11 +1967,11 @@ def do_js_beautify(self, argv): self.log_output('js_beautify ' + argv, beautyContent) def help_js_beautify(self): - print newLine + 'Usage: js_beautify variable $var_name' - print 'Usage: js_beautify file $file_name' - print 'Usage: js_beautify object $object_id [$version]' - print 'Usage: js_beautify string $javascript_code [$version]' - print newLine + 'Beautifies the Javascript code stored in the specified variable, file or object' + newLine + print(newLine + 'Usage: js_beautify variable $var_name') + print('Usage: js_beautify file $file_name') + print('Usage: js_beautify object $object_id [$version]') + print('Usage: js_beautify string $javascript_code [$version]') + print(newLine + 'Beautifies the Javascript code stored in the specified variable, file or object' + newLine) def do_js_code(self, argv): if self.pdfFile is None: @@ -2034,8 +2034,8 @@ def do_js_code(self, argv): self.log_output('js_code ' + argv, message) def help_js_code(self): - print newLine + 'Usage: js_code $object_id [$version]' - print newLine + 'Shows the Javascript code found in the object' + newLine + print(newLine + 'Usage: js_code $object_id [$version]') + print(newLine + 'Shows the Javascript code found in the object' + newLine) def do_js_eval(self, argv): error = '' @@ -2077,7 +2077,7 @@ def do_js_eval(self, argv): self.log_output('js_eval ' + argv, message) return False else: - print 'Warning: the object may not contain Javascript code...' + newLine + print('Warning: the object may not contain Javascript code...' + newLine) elif type == 'file': if not os.path.exists(src): message = '*** Error: The file does not exist!!' @@ -2093,7 +2093,7 @@ def do_js_eval(self, argv): self.log_output('js_eval ' + argv, message) return False else: - print 'Warning: the object may not contain Javascript code...' + newLine + print('Warning: the object may not contain Javascript code...' + newLine) elif type == 'object': if self.pdfFile is None: message = '*** Error: You must open a file!!' @@ -2121,7 +2121,7 @@ def do_js_eval(self, argv): self.log_output('js_eval ' + argv, message) return False else: - print 'Warning: the object may not contain Javascript code...' + newLine + print('Warning: the object may not contain Javascript code...' + newLine) objectType = object.getType() if objectType == 'stream': content = object.getStream() @@ -2170,11 +2170,11 @@ def do_js_eval(self, argv): self.log_output('js_eval ' + argv, '*** Error: ' + error) def help_js_eval(self): - print newLine + 'Usage: js_eval variable $var_name' - print 'Usage: js_eval file $file_name' - print 'Usage: js_eval object $object_id [$version]' - print 'Usage: js_eval string $javascript_code' - print newLine + 'Evaluates the Javascript code stored in the specified variable, file, object or raw code in a global context' + newLine + print(newLine + 'Usage: js_eval variable $var_name') + print('Usage: js_eval file $file_name') + print('Usage: js_eval object $object_id [$version]') + print('Usage: js_eval string $javascript_code') + print(newLine + 'Evaluates the Javascript code stored in the specified variable, file, object or raw code in a global context' + newLine) def do_js_jjdecode(self, argv): content = '' @@ -2212,7 +2212,7 @@ def do_js_jjdecode(self, argv): self.log_output('js_jjdecode ' + argv, message) return False else: - print 'Warning: the object may not contain Javascript code...' + newLine + print('Warning: the object may not contain Javascript code...' + newLine) elif type == 'file': if not os.path.exists(src): message = '*** Error: The file does not exist!!' @@ -2228,7 +2228,7 @@ def do_js_jjdecode(self, argv): self.log_output('js_jjdecode ' + argv, message) return False else: - print 'Warning: the object may not contain Javascript code...' + newLine + print('Warning: the object may not contain Javascript code...' + newLine) elif type == 'string': content = src else: @@ -2258,7 +2258,7 @@ def do_js_jjdecode(self, argv): self.log_output('js_jjdecode ' + argv, message) return False else: - print 'Warning: the object may not contain Javascript code...' + newLine + print('Warning: the object may not contain Javascript code...' + newLine) objectType = object.getType() if objectType == 'stream': content = object.getStream() @@ -2304,11 +2304,11 @@ def do_js_jjdecode(self, argv): self.log_output('js_jjdecode ' + argv, decodedContent) def help_js_jjdecode(self): - print newLine + 'Usage: js_jjdecode variable $var_name' - print 'Usage: js_jjdecode file $file_name' - print 'Usage: js_jjdecode object $object_id [$version]' - print 'Usage: js_jjdecode string $encoded_js_code [$version]' - print newLine + 'Decodes the Javascript code stored in the specified variable, file or object using the jjencode/decode algorithm by Yosuke Hasegawa (http://utf-8.jp/public/jjencode.html)' + newLine + print(newLine + 'Usage: js_jjdecode variable $var_name') + print('Usage: js_jjdecode file $file_name') + print('Usage: js_jjdecode object $object_id [$version]') + print('Usage: js_jjdecode string $encoded_js_code [$version]') + print(newLine + 'Decodes the Javascript code stored in the specified variable, file or object using the jjencode/decode algorithm by Yosuke Hasegawa (http://utf-8.jp/public/jjencode.html)' + newLine) def do_js_join(self, argv): content = '' @@ -2354,14 +2354,14 @@ def do_js_join(self, argv): self.log_output('js_join ' + argv, finalString) def help_js_join(self): - print newLine + 'Usage: js_join variable $var_name' - print 'Usage: js_join file $file_name' - print 'Usage: js_join string $my_string' - print newLine + 'Joins some strings separated by quotes and stored in the specified variable or file in a unique one' + newLine - print 'Example:' + newLine - print 'aux = "%u65"+"54"+"%u74"+"73"' + newLine - print '> js_join variable aux' + newLine - print '%u6554%u7473' + newLine + print(newLine + 'Usage: js_join variable $var_name') + print('Usage: js_join file $file_name') + print('Usage: js_join string $my_string') + print(newLine + 'Joins some strings separated by quotes and stored in the specified variable or file in a unique one' + newLine) + print('Example:' + newLine) + print('aux = "%u65"+"54"+"%u74"+"73"' + newLine) + print('> js_join variable aux' + newLine) + print('%u6554%u7473' + newLine) def do_js_unescape(self, argv): content = '' @@ -2425,14 +2425,14 @@ def do_js_unescape(self, argv): self.log_output('js_unescape ' + argv, unescapedOutput, [bytes], bytesOutput=True) def help_js_unescape(self): - print newLine + 'Usage: js_unescape variable $var_name' - print 'Usage: js_unescape file $file_name' - print 'Usage: js_unescape string $escaped_string' - print newLine + 'Unescapes the escaped characters stored in the specified variable or file' + newLine - print 'Example:' + newLine - print 'aux = "%u6554%u7473"' + newLine - print '> js_unescape variable aux' + newLine - print '54 65 73 74 |Test|' + newLine + print(newLine + 'Usage: js_unescape variable $var_name') + print('Usage: js_unescape file $file_name') + print('Usage: js_unescape string $escaped_string') + print(newLine + 'Unescapes the escaped characters stored in the specified variable or file' + newLine) + print('Example:' + newLine) + print('aux = "%u6554%u7473"' + newLine) + print('> js_unescape variable aux' + newLine) + print('54 65 73 74 |Test|' + newLine) def do_js_vars(self, argv): varName = None @@ -2479,8 +2479,8 @@ def do_js_vars(self, argv): self.log_output('js_vars ' + argv, str(varArray)) def help_js_vars(self): - print newLine + 'Usage: js_vars [$var_name]' - print newLine + 'Shows the Javascript variables defined in the execution context or the content of the specified variable' + newLine + print(newLine + 'Usage: js_vars [$var_name]') + print(newLine + 'Shows the Javascript variables defined in the execution context or the content of the specified variable' + newLine) def do_log(self, argv): args = self.parseArgs(argv) @@ -2491,9 +2491,9 @@ def do_log(self, argv): numArgs = len(args) if numArgs == 0: if self.loggingFile is None: - print newLine + 'Not logging now!!' + newLine + print(newLine + 'Not logging now!!' + newLine) else: - print newLine + 'Log file: ' + self.loggingFile + newLine + print(newLine + 'Log file: ' + self.loggingFile + newLine) elif numArgs == 1: param = args[0] if param == 'stop': @@ -2505,12 +2505,12 @@ def do_log(self, argv): return False def help_log(self): - print newLine + 'Usage: log' - print newLine + 'Shows the actual state of logging' + newLine - print 'Usage: log stop' - print newLine + 'Stops logging' + newLine - print 'Usage: log $log_file' - print newLine + 'Starts logging in the specified file' + newLine + print(newLine + 'Usage: log') + print(newLine + 'Shows the actual state of logging' + newLine) + print('Usage: log stop') + print(newLine + 'Stops logging' + newLine) + print('Usage: log $log_file') + print(newLine + 'Starts logging in the specified file' + newLine) def do_malformed_output(self, argv): malformedOptions = [] @@ -2551,15 +2551,15 @@ def do_malformed_output(self, argv): self.log_output('malformed_output ' + argv, message) def help_malformed_output(self): - print newLine + 'Usage: malformed_output [$option1 [$option2 ...] [$header_file]]' + newLine - print 'Enables malformed output when saving the file:' + newLine - print '\t0: Removes all the malformed options.' - print '\t1 [header_file]: Enable all the implemented tricks. Default option.' - print '\t2 [header_file]: Puts the default or specified header before the PDF header.' - print '\t3: Removes all the "endobj" tags.' - print '\t4: Removes all the "endstream" tags.' - print '\t5: Removes the "xref" section.' - print '\t6: Bad header: %PDF-1' + newLine + print(newLine + 'Usage: malformed_output [$option1 [$option2 ...] [$header_file]]' + newLine) + print('Enables malformed output when saving the file:' + newLine) + print('\t0: Removes all the malformed options.') + print('\t1 [header_file]: Enable all the implemented tricks. Default option.') + print('\t2 [header_file]: Puts the default or specified header before the PDF header.') + print('\t3: Removes all the "endobj" tags.') + print('\t4: Removes all the "endstream" tags.') + print('\t5: Removes the "xref" section.') + print('\t6: Bad header: %PDF-1' + newLine) def do_metadata(self, argv): if self.pdfFile is None: @@ -2620,8 +2620,8 @@ def do_metadata(self, argv): return False def help_metadata(self): - print newLine + 'Usage: metadata [$version]' - print newLine + 'Shows the metadata of the document or version of the document' + newLine + print(newLine + 'Usage: metadata [$version]') + print(newLine + 'Shows the metadata of the document or version of the document' + newLine) def do_modify(self, argv): maxDepth = 2 @@ -2710,8 +2710,8 @@ def do_modify(self, argv): self.log_output('modify ' + argv, message) def help_modify(self): - print newLine + 'Usage: modify object|stream $object_id [$version] [$file]' + newLine - print 'Modifies the object or stream specified. It\'s possible to use a file to retrieve the stream content (ONLY for stream content).' + newLine + print(newLine + 'Usage: modify object|stream $object_id [$version] [$file]' + newLine) + print('Modifies the object or stream specified. It\'s possible to use a file to retrieve the stream content (ONLY for stream content).' + newLine) def do_object(self, argv): if self.pdfFile is None: @@ -2750,8 +2750,8 @@ def do_object(self, argv): self.log_output('object ' + argv, value) def help_object(self): - print newLine + 'Usage: object $object_id [$version]' - print newLine + 'Shows the content of the object after being decoded and decrypted.' + newLine + print(newLine + 'Usage: object $object_id [$version]') + print(newLine + 'Shows the content of the object after being decoded and decrypted.' + newLine) def do_offsets(self, argv): if self.pdfFile is None: @@ -2819,8 +2819,8 @@ def do_offsets(self, argv): self.log_output('offsets ' + argv, offsetsOutput) def help_offsets(self): - print newLine + 'Usage: offsets [$version]' - print newLine + 'Shows the physical map of the file or the specified version of the document' + newLine + print(newLine + 'Usage: offsets [$version]') + print(newLine + 'Shows the physical map of the file or the specified version of the document' + newLine) def do_open(self, argv): forceMode = False @@ -2864,23 +2864,23 @@ def do_open(self, argv): self.pdfFile = None self.log_output('open ' + argv, message) if not JS_MODULE: - print 'Warning: PyV8 is not installed!!' + newLine + print('Warning: PyV8 is not installed!!' + newLine) if self.pdfFile is not None: self.do_info('') def help_open(self): - print newLine + 'Usage: open [-fl] $file_name' + newLine - print 'Opens and parses the specified file' + newLine - print 'Options:' - print '\t-f: Sets force parsing mode to ignore errors' - print '\t-l: Sets loose parsing mode for problematic files' + newLine + print(newLine + 'Usage: open [-fl] $file_name' + newLine) + print('Opens and parses the specified file' + newLine) + print('Options:') + print('\t-f: Sets force parsing mode to ignore errors') + print('\t-l: Sets loose parsing mode for problematic files' + newLine) def do_quit(self, argv): return True def help_quit(self): - print newLine + 'Usage: quit' - print newLine + 'Exits from the console' + newLine + print(newLine + 'Usage: quit') + print(newLine + 'Exits from the console' + newLine) def do_rawobject(self, argv): if self.pdfFile is None: @@ -2967,8 +2967,8 @@ def do_rawobject(self, argv): self.log_output('rawobject ' + argv, rawValue) def help_rawobject(self): - print newLine + 'Usage: rawobject [$object_id|xref|trailer [$version]]' - print newLine + 'Shows the content of the object without being decoded or decrypted (object_id, xref, trailer)' + newLine + print(newLine + 'Usage: rawobject [$object_id|xref|trailer [$version]]') + print(newLine + 'Shows the content of the object without being decoded or decrypted (object_id, xref, trailer)' + newLine) def do_rawstream(self, argv): if self.pdfFile is None: @@ -3011,8 +3011,8 @@ def do_rawstream(self, argv): self.log_output('rawstream ' + argv, value, [value], bytesOutput=True) def help_rawstream(self): - print newLine + 'Usage: rawstream $object_id [$version]' - print newLine + 'Shows the stream content of the specified document version before being decoded and decrypted' + newLine + print(newLine + 'Usage: rawstream $object_id [$version]') + print(newLine + 'Shows the stream content of the specified document version before being decoded and decrypted' + newLine) def do_references(self, argv): if self.pdfFile is None: @@ -3055,8 +3055,8 @@ def do_references(self, argv): self.log_output('references ' + argv, str(references)) def help_references(self): - print newLine + 'Usage: references to|in $object_id [$version]' - print newLine + 'Shows the references in the object or to the object in the specified version of the document' + newLine + print(newLine + 'Usage: references to|in $object_id [$version]') + print(newLine + 'Shows the references in the object or to the object in the specified version of the document' + newLine) def do_replace(self, argv): replaceOutput = '' @@ -3125,11 +3125,11 @@ def do_replace(self, argv): self.log_output('replace ' + argv, message) def help_replace(self): - print newLine + 'Usage: replace all $string1 $string2' - print newLine + 'Replaces $string1 with $string2 in the whole PDF file' + newLine - print 'Usage: replace variable $var_name $string1 $string2' - print 'Usage: replace file $file_name $string1 $string2' - print newLine + 'Replaces $string1 with $string2 in the content of the specified variable or file' + newLine + print(newLine + 'Usage: replace all $string1 $string2') + print(newLine + 'Replaces $string1 with $string2 in the whole PDF file' + newLine) + print('Usage: replace variable $var_name $string1 $string2') + print('Usage: replace file $file_name $string1 $string2') + print(newLine + 'Replaces $string1 with $string2 in the content of the specified variable or file' + newLine) def do_reset(self, argv): args = self.parseArgs(argv) @@ -3162,10 +3162,10 @@ def do_reset(self, argv): self.help_reset() def help_reset(self): - print newLine + 'Usage: reset' - print newLine + 'Cleans the console' - print newLine + 'Usage: reset $var_name' - print newLine + 'Resets the variable value to the default value if applicable' + newLine + print(newLine + 'Usage: reset') + print(newLine + 'Cleans the console') + print(newLine + 'Usage: reset $var_name') + print(newLine + 'Resets the variable value to the default value if applicable' + newLine) def do_save(self, argv): if self.pdfFile is None: @@ -3194,8 +3194,8 @@ def do_save(self, argv): self.help_save() def help_save(self): - print newLine + 'Usage: save [$file_name]' - print newLine + 'Saves the file to disk' + newLine + print(newLine + 'Usage: save [$file_name]') + print(newLine + 'Saves the file to disk' + newLine) def do_save_version(self, argv): if self.pdfFile is None: @@ -3230,8 +3230,8 @@ def do_save_version(self, argv): self.help_save_version() def help_save_version(self): - print newLine + 'Usage: save_version $version $file_name' - print newLine + 'Saves the selected file version to disk' + newLine + print(newLine + 'Usage: save_version $version $file_name') + print(newLine + 'Saves the selected file version to disk' + newLine) def do_sctest(self, argv): if not EMU_MODULE: @@ -3344,10 +3344,10 @@ def do_sctest(self, argv): self.log_output('sctest ' + argv, output) def help_sctest(self): - print newLine + 'Usage: sctest [-v] variable $var_name' - print 'Usage: sctest [-v] file $file_name' - print 'Usage: sctest [-v] raw $offset $num_bytes' - print newLine + 'Wrapper of the sctest tool (libemu) to emulate shellcodes. With -v the output is verbose, be ready for tons of data ;p' + newLine + print(newLine + 'Usage: sctest [-v] variable $var_name') + print('Usage: sctest [-v] file $file_name') + print('Usage: sctest [-v] raw $offset $num_bytes') + print(newLine + 'Wrapper of the sctest tool (libemu) to emulate shellcodes. With -v the output is verbose, be ready for tons of data ;p' + newLine) def do_search(self, argv): if self.pdfFile is None: @@ -3410,9 +3410,9 @@ def do_search(self, argv): self.log_output('search ' + argv, output) def help_search(self): - print newLine + 'Usage: search [hex] $string' - print newLine + 'Search the specified string or hexadecimal string in the objects (decoded and encrypted streams included)' + newLine - print 'Example: search hex \\x34\\x35' + newLine + print(newLine + 'Usage: search [hex] $string') + print(newLine + 'Search the specified string or hexadecimal string in the objects (decoded and encrypted streams included)' + newLine) + print('Example: search hex \\x34\\x35' + newLine) def do_set(self, argv): consoleOutput = '' @@ -3436,7 +3436,7 @@ def do_set(self, argv): consoleOutput += var + ' = ' + str(varContent) + newLine else: consoleOutput += var + ' = ' + newLine + varContent + newLine - print newLine + consoleOutput + print(newLine + consoleOutput) else: varName = args[0] value = args[1] @@ -3457,13 +3457,13 @@ def do_set(self, argv): self.variables[varName] = [value, value] def help_set(self): - print newLine + 'Usage: set [$var_name $var_value]' - print newLine + 'Sets the specified variable value or creates one with this value. Without parameters all the variables are shown.' + newLine - print 'Special variables:' + newLine - print '\theader_file: READ ONLY. Specifies the file header to be used when \'malformed_options\' are active.' + newLine - print '\tmalformed_options: READ ONLY. Variable to store the malformed options used to save the file.' + newLine - print '\toutput_limit: variable to specify the maximum number of lines to be shown at once when the output is long (no limit = -1). By default there is no limit.' + newLine - print '\tvt_key: VirusTotal Api key.' + newLine + print(newLine + 'Usage: set [$var_name $var_value]') + print(newLine + 'Sets the specified variable value or creates one with this value. Without parameters all the variables are shown.' + newLine) + print('Special variables:' + newLine) + print('\theader_file: READ ONLY. Specifies the file header to be used when \'malformed_options\' are active.' + newLine) + print('\tmalformed_options: READ ONLY. Variable to store the malformed options used to save the file.' + newLine) + print('\toutput_limit: variable to specify the maximum number of lines to be shown at once when the output is long (no limit = -1). By default there is no limit.' + newLine) + print('\tvt_key: VirusTotal Api key.' + newLine) def do_show(self, argv): args = self.parseArgs(argv) @@ -3476,31 +3476,31 @@ def do_show(self, argv): return False var = args[0] if not self.variables.has_key(var): - print newLine + '*** Error: The variable ' + var + ' does not exist!!' + newLine + print(newLine + '*** Error: The variable ' + var + ' does not exist!!' + newLine) return False if var == 'output': if self.variables[var][0] == 'stdout': - print newLine + 'output = "stdout"' + newLine + print(newLine + 'output = "stdout"' + newLine) else: if self.variables[var][0] == 'file': - print newLine + 'output = "file"' - print 'fileName = "' + self.output + '"' + newLine + print(newLine + 'output = "file"') + print('fileName = "' + self.output + '"' + newLine) else: - print newLine + 'output = "variable"' - print 'varName = "' + self.output + '"' + newLine + print(newLine + 'output = "variable"') + print('varName = "' + self.output + '"' + newLine) else: varContent = self.printResult(str(self.variables[var][0])) - print newLine + varContent + newLine + print(newLine + varContent + newLine) def help_show(self): - print newLine + 'Usage: show $var_name' - print newLine + 'Shows the value of the specified variable' + newLine - print 'Special variables:' + newLine - print '\theader_file' - print '\tmalformed_options' - print '\toutput' - print '\toutput_limit' - print '\tvt_key' + newLine + print(newLine + 'Usage: show $var_name') + print(newLine + 'Shows the value of the specified variable' + newLine) + print('Special variables:' + newLine) + print('\theader_file') + print('\tmalformed_options') + print('\toutput') + print('\toutput_limit') + print('\tvt_key' + newLine) def do_stream(self, argv): if self.pdfFile is None: @@ -3548,8 +3548,8 @@ def do_stream(self, argv): self.log_output('stream ' + argv, value, [value], bytesOutput=True) def help_stream(self): - print newLine + 'Usage: stream $object_id [$version]' - print newLine + 'Shows the object stream content of the specified version after being decoded and decrypted (if necessary)' + newLine + print(newLine + 'Usage: stream $object_id [$version]') + print(newLine + 'Shows the object stream content of the specified version after being decoded and decrypted (if necessary)' + newLine) def do_tree(self, argv): @@ -3598,8 +3598,8 @@ def do_tree(self, argv): self.log_output('tree ' + argv, treeOutput) def help_tree(self): - print newLine + 'Usage: tree [$version]' - print newLine + 'Shows the tree graph of the file or specified version' + newLine + print(newLine + 'Usage: tree [$version]') + print(newLine + 'Shows the tree graph of the file or specified version' + newLine) def do_vtcheck(self, argv): content = '' @@ -3766,15 +3766,15 @@ def do_vtcheck(self, argv): self.log_output('vtcheck ' + argv, output) def help_vtcheck(self): - print newLine + 'Usage: vtcheck' - print 'Usage: vtcheck object|rawobject|stream|rawstream $object_id [$version]' - print 'Usage: vtcheck raw $offset $num_bytes' - print 'Usage: vtcheck file $file_name' - print 'Usage: vtcheck variable $var_name' - print newLine + 'Checks the hash of the specified source on VirusTotal: raw bytes of the file, objects and streams, and the content of files or variables.' - print 'If no parameters are specified then the hash of the PDF document will be checked.' + newLine - print '*** NOTE: NO CONTENT IS SENT TO VIRUSTOTAL, JUST HASHES!!' + newLine - print '*** NOTE: You need a VirusTotal API key to use this command.' + newLine + print(newLine + 'Usage: vtcheck') + print('Usage: vtcheck object|rawobject|stream|rawstream $object_id [$version]') + print('Usage: vtcheck raw $offset $num_bytes') + print('Usage: vtcheck file $file_name') + print('Usage: vtcheck variable $var_name') + print(newLine + 'Checks the hash of the specified source on VirusTotal: raw bytes of the file, objects and streams, and the content of files or variables.') + print('If no parameters are specified then the hash of the PDF document will be checked.' + newLine) + print('*** NOTE: NO CONTENT IS SENT TO VIRUSTOTAL, JUST HASHES!!' + newLine) + print('*** NOTE: You need a VirusTotal API key to use this command.' + newLine) def do_xor(self, argv): content = '' @@ -3916,12 +3916,12 @@ def do_xor(self, argv): self.log_output('xor ' + argv, output, [output], bytesOutput=True) def help_xor(self): - print newLine + 'Usage: xor stream|rawstream $object_id [$version] [$key]' - print 'Usage: xor raw $offset $num_bytes $key' - print 'Usage: xor file $file_name $key' - print 'Usage: xor variable $var_name $key' - print newLine + 'Performs an XOR operation using the specified key with the content of the specified file or variable, raw bytes of the file or stream/rawstream.' - print 'If the key is not specified then a bruteforcing XOR is performed.' + newLine + print(newLine + 'Usage: xor stream|rawstream $object_id [$version] [$key]') + print('Usage: xor raw $offset $num_bytes $key') + print('Usage: xor file $file_name $key') + print('Usage: xor variable $var_name $key') + print(newLine + 'Performs an XOR operation using the specified key with the content of the specified file or variable, raw bytes of the file or stream/rawstream.') + print('If the key is not specified then a bruteforcing XOR is performed.' + newLine) def do_xor_search(self, argv): content = '' @@ -4065,13 +4065,13 @@ def do_xor_search(self, argv): self.log_output('xor_search ' + argv, message) def help_xor_search(self): - print newLine + 'Usage: xor_search [-i] stream|rawstream $object_id [$version] $string_to_search' - print 'Usage: xor_search [-i] raw $offset $num_bytes $string_to_search' - print 'Usage: xor_search [-i] file $file_name $string_to_search' - print 'Usage: xor_search [-i] variable $var_name $string_to_search' - print newLine + 'Searches for the specified string in the result of an XOR brute forcing operation with the content of the specified file or variable,' - print 'raw bytes of the file or stream/rawstream. The output shows the offset/s where the string is found. It\'s a case sensitive search but' - print 'it\'s possible to make it insensitive using -i.' + newLine + print(newLine + 'Usage: xor_search [-i] stream|rawstream $object_id [$version] $string_to_search') + print('Usage: xor_search [-i] raw $offset $num_bytes $string_to_search') + print('Usage: xor_search [-i] file $file_name $string_to_search') + print('Usage: xor_search [-i] variable $var_name $string_to_search') + print(newLine + 'Searches for the specified string in the result of an XOR brute forcing operation with the content of the specified file or variable,') + print('raw bytes of the file or stream/rawstream. The output shows the offset/s where the string is found. It\'s a case sensitive search but') + print('it\'s possible to make it insensitive using -i.' + newLine) def additionRequest(self, dict=False): ''' @@ -4140,7 +4140,7 @@ def addObject(self, iteration, maxDepth=10): object = PDFNull(content) elif objectType == 'array': elements = [] - print 'Please, now specify the elements of the array:' + print('Please, now specify the elements of the array:') while True: res = self.additionRequest() if res is None: @@ -4155,7 +4155,7 @@ def addObject(self, iteration, maxDepth=10): object = PDFArray(elements=elements) elif objectType == 'dictionary': elements = {} - print 'Please, now specify the elements of the dictionary:' + print('Please, now specify the elements of the dictionary:') while True: res = self.additionRequest(dict=True) if res is None: @@ -4288,7 +4288,7 @@ def log_output(self, command, output, bytesToSave=None, printOutput=True, bytesO niceOutput = newLine + niceOutput + newLine if self.variables['output_limit'][0] is None or self.variables['output_limit'][ 0] == -1 or not self.use_rawinput: - print niceOutput + print(niceOutput) else: limit = int(self.variables['output_limit'][0]) lines = niceOutput.split(newLine) @@ -4296,7 +4296,7 @@ def log_output(self, command, output, bytesToSave=None, printOutput=True, bytesO outputStepLines = lines[:limit] lines = lines[limit:] for line in outputStepLines: - print line + print(line) if len(lines) == 0: break ch = raw_input('( Press to continue or to quit )') @@ -4457,7 +4457,7 @@ def modifyRequest(self, value, rawValue, key=None, stream=False): return None else: if stream and response.lower() == 'm': - print 'Value: ' + str(value) + newLine + print('Value: ' + str(value) + newLine) return response.lower() def parseArgs(self, args): diff --git a/PDFCore.py b/PDFCore.py index 3b2fe00..cbc4ae2 100644 --- a/PDFCore.py +++ b/PDFCore.py @@ -6860,11 +6860,11 @@ def parse (self, fileName, forceMode = False, looseMode = False, manualAnalysis file = open(fileName,'rb') for line in file: if versionLine == '': - pdfHeaderIndex = line.find('%PDF-') - psHeaderIndex = line.find('%!PS-Adobe-') + pdfHeaderIndex = line.find(b'%PDF-') + psHeaderIndex = line.find(b'%!PS-Adobe-') if pdfHeaderIndex != -1 or psHeaderIndex != -1: - index = line.find('\r') - if index != -1 and index+1 < len(line) and line[index+1] != '\n': + index = line.find(b'\r') + if index != -1 and index+1 < len(line) and line[index+1] != b'\n': index += 1 versionLine = line[:index] binaryLine = line[index:] @@ -6885,9 +6885,9 @@ def parse (self, fileName, forceMode = False, looseMode = False, manualAnalysis file.close() # Getting the specification version - versionLine = versionLine.replace('\r','') - versionLine = versionLine.replace('\n','') - matchVersion = re.findall('%(PDF-|!PS-Adobe-\d{1,2}\.\d{1,2}\sPDF-)(\d{1,2}\.\d{1,2})',versionLine) + versionLine = versionLine.replace(b'\r',b'') + versionLine = versionLine.replace(b'\n',b'') + matchVersion = re.findall(b'%(PDF-|!PS-Adobe-\d{1,2}\.\d{1,2}\sPDF-)(\d{1,2}\.\d{1,2})',versionLine) if matchVersion == []: if forceMode: pdfFile.setVersion(versionLine) @@ -6902,15 +6902,15 @@ def parse (self, fileName, forceMode = False, looseMode = False, manualAnalysis # Getting the end of line if len(binaryLine) > 3: - if binaryLine[-2:] == '\r\n': - pdfFile.setEndLine('\r\n') + if binaryLine[-2:] == b'\r\n': + pdfFile.setEndLine(b'\r\n') else: - if binaryLine[-1] == '\r': - pdfFile.setEndLine('\r') - elif binaryLine[-1] == '\n': - pdfFile.setEndLine('\n') + if binaryLine[-1] == b'\r': + pdfFile.setEndLine(b'\r') + elif binaryLine[-1] == b'\n': + pdfFile.setEndLine(b'\n') else: - pdfFile.setEndLine('\n') + pdfFile.setEndLine(b'\n') # Does it contain binary characters?? if binaryLine[0] == '%' and ord(binaryLine[1]) >= 128 and ord(binaryLine[2]) >= 128 and ord(binaryLine[3]) >= 128 and ord(binaryLine[4]) >= 128: @@ -6927,15 +6927,15 @@ def parse (self, fileName, forceMode = False, looseMode = False, manualAnalysis pdfFile.setSHA256(hashlib.sha256(fileContent).hexdigest()) # Getting the number of updates in the file - while fileContent.find('%%EOF') != -1: - self.readUntilSymbol(fileContent, '%%EOF') + while fileContent.find(b'%%EOF') != -1: + self.readUntilSymbol(fileContent, b'%%EOF') self.readUntilEndOfLine(fileContent) self.fileParts.append(fileContent[:self.charCounter]) fileContent = fileContent[self.charCounter:] self.charCounter = 0 else: if self.fileParts == []: - errorMessage = '%%EOF not found' + errorMessage = b'%%EOF not found' if forceMode: pdfFile.addError(errorMessage) self.fileParts.append(fileContent) @@ -6974,17 +6974,17 @@ def parse (self, fileName, forceMode = False, looseMode = False, manualAnalysis if xrefContent != None: xrefOffset = bodyOffset + len(bodyContent) trailerOffset = xrefOffset + len(xrefContent) - bodyContent = bodyContent.strip('\r\n') - xrefContent = xrefContent.strip('\r\n') - trailerContent = trailerContent.strip('\r\n') + bodyContent = bodyContent.strip(b'\r\n') + xrefContent = xrefContent.strip(b'\r\n') + trailerContent = trailerContent.strip(b'\r\n') trailerFound = True xrefFound = True else: if trailerContent != None: xrefOffset = -1 trailerOffset = bodyOffset + len(bodyContent) - bodyContent = bodyContent.strip('\r\n') - trailerContent = trailerContent.strip('\r\n') + bodyContent = bodyContent.strip(b'\r\n') + trailerContent = trailerContent.strip(b'\r\n') else: errorMessage = 'PDF sections not found' if forceMode: @@ -7150,16 +7150,16 @@ def parsePDFSections(self, content, forceMode = False, looseMode = False): trailerContent = None global pdfFile - indexTrailer = content.find('trailer') + indexTrailer = content.find(b'trailer') if indexTrailer != -1: restContent = content[:indexTrailer] auxTrailer = content[indexTrailer:] - indexEOF = auxTrailer.find('%%EOF') + indexEOF = auxTrailer.find(b'%%EOF') if indexEOF == -1: trailerContent = auxTrailer else: trailerContent = auxTrailer[:indexEOF+5] - indexXref = restContent.find('xref') + indexXref = restContent.find(b'xref') if indexXref != -1: bodyContent = restContent[:indexXref] xrefContent = restContent[indexXref:] @@ -7169,11 +7169,11 @@ def parsePDFSections(self, content, forceMode = False, looseMode = False): pdfFile.addError('Xref section not found') return [bodyContent,xrefContent,trailerContent] - indexTrailer = content.find('startxref') + indexTrailer = content.find(b'startxref') if indexTrailer != -1: restContent = content[:indexTrailer] auxTrailer = content[indexTrailer:] - indexEOF = auxTrailer.find('%%EOF') + indexEOF = auxTrailer.find(b'%%EOF') if indexEOF == -1: trailerContent = auxTrailer else: @@ -8053,13 +8053,13 @@ def readUntilEndOfLine(self, content): @return A tuple (status,statusContent), where statusContent is the characters read in case status = 0 or an error in case status = -1 ''' global pdfFile - if not isinstance(content,str): + if not isinstance(content, bytes): return (-1,'Bad string') errorMessage = [] oldCharCounter = self.charCounter tmpContent = content[self.charCounter:] for char in tmpContent: - if char == '\r' or char == '\n': + if char == b'\r' or char == b'\n': return (0,content[oldCharCounter:self.charCounter]) self.charCounter += 1 else: diff --git a/PDFCrypto.py b/PDFCrypto.py index e16e345..a2cf408 100644 --- a/PDFCrypto.py +++ b/PDFCrypto.py @@ -26,7 +26,13 @@ ''' import hashlib,struct,random,warnings,aes,sys -from itertools import cycle, izip +from itertools import cycle + +try: + from itertools import izip +except ImportError: + izip = zip + warnings.filterwarnings("ignore") paddingString = '\x28\xBF\x4E\x5E\x4E\x75\x8A\x41\x64\x00\x4E\x56\xFF\xFA\x01\x08\x2E\x2E\x00\xB6\xD0\x68\x3E\x80\x2F\x0C\xA9\xFE\x64\x53\x69\x7A' @@ -332,4 +338,4 @@ def xor(bytes, key): @return: The xored bytes ''' key = cycle(key) - return ''.join(chr(ord(x) ^ ord(y)) for (x,y) in izip(bytes, key)) \ No newline at end of file + return ''.join(chr(ord(x) ^ ord(y)) for (x,y) in izip(bytes, key)) diff --git a/PDFUtils.py b/PDFUtils.py index 6423831..c08fc46 100644 --- a/PDFUtils.py +++ b/PDFUtils.py @@ -25,7 +25,14 @@ Module with some misc functions ''' -import os, re, htmlentitydefs, json, urllib, urllib2 +import os, re, json, urllib + +try: + from html.entities import name2codepoint + from urllib.request import urlopen, Request +except ImportError: + from htmlentitydefs import name2codepoint + from urllib2 import urlopen, Request def clearScreen(): ''' @@ -325,7 +332,7 @@ def numToHex(num, numBytes): hexString += chr(int(hexNumber[i]+hexNumber[i+1],16)) hexString = '\0'*(numBytes-len(hexString))+hexString except: - return (-1,'Error in hexadecimal conversion') + return (-1,'Error in hexadecimal conversion') return (0,hexString) def numToString(num, numDigits): @@ -369,7 +376,7 @@ def fixup(m): else: # named entity try: - text = unichr(htmlentitydefs.name2codepoint[text[1:-1]]) + text = unichr(name2codepoint[text[1:-1]]) except KeyError: pass return text # leave as is @@ -427,8 +434,8 @@ def vtcheck(md5, vtKey): parameters = {'resource':md5,'apikey':vtKey} try: data = urllib.urlencode(parameters) - req = urllib2.Request(vtUrl, data) - response = urllib2.urlopen(req) + req = Request(vtUrl, data) + response = urlopen(req) jsonResponse = response.read() except: return (-1, 'The request to VirusTotal has not been successful') @@ -436,4 +443,4 @@ def vtcheck(md5, vtKey): jsonDict = json.loads(jsonResponse) except: return (-1, 'An error has occurred while parsing the JSON response from VirusTotal') - return (0, jsonDict) \ No newline at end of file + return (0, jsonDict) diff --git a/ccitt.py b/ccitt.py index 6bcb87b..7de1ee6 100644 --- a/ccitt.py +++ b/ccitt.py @@ -36,7 +36,7 @@ def write(self, data, length): """ """ if not ( length >= 0 and (1 << length) > data ): - raise BitWriterException, "Invalid data length" + raise BitWriterException("Invalid data length") if length == 8 and not self._last_byte and self._bit_ptr == 0: self._data += chr(data) @@ -108,7 +108,7 @@ def pos(self, bits): """ """ if bits > self.size: - raise BitReaderException, "Pointer position out of data" + raise BitReaderException("Pointer position out of data") pbyte = bits >> 3 pbit = bits - (pbyte <<3) @@ -118,9 +118,9 @@ def peek(self, length): """ """ if length <= 0: - raise BitReaderException, "Invalid read length" + raise BitReaderException("Invalid read length") elif ( self.pos + length ) > self.size: - raise BitReaderException, "Insufficient data" + raise BitReaderException("Insufficient data") n = 0 byte_ptr, bit_ptr = self._byte_ptr, self._bit_ptr @@ -228,7 +228,7 @@ class CCITTFax(object): 63 : codeword('00110100') } - WHITE_TERMINAL_DECODE_TABLE = dict( (v, k) for k, v in WHITE_TERMINAL_ENCODE_TABLE.iteritems() ) + WHITE_TERMINAL_DECODE_TABLE = dict( (v, k) for k, v in WHITE_TERMINAL_ENCODE_TABLE.items() ) BLACK_TERMINAL_ENCODE_TABLE = { 0 : codeword('0000110111'), @@ -297,7 +297,7 @@ class CCITTFax(object): 63 : codeword('000001100111') } - BLACK_TERMINAL_DECODE_TABLE = dict( (v, k) for k, v in BLACK_TERMINAL_ENCODE_TABLE.iteritems() ) + BLACK_TERMINAL_DECODE_TABLE = dict( (v, k) for k, v in BLACK_TERMINAL_ENCODE_TABLE.items() ) WHITE_CONFIGURATION_ENCODE_TABLE = { 64 : codeword('11011'), @@ -343,7 +343,7 @@ class CCITTFax(object): 2560 : codeword('000000011111') } - WHITE_CONFIGURATION_DECODE_TABLE = dict( (v, k) for k, v in WHITE_CONFIGURATION_ENCODE_TABLE.iteritems() ) + WHITE_CONFIGURATION_DECODE_TABLE = dict( (v, k) for k, v in WHITE_CONFIGURATION_ENCODE_TABLE.items() ) BLACK_CONFIGURATION_ENCODE_TABLE = { 64 : codeword('0000001111'), @@ -389,7 +389,7 @@ class CCITTFax(object): 2560 : codeword('000000011111') } - BLACK_CONFIGURATION_DECODE_TABLE = dict( (v, k) for k, v in BLACK_CONFIGURATION_ENCODE_TABLE.iteritems() ) + BLACK_CONFIGURATION_DECODE_TABLE = dict( (v, k) for k, v in BLACK_CONFIGURATION_ENCODE_TABLE.items() ) def __init__(self, ): """ @@ -422,7 +422,7 @@ def decode(self, stream, k = 0, eol = False, byteAlign = False, columns = 1728, if bitr.peek(self.EOL[1]) != self.EOL[0]: if eol: - raise Exception, "No end-of-line pattern found (at bit pos %d/%d)" % (bitr.pos, bitr.size) + raise Exception("No end-of-line pattern found (at bit pos %d/%d)" % (bitr.pos, bitr.size)) else: bitr.pos += self.EOL[1] @@ -433,11 +433,11 @@ def decode(self, stream, k = 0, eol = False, byteAlign = False, columns = 1728, else: bit_length = self.get_black_bits(bitr) if bit_length == None: - raise Exception, "Unfinished line (at bit pos %d/%d), %s" % (bitr.pos, bitr.size, bitw.data) + raise Exception("Unfinished line (at bit pos %d/%d), %s" % (bitr.pos, bitr.size, bitw.data)) line_length += bit_length if line_length > columns: - raise Exception, "Line is too long (at bit pos %d/%d)" % (bitr.pos, bitr.size) + raise Exception("Line is too long (at bit pos %d/%d)" % (bitr.pos, bitr.size)) bitw.write( (current_color << bit_length) - current_color, bit_length ) @@ -486,4 +486,4 @@ def get_color_bits(self, bitr, config_words, term_words): return bits - return None \ No newline at end of file + return None diff --git a/lzw.py b/lzw.py index c825cbf..9f345b2 100644 --- a/lzw.py +++ b/lzw.py @@ -878,7 +878,7 @@ def bitstobytes(bits): try: from cStringIO import StringIO except ImportError: - from StringIO import StringIO + from io import StringIO ## LZWDecoder @@ -969,4 +969,4 @@ def lzwdecode(data): '\x2d\x2d\x2d\x2d\x2d\x41\x2d\x2d\x2d\x42' """ fp = StringIO(data) - return ''.join(LZWDecoder(fp).run()) \ No newline at end of file + return ''.join(LZWDecoder(fp).run()) diff --git a/peepdf.py b/peepdf.py index 7c162db..8c67115 100755 --- a/peepdf.py +++ b/peepdf.py @@ -31,7 +31,6 @@ import os import optparse import re -import urllib2 import hashlib import traceback import json @@ -39,6 +38,10 @@ from PDFCore import PDFParser, vulnsDict from PDFUtils import vtcheck +try: + from urllib.request import urlopen +except ImportError: + from urllib2 import urlopen VT_KEY = 'fc90df3f5ac749a94a94cb8bf87e05a681a2eb001aef34b6a0084b8c22c97a64' @@ -68,7 +71,7 @@ def getRepPaths(url, path=''): paths = [] try: - browsingPage = urllib2.urlopen(url + path).read() + browsingPage = urlopen(url + path).read() except: sys.exit('[x] Connection error while getting browsing page "' + url + path + '"') browsingPageObject = json.loads(browsingPage) @@ -83,14 +86,14 @@ def getRepPaths(url, path=''): def getLocalFilesInfo(filesList): localFilesInfo = {} - print '[-] Getting local files information...' + print('[-] Getting local files information...') for path in filesList: absFilePath = os.path.join(absPeepdfRoot, path) if os.path.exists(absFilePath): content = open(absFilePath, 'rb').read() shaHash = hashlib.sha256(content).hexdigest() localFilesInfo[path] = [shaHash, absFilePath] - print '[+] Done' + print('[+] Done') return localFilesInfo @@ -407,339 +410,341 @@ def getPeepJSON(statsDict, version, revision): help='Specifies a command from the interactive console to be executed.') (options, args) = argsParser.parse_args() -try: - # Avoid colors in the output - if not COLORIZED_OUTPUT or options.avoidColors: - warningColor = '' - errorColor = '' - alertColor = '' - staticColor = '' - resetColor = '' +#try: +# Avoid colors in the output +if not COLORIZED_OUTPUT or options.avoidColors: + warningColor = '' + errorColor = '' + alertColor = '' + staticColor = '' + resetColor = '' +else: + warningColor = Fore.YELLOW + errorColor = Fore.RED + alertColor = Fore.RED + staticColor = Fore.BLUE + resetColor = Style.RESET_ALL +if options.version: + print(peepdfHeader) +elif options.update: + updated = False + newVersion = '' + localVersion = 'v' + version + ' r' + revision + reVersion = 'version = \'(\d\.\d)\'\s*?revision = \'(\d+)\'' + repURL = 'https://api.github.com/repos/jesparza/peepdf/contents/' + rawRepURL = 'https://raw.githubusercontent.com/jesparza/peepdf/master/' + print('[-] Checking if there are new updates...') + try: + remotePeepContent = urlopen(rawRepURL + 'peepdf.py').read() + except: + sys.exit('[x] Connection error while trying to connect with the repository') + repVer = re.findall(reVersion, remotePeepContent) + if repVer: + newVersion = 'v' + repVer[0][0] + ' r' + repVer[0][1] else: - warningColor = Fore.YELLOW - errorColor = Fore.RED - alertColor = Fore.RED - staticColor = Fore.BLUE - resetColor = Style.RESET_ALL - if options.version: - print peepdfHeader - elif options.update: - updated = False - newVersion = '' - localVersion = 'v' + version + ' r' + revision - reVersion = 'version = \'(\d\.\d)\'\s*?revision = \'(\d+)\'' - repURL = 'https://api.github.com/repos/jesparza/peepdf/contents/' - rawRepURL = 'https://raw.githubusercontent.com/jesparza/peepdf/master/' - print '[-] Checking if there are new updates...' - try: - remotePeepContent = urllib2.urlopen(rawRepURL + 'peepdf.py').read() - except: - sys.exit('[x] Connection error while trying to connect with the repository') - repVer = re.findall(reVersion, remotePeepContent) - if repVer: - newVersion = 'v' + repVer[0][0] + ' r' + repVer[0][1] - else: - sys.exit('[x] Error getting the version number from the repository') - if localVersion == newVersion: - print '[+] No changes! ;)' - else: - print '[+] There are new updates!!' - print '[-] Getting paths from the repository...' - pathNames = getRepPaths(repURL, '') - print '[+] Done' - localFilesInfo = getLocalFilesInfo(pathNames) - print '[-] Checking files...' - for path in pathNames: - try: - fileContent = urllib2.urlopen(rawRepURL + path).read() - except: - sys.exit('[x] Connection error while getting file "' + path + '"') - if path in localFilesInfo: - # File exists - # Checking hash - shaHash = hashlib.sha256(fileContent).hexdigest() - if shaHash != localFilesInfo[path][0]: - open(localFilesInfo[path][1], 'wb').write(fileContent) - print '[+] File "' + path + '" updated successfully' - else: - # File does not exist - index = path.rfind('/') - if index != -1: - dirsPath = path[:index] - absDirsPath = os.path.join(absPeepdfRoot, dirsPath) - if not os.path.exists(absDirsPath): - print '[+] New directory "' + dirsPath + '" created successfully' - os.makedirs(absDirsPath) - open(os.path.join(absPeepdfRoot, path), 'wb').write(fileContent) - print '[+] New file "' + path + '" created successfully' - message = '[+] peepdf updated successfully' - if newVersion != '': - message += ' to ' + newVersion - print message - + sys.exit('[x] Error getting the version number from the repository') + if localVersion == newVersion: + print('[+] No changes! ;)') else: - if len(args) == 1: - fileName = args[0] - if not os.path.exists(fileName): - sys.exit('Error: The file "' + fileName + '" does not exist!!') - elif len(args) > 1 or (len(args) == 0 and not options.isInteractive): - sys.exit(argsParser.print_help()) + print('[+] There are new updates!!') + print('[-] Getting paths from the repository...') + pathNames = getRepPaths(repURL, '') + print('[+] Done') + localFilesInfo = getLocalFilesInfo(pathNames) + print('[-] Checking files...') + for path in pathNames: + try: + fileContent = urlopen(rawRepURL + path).read() + except: + sys.exit('[x] Connection error while getting file "' + path + '"') + if path in localFilesInfo: + # File exists + # Checking hash + shaHash = hashlib.sha256(fileContent).hexdigest() + if shaHash != localFilesInfo[path][0]: + open(localFilesInfo[path][1], 'wb').write(fileContent) + print('[+] File "' + path + '" updated successfully') + else: + # File does not exist + index = path.rfind('/') + if index != -1: + dirsPath = path[:index] + absDirsPath = os.path.join(absPeepdfRoot, dirsPath) + if not os.path.exists(absDirsPath): + print('[+] New directory "' + dirsPath + '" created successfully') + os.makedirs(absDirsPath) + open(os.path.join(absPeepdfRoot, path), 'wb').write(fileContent) + print('[+] New file "' + path + '" created successfully') + message = '[+] peepdf updated successfully' + if newVersion != '': + message += ' to ' + newVersion + print(message) - if options.scriptFile is not None: - if not os.path.exists(options.scriptFile): - sys.exit('Error: The script file "' + options.scriptFile + '" does not exist!!') +else: + if len(args) == 1: + fileName = args[0] + if not os.path.exists(fileName): + sys.exit('Error: The file "' + fileName + '" does not exist!!') + elif len(args) > 1 or (len(args) == 0 and not options.isInteractive): + sys.exit(argsParser.print_help()) - if fileName is not None: - pdfParser = PDFParser() - ret, pdf = pdfParser.parse(fileName, options.isForceMode, options.isLooseMode, options.isManualAnalysis) - if options.checkOnVT: - # Checks the MD5 on VirusTotal - md5Hash = pdf.getMD5() - ret = vtcheck(md5Hash, VT_KEY) - if ret[0] == -1: - pdf.addError(ret[1]) - else: - vtJsonDict = ret[1] - if vtJsonDict.has_key('response_code'): - if vtJsonDict['response_code'] == 1: - if vtJsonDict.has_key('positives') and vtJsonDict.has_key('total'): - pdf.setDetectionRate([vtJsonDict['positives'], vtJsonDict['total']]) - else: - pdf.addError('Missing elements in the response from VirusTotal!!') - if vtJsonDict.has_key('permalink'): - pdf.setDetectionReport(vtJsonDict['permalink']) + if options.scriptFile is not None: + if not os.path.exists(options.scriptFile): + sys.exit('Error: The script file "' + options.scriptFile + '" does not exist!!') + + if fileName is not None: + pdfParser = PDFParser() + ret, pdf = pdfParser.parse(fileName, options.isForceMode, options.isLooseMode, options.isManualAnalysis) + if options.checkOnVT: + # Checks the MD5 on VirusTotal + md5Hash = pdf.getMD5() + ret = vtcheck(md5Hash, VT_KEY) + if ret[0] == -1: + pdf.addError(ret[1]) + else: + vtJsonDict = ret[1] + if vtJsonDict.has_key('response_code'): + if vtJsonDict['response_code'] == 1: + if vtJsonDict.has_key('positives') and vtJsonDict.has_key('total'): + pdf.setDetectionRate([vtJsonDict['positives'], vtJsonDict['total']]) else: - pdf.setDetectionRate(None) + pdf.addError('Missing elements in the response from VirusTotal!!') + if vtJsonDict.has_key('permalink'): + pdf.setDetectionReport(vtJsonDict['permalink']) else: - pdf.addError('Bad response from VirusTotal!!') - statsDict = pdf.getStats() + pdf.setDetectionRate(None) + else: + pdf.addError('Bad response from VirusTotal!!') + statsDict = pdf.getStats() - if options.xmlOutput: + if options.xmlOutput: + try: + from lxml import etree + + xml = getPeepXML(statsDict, version, revision) + sys.stdout.write(xml) + except: + errorMessage = '*** Error: Exception while generating the XML file!!' + traceback.print_exc(file=open(errorsFile, 'a')) + raise Exception('PeepException', 'Send me an email ;)') + elif options.jsonOutput and not options.commands: + try: + jsonReport = getPeepJSON(statsDict, version, revision) + sys.stdout.write(jsonReport) + except: + errorMessage = '*** Error: Exception while generating the JSON report!!' + traceback.print_exc(file=open(errorsFile, 'a')) + raise Exception('PeepException', 'Send me an email ;)') + else: + if COLORIZED_OUTPUT and not options.avoidColors: try: - from lxml import etree + init() + except: + COLORIZED_OUTPUT = False + if options.scriptFile is not None: + from PDFConsole import PDFConsole - xml = getPeepXML(statsDict, version, revision) - sys.stdout.write(xml) + scriptFileObject = open(options.scriptFile, 'rb') + console = PDFConsole(pdf, VT_KEY, options.avoidColors, stdin=scriptFileObject) + try: + console.cmdloop() except: - errorMessage = '*** Error: Exception while generating the XML file!!' + errorMessage = '*** Error: Exception not handled using the batch mode!!' + scriptFileObject.close() traceback.print_exc(file=open(errorsFile, 'a')) raise Exception('PeepException', 'Send me an email ;)') - elif options.jsonOutput and not options.commands: + elif options.commands is not None: + from PDFConsole import PDFConsole + + console = PDFConsole(pdf, VT_KEY, options.avoidColors) try: - jsonReport = getPeepJSON(statsDict, version, revision) - sys.stdout.write(jsonReport) + for command in options.commands: + console.onecmd(command) except: - errorMessage = '*** Error: Exception while generating the JSON report!!' + errorMessage = '*** Error: Exception not handled using the batch commands!!' traceback.print_exc(file=open(errorsFile, 'a')) raise Exception('PeepException', 'Send me an email ;)') else: - if COLORIZED_OUTPUT and not options.avoidColors: - try: - init() - except: - COLORIZED_OUTPUT = False - if options.scriptFile is not None: - from PDFConsole import PDFConsole + if statsDict is not None: + if COLORIZED_OUTPUT and not options.avoidColors: + beforeStaticLabel = staticColor + else: + beforeStaticLabel = '' - scriptFileObject = open(options.scriptFile, 'rb') - console = PDFConsole(pdf, VT_KEY, options.avoidColors, stdin=scriptFileObject) - try: - console.cmdloop() - except: - errorMessage = '*** Error: Exception not handled using the batch mode!!' - scriptFileObject.close() - traceback.print_exc(file=open(errorsFile, 'a')) - raise Exception('PeepException', 'Send me an email ;)') - elif options.commands is not None: - from PDFConsole import PDFConsole + if not JS_MODULE: + warningMessage = 'Warning: PyV8 is not installed!!' + stats += warningColor + warningMessage + resetColor + newLine + if not EMU_MODULE: + warningMessage = 'Warning: pylibemu is not installed!!' + stats += warningColor + warningMessage + resetColor + newLine + if not PIL_MODULE: + warningMessage = 'Warning: Python Imaging Library (PIL) is not installed!!' + stats += warningColor + warningMessage + resetColor + newLine + errors = statsDict['Errors'] + for error in errors: + if error.find('Decryption error') != -1: + stats += errorColor + error + resetColor + newLine + if stats != '': + stats += newLine + statsDict = pdf.getStats() - console = PDFConsole(pdf, VT_KEY, options.avoidColors) - try: - for command in options.commands: - console.onecmd(command) - except: - errorMessage = '*** Error: Exception not handled using the batch commands!!' - traceback.print_exc(file=open(errorsFile, 'a')) - raise Exception('PeepException', 'Send me an email ;)') - else: - if statsDict is not None: + stats += beforeStaticLabel + 'File: ' + resetColor + statsDict['File'] + newLine + stats += beforeStaticLabel + 'MD5: ' + resetColor + statsDict['MD5'] + newLine + stats += beforeStaticLabel + 'SHA1: ' + resetColor + statsDict['SHA1'] + newLine + stats += beforeStaticLabel + 'SHA256: ' + resetColor + statsDict['SHA256'] + newLine + stats += beforeStaticLabel + 'Size: ' + resetColor + statsDict['Size'] + ' bytes' + newLine + if options.checkOnVT: + if statsDict['Detection'] != []: + detectionReportInfo = '' + if statsDict['Detection'] != None: + detectionColor = '' + if COLORIZED_OUTPUT and not options.avoidColors: + detectionLevel = statsDict['Detection'][0] / (statsDict['Detection'][1] / 3) + if detectionLevel == 0: + detectionColor = alertColor + elif detectionLevel == 1: + detectionColor = warningColor + detectionRate = '%s%d%s/%d' % ( + detectionColor, statsDict['Detection'][0], resetColor, statsDict['Detection'][1]) + if statsDict['Detection report'] != '': + detectionReportInfo = beforeStaticLabel + 'Detection report: ' + resetColor + \ + statsDict['Detection report'] + newLine + else: + detectionRate = 'File not found on VirusTotal' + stats += beforeStaticLabel + 'Detection: ' + resetColor + detectionRate + newLine + stats += detectionReportInfo + stats += beforeStaticLabel + 'Version: ' + resetColor + statsDict['Version'].decode() + newLine + stats += beforeStaticLabel + 'Binary: ' + resetColor + statsDict['Binary'] + newLine + stats += beforeStaticLabel + 'Linearized: ' + resetColor + statsDict['Linearized'] + newLine + stats += beforeStaticLabel + 'Encrypted: ' + resetColor + statsDict['Encrypted'] + if statsDict['Encryption Algorithms'] != []: + stats += ' (' + for algorithmInfo in statsDict['Encryption Algorithms']: + stats += algorithmInfo[0] + ' ' + str(algorithmInfo[1]) + ' bits, ' + stats = stats[:-2] + ')' + stats += newLine + stats += beforeStaticLabel + 'Updates: ' + resetColor + statsDict['Updates'] + newLine + stats += beforeStaticLabel + 'Objects: ' + resetColor + statsDict['Objects'] + newLine + stats += beforeStaticLabel + 'Streams: ' + resetColor + statsDict['Streams'] + newLine + stats += beforeStaticLabel + 'URIs: ' + resetColor + statsDict['URIs'] + newLine + stats += beforeStaticLabel + 'Comments: ' + resetColor + statsDict['Comments'] + newLine + stats += beforeStaticLabel + 'Errors: ' + resetColor + str(len(statsDict['Errors'])) + newLine * 2 + for version in range(len(statsDict['Versions'])): + statsVersion = statsDict['Versions'][version] + stats += beforeStaticLabel + 'Version ' + resetColor + str(version) + ':' + newLine + if statsVersion['Catalog'] != None: + stats += beforeStaticLabel + '\tCatalog: ' + resetColor + statsVersion['Catalog'] + newLine + else: + stats += beforeStaticLabel + '\tCatalog: ' + resetColor + 'No' + newLine + if statsVersion['Info'] != None: + stats += beforeStaticLabel + '\tInfo: ' + resetColor + statsVersion['Info'] + newLine + else: + stats += beforeStaticLabel + '\tInfo: ' + resetColor + 'No' + newLine + stats += beforeStaticLabel + '\tObjects (' + statsVersion['Objects'][ + 0] + '): ' + resetColor + str(statsVersion['Objects'][1]) + newLine + if statsVersion['Compressed Objects'] != None: + stats += beforeStaticLabel + '\tCompressed objects (' + statsVersion['Compressed Objects'][ + 0] + '): ' + resetColor + str(statsVersion['Compressed Objects'][1]) + newLine + if statsVersion['Errors'] != None: + stats += beforeStaticLabel + '\t\tErrors (' + statsVersion['Errors'][ + 0] + '): ' + resetColor + str(statsVersion['Errors'][1]) + newLine + stats += beforeStaticLabel + '\tStreams (' + statsVersion['Streams'][ + 0] + '): ' + resetColor + str(statsVersion['Streams'][1]) + if statsVersion['Xref Streams'] != None: + stats += newLine + beforeStaticLabel + '\t\tXref streams (' + statsVersion['Xref Streams'][ + 0] + '): ' + resetColor + str(statsVersion['Xref Streams'][1]) + if statsVersion['Object Streams'] != None: + stats += newLine + beforeStaticLabel + '\t\tObject streams (' + \ + statsVersion['Object Streams'][0] + '): ' + resetColor + str( + statsVersion['Object Streams'][1]) + if int(statsVersion['Streams'][0]) > 0: + stats += newLine + beforeStaticLabel + '\t\tEncoded (' + statsVersion['Encoded'][ + 0] + '): ' + resetColor + str(statsVersion['Encoded'][1]) + if statsVersion['Decoding Errors'] != None: + stats += newLine + beforeStaticLabel + '\t\tDecoding errors (' + \ + statsVersion['Decoding Errors'][0] + '): ' + resetColor + str( + statsVersion['Decoding Errors'][1]) + if statsVersion['URIs'] is not None: + stats += newLine + beforeStaticLabel + '\tObjects with URIs (' + \ + statsVersion['URIs'][0] + '): ' + resetColor + str(statsVersion['URIs'][1]) + if COLORIZED_OUTPUT and not options.avoidColors: + beforeStaticLabel = warningColor + if statsVersion['Objects with JS code'] != None: + stats += newLine + beforeStaticLabel + '\tObjects with JS code (' + \ + statsVersion['Objects with JS code'][0] + '): ' + resetColor + str( + statsVersion['Objects with JS code'][1]) + actions = statsVersion['Actions'] + events = statsVersion['Events'] + vulns = statsVersion['Vulns'] + elements = statsVersion['Elements'] + if events != None or actions != None or vulns != None or elements != None: + stats += newLine + beforeStaticLabel + '\tSuspicious elements:' + resetColor + newLine + if events != None: + for event in events: + stats += '\t\t' + beforeStaticLabel + event + ' (%d): ' % len(events[event]) + \ + resetColor + str(events[event]) + newLine + if actions != None: + for action in actions: + stats += '\t\t' + beforeStaticLabel + action + ' (%d): ' % len(actions[action]) + \ + resetColor + str(actions[action]) + newLine + if vulns != None: + for vuln in vulns: + if vulnsDict.has_key(vuln): + vulnName = vulnsDict[vuln][0] + vulnCVEList = vulnsDict[vuln][1] + stats += '\t\t' + beforeStaticLabel + vulnName + ' (' + for vulnCVE in vulnCVEList: + stats += vulnCVE + ',' + stats = stats[:-1] + ') (%d): ' % len(vulns[vuln]) + resetColor + str(vulns[vuln]) + newLine + else: + stats += '\t\t' + beforeStaticLabel + vuln + ' (%d): ' % len(vulns[vuln]) + \ + resetColor + str(vulns[vuln]) + newLine + if elements != None: + for element in elements: + if vulnsDict.has_key(element): + vulnName = vulnsDict[element][0] + vulnCVEList = vulnsDict[element][1] + stats += '\t\t' + beforeStaticLabel + vulnName + ' (' + for vulnCVE in vulnCVEList: + stats += vulnCVE + ',' + stats = stats[:-1] + '): ' + resetColor + str(elements[element]) + newLine + else: + stats += '\t\t' + beforeStaticLabel + element + ': ' + resetColor + str( + elements[element]) + newLine if COLORIZED_OUTPUT and not options.avoidColors: beforeStaticLabel = staticColor - else: - beforeStaticLabel = '' - - if not JS_MODULE: - warningMessage = 'Warning: PyV8 is not installed!!' - stats += warningColor + warningMessage + resetColor + newLine - if not EMU_MODULE: - warningMessage = 'Warning: pylibemu is not installed!!' - stats += warningColor + warningMessage + resetColor + newLine - if not PIL_MODULE: - warningMessage = 'Warning: Python Imaging Library (PIL) is not installed!!' - stats += warningColor + warningMessage + resetColor + newLine - errors = statsDict['Errors'] - for error in errors: - if error.find('Decryption error') != -1: - stats += errorColor + error + resetColor + newLine - if stats != '': - stats += newLine - statsDict = pdf.getStats() - - stats += beforeStaticLabel + 'File: ' + resetColor + statsDict['File'] + newLine - stats += beforeStaticLabel + 'MD5: ' + resetColor + statsDict['MD5'] + newLine - stats += beforeStaticLabel + 'SHA1: ' + resetColor + statsDict['SHA1'] + newLine - stats += beforeStaticLabel + 'SHA256: ' + resetColor + statsDict['SHA256'] + newLine - stats += beforeStaticLabel + 'Size: ' + resetColor + statsDict['Size'] + ' bytes' + newLine - if options.checkOnVT: - if statsDict['Detection'] != []: - detectionReportInfo = '' - if statsDict['Detection'] != None: - detectionColor = '' - if COLORIZED_OUTPUT and not options.avoidColors: - detectionLevel = statsDict['Detection'][0] / (statsDict['Detection'][1] / 3) - if detectionLevel == 0: - detectionColor = alertColor - elif detectionLevel == 1: - detectionColor = warningColor - detectionRate = '%s%d%s/%d' % ( - detectionColor, statsDict['Detection'][0], resetColor, statsDict['Detection'][1]) - if statsDict['Detection report'] != '': - detectionReportInfo = beforeStaticLabel + 'Detection report: ' + resetColor + \ - statsDict['Detection report'] + newLine - else: - detectionRate = 'File not found on VirusTotal' - stats += beforeStaticLabel + 'Detection: ' + resetColor + detectionRate + newLine - stats += detectionReportInfo - stats += beforeStaticLabel + 'Version: ' + resetColor + statsDict['Version'] + newLine - stats += beforeStaticLabel + 'Binary: ' + resetColor + statsDict['Binary'] + newLine - stats += beforeStaticLabel + 'Linearized: ' + resetColor + statsDict['Linearized'] + newLine - stats += beforeStaticLabel + 'Encrypted: ' + resetColor + statsDict['Encrypted'] - if statsDict['Encryption Algorithms'] != []: - stats += ' (' - for algorithmInfo in statsDict['Encryption Algorithms']: - stats += algorithmInfo[0] + ' ' + str(algorithmInfo[1]) + ' bits, ' - stats = stats[:-2] + ')' - stats += newLine - stats += beforeStaticLabel + 'Updates: ' + resetColor + statsDict['Updates'] + newLine - stats += beforeStaticLabel + 'Objects: ' + resetColor + statsDict['Objects'] + newLine - stats += beforeStaticLabel + 'Streams: ' + resetColor + statsDict['Streams'] + newLine - stats += beforeStaticLabel + 'URIs: ' + resetColor + statsDict['URIs'] + newLine - stats += beforeStaticLabel + 'Comments: ' + resetColor + statsDict['Comments'] + newLine - stats += beforeStaticLabel + 'Errors: ' + resetColor + str(len(statsDict['Errors'])) + newLine * 2 - for version in range(len(statsDict['Versions'])): - statsVersion = statsDict['Versions'][version] - stats += beforeStaticLabel + 'Version ' + resetColor + str(version) + ':' + newLine - if statsVersion['Catalog'] != None: - stats += beforeStaticLabel + '\tCatalog: ' + resetColor + statsVersion['Catalog'] + newLine - else: - stats += beforeStaticLabel + '\tCatalog: ' + resetColor + 'No' + newLine - if statsVersion['Info'] != None: - stats += beforeStaticLabel + '\tInfo: ' + resetColor + statsVersion['Info'] + newLine - else: - stats += beforeStaticLabel + '\tInfo: ' + resetColor + 'No' + newLine - stats += beforeStaticLabel + '\tObjects (' + statsVersion['Objects'][ - 0] + '): ' + resetColor + str(statsVersion['Objects'][1]) + newLine - if statsVersion['Compressed Objects'] != None: - stats += beforeStaticLabel + '\tCompressed objects (' + statsVersion['Compressed Objects'][ - 0] + '): ' + resetColor + str(statsVersion['Compressed Objects'][1]) + newLine - if statsVersion['Errors'] != None: - stats += beforeStaticLabel + '\t\tErrors (' + statsVersion['Errors'][ - 0] + '): ' + resetColor + str(statsVersion['Errors'][1]) + newLine - stats += beforeStaticLabel + '\tStreams (' + statsVersion['Streams'][ - 0] + '): ' + resetColor + str(statsVersion['Streams'][1]) - if statsVersion['Xref Streams'] != None: - stats += newLine + beforeStaticLabel + '\t\tXref streams (' + statsVersion['Xref Streams'][ - 0] + '): ' + resetColor + str(statsVersion['Xref Streams'][1]) - if statsVersion['Object Streams'] != None: - stats += newLine + beforeStaticLabel + '\t\tObject streams (' + \ - statsVersion['Object Streams'][0] + '): ' + resetColor + str( - statsVersion['Object Streams'][1]) - if int(statsVersion['Streams'][0]) > 0: - stats += newLine + beforeStaticLabel + '\t\tEncoded (' + statsVersion['Encoded'][ - 0] + '): ' + resetColor + str(statsVersion['Encoded'][1]) - if statsVersion['Decoding Errors'] != None: - stats += newLine + beforeStaticLabel + '\t\tDecoding errors (' + \ - statsVersion['Decoding Errors'][0] + '): ' + resetColor + str( - statsVersion['Decoding Errors'][1]) - if statsVersion['URIs'] is not None: - stats += newLine + beforeStaticLabel + '\tObjects with URIs (' + \ - statsVersion['URIs'][0] + '): ' + resetColor + str(statsVersion['URIs'][1]) - if COLORIZED_OUTPUT and not options.avoidColors: - beforeStaticLabel = warningColor - if statsVersion['Objects with JS code'] != None: - stats += newLine + beforeStaticLabel + '\tObjects with JS code (' + \ - statsVersion['Objects with JS code'][0] + '): ' + resetColor + str( - statsVersion['Objects with JS code'][1]) - actions = statsVersion['Actions'] - events = statsVersion['Events'] - vulns = statsVersion['Vulns'] - elements = statsVersion['Elements'] - if events != None or actions != None or vulns != None or elements != None: - stats += newLine + beforeStaticLabel + '\tSuspicious elements:' + resetColor + newLine - if events != None: - for event in events: - stats += '\t\t' + beforeStaticLabel + event + ' (%d): ' % len(events[event]) + \ - resetColor + str(events[event]) + newLine - if actions != None: - for action in actions: - stats += '\t\t' + beforeStaticLabel + action + ' (%d): ' % len(actions[action]) + \ - resetColor + str(actions[action]) + newLine - if vulns != None: - for vuln in vulns: - if vulnsDict.has_key(vuln): - vulnName = vulnsDict[vuln][0] - vulnCVEList = vulnsDict[vuln][1] - stats += '\t\t' + beforeStaticLabel + vulnName + ' (' - for vulnCVE in vulnCVEList: - stats += vulnCVE + ',' - stats = stats[:-1] + ') (%d): ' % len(vulns[vuln]) + resetColor + str(vulns[vuln]) + newLine - else: - stats += '\t\t' + beforeStaticLabel + vuln + ' (%d): ' % len(vulns[vuln]) + \ - resetColor + str(vulns[vuln]) + newLine - if elements != None: - for element in elements: - if vulnsDict.has_key(element): - vulnName = vulnsDict[element][0] - vulnCVEList = vulnsDict[element][1] - stats += '\t\t' + beforeStaticLabel + vulnName + ' (' - for vulnCVE in vulnCVEList: - stats += vulnCVE + ',' - stats = stats[:-1] + '): ' + resetColor + str(elements[element]) + newLine - else: - stats += '\t\t' + beforeStaticLabel + element + ': ' + resetColor + str( - elements[element]) + newLine - if COLORIZED_OUTPUT and not options.avoidColors: - beforeStaticLabel = staticColor - urls = statsVersion['URLs'] - if urls != None: - stats += newLine + beforeStaticLabel + '\tFound URLs:' + resetColor + newLine - for url in urls: - stats += '\t\t' + url + newLine - stats += newLine * 2 - if fileName != None: - print stats - if options.isInteractive: - from PDFConsole import PDFConsole + urls = statsVersion['URLs'] + if urls != None: + stats += newLine + beforeStaticLabel + '\tFound URLs:' + resetColor + newLine + for url in urls: + stats += '\t\t' + url + newLine + stats += newLine * 2 + if fileName != None: + print(stats) + if options.isInteractive: + from PDFConsole import PDFConsole - console = PDFConsole(pdf, VT_KEY, options.avoidColors) - while not console.leaving: - try: - console.cmdloop() - except KeyboardInterrupt as e: - sys.exit() - except: - errorMessage = '*** Error: Exception not handled using the interactive console!! Please, report it to the author!!' - print errorColor + errorMessage + resetColor + newLine - traceback.print_exc(file=open(errorsFile, 'a')) + console = PDFConsole(pdf, VT_KEY, options.avoidColors) + while not console.leaving: + try: + console.cmdloop() + except KeyboardInterrupt as e: + sys.exit() + except: + errorMessage = '*** Error: Exception not handled using the interactive console!! Please, report it to the author!!' + print(errorColor + errorMessage + resetColor + newLine) + traceback.print_exc(file=open(errorsFile, 'a')) +""" except Exception as e: if len(e.args) == 2: excName, excReason = e.args else: excName = excReason = None if excName == None or excName != 'PeepException': + print(e) errorMessage = '*** Error: Exception not handled!!' traceback.print_exc(file=open(errorsFile, 'a')) - print errorColor + errorMessage + resetColor + newLine + print(errorColor + errorMessage + resetColor + newLine) finally: if os.path.exists(errorsFile): message = newLine + 'Please, don\'t forget to report the errors found:' + newLine * 2 @@ -747,4 +752,5 @@ def getPeepJSON(statsDict, version, revision): errorsFile, newLine) message += '\t- And/Or creating an issue on the project webpage (https://github.com/jesparza/peepdf/issues)' + newLine message = errorColor + message + resetColor - sys.exit(message) \ No newline at end of file + sys.exit(message) +"""