181 lines
5.3 KiB
Ruby
Executable File
181 lines
5.3 KiB
Ruby
Executable File
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 <release> [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)
|
|
|
|
# </commandLineArguments>
|
|
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
|