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