origami 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. data/COPYING.LESSER +165 -0
  2. data/README +77 -0
  3. data/VERSION +1 -0
  4. data/bin/config/pdfcop.conf.yml +237 -0
  5. data/bin/gui/about.rb +46 -0
  6. data/bin/gui/config.rb +132 -0
  7. data/bin/gui/file.rb +385 -0
  8. data/bin/gui/hexdump.rb +74 -0
  9. data/bin/gui/hexview.rb +91 -0
  10. data/bin/gui/imgview.rb +72 -0
  11. data/bin/gui/menu.rb +392 -0
  12. data/bin/gui/properties.rb +132 -0
  13. data/bin/gui/signing.rb +635 -0
  14. data/bin/gui/textview.rb +107 -0
  15. data/bin/gui/treeview.rb +409 -0
  16. data/bin/gui/walker.rb +282 -0
  17. data/bin/gui/xrefs.rb +79 -0
  18. data/bin/pdf2graph +121 -0
  19. data/bin/pdf2ruby +353 -0
  20. data/bin/pdfcocoon +104 -0
  21. data/bin/pdfcop +455 -0
  22. data/bin/pdfdecompress +104 -0
  23. data/bin/pdfdecrypt +95 -0
  24. data/bin/pdfencrypt +112 -0
  25. data/bin/pdfextract +221 -0
  26. data/bin/pdfmetadata +123 -0
  27. data/bin/pdfsh +13 -0
  28. data/bin/pdfwalker +7 -0
  29. data/bin/shell/.irbrc +104 -0
  30. data/bin/shell/console.rb +136 -0
  31. data/bin/shell/hexdump.rb +83 -0
  32. data/origami.rb +36 -0
  33. data/origami/3d.rb +239 -0
  34. data/origami/acroform.rb +321 -0
  35. data/origami/actions.rb +299 -0
  36. data/origami/adobe/fdf.rb +259 -0
  37. data/origami/adobe/ppklite.rb +489 -0
  38. data/origami/annotations.rb +775 -0
  39. data/origami/array.rb +187 -0
  40. data/origami/boolean.rb +101 -0
  41. data/origami/catalog.rb +486 -0
  42. data/origami/destinations.rb +213 -0
  43. data/origami/dictionary.rb +188 -0
  44. data/origami/docmdp.rb +96 -0
  45. data/origami/encryption.rb +1293 -0
  46. data/origami/export.rb +283 -0
  47. data/origami/file.rb +222 -0
  48. data/origami/filters.rb +250 -0
  49. data/origami/filters/ascii.rb +189 -0
  50. data/origami/filters/ccitt.rb +515 -0
  51. data/origami/filters/crypt.rb +47 -0
  52. data/origami/filters/dct.rb +61 -0
  53. data/origami/filters/flate.rb +112 -0
  54. data/origami/filters/jbig2.rb +63 -0
  55. data/origami/filters/jpx.rb +53 -0
  56. data/origami/filters/lzw.rb +195 -0
  57. data/origami/filters/predictors.rb +276 -0
  58. data/origami/filters/runlength.rb +117 -0
  59. data/origami/font.rb +209 -0
  60. data/origami/functions.rb +93 -0
  61. data/origami/graphics.rb +33 -0
  62. data/origami/graphics/colors.rb +191 -0
  63. data/origami/graphics/instruction.rb +126 -0
  64. data/origami/graphics/path.rb +154 -0
  65. data/origami/graphics/patterns.rb +180 -0
  66. data/origami/graphics/state.rb +164 -0
  67. data/origami/graphics/text.rb +224 -0
  68. data/origami/graphics/xobject.rb +493 -0
  69. data/origami/header.rb +90 -0
  70. data/origami/linearization.rb +318 -0
  71. data/origami/metadata.rb +114 -0
  72. data/origami/name.rb +170 -0
  73. data/origami/null.rb +75 -0
  74. data/origami/numeric.rb +188 -0
  75. data/origami/obfuscation.rb +233 -0
  76. data/origami/object.rb +527 -0
  77. data/origami/outline.rb +59 -0
  78. data/origami/page.rb +559 -0
  79. data/origami/parser.rb +268 -0
  80. data/origami/parsers/fdf.rb +45 -0
  81. data/origami/parsers/pdf.rb +27 -0
  82. data/origami/parsers/pdf/linear.rb +113 -0
  83. data/origami/parsers/ppklite.rb +86 -0
  84. data/origami/pdf.rb +1144 -0
  85. data/origami/reference.rb +113 -0
  86. data/origami/signature.rb +474 -0
  87. data/origami/stream.rb +575 -0
  88. data/origami/string.rb +416 -0
  89. data/origami/trailer.rb +173 -0
  90. data/origami/webcapture.rb +87 -0
  91. data/origami/xfa.rb +3027 -0
  92. data/origami/xreftable.rb +447 -0
  93. data/templates/patterns.rb +66 -0
  94. data/templates/widgets.rb +173 -0
  95. data/templates/xdp.rb +92 -0
  96. data/tests/dataset/test.dummycrt +28 -0
  97. data/tests/dataset/test.dummykey +27 -0
  98. data/tests/tc_actions.rb +32 -0
  99. data/tests/tc_annotations.rb +85 -0
  100. data/tests/tc_pages.rb +37 -0
  101. data/tests/tc_pdfattach.rb +24 -0
  102. data/tests/tc_pdfencrypt.rb +110 -0
  103. data/tests/tc_pdfnew.rb +32 -0
  104. data/tests/tc_pdfparse.rb +98 -0
  105. data/tests/tc_pdfsig.rb +37 -0
  106. data/tests/tc_streams.rb +129 -0
  107. data/tests/ts_pdf.rb +45 -0
  108. metadata +193 -0
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ =begin
4
+
5
+ = Author:
6
+ Guillaume Delugré <guillaume/at/security-labs.org>
7
+
8
+ = Info:
9
+ Uncompresses all binary streams of a PDF document.
10
+
11
+ = License:
12
+ Origami is free software: you can redistribute it and/or modify
13
+ it under the terms of the GNU Lesser General Public License as published by
14
+ the Free Software Foundation, either version 3 of the License, or
15
+ (at your option) any later version.
16
+
17
+ Origami is distributed in the hope that it will be useful,
18
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
+ GNU Lesser General Public License for more details.
21
+
22
+ You should have received a copy of the GNU Lesser General Public License
23
+ along with Origami. If not, see <http://www.gnu.org/licenses/>.
24
+
25
+ =end
26
+
27
+ begin
28
+ require 'origami'
29
+ rescue LoadError
30
+ ORIGAMIDIR = "#{File.dirname(__FILE__)}/.."
31
+ $: << ORIGAMIDIR
32
+ require 'origami'
33
+ end
34
+ include Origami
35
+
36
+ require 'optparse'
37
+
38
+ class OptParser
39
+ BANNER = <<USAGE
40
+ Usage: #{$0} [<PDF-file>] [-p <password>] [-o <output-file>]
41
+ Uncompresses all binary streams of a PDF document.
42
+ Bug reports or feature requests at: http://origami-pdf.googlecode.com/
43
+
44
+ Options:
45
+ USAGE
46
+
47
+ def self.parser(options)
48
+ OptionParser.new do |opts|
49
+ opts.banner = BANNER
50
+
51
+ opts.on("-o", "--output FILE", "Output PDF file (stdout by default)") do |o|
52
+ options[:output] = o
53
+ end
54
+
55
+ opts.on_tail("-h", "--help", "Show this message") do
56
+ puts opts
57
+ exit
58
+ end
59
+ end
60
+ end
61
+
62
+ def self.parse(args)
63
+ options =
64
+ {
65
+ :output => STDOUT,
66
+ }
67
+
68
+ self.parser(options).parse!(args)
69
+
70
+ options
71
+ end
72
+ end
73
+
74
+ begin
75
+ @options = OptParser.parse(ARGV)
76
+
77
+ target = (ARGV.empty?) ? STDIN : ARGV.shift
78
+ params =
79
+ {
80
+ :verbosity => Parser::VERBOSE_QUIET,
81
+ }
82
+
83
+ pdf = PDF.read(target, params)
84
+
85
+ pdf.root_objects.find_all { |obj|
86
+ obj.is_a?(Stream)
87
+ }.each { |stream|
88
+ filters = stream.Filter
89
+ filters = [ filters ] unless filters.is_a?(::Array)
90
+
91
+ unless filters.any?{|filter| [ :JPXDecode, :DCTDecode, :JBIG2Decode ].include? filter}
92
+ stream.rawdata = stream.data
93
+ stream.dictionary.delete(:Filter)
94
+ end
95
+ }
96
+
97
+ pdf.save(@options[:output], :noindent => true)
98
+
99
+ rescue SystemExit
100
+ rescue Exception => e
101
+ STDERR.puts "#{e.class}: #{e.message}"
102
+ exit 1
103
+ end
104
+
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ =begin
4
+
5
+ = Author:
6
+ Guillaume Delugré <guillaume/at/security-labs.org>
7
+
8
+ = Info:
9
+ Decrypts a PDF document.
10
+
11
+ = License:
12
+ Origami is free software: you can redistribute it and/or modify
13
+ it under the terms of the GNU Lesser General Public License as published by
14
+ the Free Software Foundation, either version 3 of the License, or
15
+ (at your option) any later version.
16
+
17
+ Origami is distributed in the hope that it will be useful,
18
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
+ GNU Lesser General Public License for more details.
21
+
22
+ You should have received a copy of the GNU Lesser General Public License
23
+ along with Origami. If not, see <http://www.gnu.org/licenses/>.
24
+
25
+ =end
26
+
27
+ begin
28
+ require 'origami'
29
+ rescue LoadError
30
+ ORIGAMIDIR = "#{File.dirname(__FILE__)}/.."
31
+ $: << ORIGAMIDIR
32
+ require 'origami'
33
+ end
34
+ include Origami
35
+
36
+ require 'optparse'
37
+
38
+ class OptParser
39
+ BANNER = <<USAGE
40
+ Usage: #{$0} [<PDF-file>] [-p <password>] [-o <output-file>]
41
+ Decrypts a PDF document. Supports RC4 40 to 128 bits, AES128, AES256.
42
+ Bug reports or feature requests at: http://origami-pdf.googlecode.com/
43
+
44
+ Options:
45
+ USAGE
46
+
47
+ def self.parser(options)
48
+ OptionParser.new do |opts|
49
+ opts.banner = BANNER
50
+
51
+ opts.on("-o", "--output FILE", "Output PDF file (stdout by default)") do |o|
52
+ options[:output] = o
53
+ end
54
+
55
+ opts.on("-p", "--password PASSWORD", "Password of the document") do |p|
56
+ options[:password] = p
57
+ end
58
+
59
+ opts.on_tail("-h", "--help", "Show this message") do
60
+ puts opts
61
+ exit
62
+ end
63
+ end
64
+ end
65
+
66
+ def self.parse(args)
67
+ options =
68
+ {
69
+ :output => STDOUT,
70
+ :password => ''
71
+ }
72
+
73
+ self.parser(options).parse!(args)
74
+
75
+ options
76
+ end
77
+ end
78
+
79
+ begin
80
+ @options = OptParser.parse(ARGV)
81
+
82
+ target = (ARGV.empty?) ? STDIN : ARGV.shift
83
+ params =
84
+ {
85
+ :verbosity => Parser::VERBOSE_QUIET,
86
+ :password => @options[:password]
87
+ }
88
+
89
+ PDF.read(target, params).save(@options[:output], :decrypt => true, :noindent => true)
90
+ rescue SystemExit
91
+ rescue Exception => e
92
+ STDERR.puts "#{e.class}: #{e.message}"
93
+ exit 1
94
+ end
95
+
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ =begin
4
+
5
+ = Author:
6
+ Guillaume Delugré <guillaume/at/security-labs.org>
7
+
8
+ = Info:
9
+ Encrypts a PDF document.
10
+
11
+ = License:
12
+ Origami is free software: you can redistribute it and/or modify
13
+ it under the terms of the GNU Lesser General Public License as published by
14
+ the Free Software Foundation, either version 3 of the License, or
15
+ (at your option) any later version.
16
+
17
+ Origami is distributed in the hope that it will be useful,
18
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
+ GNU Lesser General Public License for more details.
21
+
22
+ You should have received a copy of the GNU Lesser General Public License
23
+ along with Origami. If not, see <http://www.gnu.org/licenses/>.
24
+
25
+ =end
26
+
27
+ begin
28
+ require 'origami'
29
+ rescue LoadError
30
+ ORIGAMIDIR = "#{File.dirname(__FILE__)}/.."
31
+ $: << ORIGAMIDIR
32
+ require 'origami'
33
+ end
34
+ include Origami
35
+
36
+ require 'optparse'
37
+
38
+ class OptParser
39
+ BANNER = <<USAGE
40
+ Usage: #{$0} [<PDF-file>] [-p <password>] [-c <cipher>] [-s <key-size>] [-o <output-file>]
41
+ Encrypts a PDF document. Supports RC4 40 to 128 bits, AES128, AES256.
42
+ Bug reports or feature requests at: http://origami-pdf.googlecode.com/
43
+
44
+ Options:
45
+ USAGE
46
+
47
+ def self.parser(options)
48
+ OptionParser.new do |opts|
49
+ opts.banner = BANNER
50
+
51
+ opts.on("-o", "--output FILE", "Output PDF file (stdout by default)") do |o|
52
+ options[:output] = o
53
+ end
54
+
55
+ opts.on("-p", "--password PASSWORD", "Password of the document") do |p|
56
+ options[:password] = p
57
+ end
58
+
59
+ opts.on("-c", "--cipher CIPHER", "Cipher used to encrypt the document (Default: AES)") do |c|
60
+ options[:cipher] = c
61
+ end
62
+
63
+ opts.on("-s", "--key-size KEYSIZE", "Key size in bits (Default: 128)") do |s|
64
+ options[:key_size] = s.to_i
65
+ end
66
+
67
+ opts.on_tail("-h", "--help", "Show this message") do
68
+ puts opts
69
+ exit
70
+ end
71
+ end
72
+ end
73
+
74
+ def self.parse(args)
75
+ options =
76
+ {
77
+ :output => STDOUT,
78
+ :password => '',
79
+ :cipher => 'aes',
80
+ :key_size => 128
81
+ }
82
+
83
+ self.parser(options).parse!(args)
84
+
85
+ options
86
+ end
87
+ end
88
+
89
+ begin
90
+ @options = OptParser.parse(ARGV)
91
+
92
+ target = (ARGV.empty?) ? STDIN : ARGV.shift
93
+ params =
94
+ {
95
+ :verbosity => Parser::VERBOSE_QUIET,
96
+ }
97
+
98
+ pdf = PDF.read(target, params)
99
+ pdf.encrypt(
100
+ :user_password => @options[:password],
101
+ :owner_password => @options[:password],
102
+ :cipher => @options[:cipher],
103
+ :key_size => @options[:key_size]
104
+ )
105
+ pdf.save(@options[:output], :noindent => true)
106
+
107
+ rescue SystemExit
108
+ rescue Exception => e
109
+ STDERR.puts "#{e.class}: #{e.message}"
110
+ exit 1
111
+ end
112
+
@@ -0,0 +1,221 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ =begin
4
+
5
+ = Author:
6
+ Guillaume Delugré <guillaume/at/security-labs.org>
7
+
8
+ = Info:
9
+ Extracts valuable data from a PDF document. Can extract:
10
+ - decoded streams
11
+ - JavaScript
12
+ - file attachments
13
+
14
+ = License:
15
+ Origami is free software: you can redistribute it and/or modify
16
+ it under the terms of the GNU Lesser General Public License as published by
17
+ the Free Software Foundation, either version 3 of the License, or
18
+ (at your option) any later version.
19
+
20
+ Origami is distributed in the hope that it will be useful,
21
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
22
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23
+ GNU Lesser General Public License for more details.
24
+
25
+ You should have received a copy of the GNU Lesser General Public License
26
+ along with Origami. If not, see <http://www.gnu.org/licenses/>.
27
+
28
+ =end
29
+
30
+ begin
31
+ require 'origami'
32
+ rescue LoadError
33
+ ORIGAMIDIR = "#{File.dirname(__FILE__)}/.."
34
+ $: << ORIGAMIDIR
35
+ require 'origami'
36
+ end
37
+ include Origami
38
+
39
+ require 'optparse'
40
+ require 'rexml/document'
41
+
42
+ class OptParser
43
+ BANNER = <<USAGE
44
+ Usage: #{$0} <PDF-file> [-afjms] [-d <output-directory>]
45
+ Extracts various data out of a document (streams, scripts, fonts, metadata, attachments).
46
+ Bug reports or feature requests at: http://origami-pdf.googlecode.com/
47
+
48
+ Options:
49
+ USAGE
50
+
51
+ def self.parser(options)
52
+ OptionParser.new do |opts|
53
+ opts.banner = BANNER
54
+
55
+ opts.on("-d", "--output-dir DIR", "Output directory") do |d|
56
+ options[:output_dir] = d
57
+ end
58
+
59
+ opts.on("-s", "--streams", "Extracts all decoded streams") do
60
+ options[:streams] = true
61
+ end
62
+
63
+ opts.on("-a", "--attachments", "Extracts file attachments") do
64
+ options[:attachments] = true
65
+ end
66
+
67
+ opts.on("-f", "--fonts", "Extracts embedded font files") do
68
+ options[:fonts] = true
69
+ end
70
+
71
+ opts.on("-j", "--js", "Extracts JavaScript scripts") do
72
+ options[:javascript] = true
73
+ end
74
+
75
+ opts.on("-m", "--metadata", "Extracts metadata streams") do
76
+ options[:metadata] = true
77
+ end
78
+
79
+ opts.on_tail("-h", "--help", "Show this message") do
80
+ puts opts
81
+ exit
82
+ end
83
+ end
84
+ end
85
+
86
+ def self.parse(args)
87
+ options =
88
+ {
89
+ }
90
+
91
+ self.parser(options).parse!(args)
92
+
93
+ options
94
+ end
95
+ end
96
+
97
+ begin
98
+ @options = OptParser.parse(ARGV)
99
+
100
+ if ARGV.empty?
101
+ STDERR.puts "Error: No filename was specified. #{$0} --help for details."
102
+ exit 1
103
+ else
104
+ target = ARGV.shift
105
+ end
106
+
107
+ unless [:streams,:javascript,:attachments,:fonts,:metadata].any? {|opt| @options[opt]}
108
+ @options[:streams] =
109
+ @options[:javascript] =
110
+ @options[:fonts] =
111
+ @options[:attachments] = true
112
+ end
113
+
114
+ if @options[:output_dir].nil?
115
+ @options[:output_dir] = "#{File.basename(target, '.pdf')}.dump"
116
+ end
117
+
118
+ OUTPUT_DIR = @options[:output_dir]
119
+ Dir::mkdir(OUTPUT_DIR) unless File.directory?(OUTPUT_DIR)
120
+
121
+ params =
122
+ {
123
+ :verbosity => Parser::VERBOSE_QUIET,
124
+ }
125
+ pdf = PDF.read(target, params)
126
+
127
+ if @options[:streams]
128
+ pdf.root_objects.find_all{|obj| obj.is_a?(Stream)}.each do |stream|
129
+ stream_file = "#{OUTPUT_DIR}/stream_#{stream.reference.refno}.dmp"
130
+ File.open(stream_file, "w") do |fd|
131
+ fd.write(stream.data)
132
+ end
133
+ end
134
+ end
135
+
136
+ if @options[:javascript]
137
+ pdf.ls(/^JS$/).each do |script|
138
+ script_file = "#{OUTPUT_DIR}/script_#{script.hash}.js"
139
+ File.open(script_file, "w") do |fd|
140
+ fd.write(
141
+ case script
142
+ when Stream then
143
+ script.data
144
+ else
145
+ script.value
146
+ end
147
+ )
148
+ end
149
+ end
150
+
151
+ # Also checking for presence of JavaScript in XML forms.
152
+ if pdf.has_form? and pdf.Catalog.AcroForm.has_key?(:XFA)
153
+ xfa = pdf.Catalog.AcroForm[:XFA].solve
154
+
155
+ case xfa
156
+ when Array then
157
+ xml = ""
158
+ i = 0
159
+ xfa.each do |packet|
160
+ if i % 2 == 1
161
+ xml << packet.solve.data
162
+ end
163
+
164
+ i = i + 1
165
+ end
166
+ when Stream then
167
+ xml = xfa.data
168
+ else
169
+ reject("Malformed XFA dictionary")
170
+ end
171
+
172
+ xfadoc = REXML::Document.new(xml)
173
+ REXML::XPath.match(xfadoc, "//script").each do |script|
174
+ script_file = "#{OUTPUT_DIR}/script_#{script.hash}.js"
175
+ File.open(script_file, 'w') do |fd|
176
+ fd.write(script.text)
177
+ end
178
+ end
179
+ end
180
+ end
181
+
182
+ if @options[:attachments]
183
+ pdf.ls_names(Names::Root::EMBEDDEDFILES).each do |name, attachment|
184
+ attached_file = "#{OUTPUT_DIR}/attached_#{File.basename(name)}"
185
+ spec = attachment.solve
186
+ ef = spec[:EF].solve
187
+ f = ef[:F].solve
188
+
189
+ File.open(attached_file, "w") do |fd|
190
+ fd.write(f.data)
191
+ end
192
+ end
193
+ end
194
+
195
+ if @options[:fonts]
196
+ pdf.root_objects.find_all{|obj| obj.is_a?(Stream)}.each do |stream|
197
+ font = stream.xrefs.find{|obj| obj.is_a?(FontDescriptor)}
198
+ if font
199
+ font_file = "#{OUTPUT_DIR}/font_#{File.basename(font.FontName.value.to_s)}"
200
+ File.open(font_file, "w") do |fd|
201
+ fd.write(stream.data)
202
+ end
203
+ end
204
+ end
205
+ end
206
+
207
+ if @options[:metadata]
208
+ pdf.root_objects.find_all{|obj| obj.is_a?(MetadataStream)}.each do |stream|
209
+ metadata_file = "#{OUTPUT_DIR}/metadata_#{stream.reference.refno}.xml"
210
+ File.open(metadata_file, "w") do |fd|
211
+ fd.write(stream.data)
212
+ end
213
+ end
214
+ end
215
+
216
+ rescue SystemExit
217
+ rescue Exception => e
218
+ STDERR.puts "#{e.class}: #{e.message}"
219
+ exit 1
220
+ end
221
+