virustotal 2.0.0

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.
data/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ Copyright (c) 2010-2011 Jacob Hammack, Hammackj LLC
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright
8
+ notice, this list of conditions and the following disclaimer.
9
+ * Redistributions in binary form must reproduce the above copyright
10
+ notice, this list of conditions and the following disclaimer in the
11
+ documentation and/or other materials provided with the distribution.
12
+ * Neither the name of the Jacob Hammack or Hammackj LLC nor the
13
+ names of its contributors may be used to endorse or promote products
14
+ derived from this software without specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ DISCLAIMED. IN NO EVENT SHALL JACOB HAMMACK or HAMMACKJ LLC BE LIABLE FOR ANY
20
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,30 @@
1
+ # News
2
+
3
+ # 2.0.0 (February 20, 2011)
4
+ - Converted the entire thing into a rubygem
5
+ - Cleaned up the code significantly
6
+ - Added a config file to store the api-key in
7
+ - fixed up the command line options some
8
+ - Optimized execution some
9
+
10
+ # 1.0.0 (September 27, 2010)
11
+ - Cleaned up some dead code
12
+ - Added URL for the report for easier web viewing.
13
+
14
+ # 0.0.5 (September 11, 2010)
15
+ - Added a url scan option -w, so that urls can be scanned using the new api
16
+ - Added file upload option -u, so that files can be uploaded and waits for results
17
+
18
+ # 0.0.4 (September 10, 2010)
19
+ - Modified to use the new virustotal.com API, the code has been simplified.
20
+
21
+ # 0.0.3 (June 10, 2010)
22
+ - Added a timer between hash lookups from files
23
+ - Added a check for the invalid hash error that seems to happen on some MD5 hashes
24
+ - Added debug output
25
+
26
+ # 0.0.2 (January 31, 2010)
27
+ - Updated a output bug on the usage statement. Thanks to smithj for finding it.
28
+
29
+ # 0.0.1 (July 11, 2009)
30
+ - Initial public release (BlackHat)
@@ -0,0 +1,42 @@
1
+ # ruby-virustotal
2
+
3
+ ruby-virustotal is [virustotal](http://www.virustotal.com) automation and convenience tool for hash, file and URL submission.
4
+
5
+ The current version is 2.0.
6
+
7
+ ## Requirements
8
+
9
+ * ruby
10
+ * rubygems
11
+ * json
12
+ * rest-client
13
+
14
+ * public api key from [virustotal.com](http://www.virustotal.com)
15
+
16
+ ## Installation
17
+
18
+ % gem install virustotal
19
+ % virustotal [options]
20
+
21
+ ## Usage
22
+
23
+ ### Searching a file of hashes
24
+
25
+ % ./virustotal.rb -f <file_with_hashes_one_per_line>
26
+
27
+ ### Searching a single hash
28
+
29
+ % ./virustotal.rb -h FD287794107630FA3116800E617466A9
30
+
31
+ ### Searching a file of hashes and outputting to XML
32
+ % ./virustotal.rb -f <file_with_hashes_one_per_line> -x
33
+
34
+ ### Upload a file to Virustotal and wait for analysis
35
+ % ./virustotal.rb -u </path/to/file>
36
+
37
+ ### Search for a single URL
38
+ % ./virustotal.rb -s "http://www.google.com"
39
+
40
+ ## Contact
41
+
42
+ You can reach me at Jacob[dot]Hammack[at]hammackj[dot]com or http://www.hammackj.com
@@ -0,0 +1,15 @@
1
+ $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
2
+
3
+ require "virustotal"
4
+
5
+ task :build do
6
+ system "gem build #{VirusTotal::APP_NAME}.gemspec"
7
+ end
8
+
9
+ task :release => :build do
10
+ system "gem push #{VirusTotal::APP_NAME}-#{VirusTotal::VERSION}.gem"
11
+ end
12
+
13
+ task :clean do
14
+ system "rm *.gem"
15
+ end
@@ -0,0 +1,8 @@
1
+ # TODO
2
+
3
+ **Release dates are estimates, and features can be changed at any time.**
4
+
5
+ ## 2.0 (5/4/2011)
6
+ - Turn into a GEM
7
+ - clean up code
8
+ - add the ability to read from file for key
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ # virustotal - a command line tool for working with virustotal.com
5
+ # Jacob Hammack <jacob.hammack@hammackj.com>
6
+ # http://www.hammackj.com
7
+ #
8
+ # hammackj - 01-05-2011 - Version 2.0.0
9
+ #
10
+
11
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '/../lib'))
12
+
13
+ require 'rubygems'
14
+ require 'virustotal'
15
+
16
+ app = VirusTotal::Application.new
17
+ app.run(ARGV)
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+
3
+ module VirusTotal
4
+ APP_NAME = "virustotal"
5
+ VERSION = "2.0.0"
6
+ CONFIG_FILE = "~/.virustotal"
7
+ end
8
+
9
+ require 'json'
10
+ require 'rest_client'
11
+ require 'optparse'
12
+ require 'yaml'
13
+
14
+ require 'virustotal/application'
15
+ require 'virustotal/virustotal'
16
+ require 'virustotal/virustotalresult'
@@ -0,0 +1,184 @@
1
+ # encoding: utf-8
2
+
3
+ module VirusTotal
4
+ class Application
5
+
6
+ # Creates a new instance of the [Application] class
7
+ #
8
+ def initialize
9
+ @options = {}
10
+ @config = {}
11
+ @hashes = Array.new
12
+ @files_of_hashes = Array.new
13
+ @sites = Array.new
14
+ @uploads = Array.new
15
+ end
16
+
17
+ # Parses the command the line options and returns the parsed options hash
18
+ #
19
+ # @return [Hash] of the parsed options
20
+ def parse_options(args)
21
+ begin
22
+ @options['output'] = :stdout
23
+ @options['debug'] = false
24
+
25
+ opt = OptionParser.new do |opt|
26
+ opt.banner = "#{APP_NAME} v#{VERSION}\nJacob Hammack\nhttp://www.hammackj.com\n\n"
27
+ opt.banner << "Usage: #{APP_NAME} <options>"
28
+ opt.separator('')
29
+ opt.separator("Search Options")
30
+
31
+ opt.on('-h HASH', '--search-hash HASH', 'Searches a single hash on virustotal.com') { |hash|
32
+ @hashes.push(hash)
33
+ }
34
+
35
+ opt.on('-f FILE', '--search-file FILE', 'Searches a each hash in a file of hashes on virustotal.com') { |file|
36
+ if File.exists?(file)
37
+ puts "[+] Adding file #{file}" if @options["debug"]
38
+ @files_of_hashes.push(file)
39
+ else
40
+ puts "[!] #{file} does not exist, please check your input!\n"
41
+ end
42
+ }
43
+
44
+ opt.on('-u FILE', '--upload-file FILE', 'Uploads a file to virustotal.com for analysis') do |file|
45
+ if File.exists?(file)
46
+ puts "[+] Adding file #{file}" if @options["debug"]
47
+ @uploads.push(file)
48
+ else
49
+ puts "[!] #{file} does not exist, please check your input!\n"
50
+ end
51
+ end
52
+
53
+ opt.on('-s SITE', '--search-site SITE', 'Searches for a single url on virustotal.com') { |site|
54
+ @sites.push(site)
55
+ }
56
+
57
+ opt.separator('')
58
+ opt.separator('Output Options')
59
+
60
+ opt.on('-x', '--xml-output', 'Print results as xml to stdout') {
61
+ @options["output"] = :xml
62
+ }
63
+
64
+ opt.on('-y', '--yaml-output', 'Print results as yaml to stdout') {
65
+ @options['output'] = :yaml
66
+ }
67
+
68
+ opt.on('--stdout-output', 'Print results as normal text line to stdout, this is default') {
69
+ @options['output'] = :stdout
70
+ }
71
+
72
+ opt.separator ''
73
+ opt.separator 'Advanced Options'
74
+
75
+ opt.on('-c', '--create-config', 'Creates a skeleton config file to use') do
76
+ if File.exists?(File.expand_path(CONFIG_FILE)) == false
77
+ File.open(File.expand_path(CONFIG_FILE), 'w+') do |f|
78
+ f.write("virustotal: \n api-key: \n timeout: 10\n\n")
79
+ end
80
+
81
+ puts "[*] An empty #{File.expand_path(CONFIG_FILE)} has been created. Please edit and fill in the correct values."
82
+ exit
83
+ else
84
+ puts "[!] #{File.expand_path(CONFIG_FILE)} already exists. Please delete it if you wish to re-create it."
85
+ exit
86
+ end
87
+ end
88
+
89
+ opt.on('-d', '--debug', 'Print verbose debug information') do |d|
90
+ @options["debug"] = d
91
+ end
92
+
93
+ opt.separator ''
94
+ opt.separator 'Other Options'
95
+
96
+ opt.on('-v', '--version', "Shows application version information") do
97
+ puts "#{APP_NAME} - #{VERSION}"
98
+ exit
99
+ end
100
+
101
+ opt.on_tail("-?", "--help", "Show this message") { |help|
102
+ puts opt.to_s + "\n"
103
+ exit
104
+ }
105
+ end
106
+
107
+ if ARGV.length != 0
108
+ opt.parse!
109
+ else
110
+ puts opt.to_s + "\n"
111
+ exit
112
+ end
113
+ rescue OptionParser::MissingArgument => m
114
+ puts opt.to_s + "\n"
115
+ exit
116
+ end
117
+ end
118
+
119
+ # Loads the .virustotal config file for the api key
120
+ #
121
+ def load_config
122
+ if File.exists?(File.expand_path(CONFIG_FILE))
123
+ @config = YAML.load_file File.expand_path(CONFIG_FILE)
124
+ else
125
+ puts "[!] #{CONFIG_FILE} does not exist. Please run virustotal --create-config, to create it."
126
+ exit
127
+ end
128
+ end
129
+
130
+ # Processes all of the command line arguments and displays the results
131
+ #
132
+ def run(args)
133
+ parse_options(args)
134
+ load_config
135
+
136
+ vt = VirusTotal.new(@config["virustotal"]["api-key"], @config["virustotal"]["timeout"], @options["debug"])
137
+
138
+ if @options['output'] == :stdout
139
+ output_method = :to_stdout
140
+ elsif @options['output'] == :yaml
141
+ output_method = :to_yaml
142
+ elsif @options['output'] == :xml
143
+ output_method = :to_xml
144
+ print "<results>\n"
145
+ end
146
+
147
+ if @files_of_hashes != nil
148
+ @files_of_hashes.each do |file|
149
+ f = File.open(file, 'r')
150
+
151
+ f.each do |hash|
152
+ hash.chomp!
153
+ @hashes.push hash
154
+ end
155
+ end
156
+ end
157
+
158
+ if @hashes != nil
159
+ @hashes.each do |hash|
160
+ result = vt.query_hash hash
161
+ print result.send output_method
162
+ end
163
+ end
164
+
165
+ if @sites != nil
166
+ @sites.each do |site|
167
+ result = vt.query_site site
168
+ print result.send output_method
169
+ end
170
+ end
171
+
172
+ if @uploads != nil
173
+ @uploads.each do |upload|
174
+ result = vt.query_upload upload
175
+ print result.send output_method
176
+ end
177
+ end
178
+
179
+ if @options['output'] == :xml
180
+ print "</results>\n"
181
+ end
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,104 @@
1
+ # encoding: utf-8
2
+
3
+ module VirusTotal
4
+ class VirusTotal
5
+
6
+ # Creates a new instance of the [VirusTotal] class
7
+ #
8
+ # @return [VirusTotal]
9
+ def initialize(api_key, timeout = 7, debug = false)
10
+ @api_key = api_key
11
+ @timeout = timeout.to_i
12
+ @debug = debug
13
+ end
14
+
15
+ # Queries a single hash on virustotal.com
16
+ #
17
+ # @return [VirusTotalResult] of the results from the query
18
+ def query_hash hash
19
+ begin
20
+ puts "[*] Querying hash #{hash}" if @debug
21
+ hash.chomp!
22
+ if hash.include?('-')
23
+ hash = hash.split('-')[0]
24
+ end
25
+
26
+ response = RestClient.post 'https://www.virustotal.com/api/get_file_report.json', { :resource => hash, :key => @api_key }
27
+ results = VirusTotalResult.new hash, :hash, JSON.parse(response)
28
+
29
+ return results
30
+ rescue Exception => e
31
+ puts e.message
32
+ puts e.backtrace.join("\n")
33
+ STDERR.puts "[!] An error has occured. Retrying #{hash} in #{@timeout} seconds.\n"
34
+ sleep @timeout #So we do not DOS virustotal.com we wait at least 5 seconds between each query
35
+ retry
36
+ end
37
+ end
38
+
39
+ # Queries a single url on virustotal.com
40
+ #
41
+ # @return [VirusTotalResult] of the results from the query
42
+ def query_site url
43
+ begin
44
+ puts "[*] Querying url #{url}" if @debug
45
+
46
+ response = RestClient.post 'https://www.virustotal.com/api/get_url_report.json', { :resource => url, :key => @api_key }
47
+ results = VirusTotalResult.new url, :site, JSON.parse(response)
48
+
49
+ return results
50
+ rescue Exception => e
51
+ puts e.message
52
+ puts e.backtrace.join("\n")
53
+ STDERR.puts "[!] An error has occured. Retrying #{url} in #{@timeout} seconds\n"
54
+ sleep @timeout #So we do not DOS virustotal.com we wait at least 5 seconds between each query
55
+ retry
56
+ end
57
+ end
58
+
59
+ # Fetch results from virustotal using a specific hash
60
+ #
61
+ def query_upload file
62
+ results = Array.new
63
+ file = file.chomp
64
+
65
+ begin
66
+ puts "[*] Attempting to upload file #{file}" if @debug
67
+
68
+ response = RestClient.post 'https://www.virustotal.com/api/scan_file.json', { :key => @api_key, :file => File.new(file, 'rb') }
69
+ result = JSON.parse(response)
70
+
71
+ puts "[*] File #{file} uploaded, waiting for results this could take several minutes..." if @debug
72
+
73
+ if result['result'] == 1
74
+ results = query_hash result['scan_id']
75
+
76
+ while results.results[0]['result'] == "Hash Not Found"
77
+ puts "[*] File has not been analyized yet, waiting 60 seconds to try again" if @debug
78
+ sleep 60
79
+ results = query_hash result['scan_id']
80
+ end
81
+ elsif result['result'] == -2
82
+ puts "[!] Virustotal limits exceeded, ***do not edit the time out values.***"
83
+ else
84
+ fres = Hash.new
85
+ fres['hash'] = file
86
+ fres['scanner'] = '-'
87
+ fres['version'] = '-'
88
+ fres['date'] = '-'
89
+ fres['result'] = "File failed to upload"
90
+
91
+ results.push fres
92
+ end
93
+ rescue Exception => e
94
+ puts e.message
95
+ puts e.backtrace.join("\n")
96
+ STDERR.puts "[!] An error has occured. Retrying #{file} in #{@timeout} seconds\n"
97
+ sleep @timeout #So we do not DOS virustotal.com we wait at least 5 seconds between each query
98
+ retry
99
+ end
100
+
101
+ return results
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,110 @@
1
+ # encoding: utf-8
2
+
3
+ module VirusTotal
4
+
5
+ # A Wrapper class for the results from a virustotal.com
6
+ #
7
+ # @author Jacob Hammack <jacob.hammack@hammackj.com>
8
+ class VirusTotalResult
9
+ attr_accessor :results
10
+
11
+ # Creates a new instance of the [VirusTotalResult] class
12
+ #
13
+ def initialize hash, type, result
14
+ @type = type
15
+ @results = Array.new
16
+ fres = Hash.new
17
+
18
+ if result["result"] == 0
19
+
20
+ fres = Hash.new
21
+ fres['hash'] = hash
22
+ fres['scanner'] = '-'
23
+ fres['date'] = '-'
24
+ fres['permalink'] = '-'
25
+
26
+ if @type == :hash
27
+ fres['result'] = "Hash Not Found"
28
+ elsif @type == :site
29
+ fres['result'] = "Site Not Found"
30
+ end
31
+
32
+ @results.push fres
33
+ elsif result["result"] == -1
34
+ puts "[!] Invalid API KEY! Please correct this!"
35
+ exit
36
+ else
37
+ permalink = result["permalink"]
38
+ date = result["report"][0]
39
+ result["report"][1].each do |scanner, res|
40
+ if res != ''
41
+ fres = Hash.new
42
+ fres['hash'] = hash
43
+ fres['scanner'] = scanner
44
+ fres['date'] = date
45
+ fres['permalink'] = permalink unless permalink == nil
46
+ fres['result'] = res
47
+
48
+ @results.push fres
49
+ end
50
+ end
51
+ end
52
+
53
+ #if we didn't have any results let create a fake not found
54
+ if @results.size == 0
55
+ fres = Hash.new
56
+ fres['hash'] = hash
57
+ fres['scanner'] = '-'
58
+ fres['date'] = '-'
59
+ fres['permalink'] = '-'
60
+ if @type == :hash
61
+ fres['result'] = "No Results for Hash"
62
+ elsif @type == :site
63
+ fres['result'] = "No Results for Site"
64
+ end
65
+ @results.push fres
66
+ end
67
+ end
68
+
69
+ # Prints the [VirusTotalResult] object to screen
70
+ #
71
+ def to_stdout
72
+ result_string = String.new
73
+ @results.each do |result|
74
+ result_string << "#{result['hash']}: Scanner: #{result['scanner']} Result: #{result['result']}\n"
75
+ end
76
+ print result_string
77
+ end
78
+
79
+ # Prints the [VirusTotalResult] object as a xml string to the screen
80
+ #
81
+ def to_xml
82
+ result_string = String.new
83
+ @results.each do |result|
84
+ result_string << "\t<vtresult>\n"
85
+ result_string << "\t\t<hash>#{result['hash']}</hash>\n"
86
+ result_string << "\t\t<scanner>#{result['scanner']}</scanner>\n"
87
+ result_string << "\t\t<date>#{result['date']}</date>\n"
88
+ result_string << "\t\t<permalink>#{result['permalink']}</permalink>\n" unless result['permalink'] == nil
89
+ result_string << "\t\t<result>#{result['result']}</result>\n"
90
+ result_string << "\t</vtresult>\n"
91
+ end
92
+ print result_string
93
+ end
94
+
95
+ # Prints the [VirusTotalResult] object as a yaml string to the screen
96
+ #
97
+ def to_yaml
98
+ result_string = String.new
99
+ @results.each do |result|
100
+ result_string << "vt-result:\n"
101
+ result_string << " hash: #{result['hash']}\n"
102
+ result_string << " scanner: #{result['scanner']}\n"
103
+ result_string << " date: #{result['date']}\n"
104
+ result_string << " permalink: #{result['permalink']}\n" unless result['permalink'] == nil
105
+ result_string << " result: #{result['result']}\n\n"
106
+ end
107
+ print result_string
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+
3
+ base = __FILE__
4
+ $:.unshift(File.join(File.dirname(base), 'lib'))
5
+
6
+ require 'virustotal'
7
+
8
+ Gem::Specification.new do |s|
9
+ s.name = 'virustotal'
10
+ s.version = VirusTotal::VERSION
11
+ s.homepage = "http://github.com/hammackj/ruby-virustotal/"
12
+ s.summary = "virustotal"
13
+ s.description = "virustotal is a script for automating virustotal.com queries"
14
+ s.license = "BSD"
15
+
16
+ s.author = "Jacob Hammack"
17
+ s.email = "jacob.hammack@hammackj.com"
18
+
19
+ s.files = Dir['[A-Z]*'] + Dir['lib/**/*'] + ['virustotal.gemspec']
20
+ s.default_executable = 'virustotal'
21
+ s.executables = ['virustotal']
22
+ s.require_paths = ["lib"]
23
+
24
+ s.required_rubygems_version = ">= 1.3.6"
25
+ s.rubyforge_project = "virustotal"
26
+
27
+ s.add_development_dependency("rspec", ">= 2.4.0")
28
+ s.add_development_dependency("yard", ">= 0.6.4")
29
+
30
+ s.has_rdoc = 'yard'
31
+ s.extra_rdoc_files = ["README.markdown", "LICENSE", "NEWS.markdown", "TODO.markdown"]
32
+
33
+ s.add_dependency('json', '>= 1.5.1')
34
+ s.add_dependency('rest-client', '>= 1.6.1')
35
+
36
+ end
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: virustotal
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 2.0.0
6
+ platform: ruby
7
+ authors:
8
+ - Jacob Hammack
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-02-18 00:00:00 -06:00
14
+ default_executable: virustotal
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: rspec
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: 2.4.0
25
+ type: :development
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: yard
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: 0.6.4
36
+ type: :development
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: json
40
+ prerelease: false
41
+ requirement: &id003 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 1.5.1
47
+ type: :runtime
48
+ version_requirements: *id003
49
+ - !ruby/object:Gem::Dependency
50
+ name: rest-client
51
+ prerelease: false
52
+ requirement: &id004 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: 1.6.1
58
+ type: :runtime
59
+ version_requirements: *id004
60
+ description: virustotal is a script for automating virustotal.com queries
61
+ email: jacob.hammack@hammackj.com
62
+ executables:
63
+ - virustotal
64
+ extensions: []
65
+
66
+ extra_rdoc_files:
67
+ - README.markdown
68
+ - LICENSE
69
+ - NEWS.markdown
70
+ - TODO.markdown
71
+ files:
72
+ - LICENSE
73
+ - NEWS.markdown
74
+ - Rakefile
75
+ - README.markdown
76
+ - TODO.markdown
77
+ - lib/virustotal/application.rb
78
+ - lib/virustotal/virustotal.rb
79
+ - lib/virustotal/virustotalresult.rb
80
+ - lib/virustotal.rb
81
+ - virustotal.gemspec
82
+ - bin/virustotal
83
+ has_rdoc: yard
84
+ homepage: http://github.com/hammackj/ruby-virustotal/
85
+ licenses:
86
+ - BSD
87
+ post_install_message:
88
+ rdoc_options: []
89
+
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: "0"
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 1.3.6
104
+ requirements: []
105
+
106
+ rubyforge_project: virustotal
107
+ rubygems_version: 1.5.2
108
+ signing_key:
109
+ specification_version: 3
110
+ summary: virustotal
111
+ test_files: []
112
+