ZenHAX

Free Game Research Forum | Official QuickBMS support | twitter @zenhax | SSL HTTPS://zenhax.com
It is currently Mon Apr 12, 2021 5:42 am

All times are UTC




Post new topic  Reply to topic  [ 5 posts ] 
Author Message
PostPosted: Sun Dec 27, 2020 4:01 pm 

Joined: Thu Aug 07, 2014 10:28 pm
Posts: 363
If you have a unity game that you can't figure out the encryption for you can use this method to have the game decrypt the files for you.
Things you will need.
1. rooted android phone.
2. install python on your pc and then install Frida-tools (pip install frida-tools)
3. Frida server on your android phone.
4. Ida pro or ghidra to find the functions you want.

Step1.
load your unity games libil2cpp.so file into your disassembler of choice and then apply names to the functions using Il2CppDumper.
https://github.com/Perfare/Il2CppDumper
just load it into ida or ghidra and after it is finished analyzing it run the script that Il2CppDumper gave you.

Step2.
Find the function that is doing the decryption.
This can be found in unity games by looking at the LoadAssetBundle functions.
Lets look at this example.
com.tencent.hlfish
https://anonfiles.com/r3Ebcf35p5/com.te ... 711f9d_apk
So if I search for LoadAssetBundleSync in the function window I get 1 result
Image
and if i look at the pseudo code generated i see this function.
Image
HLArcade_HLUtils__CreateABFromEncryptFile
Now we go into this function we will notice 2 important things.
Image
The first thing is the load from memory function.
UnityEngine_AssetBundle__LoadFromMemory_20449300
All unity games decrypt their files into memory then load them from memory so we can see its taking in v7.
And if we go up a little bit we see v7 being created from HLArcade_HLFileCryptNew__DecryptFileNew
So lets hop into this function.
Image
looks like its taking a string (file path) and then decrypting it for us so lets see what it does when it runs.
you can see in the bottom left the function offset 00683014
so we are going to use Frida to see what its doing

Step3.
Install the apk onto your phone.
now use adb to setup frida server (Magisk can do this part as a plugin for you if you have it installed).
https://github.com/frida/frida/releases frida-server-14.2.2-android-arm64.xz (extract this with 7z)
adb push c:\frida-server-14.2.2-android-arm64 /data/local/tmp/frida-server
now do adb shell
then type su to change to root mode
now change to the directory /data/local/tmp
cd /data/local/tmp
and make Frida server executable
chmod 777 ./frida-server
now run Frida server
./frida-server

Step4
test and make sure you can see your device in Frida
(Frida installs itself into the scripts directory in your python install)
frida-ps.exe -U
and you should see the running programs on your phone.
Image

Step5
lets launch or game and attach to it with Frida.
frida.exe -U -f com.tencent.hlfish
and it should show a black screen on your phone and 'your command prompt should look like this.
Image
if you typed %resume the game would start up like normal with Frida attached but we want o write our monitor code first.
Code:
var moduleName = "libil2cpp.so"; 
var nativeFuncAddr = 0x00683014; //
 
Interceptor.attach(Module.findExportByName(null, "dlopen"), {
    onEnter: function(args) {
        this.lib = Memory.readUtf8String(args[0]);
        console.log("dlopen called with: " + this.lib);
    },
    onLeave: function(retval) {
        if (this.lib.endsWith(moduleName)) {
            console.log("ret: " + retval);
            var baseAddr = Module.findBaseAddress(moduleName);
            Interceptor.attach(baseAddr.add(nativeFuncAddr), {
                onEnter: function(args) {
                    console.log("[-] hook invoked");
                    //var keyDump = Memory.readByteArray(args[0], 0x300);
                    //var keyDump2 = Memory.readByteArray(args[1], 0x300);
                    //console.log(hexdump(keyDump));
                    //console.log(hexdump(keyDump2));
                    console.log(JSON.stringify({
                        a0: args[0],
                        a1: args[1],
                        a2: args[2]
                    }, null, '\t'));
                },
        onLeave: function (retval) {
        console.log(retval);
        //var keyDump2 = Memory.readByteArray(retval, 0x300);
        //console.log(hexdump(keyDump2));
        }
            });
        }
    }
});

