pedump 0.3.2 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +56 -0
- data/README.md.tpl +35 -0
- data/Rakefile +75 -0
- data/VERSION +1 -1
- data/data/sig.bin +0 -0
- data/data/sig.txt +14083 -0
- data/lib/pedump/cli.rb +61 -12
- data/lib/pedump/packer.rb +124 -0
- data/lib/pedump/version.rb +10 -0
- data/lib/pedump.rb +26 -0
- data/pedump.gemspec +11 -4
- data/samples/calc.7z +0 -0
- metadata +24 -17
- data/README.rdoc +0 -19
data/lib/pedump/cli.rb
CHANGED
@@ -14,10 +14,10 @@ class PEdump::CLI
|
|
14
14
|
|
15
15
|
KNOWN_ACTIONS = (
|
16
16
|
%w'mz dos_stub rich pe data_directory sections' +
|
17
|
-
%w'strings resources resource_directory imports exports web'
|
17
|
+
%w'strings resources resource_directory imports exports packer web packer_only'
|
18
18
|
).map(&:to_sym)
|
19
19
|
|
20
|
-
DEFAULT_ALL_ACTIONS = KNOWN_ACTIONS - %w'resource_directory web'.map(&:to_sym)
|
20
|
+
DEFAULT_ALL_ACTIONS = KNOWN_ACTIONS - %w'resource_directory web packer_only'.map(&:to_sym)
|
21
21
|
|
22
22
|
URL_BASE = "http://pedump.me"
|
23
23
|
|
@@ -31,28 +31,35 @@ class PEdump::CLI
|
|
31
31
|
optparser = OptionParser.new do |opts|
|
32
32
|
opts.banner = "Usage: pedump [options]"
|
33
33
|
|
34
|
+
opts.on "-V", "--version", "Print version information and exit" do
|
35
|
+
puts PEdump::VERSION
|
36
|
+
exit
|
37
|
+
end
|
34
38
|
opts.on "-v", "--[no-]verbose", "Run verbosely" do |v|
|
35
39
|
@options[:verbose] ||= 0
|
36
40
|
@options[:verbose] += 1
|
37
41
|
end
|
38
|
-
opts.on "-F", "--force", "Try to dump by all means
|
42
|
+
opts.on "-F", "--force", "Try to dump by all means","(can cause exceptions & heavy wounds)" do |v|
|
39
43
|
@options[:force] ||= 0
|
40
44
|
@options[:force] += 1
|
41
45
|
end
|
42
46
|
opts.on "-f", "--format FORMAT", [:binary, :c, :dump, :hex, :inspect, :table],
|
43
|
-
"Output format: bin,c,dump,hex,inspect,table
|
47
|
+
"Output format: bin,c,dump,hex,inspect,table","(default: table)" do |v|
|
44
48
|
@options[:format] = v
|
45
49
|
end
|
46
50
|
KNOWN_ACTIONS.each do |t|
|
47
51
|
opts.on "--#{t.to_s.tr('_','-')}", eval("lambda{ |_| @actions << :#{t.to_s.tr('-','_')} }")
|
48
52
|
end
|
49
|
-
opts.on "--
|
53
|
+
opts.on '-P', "--packer-only", "packer/compiler detect only,","mimics 'file' command output" do
|
54
|
+
@actions << :packer_only
|
55
|
+
end
|
56
|
+
opts.on "--all", "Dump all but resource-directory (default)" do
|
50
57
|
@actions = DEFAULT_ALL_ACTIONS
|
51
58
|
end
|
52
59
|
opts.on "--va2file VA", "Convert RVA to file offset" do |va|
|
53
60
|
@actions << [:va2file,va]
|
54
61
|
end
|
55
|
-
opts.on "-W", "--web", "
|
62
|
+
opts.on "-W", "--web", "Uploads files to a #{URL_BASE}","for a nice HTML tables with image previews,","candies & stuff" do
|
56
63
|
@actions << :web
|
57
64
|
end
|
58
65
|
end
|
@@ -68,13 +75,16 @@ class PEdump::CLI
|
|
68
75
|
end
|
69
76
|
@actions = DEFAULT_ALL_ACTIONS if @actions.empty?
|
70
77
|
|
78
|
+
if @actions.include?(:packer_only)
|
79
|
+
raise "[!] can't mix --packer-only with other actions" if @actions.size > 1
|
80
|
+
dump_packer_only(argv)
|
81
|
+
return
|
82
|
+
end
|
83
|
+
|
71
84
|
argv.each_with_index do |fname,idx|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
puts "# #{fname}"
|
76
|
-
puts "# -----------------------------------------------"
|
77
|
-
end
|
85
|
+
@need_fname_header = (argv.size > 1)
|
86
|
+
@file_idx = idx
|
87
|
+
@file_name = fname
|
78
88
|
|
79
89
|
File.open(fname,'rb') do |f|
|
80
90
|
@pedump = PEdump.new(fname, :force => @options[:force]).tap do |x|
|
@@ -99,6 +109,23 @@ class PEdump::CLI
|
|
99
109
|
# prevents a 'Broken pipe - <STDOUT> (Errno::EPIPE)' message
|
100
110
|
end
|
101
111
|
|
112
|
+
def dump_packer_only fnames
|
113
|
+
max_fname_len = fnames.map(&:size).max
|
114
|
+
fnames.each do |fname|
|
115
|
+
File.open(fname,'rb') do |f|
|
116
|
+
@pedump = PEdump.new(fname, :force => @options[:force]).tap do |x|
|
117
|
+
if @options[:verbose]
|
118
|
+
x.logger.level = @options[:verbose] > 1 ? Logger::INFO : Logger::DEBUG
|
119
|
+
end
|
120
|
+
end
|
121
|
+
packers = @pedump.packers(f)
|
122
|
+
pname = Array(packers).first.try(:packer).try(:name)
|
123
|
+
pname ||= "unknown" if @options[:verbose]
|
124
|
+
printf("%-*s %s\n", max_fname_len+1, "#{fname}:", pname) if pname
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
102
129
|
class ProgressProxy
|
103
130
|
attr_reader :pbar
|
104
131
|
|
@@ -173,8 +200,17 @@ class PEdump::CLI
|
|
173
200
|
end
|
174
201
|
|
175
202
|
def action_title action
|
203
|
+
if @need_fname_header
|
204
|
+
@need_fname_header = false
|
205
|
+
puts if @file_idx > 0
|
206
|
+
puts "# -----------------------------------------------"
|
207
|
+
puts "# #@file_name"
|
208
|
+
puts "# -----------------------------------------------"
|
209
|
+
end
|
210
|
+
|
176
211
|
s = action.to_s.upcase.tr('_',' ')
|
177
212
|
s += " Header" if [:mz, :pe, :rich].include?(action)
|
213
|
+
s = "Packer / Compiler" if action == :packer
|
178
214
|
"\n=== %s ===\n\n" % s
|
179
215
|
end
|
180
216
|
|
@@ -310,6 +346,8 @@ class PEdump::CLI
|
|
310
346
|
dump_strings data
|
311
347
|
when PEdump::IMAGE_IMPORT_DESCRIPTOR
|
312
348
|
dump_imports data
|
349
|
+
when PEdump::Packer::Match
|
350
|
+
dump_packers data
|
313
351
|
else
|
314
352
|
puts "[?] don't know how to dump: #{data.inspect[0,50]}" unless data.empty?
|
315
353
|
end
|
@@ -322,6 +360,17 @@ class PEdump::CLI
|
|
322
360
|
end
|
323
361
|
end
|
324
362
|
|
363
|
+
def dump_packers data
|
364
|
+
if @options[:verbose]
|
365
|
+
data.each do |p|
|
366
|
+
printf "%8x %4d %s\n", p.offset, p.packer.size, p.packer.name
|
367
|
+
end
|
368
|
+
else
|
369
|
+
# show only largest detected unless verbose output requested
|
370
|
+
puts " #{data.first.packer.name}"
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
325
374
|
def dump_exports data
|
326
375
|
printf "# module %s\n# flags=0x%x ts=%s version=%d.%d ord_base=%d\n",
|
327
376
|
data.name.inspect,
|
@@ -0,0 +1,124 @@
|
|
1
|
+
class PEdump
|
2
|
+
class Packer < Struct.new(:name, :re, :ep_only, :size)
|
3
|
+
|
4
|
+
DATA_ROOT = File.dirname(File.dirname(File.dirname(__FILE__)))
|
5
|
+
BIN_SIGS_FILE = File.join(DATA_ROOT, "data", "sig.bin")
|
6
|
+
TEXT_SIGS_FILE = File.join(DATA_ROOT, "data", "sig.txt")
|
7
|
+
|
8
|
+
Match = Struct.new :offset, :packer
|
9
|
+
|
10
|
+
class << self
|
11
|
+
|
12
|
+
def all
|
13
|
+
@@all ||=
|
14
|
+
begin
|
15
|
+
r = unmarshal
|
16
|
+
unless r
|
17
|
+
if PEdump.respond_to?(:logger) && PEdump.logger
|
18
|
+
PEdump.logger.warn "[?] #{self}: unmarshal failed, using slow text parsing instead"
|
19
|
+
else
|
20
|
+
STDERR.puts "[?] #{self}: unmarshal failed, using slow text parsing instead"
|
21
|
+
end
|
22
|
+
r = parse
|
23
|
+
end
|
24
|
+
r
|
25
|
+
end
|
26
|
+
end
|
27
|
+
alias :load :all
|
28
|
+
|
29
|
+
def max_size
|
30
|
+
@@max_size ||= all.map(&:size).max
|
31
|
+
end
|
32
|
+
|
33
|
+
def of data, ep_offset = nil
|
34
|
+
if data.respond_to?(:read) && data.respond_to?(:seek) && ep_offset
|
35
|
+
of_file data, ep_offset
|
36
|
+
else
|
37
|
+
of_data data
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# try to determine packer of FILE f, ep_offset - offset to entrypoint from start of file
|
42
|
+
def of_file f, ep_offset
|
43
|
+
f.seek(ep_offset)
|
44
|
+
of_data f.read(max_size)
|
45
|
+
end
|
46
|
+
|
47
|
+
def of_data data
|
48
|
+
r = []
|
49
|
+
each do |packer|
|
50
|
+
if (idx=data.index(packer.re)) == 0
|
51
|
+
r << Match.new(idx, packer)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
r.any? ? r.sort_by{ |x| -x.packer.size } : nil
|
55
|
+
end
|
56
|
+
|
57
|
+
def method_missing *args, &block
|
58
|
+
all.respond_to?(args.first) ? all.send(*args,&block) : super
|
59
|
+
end
|
60
|
+
|
61
|
+
def unmarshal
|
62
|
+
File.open(BIN_SIGS_FILE,"rb") do |f|
|
63
|
+
Marshal.load(f)
|
64
|
+
end
|
65
|
+
rescue
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
|
69
|
+
# parse text signatures
|
70
|
+
def parse fname = TEXT_SIGS_FILE
|
71
|
+
sigs = {}; sig = nil
|
72
|
+
|
73
|
+
File.open(fname,'r:utf-8') do |f|
|
74
|
+
while line = f.gets
|
75
|
+
line.strip!
|
76
|
+
|
77
|
+
# XXX
|
78
|
+
# "B\xE9rczi G\xE1bor".force_encoding('binary').to_yaml:
|
79
|
+
# RuntimeError: expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS
|
80
|
+
|
81
|
+
case line
|
82
|
+
when /^;/,/^$/
|
83
|
+
next
|
84
|
+
when /^\[(.+)\]$/
|
85
|
+
sig = Packer.new($1.sub(/^\*\s+/,'').sub(/\s+\(h\)$/,''))
|
86
|
+
when /^signature = (.+)$/
|
87
|
+
sig.re = $1
|
88
|
+
if sigs[sig.re]
|
89
|
+
next if sigs[sig.re].name == sig.name
|
90
|
+
printf "[?] dup %-40s, %s\n", sigs[sig.re].name.inspect, sig.name.inspect
|
91
|
+
end
|
92
|
+
sigs[sig.re] = sig
|
93
|
+
when /^ep_only = (.+)$/
|
94
|
+
sig.ep_only = ($1.strip.downcase == 'true')
|
95
|
+
else raise line
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
sigs = sigs.values
|
101
|
+
sigs.each do |sig|
|
102
|
+
sig.re = Regexp.new(
|
103
|
+
sig.re.split(' ').tap do |a|
|
104
|
+
sig.size = a.size
|
105
|
+
end.map do |x|
|
106
|
+
case x
|
107
|
+
when '??'
|
108
|
+
'.'
|
109
|
+
when /[a-f0-9]{2}/i
|
110
|
+
Regexp::escape x.to_i(16).chr
|
111
|
+
else raise x
|
112
|
+
end
|
113
|
+
end.join
|
114
|
+
)
|
115
|
+
if sig.name[/-+>/]
|
116
|
+
a = sig.name.split(/-+>/,2).map(&:strip)
|
117
|
+
sig.name = "#{a[0]} (#{a[1]})"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
sigs
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
data/lib/pedump.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'logger'
|
3
|
+
require 'pedump/version'
|
3
4
|
|
4
5
|
# pedump.rb by zed_0xff
|
5
6
|
#
|
@@ -37,6 +38,8 @@ end
|
|
37
38
|
class PEdump
|
38
39
|
attr_accessor :fname, :logger, :force
|
39
40
|
|
41
|
+
VERSION = Version::STRING
|
42
|
+
|
40
43
|
def initialize fname, params = {}
|
41
44
|
@fname = fname
|
42
45
|
@force = params[:force]
|
@@ -522,6 +525,7 @@ class PEdump
|
|
522
525
|
nil
|
523
526
|
end
|
524
527
|
end
|
528
|
+
x[tbl] && x[tbl].compact!
|
525
529
|
end
|
526
530
|
if x.original_first_thunk && !x.first_thunk
|
527
531
|
logger.warn "[?] import table: empty FirstThunk of #{x.module_name}"
|
@@ -967,6 +971,28 @@ class PEdump
|
|
967
971
|
end
|
968
972
|
end.flatten.compact
|
969
973
|
end
|
974
|
+
|
975
|
+
def packer f = nil
|
976
|
+
@packer ||= pe(f) && @pe.ioh &&
|
977
|
+
begin
|
978
|
+
if !(va=@pe.ioh.AddressOfEntryPoint)
|
979
|
+
logger.error "[?] can't find EntryPoint RVA"
|
980
|
+
nil
|
981
|
+
elsif !(ofs = va2file(va))
|
982
|
+
logger.error "[?] can't find EntryPoint RVA (0x#{va.to_s(16)}) file offset"
|
983
|
+
nil
|
984
|
+
else
|
985
|
+
require 'pedump/packer'
|
986
|
+
if PEdump::Packer.all.size == 0
|
987
|
+
logger.error "[?] no packer definitions found"
|
988
|
+
nil
|
989
|
+
else
|
990
|
+
Packer.of(f, ofs)
|
991
|
+
end
|
992
|
+
end
|
993
|
+
end
|
994
|
+
end
|
995
|
+
alias :packers :packer
|
970
996
|
end
|
971
997
|
|
972
998
|
####################################################################################
|
data/pedump.gemspec
CHANGED
@@ -5,17 +5,18 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "pedump"
|
8
|
-
s.version = "0.3.
|
8
|
+
s.version = "0.3.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Andrey \"Zed\" Zaikin"]
|
12
|
-
s.date = "2011-12-
|
12
|
+
s.date = "2011-12-13"
|
13
13
|
s.description = "dump headers, sections, extract resources of win32 PE exe,dll,etc"
|
14
14
|
s.email = "zed.0xff@gmail.com"
|
15
15
|
s.executables = ["pedump"]
|
16
16
|
s.extra_rdoc_files = [
|
17
17
|
"LICENSE.txt",
|
18
|
-
"README.
|
18
|
+
"README.md",
|
19
|
+
"README.md.tpl"
|
19
20
|
]
|
20
21
|
s.files = [
|
21
22
|
".document",
|
@@ -23,13 +24,19 @@ Gem::Specification.new do |s|
|
|
23
24
|
"Gemfile",
|
24
25
|
"Gemfile.lock",
|
25
26
|
"LICENSE.txt",
|
26
|
-
"README.
|
27
|
+
"README.md",
|
28
|
+
"README.md.tpl",
|
27
29
|
"Rakefile",
|
28
30
|
"VERSION",
|
29
31
|
"bin/pedump",
|
32
|
+
"data/sig.bin",
|
33
|
+
"data/sig.txt",
|
30
34
|
"lib/pedump.rb",
|
31
35
|
"lib/pedump/cli.rb",
|
36
|
+
"lib/pedump/packer.rb",
|
37
|
+
"lib/pedump/version.rb",
|
32
38
|
"pedump.gemspec",
|
39
|
+
"samples/calc.7z",
|
33
40
|
"spec/pedump_spec.rb",
|
34
41
|
"spec/spec_helper.rb"
|
35
42
|
]
|
data/samples/calc.7z
ADDED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pedump
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-12-
|
12
|
+
date: 2011-12-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: multipart-post
|
16
|
-
requirement: &
|
16
|
+
requirement: &70135365235740 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 1.1.4
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70135365235740
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: progressbar
|
27
|
-
requirement: &
|
27
|
+
requirement: &70135365807020 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 0.9.2
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70135365807020
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rspec
|
38
|
-
requirement: &
|
38
|
+
requirement: &70135365806000 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: 2.3.0
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70135365806000
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: bundler
|
49
|
-
requirement: &
|
49
|
+
requirement: &70135365804780 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 1.0.0
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70135365804780
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: jeweler
|
60
|
-
requirement: &
|
60
|
+
requirement: &70135365803680 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ~>
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: 1.6.4
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70135365803680
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rcov
|
71
|
-
requirement: &
|
71
|
+
requirement: &70135365802300 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,7 +76,7 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70135365802300
|
80
80
|
description: dump headers, sections, extract resources of win32 PE exe,dll,etc
|
81
81
|
email: zed.0xff@gmail.com
|
82
82
|
executables:
|
@@ -84,20 +84,27 @@ executables:
|
|
84
84
|
extensions: []
|
85
85
|
extra_rdoc_files:
|
86
86
|
- LICENSE.txt
|
87
|
-
- README.
|
87
|
+
- README.md
|
88
|
+
- README.md.tpl
|
88
89
|
files:
|
89
90
|
- .document
|
90
91
|
- .rspec
|
91
92
|
- Gemfile
|
92
93
|
- Gemfile.lock
|
93
94
|
- LICENSE.txt
|
94
|
-
- README.
|
95
|
+
- README.md
|
96
|
+
- README.md.tpl
|
95
97
|
- Rakefile
|
96
98
|
- VERSION
|
97
99
|
- bin/pedump
|
100
|
+
- data/sig.bin
|
101
|
+
- data/sig.txt
|
98
102
|
- lib/pedump.rb
|
99
103
|
- lib/pedump/cli.rb
|
104
|
+
- lib/pedump/packer.rb
|
105
|
+
- lib/pedump/version.rb
|
100
106
|
- pedump.gemspec
|
107
|
+
- samples/calc.7z
|
101
108
|
- spec/pedump_spec.rb
|
102
109
|
- spec/spec_helper.rb
|
103
110
|
homepage: http://github.com/zed-0xff/pedump
|
@@ -115,7 +122,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
115
122
|
version: '0'
|
116
123
|
segments:
|
117
124
|
- 0
|
118
|
-
hash:
|
125
|
+
hash: -3106600206779889876
|
119
126
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
127
|
none: false
|
121
128
|
requirements:
|
data/README.rdoc
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
= pedump
|
2
|
-
|
3
|
-
Description goes here.
|
4
|
-
|
5
|
-
== Contributing to pedump
|
6
|
-
|
7
|
-
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
8
|
-
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
9
|
-
* Fork the project
|
10
|
-
* Start a feature/bugfix branch
|
11
|
-
* Commit and push until you are happy with your contribution
|
12
|
-
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
13
|
-
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
14
|
-
|
15
|
-
== Copyright
|
16
|
-
|
17
|
-
Copyright (c) 2011 Andrey "Zed" Zaikin. See LICENSE.txt for
|
18
|
-
further details.
|
19
|
-
|