support fetch builds from repo

This commit is contained in:
david942j 2017-02-12 00:32:48 +08:00
parent 9cb7af4876
commit a6c30074cd
4 changed files with 82 additions and 7 deletions

View File

@ -45,11 +45,14 @@ module OneGadget
require_all if BUILDS.empty? require_all if BUILDS.empty?
return BUILDS[build_id] if BUILDS.key?(build_id) return BUILDS[build_id] if BUILDS.key?(build_id)
# fetch remote builds # fetch remote builds
# table = OneGadget::Helper.remote_builds.find { |c| c.include?(build_id) } table = OneGadget::Helper.remote_builds.find { |c| c.include?(build_id) }
# return [] if table.nil? # remote doesn't have this one. return [] if table.nil? # remote doesn't have this one either.
# builds found in remote! Ask update gem and download remote gadgets. # builds found in remote! Ask update gem and download remote gadgets.
# TODO: fetch remote builds information. OneGadget::Helper.ask_update(msg: 'The desired one-gadget can be found in lastest version!')
[] tmp_file = OneGadget::Helper.download_build(table)
require tmp_file.path
tmp_file.unlink
BUILDS[build_id]
end end
# Add a gadget, for scripts in builds/ to use. # Add a gadget, for scripts in builds/ to use.

View File

@ -1,5 +1,8 @@
require 'pathname' require 'pathname'
require 'shellwords' require 'shellwords'
require 'net/http'
require 'openssl'
require 'tempfile'
module OneGadget module OneGadget
# Define some helpful methods here. # Define some helpful methods here.
@ -60,6 +63,65 @@ module OneGadget
color = cc.key?(sev) ? cc[sev] : '' color = cc.key?(sev) ? cc[sev] : ''
"#{color}#{str.sub(cc[:esc_m], color)}#{cc[:esc_m]}" "#{color}#{str.sub(cc[:esc_m], color)}#{cc[:esc_m]}"
end end
# Fetch the latest release version's tag name.
# @return [String] The tag name, in form +vx.x.x+.
def latest_tag
latest = url_request('https://github.com/david942j/one_gadget/releases').scan(%r{/tree/v([\d.]+)"}).map do |tag|
Gem::Version.new(tag.first)
end.max.to_s
'v' + latest
end
# Get the url which can fetch +filename+ from remote repo.
# @param [String] filename
# @return [String] The url.
def url_of_file(filename)
raw_file_url = 'https://raw.githubusercontent.com/david942j/one_gadget/@tag/@file'
raw_file_url.gsub('@tag', latest_tag).gsub('@file', filename)
end
# Download the latest version of +file+ in +lib/one_gadget/builds/+ from remote repo.
#
# @param [String] file The filename desired.
# @return [Tempfile] The temp file be created.
def download_build(file)
temp = Tempfile.new(['gadgets', file + '.rb'])
url_request(url_of_file(File.join('lib', 'one_gadget', 'builds', file + '.rb')))
temp.write url_request(url_of_file(File.join('lib', 'one_gadget', 'builds', file + '.rb')))
temp.close
temp
end
# Get the latest builds list from repo.
# @return [Array<String>] List of build ids.
def remote_builds
url_request(url_of_file('builds_list')).lines.map(&:strip)
end
# Get request.
# @param [String] url The url.
# @return [String] The request response body.
def url_request(url)
# TODO: add timeout to handle github crashed or in no network environment.
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = ::OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Get.new(uri.request_uri)
response = http.request(request)
response.body
end
# Show the message of ask user to update gem.
# @return [void]
def ask_update(msg: '')
name = 'one_gadget'
cmd = colorize("gem update #{name}")
STDERR.puts msg + "\n" + "Update with: $ #{cmd}"
end
end end
extend ClassMethods extend ClassMethods
end end

View File

@ -7,6 +7,10 @@ describe OneGadget::Gadget do
OneGadget::Gadget.add(@build_id, 0x1234, constraints: ['[rsp+0x30] == NULL', 'rax == 0']) OneGadget::Gadget.add(@build_id, 0x1234, constraints: ['[rsp+0x30] == NULL', 'rax == 0'])
end end
after(:all) do
OneGadget::Gadget::ClassMethods::BUILDS.delete @build_id
end
it 'inspect' do it 'inspect' do
expect(OneGadget::Gadget.builds(@build_id).map(&:inspect).join).to eq <<-EOS expect(OneGadget::Gadget.builds(@build_id).map(&:inspect).join).to eq <<-EOS
offset: 0x1234 offset: 0x1234

View File

@ -1,9 +1,7 @@
require 'one_gadget' require 'one_gadget'
describe 'one_gadget' do describe 'one_gadget' do
before(:all) do before(:each) do
# To force require all again.
OneGadget::Gadget::ClassMethods::BUILDS.clear
@build_id = '60131540dadc6796cab33388349e6e4e68692053' @build_id = '60131540dadc6796cab33388349e6e4e68692053'
@libcpath = File.join(File.dirname(__FILE__), 'data', 'libc-2.19.so') @libcpath = File.join(File.dirname(__FILE__), 'data', 'libc-2.19.so')
end end
@ -21,5 +19,13 @@ describe 'one_gadget' do
it 'invalid' do it 'invalid' do
expect { OneGadget.gadgets(build_id: '^_^') }.to raise_error(ArgumentError, 'invalid BuildID format: "^_^"') expect { OneGadget.gadgets(build_id: '^_^') }.to raise_error(ArgumentError, 'invalid BuildID format: "^_^"')
end end
it 'fetch from remote' do
entry = OneGadget::Gadget::ClassMethods::BUILDS.delete(@build_id)
OneGadget::Gadget::ClassMethods::BUILDS[:a] = 1
expect(OneGadget.gadgets(build_id: @build_id)).not_to be_empty
OneGadget::Gadget::ClassMethods::BUILDS.delete(:a)
OneGadget::Gadget::ClassMethods::BUILDS[@build_id] = entry unless entry.nil?
end
end end
end end