if you paste this in it should look like this
Image
if you see any red text you did something wrong and check your commands again.
This code is hooking when libil2cpp.so is loaded then hooking the function at address 0x00683014 in that .so and printing its arguments and return value.
so lets type %resume and see if we get a hit.
Image
We found the module loading.
Image
and we hooked the function.
so the parameters passed to the function are.
"a0": "0x0",
"a1": "0xb1a845f0",
"a2": "0xc62c3b84"
so the first parameter is 0
the 2nd is a pointer to the file name
and the 3rd is a pointer to the file size that this function writes there.
and the return value is a pointer to the decrypted asset bundle in memory.
we can look at these using this command
Memory.readByteArray(new NativePointer(0xb1a845f0),0x100);
hey look the first file it decrypts
Image
and if we look at the next part
its just all 0's where it wants to write the size to.
and if we look at the return address.
Image
bingo a unity header

so now we just need a function to create our string for us for the file we want to decrypt.
if we search for CreateString it comes right up.
System_String_o *__cdecl System_String__CreateString(System_String_o *this, int8_t *value, const MethodInfo *method)
Image

so lets try creating a string.
You will get an error if you do this outside the hook code but it will still work
Code:
var moduleName = "libil2cpp.so"; 
var moduleBase = Module.findBaseAddress(moduleName);
var careate_str = ptr(parseInt(moduleBase) +   0x00FCA590 )
var careate_str_f = new NativeFunction(careate_str, 'pointer' , [ 'pointer' , 'pointer' ]);
var root = '/storage/emulated/0/Android/data/com.tencent.hlfish/files/AssetBundles/'
var path = 'kernel'
var path_str_utf8 = Memory.allocUtf8String(root + path)
var path_str = careate_str_f(new NativePointer(path_str_utf8), path_str_utf8);

Memory.readByteArray(new NativePointer(path_str), 0x100);

Image
so lets try decrypting that file.
So restart the game with Frida and just type %resume till you are at the logon page.
now lets decrypt this file
Image
we see the file is 0x14F2AC in size so les dump it
Code:
//Construction parameter 2 path parameter
var moduleName = "libil2cpp.so";
var moduleBase = Module.findBaseAddress(moduleName);
var careate_str = ptr(parseInt(moduleBase) +   0x00FCA590 )
var careate_str_f = new NativeFunction(careate_str, 'pointer' , [ 'pointer' , 'pointer' ]);
var root = '/storage/emulated/0/Android/data/com.tencent.hlfish/files/AssetBundles/'
var path = 'kernel'
var path_str_utf8 = Memory.allocUtf8String(root + path)
var path_str = careate_str_f(new NativePointer(path_str_utf8), path_str_utf8);

Memory.readByteArray(new NativePointer(path_str), 0x100);

//Construction parameter 3
var arg3_ptr = Memory.alloc( 0x4 )
Memory.writeInt(arg3_ptr, 0x0 )


//decrypt
var decrypt = parseInt(moduleBase) +  0x00683014;
var decrypt_f = new NativeFunction(ptr(decrypt), 'pointer', ['int','pointer', 'pointer']);
var retval = decrypt_f(0,path_str, arg3_ptr)
var file_bgein = retval.add(0x10)

//dump
var dump = Memory.readByteArray(new NativePointer(file_bgein), 0x14F2AC);
var file = new File("/storage/emulated/0/Android/data/com.tencent.hlfish/files/AssetBundles/kernel.unity3d","w");
file.write(dump);
file.close();

Image
now lets grab our dumped file
now I have all the games logic lua files.
Image
Image


Top
   
PostPosted: Tue Feb 09, 2021 7:58 am 

Joined: Sun Nov 22, 2020 11:02 am
Posts: 2
Yeah i tried that but i heard some majority of us are having problems with python and bluestacks, so we don't know how to do it, is there an easy way by script?


Top
   
PostPosted: Tue Feb 09, 2021 1:24 pm 

Joined: Thu Aug 07, 2014 10:28 pm
Posts: 363
You need to use a real phone.


Top
   
PostPosted: Sun Mar 07, 2021 1:31 pm 

Joined: Thu Mar 04, 2021 6:23 am
Posts: 7
hello i have some questions.

1.is the code universal can I take it as is or do I need to write my own code(and any tips on where to learn how to type the code)

2.does it work if the asset folder contains many encrypted files(possibly 100s up to 1000 files) rather than one big file?

3.when we discovered the unity file i cant find that address in any picture. where did it come from.
thanks.


Last edited by omegali on Mon Mar 08, 2021 5:37 pm, edited 2 times in total.

Top
   
PostPosted: Mon Mar 08, 2021 10:56 am 

Joined: Thu Aug 07, 2014 10:28 pm
Posts: 363
This is just an example you still need to find a relevant function to use from the game.
It can work on an unlimited number o files if it works on one file.
The code is just python / java script you can google how to learn python / java script.


Top
   
Display posts from previous:  Sort by  
Post new topic  Reply to topic  [ 5 posts ] 

All times are UTC


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Limited