one_gadget as library, closed #47

This commit is contained in:
david942j 2018-10-23 07:49:34 -07:00
parent c8a5277d3c
commit 4a18b9eb0e
2 changed files with 74 additions and 68 deletions

View File

@ -4,70 +4,12 @@
# Main module.
module OneGadget
class << self
# The man entry of gem +one_gadget+.
# If want to find gadgets from file, it will search gadgets by its
# build id first.
#
# @param [String] file
# The relative path of libc.so.6.
# @param [String] build_id
# The BuildID of target libc.so.6.
# @param [Boolean] details
# Return gadget objects or offset only.
# @param [Boolean] force_file
# When +file+ is given, {OneGadget} will search gadgets according its
# build id first. +force_file = true+ to disable this feature.
# @param [Integer] level
# Output level.
# If +level+ equals to zero, only gadgets with highest successful probability would be output.
# @return [Array<OneGadget::Gadget::Gadget>, Array<Integer>]
# The gadgets found.
# @example
# OneGadget.gadgets(file: './libc.so.6')
# OneGadget.gadgets(build_id: '60131540dadc6796cab33388349e6e4e68692053')
def gadgets(file: nil, build_id: nil, details: false, force_file: false, level: 0)
ret = if build_id
OneGadget::Fetcher.from_build_id(build_id) || OneGadget::Logger.not_found(build_id)
else
from_file(OneGadget::Helper.abspath(file), force: force_file)
end
ret = refine_gadgets(ret, level)
ret.map!(&:offset) unless details
ret
rescue OneGadget::Error::Error => e
OneGadget::Logger.error("#{e.class.name.split('::').last}: #{e.message}")
[]
end
private
# Try from build id first, then file
def from_file(path, force: false)
OneGadget::Helper.verify_elf_file!(path)
gadgets = try_from_build(path) unless force
gadgets || OneGadget::Fetcher.from_file(path)
end
def try_from_build(file)
build_id = OneGadget::Helper.build_id_of(file)
return unless build_id
OneGadget::Fetcher.from_build_id(build_id, remote: false)
end
# Remove hard-to-reach-constrains gadgets according to level
def refine_gadgets(gadgets, level)
return [] if gadgets.empty?
return gadgets if level > 0 # currently only supports level > 0 or not
# remain gadgets with the fewest constraints
best = gadgets.map { |g| g.constraints.size }.min
gadgets.select { |g| g.constraints.size == best }
end
end
end
require 'one_gadget/helper'
require 'one_gadget/one_gadget'
require 'one_gadget/version'
# Shorter way to use one gadget.
# @param [String?] arg
# Can be either +build_id+ or path to libc.
@ -92,9 +34,3 @@ end
require 'one_gadget/update'
OneGadget::Update.check!
require 'one_gadget/error'
require 'one_gadget/fetcher'
require 'one_gadget/helper'
require 'one_gadget/logger'
require 'one_gadget/version'

View File

@ -0,0 +1,70 @@
require 'one_gadget/error'
require 'one_gadget/fetcher'
require 'one_gadget/helper'
require 'one_gadget/logger'
# Main module.
module OneGadget
class << self
# The man entry of gem +one_gadget+.
# If want to find gadgets from file, it will search gadgets by its
# build id first.
#
# @param [String] file
# The relative path of libc.so.6.
# @param [String] build_id
# The BuildID of target libc.so.6.
# @param [Boolean] details
# Return gadget objects or offset only.
# @param [Boolean] force_file
# When +file+ is given, {OneGadget} will search gadgets according its
# build id first. +force_file = true+ to disable this feature.
# @param [Integer] level
# Output level.
# If +level+ equals to zero, only gadgets with highest successful probability would be output.
# @return [Array<OneGadget::Gadget::Gadget>, Array<Integer>]
# The gadgets found.
# @example
# OneGadget.gadgets(file: './libc.so.6')
# OneGadget.gadgets(build_id: '60131540dadc6796cab33388349e6e4e68692053')
def gadgets(file: nil, build_id: nil, details: false, force_file: false, level: 0)
ret = if build_id
OneGadget::Fetcher.from_build_id(build_id) || OneGadget::Logger.not_found(build_id)
else
from_file(OneGadget::Helper.abspath(file), force: force_file)
end
ret = refine_gadgets(ret, level)
ret.map!(&:offset) unless details
ret
rescue OneGadget::Error::Error => e
OneGadget::Logger.error("#{e.class.name.split('::').last}: #{e.message}")
[]
end
private
# Try from build id first, then file
def from_file(path, force: false)
OneGadget::Helper.verify_elf_file!(path)
gadgets = try_from_build(path) unless force
gadgets || OneGadget::Fetcher.from_file(path)
end
def try_from_build(file)
build_id = OneGadget::Helper.build_id_of(file)
return unless build_id
OneGadget::Fetcher.from_build_id(build_id, remote: false)
end
# Remove hard-to-reach-constrains gadgets according to level
def refine_gadgets(gadgets, level)
return [] if gadgets.empty?
return gadgets if level > 0 # currently only supports level > 0 or not
# remain gadgets with the fewest constraints
best = gadgets.map { |g| g.constraints.size }.min
gadgets.select { |g| g.constraints.size == best }
end
end
end