require 'getoptlong' require 'Logger' require 'pp' require 'securerandom' require 'fileutils' # Setting up RS_BUILDBRANCH = ENV['RS_BUILDBRANCH'] RS_TOOLSROOT = ENV['RS_TOOLSROOT'] PROTECTION_PATH = RS_TOOLSROOT + "/script/coding/protection" GENERATED_PATH = PROTECTION_PATH + "/generated" COMMON_RUBY_PATH = RS_TOOLSROOT + "/script/coding/protection/common/ruby" $LOAD_PATH << COMMON_RUBY_PATH require 'RsgLog' LOG_SEVERITY_LEVEL = Logger::INFO CURR_TIME = Time.now.strftime("%Y%m%d.%H.%M.%S") class Parameters attr_reader :game_path attr_reader :debug def initialize @game_path = "" #false @debug = false @opts = GetoptLong.new( [ '--help', '-h', GetoptLong::NO_ARGUMENT ], [ '--path', '-p', GetoptLong::REQUIRED_ARGUMENT ], [ '--debug', '-d', GetoptLong::NO_ARGUMENT ] ) end def PrintHelp() puts "Usage: ruby protectit.rb -r [options] " puts " " puts "-h --help Display this " puts "-p --path Required. Full path to the executable." end def ParseArguments() @opts.each do |opt, arg| case opt when '--help' PrintHelp() exit when '--path' @game_path = arg when '--debug' @debug = true end end if(@game_path == "" || !File.exists?(@game_path)) puts "Invalid path to file \"" + @game_path + "\"\n\n" PrintHelp() exit end end end # Then our generated path begin Dir.mkdir(GENERATED_PATH) rescue Exception =>e puts e.message end log = RsgLog::RsgLog.instance() log.SetParameters(GENERATED_PATH,CURR_TIME, LOG_SEVERITY_LEVEL) # parameters = Parameters.new parameters.ParseArguments() gamePath = parameters.game_path protectionPath = RS_TOOLSROOT + "/script/coding/protection" rttiHandlingPath = protectionPath + "/rttihandling" # Create our storage paths replaceStorePath = rttiHandlingPath + "/replaceStrings.store" warningStorePath = rttiHandlingPath + "/warningStrings.store" # Build our strings command, and execute it stringsPath = rttiHandlingPath + "/strings.exe" stringsCmd = stringsPath + " --radix=d \"" + gamePath + "\"" stringsOutput = `#{stringsCmd}` # Build our new file names # Handle frozen status, if necessary if (gamePath.frozen?) gamePath = gamePath.dup end extension = File.extname(gamePath); gamePath.slice! "#{extension}" logPath = gamePath + ".stringWarnings.log" replacementslogPath = gamePath + ".stringReplacements.log" gameUnpatchedPath = gamePath + ".unpatchedstrings#{extension}" gamePatchedPath = gamePath + ".patchedstrings#{extension}" gamePath += "#{extension}" replaceHash = Hash.new(0) # Read from our storage files replaceStoreLines = File.read(replaceStorePath) warningStoreLines = File.read(warningStorePath) # Create our replacing hash replaceHash = Hash.new(0) replaceStoreLines.each_line do |replaceLine| stringsOutput.each_line do |stringsLine| if ( stringsLine =~ /#{replaceLine}/) splitString = stringsLine.split(' ') replaceHash[splitString[0]] = splitString[1].strip; end end end # Create our replacing hash warningHash = Hash.new(0) warningStoreLines.each_line do |warningLine| stringsOutput.each_line do |stringsLine| if ( stringsLine =~ /#{warningLine}/i) splitString = stringsLine.split(' ') stringsLine.slice! "#{splitString[0]}" warningHash[splitString[0]] = stringsLine.strip end end end # Read our game file in binary gameBytes = open(gamePath, "rb") {|io| io.read } # Create our log file handler replacementslogFileHandle = File.open(replacementslogPath, 'w') replacementslogFileHandle.write("List of detected strings, listed by their addresses and their full strings\n") # Create our log file handler logFileHandle = File.open(logPath, 'w') logFileHandle.write("List of detected strings, listed by their addresses and their full strings\n") # Create our output EXE if parameters.debug == false outFile = File.open(gamePatchedPath, 'wb') end i = 0 replaceHash.each { |key, value| stringToReplace = value replacementslogFileHandle.write("#{stringToReplace} / #{key.to_s}\n") if stringToReplace.length > 3 puts "Replacing #{stringToReplace}" for j in 0...stringToReplace.length myChar = 1 + rand(255 - 1) gameBytes[key.to_i+j]=myChar.chr end end } warningHash.each { |key, value| stringToCheck = value logFileHandle.write("0x" + key.hex.to_s + "\t" + value + "\n") } if parameters.debug == false outFile.write(gameBytes) end # Close our handles logFileHandle.close if parameters.debug == false outFile.close # Now lets move the files to their appropriately names FileUtils.mv(gamePath, gameUnpatchedPath) FileUtils.mv(gamePatchedPath, gamePath) end