Skip to content

Commit

Permalink
Add updater-polyglot extraction & zlib inflation; Switch from UEFIDum…
Browse files Browse the repository at this point in the history
…p to UEFIExtract; Decrease verbosity;
  • Loading branch information
coderobe committed Jul 8, 2018
1 parent 3edc877 commit ea89d34
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 57 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Laptops with NVIDIA Optimus graphics often have the dGPU VBIOS integrated in the
## Dependencies
- Ruby
- bundler **(a ruby gem)**
- [UEFIDump](https://github.com/LongSoft/UEFITool) **(note: UEFIDump can be found in the branch `new_engine`)**
- [UEFIExtract](https://github.com/LongSoft/UEFITool) **(note: UEFIExtract can be found in the branch `new_engine`)**
- [rom-parser](https://github.com/awilliam/rom-parser)
- p7zip **(optional)**
- [innoextract](https://github.com/dscharrer/innoextract) **(optional)**
Expand Down
4 changes: 4 additions & 0 deletions src/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ def extract file=nil
puts "no file specified".colorize(:red)
return
end
if File.directory? wd
puts "dirty work directory! remove #{wd}".colorize(:red)
exit 1
end
FileUtils.mkdir_p wd
Kernel.at_exit do
puts "Cleaning up garbage".colorize(:blue)
Expand Down
25 changes: 25 additions & 0 deletions src/extract-polyglot.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module VBiosFinder
class Extract
def self.polyglot file
File.open file, "r:ASCII-8BIT" do |data|
regex = /(.{4})\xAA\xEE\xAA\x76\x1B\xEC\xBB\x20\xF1\xE6\x51(.{1})/n
input = data.read
matches = regex.match input
payload_size = matches.captures.first.unpack('V').first
payload_offset = matches.offset(2).last
data.seek payload_offset
File.open "#{file}-polyglot", "w:ASCII-8BIT" do |outdata|
outdata.write data.read
end
end
end
end
class Test
def self.polyglot file
File.open file, "r:ASCII-8BIT" do |data|
regex = /(.{4})\xAA\xEE\xAA\x76\x1B\xEC\xBB\x20\xF1\xE6\x51.{1}/n
return !(regex.match(data.read).nil?)
end
end
end
end
10 changes: 5 additions & 5 deletions src/extract-uefi.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@ module VBiosFinder
class Extract
def self.uefi file
begin
line = Cocaine::CommandLine.new("UEFIDump", ":file")
puts line.run(file: file)
line = Cocaine::CommandLine.new("UEFIExtract", ":file all")
line.run(file: file)
rescue Cocaine::ExitStatusError => e
# TODO: fix Test::uefi before uncommenting this
# puts e.message
puts e.message
return
end
end
end
class Test
def self.uefi file
begin
line = Cocaine::CommandLine.new("UEFIDump", ":file")
puts line.run(file: file)
line = Cocaine::CommandLine.new("UEFIExtract", ":file report")
line.run(file: file)
true
rescue Cocaine::ExitStatusError => e
false
Expand Down
21 changes: 21 additions & 0 deletions src/extract-zlib.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
require "zlib"

module VBiosFinder
class Extract
def self.zlib file
File.open file, "r:ASCII-8BIT" do |data|
File.open "#{file}-zlib", "w:ASCII-8BIT" do |outdata|
outdata.write Zlib::Inflate.inflate(data.read)
end
end
end
end
class Test
def self.zlib file
File.open file, "r:ASCII-8BIT" do |data|
regex = /^\x78\x9C/n
return !(regex.match(data.read).nil?)
end
end
end
end
4 changes: 2 additions & 2 deletions src/extraction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
module VBiosFinder
class Extraction
def self.attempt method_s, requires, reason, file
if Utils::installed?(requires, reason) && Test.method(method_s).call(file)
if Test.method(method_s).call(file)
puts "found #{requires} archive".colorize(:green)
Extract.method(method_s).call(file)
else
puts "not extractable with #{requires}".colorize(:red)
#puts "not extractable with #{requires}".colorize(:red)
end
end
end
Expand Down
113 changes: 65 additions & 48 deletions src/methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,66 +6,83 @@
require "./src/extract-upx"
require "./src/extract-uefi"
require "./src/extract-7z"
require "./src/extract-polyglot"
require "./src/extract-zlib"

module VBiosFinder
class Main
def self.run file
puts "trying to extract #{file}"
@extractions = []
@extractions << [:polyglot, "polyglot", "builtin module for polyglot files"]
@extractions << [:zlib, "zlib", "builtin module for zlib data"]
@extractions << [:innosetup, "innoextract", "required for Inno Installers"]
@extractions << [:upx, "upx", "required for UPX executables"]
@extractions << [:p7zip, "7z", "required for 7z (self-extracting) archives"]

def self.extract file
puts "trying to extract #{file}"
# Attempt all known extraction methods
extractions = []
extractions << [:innosetup, "innoextract", "required for Inno Installers", file]
extractions << [:upx, "upx", "required for UPX executables", file]
extractions << [:p7zip, "7z", "required for 7z (self-extracting) archives", file]
extractions.each{|e| Extraction::attempt(*e)}
@extractions.each{|e| Extraction::attempt(*e, file)}
end

def self.run file
@extractions.select! do |sym, requires, reason, arg|
reason.start_with?("builtin") || Utils::installed?(requires, reason)
end

files = Utils::get_new_files
files << file

while files.size > 0
files.each do |e|
extract e
end
files = Utils::get_new_files
end

# Try to find an UEFI bios image now
if Utils::installed?("UEFIDump", "required for UEFI images") && Test::uefi(file)
puts "found UEFI image".colorize(:green)
outpath = "#{Dir.pwd}/../output"
FileUtils.mkdir_p outpath
FileUtils.cp file, "#{outpath}/bios_#{File.basename file}"
Extract::uefi file
puts "extracted. filtering modules...".colorize(:blue)
modules = Find.find("#{file}.dump").reject{|e| File.directory? e}.select{|e| e.end_with? ".bin"}
puts "got #{modules.length} modules".colorize(:blue)
puts "finding vbios".colorize(:blue)
line = Cocaine::CommandLine.new("file", "-b :file")
modules = modules.select{|e| line.run(file: e).include? "Video"}
if modules.length > 0
puts "#{modules.length} possible candidates".colorize(:green)
if Utils::installed?("rom-parser", "required for proper rom naming & higher accuracy")
modules.each do |mod|
rom_parser = Cocaine::CommandLine.new("rom-parser", ":file")
begin
romdata = rom_parser.run(file: mod)
romdata = romdata.split("\n")[1].split(", ").map{|e| e.split(": ")}.to_h rescue nil
unless romdata.nil? || romdata['vendor'].nil? || romdata['device'].nil?
puts "Found VBIOS for device #{romdata['vendor']}:#{romdata['device']}!".colorize(:green)
new_filename = "vbios_#{romdata['vendor']}_#{romdata['device']}.rom"
FileUtils.cp(mod, "#{outpath}/#{new_filename}")
end
rescue Cocaine::ExitStatusError => e
puts "can't determine vbios type"
puts "extracting uefi data".colorize(:blue)
Find.find(".").reject{|e| File.directory? e}.each do |e|
puts "trying to extract #{e}"
Extraction::attempt(:uefi, "UEFIExtract", "required for UEFI images", e)
end

outpath = "#{Dir.pwd}/../output"
FileUtils.mkdir_p outpath
FileUtils.cp file, "#{outpath}/bios_#{File.basename file}"
puts "filtering for modules...".colorize(:blue)
uefibins = Find.find(".").reject{|e| File.directory? e}.select{|e| e.end_with? ".bin"}
puts "got #{uefibins.length} modules".colorize(:blue)
puts "finding vbios".colorize(:blue)
line = Cocaine::CommandLine.new("file", "-b :file")
modules = uefibins.select{|e| line.run(file: e).include? "Video"}
if modules.length > 0
puts "#{modules.length} possible candidates".colorize(:green)
if Utils::installed?("rom-parser", "required for proper rom naming & higher accuracy")
modules.each do |mod|
rom_parser = Cocaine::CommandLine.new("rom-parser", ":file")
begin
romdata = rom_parser.run(file: mod)
romdata = romdata.split("\n")[1].split(", ").map{|e| e.split(": ")}.to_h rescue nil
unless romdata.nil? || romdata['vendor'].nil? || romdata['device'].nil?
puts "Found VBIOS for device #{romdata['vendor']}:#{romdata['device']}!".colorize(:green)
new_filename = "vbios_#{romdata['vendor']}_#{romdata['device']}.rom"
FileUtils.cp(mod, "#{outpath}/#{new_filename}")
end
end
else
modules.each do |mod|
FileUtils.cp(mod, outpath)
rescue Cocaine::ExitStatusError => e
puts "can't determine vbios type"
end
end
puts "Job done. Extracted files can be found in #{outpath}".colorize(:green)
else
puts "no candidates found :(".colorize(:red)
modules.each do |mod|
FileUtils.cp(mod, outpath)
end
end
exit 0
puts "Job done. Extracted files can be found in #{outpath}".colorize(:green)
else
puts "not an uefi image"
end

Utils::get_new_files.each do |e|
puts
run e
puts "no candidates found :(".colorize(:red)
if uefibins.length > 0
puts "input contains uefi data but no vbios could be found".colorize(:yellow)
puts "the vbios might not be baked into the input!".colorize(:yellow)
end
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion src/utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def self.get_new_files
end
def self.installed? program, reason="optional"
if find_executable(program).nil?
puts "Install '#{program}' on your system (#{reason})"
puts "Install '#{program}' on your system (#{reason})".colorize(:red)
false
else
true
Expand Down

0 comments on commit ea89d34

Please sign in to comment.