When I looked at the file with a hex editor, I saw a lot of repeating patterns, which implied weak XOR encryption. Long strings of the 0x05
byte really made this seem likely, which I suspected were spaces (0x20
) in the original Lua file. I XOR'd every byte of the file with 0x25
to test this theory, and it worked! Here's the result:
EnterGame = { }
-- private variables
local loadBox
local enterGame
local motdWindow
clientBox = nil
local protocolLogin
local motdEnabled = true
local progressWindow
local startTime
-- private functions
local function onError(protocol, message, errorCode)
if loadBox then
loadBox:destroy()
loadBox = nil
end
if enterGame:getChildById('rememberPasswordBox'):isChecked() then
--local account = g_crypt.xorCrypt(G.account, 123)
--local password = g_crypt.xorCrypt(G.password, 123)
local account = g_crypt.encrypt(G.account)
local password = g_crypt.encrypt(G.password)
if account ~= "" and password ~= "" then
g_settings.set('account', account)
g_settings.set('password', password)
ServerList.setServerAccount(G.host, account)
ServerList.setServerPassword(G.host, password)
end
else
-- reset server list account/password
ServerList.setServerAccount(G.host, '')
ServerList.setServerPassword(G.host, '')
EnterGame.clearAccountFields()
end
local errorBox = displayErrorBox(tr('Login Error'), message)
connect(errorBox, { onOk = EnterGame.show })
end
local function onMotd(protocol, motd)
G.motdNumber = tonumber(motd:sub(0, motd:find("\n")))
G.motdMessage = motd:sub(motd:find("\n") + 1, #motd)
if motdEnabled then
end
end
local function onCharacterList(protocol, characters, account, otui)
-- Try add server to the server list
ServerList.add(G.host, G.port, g_game.getClientVersion())
if enterGame:getChildById('rememberPasswordBox'):isChecked() then
local account = g_crypt.encrypt(G.account)
local password = g_crypt.encrypt(G.password)
--local account = g_crypt.xorCrypt(G.account, 123)
--local password = g_crypt.xorCrypt(G.password, 123)
if account ~= "" and password ~= "" then
g_settings.set('account', account)
g_settings.set('password', password)
ServerList.setServerAccount(G.host, account)
ServerList.setServerPassword(G.host, password)
end
else
-- reset server list account/password
ServerList.setServerAccount(G.host, '')
ServerList.setServerPassword(G.host, '')
EnterGame.clearAccountFields()
end
loadBox:destroy()
loadBox = nil
CharacterList.create(characters, account, otui)
CharacterList.show()
if motdEnabled then
local lastMotdNumber = g_settings.getNumber("motd")
if G.motdNumber and G.motdNumber ~= lastMotdNumber then
g_settings.set("motd", G.motdNumber)
motdWindow = displayInfoBox(tr('Message of the day'), G.motdMessage)
connect(motdWindow, { onOk = function() CharacterList.show() motdWindow = nil end })
CharacterList.hide()
end
end
end
-- public functions
function EnterGame.init()
connect(g_app, { onExit = onExitFunc })
enterGame = g_ui.displayUI('entergame')
g_keyboard.bindKeyDown('Ctrl+G', EnterGame.openWindow)
local account = g_settings.get('account')
local password = g_settings.get('password')
local host = g_settings.get('host')
local port = g_settings.get('port')
local clientVersion = g_settings.getInteger('client-version')
local proxy = g_settings.get('proxy')
if clientVersion == 0 then clientVersion = 772 end
if port == nil or port == 0 then port = 7181 end
if account ~= "" then
EnterGame.setAccountName(account)
end
if password ~= "" then
EnterGame.setPassword(password)
end
enterGame:getChildById('serverHostTextEdit'):setText(host)
enterGame:getChildById('serverPortTextEdit'):setText(port)
clientBox = enterGame:getChildById('clientComboBox')
clientBox:addOption("Prosperity")
clientBox:addOption("Encounter")
clientBox:addOption("Redemption")
clientBox:addOption("War")
--clientBox:addOption("test")
clientBox:setCurrentOption(proxy)
clientBox.menuHeight = 97
--clientBox:hide()
enterGame:hide()
if g_app.isRunning() and not g_game.isOnline() then
enterGame:show()
end
end
function EnterGame.terminate()
disconnect(g_app, { onExit = onExitFunc })
g_keyboard.unbindKeyDown('Ctrl+G')
enterGame:destroy()
enterGame = nil
clientBox = nil
if motdWindow then
motdWindow:destroy()
motdWindow = nil
end
if loadBox then
loadBox:destroy()
loadBox = nil
end
if protocolLogin then
protocolLogin:cancelLogin()
protocolLogin = nil
end
cancelDownload()
EnterGame = nil
end
function EnterGame.show()
if modules.client.startBox or modules.client.failDownloadBox or modules.client.finishBox or modules.client.failCheckBox then return false end
if modules.client.updateBox and modules.client.updateBox:isVisible() then return false end
if g_game.isLogging() or CharacterList.isVisible() then return false end
if loadBox or progressWindow then return end
enterGame:show()
enterGame:raise()
enterGame:focus()
end
function EnterGame.hide()
enterGame:hide()
end
function EnterGame.openWindow()
if g_game.isOnline() then
CharacterList.show()
elseif not g_game.isLogging() and not CharacterList.isVisible() then
EnterGame.show()
end
end
function EnterGame.setAccountName(account)
local account = g_crypt.decrypt(account)
--local account = g_crypt.xorCrypt(account, 123)
enterGame:getChildById('accountNameTextEdit'):setText(account)
enterGame:getChildById('accountNameTextEdit'):setCursorPos(-1)
enterGame:getChildById('rememberPasswordBox'):setChecked(#account > 0)
end
function EnterGame.setPassword(password)
local password = g_crypt.decrypt(password)
--local password = g_crypt.xorCrypt(password, 123)
enterGame:getChildById('accountPasswordTextEdit'):setText(password)
end
function EnterGame.clearAccountFields()
local accountText = enterGame:getChildById('accountNameTextEdit')
local passwordText = enterGame:getChildById('accountPasswordTextEdit')
if accountText:getText() ~= "" then
accountText:clearText()
end
if passwordText:getText() ~= "" then
passwordText:clearText()
end
enterGame:getChildById('accountNameTextEdit'):focus()
g_settings.remove('account')
g_settings.remove('password')
end
function EnterGame.doLogin(cast, cams)
G.account = enterGame:getChildById('accountNameTextEdit'):getText()
G.password = enterGame:getChildById('accountPasswordTextEdit'):getText()
G.host = enterGame:getChildById('serverHostTextEdit'):getText()
G.port = tonumber(enterGame:getChildById('serverPortTextEdit'):getText())
local clientVersion = tonumber("772")
EnterGame.hide()
if g_game.isOnline() then
local errorBox = displayErrorBox(tr('Login Error'), tr('You are already logged in.'))
connect(errorBox, { onOk = EnterGame.show })
return
end
g_settings.set('host', G.host)
g_settings.set('port', G.port)
g_settings.set('client-version', clientVersion)
g_settings.set('proxy', clientBox:getCurrentOption().text)
protocolLogin = ProtocolLogin.create()
protocolLogin.onLoginError = onError
protocolLogin.onMotd = onMotd
protocolLogin.onCharacterList = onCharacterList
protocolLogin.onUpdateNeeded = onUpdateNeeded
loadBox = displayCancelBox(tr('Please wait'), tr('Your character list is being loaded. Please wait.'))
connect(loadBox, { onCancel = function(msgbox)
loadBox = nil
protocolLogin:cancelLogin()
EnterGame.show()
end })
g_game.setProtocolVersion(g_game.getClientProtocolVersion(clientVersion))
g_game.chooseRsa(G.host)
if modules.game_things.isLoaded() then
if clientBox:getCurrentOption().text == "Redemption" then
G.port = "7171"
elseif clientBox:getCurrentOption().text == "Prosperity" then
G.port = "7175"
elseif clientBox:getCurrentOption().text == "War" then
G.port = "7181"
elseif clientBox:getCurrentOption().text == "test" then
G.port = "7177"
elseif clientBox:getCurrentOption().text == "Encounter" then
G.port = "7185"
end
if cast then
G.account = ""
end
if cams then
G.account = ""
G.port = 7194
end
protocolLogin:login(G.host, G.port, G.account, G.password)
else
loadBox:destroy()
loadBox = nil
EnterGame.show()
end
end
function EnterGame.displayMotd()
if not motdWindow then
motdWindow = displayInfoBox(tr('Message of the day'), G.motdMessage)
motdWindow.onOk = function() motdWindow = nil end
end
end
function EnterGame.setDefaultServer(host, port, protocol)
local hostTextEdit = enterGame:getChildById('serverHostTextEdit')
local portTextEdit = enterGame:getChildById('serverPortTextEdit')
local clientLabel = enterGame:getChildById('clientLabel')
local accountTextEdit = enterGame:getChildById('accountNameTextEdit')
local passwordTextEdit = enterGame:getChildById('accountPasswordTextEdit')
if hostTextEdit:getText() ~= host then
hostTextEdit:setText(host)
portTextEdit:setText(port)
accountTextEdit:setText('')
passwordTextEdit:setText('')
end
end
function EnterGame.setUniqueServer(host, port, protocol, windowWidth, windowHeight)
local hostTextEdit = enterGame:getChildById('serverHostTextEdit')
hostTextEdit:setText(host)
hostTextEdit:setVisible(false)
hostTextEdit:setHeight(0)
local portTextEdit = enterGame:getChildById('serverPortTextEdit')
portTextEdit:setText(port)
portTextEdit:setVisible(false)
portTextEdit:setHeight(0)
local portLabel = enterGame:getChildById('portLabel')
portLabel:setVisible(false)
portLabel:setHeight(0)
local clientLabel = enterGame:getChildById('clientLabel')
clientLabel:setVisible(false)
clientLabel:setHeight(0)
local serverListButton = enterGame:getChildById('serverListButton')
serverListButton:setVisible(false)
serverListButton:setHeight(0)
serverListButton:setWidth(0)
local rememberPasswordBox = enterGame:getChildById('rememberPasswordBox')
if not windowWidth then windowWidth = 240 end
enterGame:setWidth(windowWidth)
if not windowHeight then windowHeight = 230 end
enterGame:setHeight(windowHeight)
end
function EnterGame.setServerInfo(message)
local label = enterGame:getChildById('serverInfoLabel')
label:setText(message)
end
function EnterGame.disableMotd()
motdEnabled = false
end