Skip to content
View in the app

A better way to browse. Learn more.

ResHax

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.
Help us keep the site running.

Decrypt unity 3d files with Frida

Featured Replies

  • Author
  • Localization

chrrox, posted Sun Dec 27, 2020 4:01 pm (61320)


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
  • Author
  • Localization

Taiwan_Guy, posted Tue Feb 09, 2021 7:58 am (62083)


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?
  • Author
  • Localization

chrrox, posted Tue Feb 09, 2021 1:24 pm (62094)


You need to use a real phone.
  • Author
  • Localization

omegali, posted Sun Mar 07, 2021 1:31 pm (62717)


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.
  • Author
  • Localization

chrrox, posted Mon Mar 08, 2021 10:56 am (62727)


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.
Guest
This topic is now closed to further replies.

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.