class Elf::Tool
Public Class Methods
after_options()
click to toggle source
# File lib/elf/tools.rb, line 67 def self.after_options end
execute(filename)
click to toggle source
# File lib/elf/tools.rb, line 118 def self.execute(filename) begin analysis(filename) rescue Errno::ENOENT, Errno::EACCES, Errno::EISDIR, Elf::File::NotAnELF, Elf::File::InvalidElfClass, Elf::File::InvalidDataEncoding, Elf::File::UnsupportedElfVersion, Elf::File::InvalidOsAbi, Elf::File::InvalidElfType, Elf::File::InvalidMachine => e # The Errno exceptions have their message ending in " - FILENAME", # so we take the FILENAME out and just use the one we know # already. We also take out the final dot on the phrase so that # we follow the output messages from other tools, like cat. putnotice "#{filename}: #{e.message.gsub(/\.? - .*/, '')}" rescue Exception => e puterror "#{filename}: #{e.message} (#{e.class})\n\t#{e.backtrace.join("\n\t")}" exit -1 end end
execute_on(param)
click to toggle source
Execute the analysis function on all the elements of an array.
# File lib/elf/tools.rb, line 192 def self.execute_on(param) param = ::File.new(param) if param.is_a? String param = param.read.split(/\r?\n/) if param.is_a? IO param.each do |filename| try_execute(filename) end end
inherited(klass)
click to toggle source
# File lib/elf/tools.rb, line 32 def self.inherited(klass) raise Exception.new("Another Tool has been already defined") if @tool_defined @tool_defined = true at_exit do unless $! klass.main end end end
initialize()
click to toggle source
# File lib/elf/tools.rb, line 204 def self.initialize @output_mutex = Mutex.new @execution_threads = ThreadGroup.new @options = [ ["--help", "-?", GetoptLong::NO_ARGUMENT], ["--quiet", "-q", GetoptLong::NO_ARGUMENT], ["--recursive", "-R", GetoptLong::NO_ARGUMENT], ] end
main()
click to toggle source
# File lib/elf/tools.rb, line 215 def self.main initialize begin parse_arguments # collect all the arguments passed; if the argument starts # with '@', then open the file and split the lines in further # arguments. @targets = ARGV.collect { |argument| if argument[0..0] == "@" ::File.read(argument[1..-1]).split(/\r?\n/) else argument end }.flatten after_options # if we have no targets (neither direct arguments, nor added # by #after_options, we readthe targets from stdin. if @targets.empty? $stdin.each_line { |input| try_execute(input.sub(/\r?\n/, '')) } else $stdin.close @targets.uniq.each { |target| try_execute(target) } end if @execution_threads @execution_threads.list.each do |thread| thread.join end end results rescue Interrupt puterror "Interrupted" exit 1 end end
parse_arguments()
click to toggle source
Parse the arguments for the tool; it does not parse the @file options, since they are only expected to contain file names, rather than options.
# File lib/elf/tools.rb, line 73 def self.parse_arguments opts = GetoptLong.new(*@options) opts.each do |opt, arg| if opt == "--help" # check if we're executing from a tarball or the git repository, # if so we can't use the system man page. manpage = File.expand_path("../../../manpages/#{to_s}.1", __FILE__) manpage = to_s unless File.exist?(manpage) exec("man #{manpage}") end attrname = opt.gsub(/^--/, "").gsub("-", "_") attrval = arg.size == 0 ? true : arg # If there is a function with the same name of the parameter # defined (with a _cb suffix), call that, otherwise set the # attribute with the same name to the given value. cb = method("#{attrname}_cb") rescue nil case when cb.nil? instance_variable_set("@#{attrname}", attrval) when cb.arity == 0 raise ArgumentError("wrong number of arguments in callback (0 for 1)") unless arg.size == 0 cb.call when cb.arity == 1 # fallback to provide a single "true" parameter if there was no # required argument cb.call(attrval) else raise ArgumentError("wrong number of arguments in callback (#{cb.arity} for #{arg.size})") end end @parsed_options = true end
puterror(string)
click to toggle source
Output an error message, prefixed with the tool name.
# File lib/elf/tools.rb, line 49 def self.puterror(string) return if @quiet @output_mutex.synchronize { $stderr.puts "#{to_s}: #{string}" } end
putnotice(message)
click to toggle source
Output a notice about a file, do not prefix with the tool name, do not print if doing recursive analysis
# File lib/elf/tools.rb, line 59 def self.putnotice(message) return if @quiet or @recursive @output_mutex.synchronize { $stderr.puts message } end
results()
click to toggle source
# File lib/elf/tools.rb, line 201 def self.results end
single_target?()
click to toggle source
# File lib/elf/tools.rb, line 110 def self.single_target? raise Exception.new("You can't call this until options are parsed") unless @parsed_options # We consider having a single target means that we're given exactly # one argument, and that argument is not a targets' list itself. return @targets.size == 1 end
thread_execute(filename)
click to toggle source
# File lib/elf/tools.rb, line 136 def self.thread_execute(filename) # If our child set @execution_threads to nil, it doesn't really # support running multithreaded, this is the case for instance # of the link collision harvester script, where the db access # and pkey generation has to be synchronous. unless @execution_threads.nil? @execution_threads.add(Thread.new { execute(filename) }) else execute(filename) end end
to_s()
click to toggle source
Gets the name of the tool
# File lib/elf/tools.rb, line 44 def self.to_s File.basename($0) end
try_execute(filename)
click to toggle source
Try to execute the analysis function on a given filename argument.
# File lib/elf/tools.rb, line 151 def self.try_execute(filename) begin # find the file type so we don't have to look it up many times; if # we're running a recursive scan, we don't want to look into # symlinks as they might create loops or duplicate content, while # we usually want to check them out if they are given directly in # the list of files to analyse file_stat = if @recursive File.lstat(filename) else File.stat(filename) end # if the path references a directory, and we're going to run # recursively, descend into that. if @recursive and file_stat.directory? Dir.foreach(filename) do |children| next if children == "." or children == ".." try_execute(File.join(filename, children)) end # if the path does not point to a regular file, ignore it elsif not file_stat.file? putnotice "#{filename}: not a regular file" else thread_execute(filename) end rescue Errno::ENOENT, Errno::EACCES, Errno::EISDIR, Elf::File::NotAnELF => e # The Errno exceptions have their message ending in " - FILENAME", # so we take the FILENAME out and just use the one we know # already. We also take out the final dot on the phrase so that # we follow the output messages from other tools, like cat. putnotice "#{filename}: #{e.message.gsub(/\.? - .*/, '')}" rescue SystemExit => e exit e.status rescue Exception => e puterror "#{filename}: #{e.message} (#{e.class})\n\t#{e.backtrace.join("\n\t")}" exit -1 end end