origami 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,353 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ =begin
4
+
5
+ = Info
6
+ Convert a PDF document to an Origami script.
7
+ Experimental.
8
+
9
+ = License:
10
+ Origami is free software: you can redistribute it and/or modify
11
+ it under the terms of the GNU Lesser General Public License as published by
12
+ the Free Software Foundation, either version 3 of the License, or
13
+ (at your option) any later version.
14
+
15
+ Origami is distributed in the hope that it will be useful,
16
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
+ GNU Lesser General Public License for more details.
19
+
20
+ You should have received a copy of the GNU Lesser General Public License
21
+ along with Origami. If not, see <http://www.gnu.org/licenses/>.
22
+
23
+ = Author
24
+ Guillaume Delugré
25
+
26
+ =end
27
+
28
+ require 'optparse'
29
+ require 'ftools'
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
+ @var_hash = {}
40
+ @code_hash = {}
41
+ @obj_route = []
42
+ @current_idx = nil
43
+
44
+ class OptParser
45
+ def self.parse(args)
46
+ options = {}
47
+ options[:verbose] =
48
+ options[:xstreams] = false
49
+
50
+ opts = OptionParser.new do |opts|
51
+ opts.banner = <<BANNER
52
+ Usage: #{$0} [-v] [-x] <PDF-file>
53
+ Convert a PDF document to an Origami script (experimental).
54
+
55
+ Options:
56
+ BANNER
57
+
58
+ opts.on("-v", "--verbose", "Verbose mode") do
59
+ options[:verbose] = true
60
+ end
61
+
62
+ opts.on("-x", "--extract-streams", "Extract PDF streams to separate files") do
63
+ options[:xstreams] = true
64
+ end
65
+
66
+ opts.on_tail("-h", "--help", "Show this message") do
67
+ puts opts
68
+ exit
69
+ end
70
+ end
71
+ opts.parse!(args)
72
+
73
+ options
74
+ end
75
+ end
76
+
77
+ @options = OptParser.parse(ARGV)
78
+
79
+ if ARGV.empty?
80
+ STDERR.puts "Error: No filename was specified. #{$0} --help for details."
81
+ exit 1
82
+ else
83
+ TARGET = ARGV.shift
84
+ end
85
+
86
+ TARGET_DIR = File.basename(TARGET, '.pdf')
87
+ TARGET_FILE = "#{TARGET_DIR}/#{TARGET_DIR}.rb"
88
+ STREAM_DIR = "streams"
89
+
90
+ def objectToRuby(obj, inclevel = 0, internalname = nil, do_convert = false)
91
+ code = ""
92
+
93
+ code <<
94
+ case obj
95
+ when Origami::Null
96
+ "Null.new"
97
+ when Origami::Boolean, Origami::Number
98
+ obj.value.to_s
99
+ when Origami::String
100
+ "'#{obj.value.gsub("'","\\\\'")}'"
101
+ when Origami::Dictionary
102
+ customtype = nil
103
+ if obj[:Type] and @@dict_special_types.include?(obj[:Type].value)
104
+ customtype = @@dict_special_types[obj[:Type].value]
105
+ end
106
+ dictionaryToRuby(obj, inclevel, internalname, customtype)
107
+ when Origami::Array
108
+ arrayToRuby(obj, inclevel, internalname)
109
+ when Origami::Stream
110
+ streamToRuby(obj, internalname)
111
+ when Origami::Name
112
+ nameToRuby(obj)
113
+ when Origami::Reference
114
+ referenceToRuby(obj, internalname)
115
+ else
116
+ raise RuntimeError, "Unknown object type: #{obj.class}"
117
+ end
118
+
119
+ case obj
120
+ when Origami::String, Origami::Dictionary, Origami::Array, Origami::Name
121
+ code << ".to_o" if do_convert
122
+ end
123
+
124
+ code
125
+ end
126
+
127
+ def referenceToRuby(ref, internalname)
128
+ varname = @var_hash[ref]
129
+
130
+ if varname.nil?
131
+ "nil"
132
+ elsif @obj_route[0..@current_idx].include?(varname)
133
+ @code_hash[varname] ||= {}
134
+ @code_hash[varname][:afterDecl] ||= []
135
+ @code_hash[varname][:afterDecl] << "#{internalname} = #{varname}"#.to_o.set_indirect(true)"
136
+
137
+ "nil"
138
+ else
139
+ @obj_route.push(varname) unless @obj_route.include?(varname)
140
+ varname
141
+ end
142
+ end
143
+
144
+ def nameToRuby(name)
145
+ code = ':'
146
+ valid = (name.value.to_s =~ /[+.:-]/).nil?
147
+
148
+ code << '"' unless valid
149
+ code << name.value.to_s
150
+ code << '"' unless valid
151
+
152
+ code
153
+ end
154
+
155
+ def arrayToRuby(arr, inclevel, internalname)
156
+ i = 0
157
+ code = "\n" + " " * inclevel + "["
158
+ arr.each do |obj|
159
+ subintname = "#{internalname}[#{i}]"
160
+
161
+ code << "#{objectToRuby(obj, inclevel + 1, subintname)}"
162
+ code << ", " unless i == arr.length - 1
163
+ i = i + 1
164
+ end
165
+ code << "]"
166
+
167
+ code
168
+ end
169
+
170
+ def dictionaryToRuby(dict, inclevel, internalname, customtype = nil)
171
+ i = 0
172
+ code = "\n" + " " * inclevel
173
+
174
+ if customtype
175
+ code << "#{customtype}.new(#{dictionaryToHashMap(dict, inclevel, internalname)}"
176
+ code << " " * inclevel + ")"
177
+ else
178
+ code << "{\n"
179
+ dict.each_pair do |key, val|
180
+ rubyname = nameToRuby(key)
181
+ subintname = "#{internalname}[#{rubyname}]"
182
+
183
+ if val.is_a?(Origami::Reference) and @var_hash[val] and @var_hash[val][0,3] == "obj"
184
+ oldname = @var_hash[val]
185
+ newname = (key.value.to_s.downcase + "_" + @var_hash[val][4..-1]).gsub('.','_')
186
+
187
+ if not @obj_route.include?(oldname)
188
+ @var_hash[val] = newname
189
+ @code_hash[newname] = @code_hash[oldname]
190
+ @code_hash.delete(oldname)
191
+ end
192
+ end
193
+
194
+ code << " " * (inclevel + 1) +
195
+ "#{rubyname} => #{objectToRuby(val, inclevel + 2, subintname)}"
196
+ code << ", " unless i == dict.length - 1
197
+
198
+ i = i + 1
199
+ code << "\n"
200
+ end
201
+ code << " " * inclevel + "}"
202
+ end
203
+
204
+ code
205
+ end
206
+
207
+ def dictionaryToHashMap(dict, inclevel, internalname)
208
+ i = 0
209
+ code = "\n"
210
+ dict.each_pair do |key, val|
211
+ rubyname = nameToRuby(key)
212
+ subintname = "#{internalname}[#{rubyname}]"
213
+
214
+ if val.is_a?(Origami::Reference) and @var_hash[val] and @var_hash[val][0,3] == "obj"
215
+ oldname = @var_hash[val]
216
+ newname = (key.value.to_s.downcase + "_" + @var_hash[val][4..-1]).gsub('.','_')
217
+
218
+ if not @obj_route.include?(oldname)
219
+ @var_hash[val] = newname
220
+ @code_hash[newname] = @code_hash[oldname]
221
+ @code_hash.delete(oldname)
222
+ end
223
+ end
224
+
225
+ code << " " * (inclevel + 1) +
226
+ "#{rubyname} => #{objectToRuby(val, inclevel + 2, subintname)}"
227
+ code << ", " unless i == dict.length - 1
228
+ i = i + 1
229
+ code << "\n"
230
+ end
231
+
232
+ code
233
+ end
234
+
235
+ def streamToRuby(stm, internalname)
236
+ dict = stm.dictionary.dup.delete_if{|k,v| k == :Length or k == :Filter}
237
+
238
+ code = "Stream.new("
239
+
240
+ if @options[:xstreams]
241
+ stmdir = "#{TARGET_DIR}/#{STREAM_DIR}"
242
+ Dir::mkdir(stmdir) unless File.directory? stmdir
243
+ stmfile = "#{stmdir}/stm_#{stm.reference.refno}.data"
244
+ File.open(stmfile, "w") do |stmfd|
245
+ stmfd.write stm.data
246
+ end
247
+
248
+ code << "File.read('#{STREAM_DIR}/stm_#{stm.reference.refno}.data')"
249
+ else
250
+ code << stm.data.inspect
251
+ end
252
+
253
+ code << ", #{dictionaryToHashMap(dict, 1, internalname)}" unless dict.empty?
254
+ code << ")"
255
+ if stm.dictionary.has_key? :Filter
256
+ code << ".setFilter(#{objectToRuby(stm.Filter, 1, internalname)})"
257
+ end
258
+
259
+ code
260
+ end
261
+
262
+ colorprint "[*] ", Colors::RED
263
+ puts "Loading document '#{TARGET}'"
264
+ verbosity = @options[:verbose] ? Parser::VERBOSE_INSANE : Parser::VERBOSE_QUIET
265
+ target = PDF.read(TARGET, :verbosity => verbosity)
266
+ colorprint "[*] ", Colors::RED
267
+ puts "Document successfully loaded into Origami"
268
+
269
+ Dir::mkdir(TARGET_DIR) unless File.directory? TARGET_DIR
270
+ fd = File.open(TARGET_FILE, 'w', 0700)
271
+
272
+ DOCREF = "pdf"
273
+ ORIGAMI_PATH = ORIGAMIDIR[0,1] == '/' ?
274
+ ORIGAMIDIR :
275
+ "../#{ORIGAMIDIR}"
276
+
277
+ fd.puts <<RUBY
278
+ #!/usr/bin/env ruby
279
+
280
+ begin
281
+ require 'origami'
282
+ rescue LoadError
283
+ ORIGAMIDIR = "#{ORIGAMI_PATH}"
284
+ $: << ORIGAMIDIR
285
+ require 'origami'
286
+ end
287
+ include Origami
288
+
289
+ OUTPUT = "\#{File.basename(__FILE__, '.rb')}.pdf"
290
+
291
+ #
292
+ # Creates the PDF object.
293
+ #
294
+ #{DOCREF} = PDF.new
295
+
296
+ RUBY
297
+
298
+ colorprint "[*] ", Colors::RED
299
+ puts "Retrieving all indirect objects..."
300
+ roots = target.root_objects
301
+ roots.each do |obj|
302
+ varname = "obj_" + obj.no.to_s
303
+ @var_hash[obj.reference] = varname
304
+ end
305
+
306
+ colorprint "[*] ", Colors::RED
307
+ puts "Retrieving the document Catalog..."
308
+ catalog = target.Catalog
309
+
310
+ @var_hash[catalog.reference] = "#{DOCREF}.Catalog"
311
+ @obj_route.push "#{DOCREF}.Catalog"
312
+
313
+ colorprint "[*] ", Colors::RED
314
+ puts "Processing the object hierarchy..."
315
+ @current_idx = 0
316
+ while @current_idx != @obj_route.size
317
+ varname = @obj_route[@current_idx]
318
+ obj = target[@var_hash.index(varname)]
319
+
320
+ @code_hash[varname] ||= {}
321
+ @code_hash[varname][:body] = objectToRuby(obj, 0, varname, true)
322
+
323
+ @current_idx = @current_idx + 1
324
+ end
325
+
326
+ @obj_route.reverse.each do |varname|
327
+ fd.puts "#{varname} = #{@code_hash[varname][:body]}"
328
+ if @code_hash[varname][:afterDecl]
329
+ @code_hash[varname][:afterDecl].each do |decl|
330
+ fd.puts decl
331
+ end
332
+ end
333
+ fd.puts
334
+ end
335
+
336
+ @obj_route.each do |varname|
337
+ fd.puts "#{DOCREF}.insert(#{varname})" unless varname == "#{DOCREF}.Catalog"
338
+ end
339
+ fd.puts
340
+
341
+ fd.puts <<RUBY
342
+ #
343
+ # Saves the document.
344
+ #
345
+ #{DOCREF}.save(OUTPUT)
346
+
347
+ RUBY
348
+
349
+ colorprint "[*] ", Colors::RED
350
+ puts "Successfully generated script '#{TARGET_FILE}'"
351
+ fd.close
352
+ exit
353
+
@@ -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
+ Embeds and PDF document into a trojan 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>] [-o <output-file>]
41
+ Embeds and PDF document into a trojan 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
+
79
+ EMBEDDEDNAME = "#{::Array.new(5){ rand(26) + 97}}.pdf"
80
+
81
+ pdf = PDF.new
82
+
83
+ objstm = ObjectStream.new.setFilter(:FlateDecode)
84
+ pdf.insert(objstm)
85
+
86
+ pagetree = PageTreeNode.new.insert_page(0, page = Page.new)
87
+ pdf.Catalog.Pages = objstm.insert(pagetree)
88
+ objstm.insert(page)
89
+
90
+ file = objstm.insert(pdf.attach_file(target, :Register => false))
91
+ pdf.Catalog.Names = objstm.insert(
92
+ Names.new.setEmbeddedFiles(NameTreeNode.new.setNames([ EMBEDDEDNAME, file ]))
93
+ )
94
+
95
+ page.onOpen Action::GoToE.new(EMBEDDEDNAME, Destination::GlobalFit.new(0))
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
+