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,268 @@
1
+ =begin
2
+
3
+ = File
4
+ parser.rb
5
+
6
+ = Info
7
+ Origami is free software: you can redistribute it and/or modify
8
+ it under the terms of the GNU Lesser General Public License as published by
9
+ the Free Software Foundation, either version 3 of the License, or
10
+ (at your option) any later version.
11
+
12
+ Origami is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU Lesser General Public License for more details.
16
+
17
+ You should have received a copy of the GNU Lesser General Public License
18
+ along with Origami. If not, see <http://www.gnu.org/licenses/>.
19
+
20
+ =end
21
+
22
+ require 'strscan'
23
+
24
+ module Origami
25
+
26
+ if RUBY_PLATFORM =~ /win32/ or RUBY_PLATFORM =~ /mingw32/
27
+ require "Win32API"
28
+
29
+ getStdHandle = Win32API.new("kernel32", "GetStdHandle", ['L'], 'L')
30
+ @@setConsoleTextAttribute = Win32API.new("kernel32", "SetConsoleTextAttribute", ['L', 'N'], 'I')
31
+
32
+ @@hOut = getStdHandle.call(-11)
33
+ end
34
+
35
+ module Colors #:nodoc;
36
+ if RUBY_PLATFORM =~ /win32/ or RUBY_PLATFORM =~ /mingw32/
37
+ BLACK = 0
38
+ BLUE = 1
39
+ GREEN = 2
40
+ CYAN = 3
41
+ RED = 4
42
+ MAGENTA = 5
43
+ YELLOW = 6
44
+ GREY = 7
45
+ WHITE = 8
46
+ else
47
+ GREY = '0;0'
48
+ BLACK = '0;30'
49
+ RED = '0;31'
50
+ GREEN = '0;32'
51
+ YELLOW = '0;33'
52
+ BLUE = '0;34'
53
+ MAGENTA = '0;35'
54
+ CYAN = '0;36'
55
+ WHITE = '0;37'
56
+ BRIGHT_GREY = '1;30'
57
+ BRIGHT_RED = '1;31'
58
+ BRIGHT_GREEN = '1;32'
59
+ BRIGHT_YELLOW = '1;33'
60
+ BRIGHT_BLUE = '1;34'
61
+ BRIGHT_MAGENTA = '1;35'
62
+ BRIGHT_CYAN = '1;36'
63
+ BRIGHT_WHITE = '1;37'
64
+ end
65
+ end
66
+
67
+ def set_fg_color(color, bright = false, fd = STDOUT) #:nodoc:
68
+ if RUBY_PLATFORM =~ /win32/ or RUBY_PLATFORM =~ /mingw32/
69
+ if bright then color |= Colors::WHITE end
70
+ @@setConsoleTextAttribute.call(@@hOut, color)
71
+ yield
72
+ @@setConsoleTextAttribute.call(@@hOut, Colors::GREY)
73
+ else
74
+ col, nocol = [color, Colors::GREY].map! { |key| "\033[#{key}m" }
75
+ fd << col
76
+ yield
77
+ fd << nocol
78
+ end
79
+ end
80
+
81
+ unless RUBY_PLATFORM =~ /win32/ or RUBY_PLATFORM =~ /mingw32/
82
+ def colorize(text, color, bright = false)
83
+ col, nocol = [color, Colors::GREY].map! { |key| "\033[#{key}m" }
84
+ "#{col}#{text}#{nocol}"
85
+ end
86
+ end
87
+
88
+ def colorprint(text, color, bright = false, fd = STDOUT) #:nodoc:
89
+ set_fg_color(color, bright, fd) {
90
+ fd << text
91
+ }
92
+ end
93
+
94
+ EOL = "\r\n" #:nodoc:
95
+ DEFINED_TOKENS = "[<\\[(%\\/)\\]>]" #:nodoc:
96
+ WHITESPACES = "([ \\f\\t\\r\\n\\0]|%[^\\n]*\\n)*" #:nodoc:
97
+ WHITECHARS = "[ \\f\\t\\r\\n\\0]*" #:nodoc:
98
+ WHITECHARS_NORET = "[ \\f\\t\\0]*" #:nodoc:
99
+
100
+ REGEXP_WHITESPACES = Regexp.new(WHITESPACES) #:nodoc:
101
+
102
+ class Parser #:nodoc:
103
+
104
+ class ParsingError < Exception #:nodoc:
105
+ end
106
+
107
+ #
108
+ # Do not output debug information.
109
+ #
110
+ VERBOSE_QUIET = 0
111
+
112
+ #
113
+ # Output some useful information.
114
+ #
115
+ VERBOSE_INFO = 1
116
+
117
+ #
118
+ # Output debug information.
119
+ #
120
+ VERBOSE_DEBUG = 2
121
+
122
+ #
123
+ # Output every objects read
124
+ #
125
+ VERBOSE_INSANE = 3
126
+
127
+ attr_accessor :options
128
+
129
+ def initialize(options = {}) #:nodoc:
130
+
131
+ #Default options values
132
+ @options =
133
+ {
134
+ :verbosity => VERBOSE_INFO, # Verbose level.
135
+ :ignore_errors => true, # Try to keep on parsing when errors occur.
136
+ :callback => Proc.new {}, # Callback procedure whenever a structure is read.
137
+ :password => '', # Default password being tried when opening a protected document.
138
+ :prompt_password => Proc.new { print "Password: "; gets.chomp }, # Callback procedure to prompt password when document is encrypted.
139
+ :force => false # Force PDF header detection
140
+ }
141
+
142
+ @options.update(options)
143
+ end
144
+
145
+ def parse(stream)
146
+ data =
147
+ if stream.respond_to? :read
148
+ if ''.respond_to? :force_encoding
149
+ StringScanner.new(stream.read.force_encoding('binary')) # 1.9 compat
150
+ else
151
+ StringScanner.new(stream.read)
152
+ end
153
+ elsif stream.is_a? ::String
154
+ if ''.respond_to? :force_encoding
155
+ StringScanner.new(File.open(stream, "r", :encoding => 'binary').binmode.read)
156
+ else
157
+ StringScanner.new(File.open(stream, "r").binmode.read)
158
+ end
159
+ elsif stream.is_a? StringScanner
160
+ stream
161
+ else
162
+ raise TypeError
163
+ end
164
+
165
+ @data = data
166
+ @data.pos = 0
167
+ end
168
+
169
+ def parse_objects(file) #:nodoc:
170
+ begin
171
+ loop do
172
+ obj = Object.parse(@data)
173
+ return if obj.nil?
174
+
175
+ trace "Read #{obj.type} object#{if obj.type != obj.real_type then " (" + obj.real_type.to_s.split('::').last + ")" end}, #{obj.reference}"
176
+
177
+ file << obj
178
+
179
+ @options[:callback].call(obj)
180
+ end
181
+
182
+ rescue UnterminatedObjectError => e
183
+ error e.message
184
+ file << e.obj
185
+
186
+ @options[:callback].call(e.obj)
187
+
188
+ Object.skip_until_next_obj(@data)
189
+ retry
190
+
191
+ rescue Exception => e
192
+ error "Breaking on: #{(@data.peek(10) + "...").inspect} at offset 0x#{@data.pos.to_s(16)}"
193
+ error "Last exception: [#{e.class}] #{e.message}"
194
+ debug "-> Stopped reading body : #{file.revisions.last.body.size} indirect objects have been parsed" if file.is_a?(PDF)
195
+ abort("Manually fix the file or set :ignore_errors parameter.") if not @options[:ignore_errors]
196
+
197
+ debug 'Skipping this indirect object.'
198
+ raise(e) if not Object.skip_until_next_obj(@data)
199
+
200
+ retry
201
+ end
202
+ end
203
+
204
+ def parse_xreftable(file) #:nodoc:
205
+ begin
206
+ info "...Parsing xref table..."
207
+ file.revisions.last.xreftable = XRef::Section.parse(@data)
208
+ @options[:callback].call(file.revisions.last.xreftable)
209
+ rescue Exception => e
210
+ debug "Exception caught while parsing xref table : " + e.message
211
+ warn "Unable to parse xref table! Xrefs might be stored into an XRef stream."
212
+
213
+ @data.pos -= 'trailer'.length unless @data.skip_until(/trailer/).nil?
214
+ end
215
+ end
216
+
217
+ def parse_trailer(file) #:nodoc:
218
+ begin
219
+ info "...Parsing trailer..."
220
+ trailer = Trailer.parse(@data)
221
+
222
+ if file.is_a?(PDF)
223
+ xrefstm = file.get_object_by_offset(trailer.startxref) ||
224
+ (file.get_object_by_offset(trailer.XRefStm) if trailer.has_field? :XRefStm)
225
+ end
226
+
227
+ if not xrefstm.nil?
228
+ debug "Found a XRefStream for this revision at #{xrefstm.reference}"
229
+ file.revisions.last.xrefstm = xrefstm
230
+ end
231
+
232
+ file.revisions.last.trailer = trailer
233
+ @options[:callback].call(file.revisions.last.trailer)
234
+
235
+ rescue Exception => e
236
+ debug "Exception caught while parsing trailer : " + e.message
237
+ warn "Unable to parse trailer!"
238
+
239
+ abort("Manually fix the file or set :ignore_errors parameter.") if not @options[:ignore_errors]
240
+
241
+ raise
242
+ end
243
+ end
244
+
245
+ private
246
+
247
+ def error(str = "") #:nodoc:
248
+ colorprint("[error] #{str}\n", Colors::RED, false, STDERR)
249
+ end
250
+
251
+ def warn(str = "") #:nodoc:
252
+ colorprint("[info ] Warning: #{str}\n", Colors::YELLOW, false, STDERR) if @options[:verbosity] >= VERBOSE_INFO
253
+ end
254
+
255
+ def info(str = "") #:nodoc:
256
+ (colorprint("[info ] ", Colors::GREEN, false, STDERR); STDERR << "#{str}\n") if @options[:verbosity] >= VERBOSE_INFO
257
+ end
258
+
259
+ def debug(str = "") #:nodoc:
260
+ (colorprint("[debug] ", Colors::MAGENTA, false, STDERR); STDERR << "#{str}\n") if @options[:verbosity] >= VERBOSE_DEBUG
261
+ end
262
+
263
+ def trace(str = "") #:nodoc:
264
+ (colorprint("[trace] ", Colors::CYAN, false, STDERR); STDERR << "#{str}\n") if @options[:verbosity] >= VERBOSE_INSANE
265
+ end
266
+ end
267
+ end
268
+
@@ -0,0 +1,45 @@
1
+ =begin
2
+
3
+ = File
4
+ parsers/fdf.rb
5
+
6
+ = Info
7
+ Origami is free software: you can redistribute it and/or modify
8
+ it under the terms of the GNU Lesser General Public License as published by
9
+ the Free Software Foundation, either version 3 of the License, or
10
+ (at your option) any later version.
11
+
12
+ Origami is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU Lesser General Public License for more details.
16
+
17
+ You should have received a copy of the GNU Lesser General Public License
18
+ along with Origami. If not, see <http://www.gnu.org/licenses/>.
19
+
20
+ =end
21
+
22
+ require 'origami/parser'
23
+ require 'origami/adobe/fdf'
24
+
25
+ module Origami
26
+
27
+ class Adobe::FDF
28
+ class Parser < Origami::Parser
29
+ def parse(stream) #:nodoc:
30
+ super
31
+
32
+ fdf = Adobe::FDF.new
33
+ fdf.header = Adobe::FDF::Header.parse(stream)
34
+ @options[:callback].call(fdf.header)
35
+
36
+ parse_objects(fdf)
37
+ parse_xreftable(fdf)
38
+ parse_trailer(fdf)
39
+
40
+ addrbk
41
+ end
42
+ end
43
+ end
44
+ end
45
+
@@ -0,0 +1,27 @@
1
+ =begin
2
+
3
+ = File
4
+ parsers/pdf.rb
5
+
6
+ = Info
7
+ This file is part of Origami, PDF manipulation framework for Ruby
8
+ Copyright (C) 2010 Guillaume Delugré <guillaume@security-labs.org>
9
+ All right reserved.
10
+
11
+ Origami is free software: you can redistribute it and/or modify
12
+ it under the terms of the GNU Lesser General Public License as published by
13
+ the Free Software Foundation, either version 3 of the License, or
14
+ (at your option) any later version.
15
+
16
+ Origami is distributed in the hope that it will be useful,
17
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ GNU Lesser General Public License for more details.
20
+
21
+ You should have received a copy of the GNU Lesser General Public License
22
+ along with Origami. If not, see <http://www.gnu.org/licenses/>.
23
+
24
+ =end
25
+
26
+ require 'origami/parsers/pdf/linear'
27
+
@@ -0,0 +1,113 @@
1
+ =begin
2
+
3
+ = File
4
+ parsers/linear.rb
5
+
6
+ = Info
7
+ Origami is free software: you can redistribute it and/or modify
8
+ it under the terms of the GNU Lesser General Public License as published by
9
+ the Free Software Foundation, either version 3 of the License, or
10
+ (at your option) any later version.
11
+
12
+ Origami is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU Lesser General Public License for more details.
16
+
17
+ You should have received a copy of the GNU Lesser General Public License
18
+ along with Origami. If not, see <http://www.gnu.org/licenses/>.
19
+
20
+ =end
21
+
22
+
23
+ require 'origami/parser'
24
+ require 'origami/pdf'
25
+
26
+ module Origami
27
+
28
+ class PDF
29
+
30
+ #
31
+ # Create a new PDF linear Parser.
32
+ #
33
+ class LinearParser < Origami::Parser
34
+ def parse(stream)
35
+ super
36
+
37
+ if @options[:force] == true
38
+ @data.skip_until(/%PDF-/).nil?
39
+ @data.pos = @data.pos - 5
40
+ end
41
+
42
+ pdf = PDF.new(false)
43
+
44
+ info "...Reading header..."
45
+ begin
46
+ pdf.header = PDF::Header.parse(@data)
47
+ @options[:callback].call(pdf.header)
48
+ rescue InvalidHeaderError => e
49
+ if @options[:ignore_errors] == true
50
+ warn "PDF header is invalid, ignoring..."
51
+ else
52
+ raise e
53
+ end
54
+ end
55
+
56
+ #
57
+ # Parse each revision
58
+ #
59
+ revision = 0
60
+ until @data.eos? do
61
+
62
+ begin
63
+
64
+ pdf.add_new_revision unless revision.zero?
65
+ revision = revision.succ
66
+
67
+ info "...Parsing revision #{pdf.revisions.size}..."
68
+ parse_objects(pdf)
69
+ parse_xreftable(pdf)
70
+ parse_trailer(pdf)
71
+
72
+ rescue SystemExit
73
+ raise
74
+ rescue Exception => e
75
+ error "Cannot read : " + (@data.peek(10) + "...").inspect
76
+ error "Stopped on exception : " + e.message
77
+
78
+ break
79
+ end
80
+
81
+ end
82
+
83
+ warn "This file has been linearized." if pdf.is_linearized?
84
+
85
+ #
86
+ # Decrypt encrypted file contents
87
+ #
88
+ if pdf.is_encrypted?
89
+ warn "This document contains encrypted data!"
90
+
91
+ passwd = @options[:password]
92
+ begin
93
+ pdf.decrypt(passwd)
94
+ rescue EncryptionInvalidPasswordError
95
+ if passwd.empty?
96
+ passwd = @options[:prompt_password].call
97
+ retry unless passwd.empty?
98
+ end
99
+
100
+ raise EncryptionInvalidPasswordError
101
+ end
102
+ end
103
+
104
+ if pdf.is_signed?
105
+ warn "This document has been signed!"
106
+ end
107
+
108
+ pdf
109
+ end
110
+ end
111
+ end
112
+ end
113
+