Tutorial How to Decrypt LUA files

Killerdon

Platinian
Intro:
There's a bunch of tries to to decrypting lua but none of it isnt clear enough how to do it. I'm aware that this approach isnt good enough, because too much step that you'll not need to do but i'm still write it instead. Code in this tutorial ofcourse just bunch of copy-pasta stackoverflow.

Prerequisites
1. Frida (optional)
2. Disassembler (IDA, r2, ..)
3. Python (optional) (I'll use python in this tutorial)
4. A little knowledge about this

What will you need to do?
1. Get the KEY for decryption,
2. Write a script for decryption,
3. Edit the lua (Self explanation),
4. Encrypt back the file (Self explaination) (Same as step 2, but you'll encrypt instead of decrypt),
5. PROFIT.

---- Step by step ----

Get the KEY for decryption
There's bunch of way to do it, some of them:
1. XREFS for XXTeaLuaLoader::setXXTeaKey(string), and you can see it clearly. Most used methods among many games.
nJX33Yr.png

2. Use Frida. I'll explain it on 2nd post.
3. [Q] Angry Birds Rio encrypts settings/highscores with AES
4. etc.. You get the idea.

Write a script for decryption
This is an example of use for XXTEA encryption, requirements(xxtea-py)


Code (Text):





#!/usr/bin/env python
import xxtea

chiper = open("assets/script/fund.lua", "rb").read()

out = open("out.lua", "wb")

key = b'mrgj'

out.write(xxtea.encrypt(chiper, key))

out.close()END
Example of use of frida (GitHub - antojoseph/frida-android-hooks: Lets you hook Method Calls in Frida ( Android ))

As described here,

Opening the lua files with hex editor reveals that they use XXTEA block cipher.

Analyze libjinqu.so and it blatantly shows the following decryption subroutines:
xxtea_decrypt
cocos2d::extra::CCCrypto::decryptXXTEA

Get a pseudocode generator and copy the program in C++.
. We need to put a hook either at xxtea_decrypt or cocos2d::extra::CCCrypto::decryptXXTEA. Then prints out the arguments passed.
We know that args[2] is the one holding the pointer to key from decompile xxtea_decrypt lib.so
Oh5SCFC.png

Explaination, v9 is the one holding the chiper text, v30 chipertext len(?), v13 pointer to key, v14 is key.length.
Its obvious if we want to leak the key we need to print args[3] bytes at args[2]. This is an example of use for it.



#!/usr/bin/env python
import frida
import sys

package_name = "com.gamebau.pq"

def get_messages_from_js(message, data):
print(message)

jsc = """
Interceptor.attach (Module.findExportByName( "libgame.so", "xxtea_decrypt"), {
onEnter: function (args) {
console.log("----------------BEGIN----------------");
console.log(hexdump(Memory.readByteArray(args[2], 12),{
offset: 0,
length: 12,
header: true,
ansi: true
}));
},
onLeave: function (retval) {
console.log("Decrypt:");
console.log(hexdump(Memory.readByteArray(retval, 16),{
offset: 0,
length: 16,
header: true,
ansi: true
}));
console.log("-----------------END-----------------");
}
});
"""

process = frida.get_usb_device().attach(package_name)
script = process.create_script(jsc)
script.on('message',get_messages_from_js)
script.load()
sys.stdin.read()
profit,
gohBm09.png


--Update, forgot to mention about this. Another note, some games tries to pack the assets with common file compressor. While loading it, it tries to unpack the assets on stream. As you can see on the image, its PK file header. With simple google search you can deduce its a zip alike compression. Try to extract the decrypted file with 7zip/Winrar/etc.. and you could see the unpacked file.

Image:
gohBm09.png



Credits: Wobm And Stack Overflow
 
Back
Top Bottom