283 lines
7.8 KiB
Ruby
Executable File
283 lines
7.8 KiB
Ruby
Executable File
require 'getoptlong'
|
|
require 'csv'
|
|
# Setting up
|
|
RAGE_DIR = ENV['RAGE_DIR'].gsub(/\\/, "/")
|
|
RS_CODEBRANCH = ENV['RS_CODEBRANCH'].gsub(/\\/, "/")
|
|
RS_BUILDBRANCH = ENV['RS_BUILDBRANCH'].gsub(/\\/, "/")
|
|
RS_TOOLSROOT = ENV['RS_TOOLSROOT'].gsub(/\\/, "/")
|
|
RS_TITLE = ENV['RS_TITLE']
|
|
USER_PROFILE = ENV['USERPROFILE']
|
|
USER_DESKTOP = USER_PROFILE + "/Desktop"
|
|
USERNAME = ENV['USERNAME']
|
|
PROTECTION_PATH = RS_TOOLSROOT + "/script/coding/protection"
|
|
COMMON_RUBY_PATH = RS_TOOLSROOT + "/script/coding/protection/common/ruby"
|
|
TOOL_PATH = PROTECTION_PATH + "/rpfEncryptionFinder"
|
|
GENERATED_PATH = PROTECTION_PATH + "/generated"
|
|
CURR_TIME = Time.now.strftime("%Y%m%d.%H.%M.%S")
|
|
$LOAD_PATH << COMMON_RUBY_PATH
|
|
|
|
# Creating our logger
|
|
require 'RsgLog'
|
|
LOG_SEVERITY_LEVEL = Logger::INFO
|
|
log = RsgLog::RsgLog.instance()
|
|
log.SetParameters(GENERATED_PATH,CURR_TIME, LOG_SEVERITY_LEVEL)
|
|
|
|
# Alright, lets start the fun
|
|
|
|
# Do the work for our parameters
|
|
|
|
class Parameters
|
|
attr_reader :path
|
|
attr_reader :outdir
|
|
def initialize
|
|
@outdir = ""
|
|
@path = ""
|
|
@opts = GetoptLong.new(
|
|
[ '--path', '-p', GetoptLong::REQUIRED_ARGUMENT ],
|
|
[ '--outdir', '-o', GetoptLong::REQUIRED_ARGUMENT ]
|
|
)
|
|
end
|
|
def PrintHelp()
|
|
RsgLog::RsgLog.instance().info("DNE Yet");
|
|
end
|
|
def ParseArguments()
|
|
@opts.each do |opt, arg|
|
|
case opt
|
|
when '--help'
|
|
PrintHelp()
|
|
exit
|
|
when '--path'
|
|
@path = arg
|
|
when '--outdir'
|
|
@outdir = arg
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
# Define a class for our results
|
|
class RpfItem
|
|
attr_accessor :file
|
|
attr_accessor :directory
|
|
attr_accessor :resource
|
|
attr_accessor :keyid
|
|
attr_accessor :path
|
|
|
|
@@array = Array.new
|
|
@@files = Array.new
|
|
@@rpffiles = Array.new
|
|
@@resources = Array.new
|
|
@@directories = Array.new
|
|
|
|
def self.all_instances
|
|
@@array
|
|
end
|
|
|
|
|
|
def self.all_rpffiles
|
|
@@rpffiles
|
|
end
|
|
|
|
def self.all_files
|
|
@@files
|
|
end
|
|
|
|
def self.all_resources
|
|
@@resources
|
|
end
|
|
|
|
def self.all_directories
|
|
@@directories
|
|
end
|
|
|
|
def initialize(path="", file=false, directory=false, resource=false, keyid="N/A")
|
|
@file = file
|
|
@directory = directory
|
|
@resource = resource
|
|
if resource == true
|
|
@keyid = "N/A"
|
|
else
|
|
@keyid = keyid
|
|
end
|
|
@path = path
|
|
|
|
|
|
if file == true
|
|
@@files << self
|
|
elsif directory == true
|
|
@@directories << self
|
|
elsif resource == true
|
|
@@resources << self
|
|
end
|
|
|
|
if File.extname(path) == ".rpf"
|
|
@@rpffiles << self
|
|
end
|
|
@@array << self
|
|
end
|
|
|
|
def to_s
|
|
"\nPath:\t#{@path}\nIsFile:\t#{@file}\nIsDir:\t#{@directory}\nIsRes:\t#{@resource}\nKeyId:\t#{@keyid}"
|
|
end
|
|
|
|
def to_array
|
|
{"PATH"=> @path, "KEYID"=>@keyid, "IS_FILE"=>@file, "IS_DIRECTORY"=>@directory, "IS_RESOURCE"=>@resource, "IS_RPF"=>(File.extname(path)==".rpf")}
|
|
end
|
|
end
|
|
log.info("Starting the magic...")
|
|
log.info("Parsing arguments...")
|
|
parameters = Parameters.new
|
|
parameters.ParseArguments()
|
|
|
|
|
|
if parameters.path == "" || (File::file?(parameters.path) == 0 && File.directory?(parameters.path) ==0)
|
|
parameters.PrintHelp()
|
|
log.error("Invalid path [#{parameters.path}] specified")
|
|
exit
|
|
elsif parameters.outdir == "" || File.directory?(parameters.path) ==0
|
|
parameters.PrintHelp()
|
|
log.error("Invalid output path [#{parameters.outdir}] specified")
|
|
exit
|
|
end
|
|
|
|
# Set whether we're starting from a directory or a file
|
|
isInputDirectory = false
|
|
isInputFile = false
|
|
|
|
if File::file?(parameters.path)
|
|
log.info("Input parameter is a file.")
|
|
isInputFile = true
|
|
elsif File::directory?(parameters.path)
|
|
log.info("Input parameter is a directory.")
|
|
isInputDirectory = true
|
|
end
|
|
|
|
# Declare our input array
|
|
inputArray = Array.new
|
|
# Now lets build our input set of data
|
|
if isInputDirectory == true
|
|
# Apparently glob only works when the slashes are set correctly
|
|
unixDir = parameters.path.gsub(/\\/, "/")
|
|
# Iterate over the dir
|
|
Dir.glob("#{unixDir}/*.rpf").each do |f|
|
|
inputArray << f
|
|
end
|
|
else
|
|
inputArray << parameters.path
|
|
end
|
|
|
|
|
|
# First lets nuke the contents of the directoryu
|
|
FileUtils.rm_rf("#{parameters.outdir}")
|
|
# Now rebuild it
|
|
|
|
def IterateRpfs(rpfArray, subdir)
|
|
log = RsgLog::RsgLog.instance()
|
|
recursiveArray = Array.new
|
|
|
|
begin
|
|
Dir.mkdir(subdir)
|
|
rescue Exception =>e
|
|
puts e.message
|
|
end
|
|
|
|
# Good, now lets call our extraction script
|
|
rpfArray.each { |inputFile|
|
|
log.info(inputFile)
|
|
|
|
|
|
# This needs to be looped up
|
|
cmd = "#{RS_TOOLSROOT}/ironlib/lib/RSG.Pipeline.RpfExtract.exe --output \"#{subdir}\" --verbose \"#{inputFile}\""
|
|
# Capture the output
|
|
log.info("Extracting \[#{inputFile}\] to \[#{subdir}\]...")
|
|
log.info(cmd)
|
|
output = `#{cmd}`
|
|
|
|
log.info("Completed extraction...")
|
|
|
|
regexp = Regexp.new('.*\[KEY\]\[(.*)\]\[DIR\]\[(.*)\]\[FILE\]\[(.*)\]\[RES\]\[(.*)\].*Extracting: (.*)\.')
|
|
|
|
itemCollection = Array.new
|
|
|
|
output.each do |line|
|
|
|
|
matchData = regexp.match(line.strip)
|
|
if matchData == nil
|
|
#log.debug("No bueno RegExp for #{line}")
|
|
else
|
|
keyid = matchData[1]
|
|
dir = false
|
|
file = false
|
|
res = false
|
|
if matchData[2].downcase == "true"
|
|
dir = true
|
|
end
|
|
if matchData[3].downcase == "true"
|
|
file = true
|
|
end
|
|
if matchData[4].downcase == "true"
|
|
res = true
|
|
end
|
|
path = matchData[5]
|
|
|
|
log.info(line)
|
|
if File.extname(path) == ".rpf" && path!=inputFile
|
|
outPath = File.dirname(path)
|
|
outPath = outPath + "/" + File.basename(path, ".rpf")
|
|
IterateRpfs(path, outPath)
|
|
else
|
|
RpfItem.new(path, file, dir, res, keyid)
|
|
end
|
|
end
|
|
end
|
|
|
|
}
|
|
end
|
|
|
|
IterateRpfs(inputArray, parameters.outdir)
|
|
|
|
log.info("Found #{RpfItem.all_instances.length} items in this pass...")
|
|
# File Statistics
|
|
log.info("\t#{RpfItem.all_files.length} Files found")
|
|
numTransformIT = 0
|
|
RpfItem.all_files.each do |file|
|
|
if file.keyid == "0xFEFFFFF"
|
|
numTransformIT = numTransformIT+1
|
|
end
|
|
end
|
|
log.info("\t\t#{numTransformIT} TransformIT Encrypted")
|
|
|
|
# RPF File Statistics
|
|
log.info("\t\t#{RpfItem.all_rpffiles.length} RPF Files ")
|
|
numTransformIT = 0
|
|
RpfItem.all_rpffiles.each do |file|
|
|
if file.keyid == "0xFEFFFFF"
|
|
numTransformIT = numTransformIT+1
|
|
end
|
|
end
|
|
log.info("\t\t\t#{numTransformIT} TransformIT Encrypted")
|
|
# Directory Statistics
|
|
log.info("\t#{RpfItem.all_directories.length} Directories")
|
|
|
|
# Resource Statistics
|
|
log.info("\t#{RpfItem.all_resources.length} Resources")
|
|
|
|
# Now lets write out a CSV
|
|
writeArray = Array.new
|
|
RpfItem.all_instances.each do |file |
|
|
writeArray << file.to_array
|
|
end
|
|
|
|
if writeArray == nil || writeArray.first == nil
|
|
log.error("Something was wrong with the output of the rpfLog file. Exiting out.")
|
|
exit
|
|
end
|
|
|
|
writeArrayColumns = writeArray.first.keys
|
|
|
|
CSV.open("myfile.csv", "w") do |csv|
|
|
csv << writeArrayColumns
|
|
writeArray.each do |row|
|
|
csv << row.values
|
|
end
|
|
end |