Poll time! Click here: Are you interested in the chiptune scene? If so, which?. Let's see what our community thinks of the chiptune scene. :) !

Question - Extracting .unity3d file with non-"UnityFS" header

The Original Forum. Game archives, full of resources. How to open them? Get help here.
AltiV
n00b
Posts: 12
Joined: Mon Feb 08, 2021 10:16 am

Re: Question - Extracting .unity3d file with non-"UnityFS" header

Post by AltiV » Thu Feb 11, 2021 8:54 pm

I had actually done that already (got stuck at the part right after it) but I didn't document it here in detail.

To review, this is the CreateString function (again, working in com.tencent.hlfish for now) located at 0x0154edec:

Code: Select all


int System.String$$CreateString(undefined4 param_1,int param_2)

{
  int iVar1;
  int iVar2;
  int iVar3;
  
  if (DAT_0298d2d8 == '\0') {
    thunk_FUN_006b1bd0(0x8ae8);
    DAT_0298d2d8 = '\x01';
  }
  if ((param_2 == 0) || (iVar1 = System.String$$wcslen(param_2), iVar1 == 0)) {
    iVar2 = **(int **)(string_TypeInfo + 0x5c);
  }
  else {
    iVar2 = thunk_FUN_006ba618();
    iVar3 = iVar2;
    if (iVar2 != 0) {
      iVar3 = System.Runtime.CompilerServices.RuntimeHelpers$$get_OffsetToStringData(0);
      iVar3 = iVar3 + iVar2;
    }
    System.Buffer$$Memcpy(iVar3,param_2,iVar1 << 1,0);
  }
  return iVar2;
}
This is the create string code from your tutorial with the appropriate address change (from 0x00FCA590 to 0x0154edec), which is run after the game application reaches the login screen:

Code: Select all

var moduleName = "libil2cpp.so"; 
var moduleBase = Module.findBaseAddress(moduleName);
var careate_str = ptr(parseInt(moduleBase) + 0x0154edec) 
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);
Result:

Code: Select all

0000  80 98 ce 98 00 00 00 00 27 00 00 00 2f 73 74 6f   ........'.../sto
0010  72 61 67 65 2f 65 6d 75 6c 61 74 65 64 2f 30 2f   rage/emulated/0/
0020  41 6e 64 72 6f 69 64 2f 64 61 74 61 2f 63 6f 6d   Android/data/com
0030  2e 74 65 6e 63 65 6e 74 2e 68 6c 66 69 73 68 2f   .tencent.hlfish/
0040  66 69 6c 65 73 2f 41 73 73 65 74 42 75 6e 64 6c   files/AssetBundl
0050  65 73 2f 6b 65 72 6e 65 6c 00 00 00 74 00 69 00   es/kernel...t.i.
0060  80 98 ce 98 00 00 00 00 25 00 00 00 41 00 70 00   ........%...A.p.
0070  6f 00 6c 00 6c 00 6f 00 2e 00 50 00 6c 00 75 00   o.l.l.o...P.l.u.
0080  67 00 69 00 6e 00 73 00 2e 00 4d 00 73 00 64 00   g.i.n.s...M.s.d.
0090  6b 00 2e 00 41 00 70 00 6f 00 6c 00 6c 00 6f 00   k...A.p.o.l.l.o.
00a0  53 00 65 00 72 00 76 00 69 00 63 00 65 00 54 00   S.e.r.v.i.c.e.T.
00b0  79 00 70 00 65 00 00 00 6c 00 65 00 73 00 5f 00   y.p.e...l.e.s._.
00c0  40 19 d3 8c 00 00 00 00 00 00 00 00 13 00 00 00   @...............
00d0  06 00 00 00 0e 00 00 00 00 00 00 00 00 00 00 00   ................
00e0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
00f0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
[Nexus 5::com.tencent.hlfish]->
I don't actually get an error afterwards as the tutorial suggests. Now I am going to attempt to run the decrypt portion of your code one line at a time (your tutorial screenshot seems to show a bit of duplicate and out-of-order code but the general flow still makes sense):

Construction Parameter 3/Decyrpt portion of code (replace tutorial's 0x00683014 with 0x00c0eb94, which as a reminder is the DecryptFileNew function):

Code: Select all

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

//decrypt
var decrypt = parseInt(moduleBase) +  0x00c0eb94;
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)

Here is a screenshot of the result:

Image

User avatar
chrrox
Moderator
Posts: 2602
Joined: Sun May 18, 2008 3:01 pm
Has thanked: 57 times
Been thanked: 1361 times

Re: Question - Extracting .unity3d file with non-"UnityFS" header

Post by chrrox » Thu Feb 11, 2021 11:15 pm

The address should never change.
Your creating a normal string instead of a Unicode string.
The address for the function can be seen in gidra when you click the start of the function.

AltiV
n00b
Posts: 12
Joined: Mon Feb 08, 2021 10:16 am

Re: Question - Extracting .unity3d file with non-"UnityFS" header

Post by AltiV » Thu Feb 11, 2021 11:55 pm

Yes I know the address should never change...I am writing in context of the function addresses in my libil2cpp.so file in comparison to the function in addresses in the libil2cpp.so file that you used for the sample tutorial, most likely because they are different versions; the CreateString function in your file was located at 0x00FCA590, but the CreateString function in my file is located in one of these addresses, as per my previous post:

Code: Select all

System.Net.UnsafeNclNativeMethods.SecureStringHelper$$CreateString	00ce2c18	undefined System.Net.UnsafeNclNativeMethods.SecureStringHelper$$CreateString()	292
System.Globalization.CodePageDataItem$$CreateString	00d7a52c	undefined System.Globalization.CodePageDataItem$$CreateString()	236
System.String$$CreateStringFromEncoding	01558198	undefined System.String$$CreateStringFromEncoding()	232
System.String$$CreateString	0155e9c8	undefined System.String$$CreateString()	164
System.String$$CreateString	0155ea78	undefined System.String$$CreateString(undefined param_1, undefined param_2, undefined param_3, undefined param_4, undefined4 param_5)	608
System.String$$CreateString	0155edcc	undefined System.String$$CreateString()	1
System.String$$CreateString	0155edec	thunk undefined System.String$$CreateString()	4
System.String$$CreateString	0155edf0	undefined System.String$$CreateString()	24
System.String$$CreateString	0155ee08	undefined System.String$$CreateString()	24
System.String$$CreateString	0155ee20	thunk undefined System.String$$CreateString()	4
System.String$$CreateString	0155ee24	undefined System.String$$CreateString()	240
Of those options, only two don't throw access violation errors (0x00d7a52c and 0x0155edec RVAs), and it looks like they both print normal strings instead of Unicode strings? Obviously I did try 0x00FCA590 anyways which didn't work.

For reference:

0x00d7a52c function:

Code: Select all

int System.Globalization.CodePageDataItem$$CreateString(int param_1,uint param_2)

{
  int iVar1;
  undefined4 uVar2;
  
  if (DAT_02988e23 == '\0') {
    thunk_FUN_006b1bd0(0x1c4c);
    DAT_02988e23 = '\x01';
  }
  if (param_1 == 0) {
                    /* WARNING: Subroutine does not return */
    thunk_FUN_006a9668();
  }
  iVar1 = System.String$$get_Chars(param_1,0,0);
  if (iVar1 == 0x7c) {
    if (((*(byte *)(System.Globalization.CodePageDataItem_TypeInfo + 0xbb) & 2) != 0) &&
       (*(int *)(System.Globalization.CodePageDataItem_TypeInfo + 0x74) == 0)) {
      thunk_FUN_006aae30();
    }
    if (param_1 == 0) {
                    /* WARNING: Subroutine does not return */
      thunk_FUN_006a9668();
    }
    iVar1 = System.String$$Split
                      (param_1,**(undefined4 **)
                                 (System.Globalization.CodePageDataItem_TypeInfo + 0x5c),1,0);
    if (iVar1 == 0) {
                    /* WARNING: Subroutine does not return */
      thunk_FUN_006a9668();
    }
    if (*(uint *)(iVar1 + 0xc) <= param_2) {
      uVar2 = thunk_FUN_006aa464();
      FUN_006f98a4(uVar2,0);
    }
    param_1 = *(int *)(iVar1 + param_2 * 4 + 0x10);
  }
  return param_1;
}
0x0155edec function:

Code: Select all

int System.String$$CreateString(undefined4 param_1,int param_2)

{
  int iVar1;
  int iVar2;
  int iVar3;
  
  if (DAT_0298d2d8 == '\0') {
    thunk_FUN_006b1bd0(0x8ae8);
    DAT_0298d2d8 = '\x01';
  }
  if ((param_2 == 0) || (iVar1 = System.String$$wcslen(param_2), iVar1 == 0)) {
    iVar2 = **(int **)(string_TypeInfo + 0x5c);
  }
  else {
    iVar2 = thunk_FUN_006ba618();
    iVar3 = iVar2;
    if (iVar2 != 0) {
      iVar3 = System.Runtime.CompilerServices.RuntimeHelpers$$get_OffsetToStringData(0);
      iVar3 = iVar3 + iVar2;
    }
    System.Buffer$$Memcpy(iVar3,param_2,iVar1 << 1,0);
  }
  return iVar2;
}

User avatar
chrrox
Moderator
Posts: 2602
Joined: Sun May 18, 2008 3:01 pm
Has thanked: 57 times
Been thanked: 1361 times

Re: Question - Extracting .unity3d file with non-"UnityFS" header

Post by chrrox » Fri Feb 12, 2021 12:48 am

I reuploaded that apk for you to use for the example.
https://www100.zippyshare.com/v/XBTE3aAV/file.html

AltiV
n00b
Posts: 12
Joined: Mon Feb 08, 2021 10:16 am

Re: Question - Extracting .unity3d file with non-"UnityFS" header

Post by AltiV » Fri Feb 12, 2021 6:15 am

Okay, testing with the APK that you linked, the tutorial works just fine with regards to creating the string and retrieving the decrypted file. I don't even seem to run into supposed RAM issues when scanning the memory, as I can see the UnityFS header just fine. Rather annoying how this doesn't seem as straightforward with the newer com.tencent.hlfish, not to mention my original intention of trying to decrypt com.nexon.kart.

While I try to work backwards now and try the newer com.tencent.hlfish again, does this method only allow decrypting of files that are picked up by the initial monitoring code? My particular use case for example has like 1,000+ .unity3d files, of which maybe like five are loaded before the login screen.

rayleigh
n00b
Posts: 16
Joined: Wed Jul 08, 2015 8:58 pm
Has thanked: 2 times

Re: Question - Extracting .unity3d file with non-"UnityFS" header

Post by rayleigh » Fri Feb 12, 2021 7:57 am

@AltiV do you get same
parameters like in the tut viewtopic.php?f=29&t=23228 ?
"a0": "0x0",
"a1": "0xb1a845f0",
"a2": "0xc62c3b84"

my change every time when i run frida

AltiV
n00b
Posts: 12
Joined: Mon Feb 08, 2021 10:16 am

Re: Question - Extracting .unity3d file with non-"UnityFS" header

Post by AltiV » Fri Feb 12, 2021 9:21 am

You are going to get different values every time. I assume because it is writing to RAM it will just try and find a location where space is available, which can change every run.

User avatar
chrrox
Moderator
Posts: 2602
Joined: Sun May 18, 2008 3:01 pm
Has thanked: 57 times
Been thanked: 1361 times

Re: Question - Extracting .unity3d file with non-"UnityFS" header

Post by chrrox » Fri Feb 12, 2021 1:44 pm

You can dump any file with the code.
You can hook the function and just play the game and it will dump the files as they load.
or manually supply the file list and tell the game to decrypt them by calling its function.

rayleigh
n00b
Posts: 16
Joined: Wed Jul 08, 2015 8:58 pm
Has thanked: 2 times

Re: Question - Extracting .unity3d file with non-"UnityFS" header

Post by rayleigh » Sat Feb 13, 2021 5:45 am

Can someone help me pls
i use this viewtopic.php?f=29&t=23228 tut
With the demo apk it works
But when i use a other apk i cant find the decryption func
i use ida pro
Here is the apk https://www83.zippyshare.com/v/mDtnZpvE/file.html

User avatar
chrrox
Moderator
Posts: 2602
Joined: Sun May 18, 2008 3:01 pm
Has thanked: 57 times
Been thanked: 1361 times

Re: Question - Extracting .unity3d file with non-"UnityFS" header

Post by chrrox » Sat Feb 13, 2021 2:18 pm

Make a new topic for your game and show where you are stuck.
https://www.tap.io/app/195056?region=us

rayleigh
n00b
Posts: 16
Joined: Wed Jul 08, 2015 8:58 pm
Has thanked: 2 times

Re: Question - Extracting .unity3d file with non-"UnityFS" header

Post by rayleigh » Mon Feb 15, 2021 11:29 pm

Whats when

Code: Select all

 Interceptor.attach(baseAddr.add(nativeFuncAddr), {          
                onEnter: function(args) {
                    console.log("[-] hook invoked");
dont call?

User avatar
chrrox
Moderator
Posts: 2602
Joined: Sun May 18, 2008 3:01 pm
Has thanked: 57 times
Been thanked: 1361 times

Re: Question - Extracting .unity3d file with non-"UnityFS" header

Post by chrrox » Tue Feb 16, 2021 11:45 am

If you don't see hook called then the game never called the function after you tried to hook it.
This is the latest version of the game I found.
Image

rayleigh
n00b
Posts: 16
Joined: Wed Jul 08, 2015 8:58 pm
Has thanked: 2 times

Re: Question - Extracting .unity3d file with non-"UnityFS" header

Post by rayleigh » Tue Feb 16, 2021 12:05 pm

thx i found the bug was a bug with frida i restart my samsung s5 and reinstall frida server now it works very strange bug :?

User avatar
chrrox
Moderator
Posts: 2602
Joined: Sun May 18, 2008 3:01 pm
Has thanked: 57 times
Been thanked: 1361 times

Re: Question - Extracting .unity3d file with non-"UnityFS" header

Post by chrrox » Tue Feb 16, 2021 8:14 pm

I use the module in magisk for frida.

AltiV
n00b
Posts: 12
Joined: Mon Feb 08, 2021 10:16 am

Re: Question - Extracting .unity3d file with non-"UnityFS" header

Post by AltiV » Tue Feb 23, 2021 1:49 am

I know there's been a bit of a gap between my previous post and now, but I am still hoping to find successful resolution with this task. If someone could just help me decrypt the files to begin with that would be preferable, but I understand that may be too greedy.

I've looked into com.nexon.kart some more (since the tutorial APK is more or less resolved, at least with the exact version covered and not the up-to-date version), and it seems like I still can't really follow the functions used.

To recap, some of the relevant functions that I talked about previous are as such:
  • undefined4 ABLoadReq$$LoadAssetBundle(int param_1,undefined4 param_2) - 02d1b8a0
  • void ABLoadReq$$LoadEncryptedAB(undefined4 param_1,undefined4 param_2) - 02d1bcc4
  • void Utils$$TeaDecrypt(undefined4 param_1) - 025aaae0
  • UnityEngine.AssetBundle$$LoadFromMemory(uVar2,0) - 068aa44c
From the above, you could say that the functions are nested within each other (second function is called in the first, third function is called in the second, etc.).

The LoadAssetBundle function seems to hook just fine, with the second address/parameter returning expected results:

Code: Select all

0000  00 58 16 ab 00 00 00 00 a7 00 00 00 6a 00 61 00   .X..........j.a.
0010  72 00 3a 00 66 00 69 00 6c 00 65 00 3a 00 2f 00   r.:.f.i.l.e.:./.
0020  2f 00 2f 00 73 00 74 00 6f 00 72 00 61 00 67 00   /./.s.t.o.r.a.g.
0030  65 00 2f 00 65 00 6d 00 75 00 6c 00 61 00 74 00   e./.e.m.u.l.a.t.
0040  65 00 64 00 2f 00 30 00 2f 00 41 00 6e 00 64 00   e.d./.0./.A.n.d.
0050  72 00 6f 00 69 00 64 00 2f 00 6f 00 62 00 62 00   r.o.i.d./.o.b.b.
0060  2f 00 63 00 6f 00 6d 00 2e 00 6e 00 65 00 78 00   /.c.o.m...n.e.x.
0070  6f 00 6e 00 2e 00 6b 00 61 00 72 00 74 00 2f 00   o.n...k.a.r.t./.
0080  70 00 61 00 74 00 63 00 68 00 2e 00 31 00 30 00   p.a.t.c.h...1.0.
0090  31 00 30 00 39 00 30 00 2e 00 63 00 6f 00 6d 00   1.0.9.0...c.o.m.
00a0  2e 00 6e 00 65 00 78 00 6f 00 6e 00 2e 00 6b 00   ..n.e.x.o.n...k.
00b0  61 00 72 00 74 00 2e 00 6f 00 62 00 62 00 21 00   a.r.t...o.b.b.!.
00c0  2f 00 61 00 73 00 73 00 65 00 74 00 73 00 2f 00   /.a.s.s.e.t.s./.
00d0  50 00 6c 00 61 00 74 00 66 00 6f 00 72 00 6d 00   P.l.a.t.f.o.r.m.
00e0  41 00 73 00 73 00 65 00 74 00 73 00 2f 00 41 00   A.s.s.e.t.s./.A.
00f0  6e 00 64 00 72 00 6f 00 69 00 64 00 2f 00 61 00   n.d.r.o.i.d./.a.
However, the LoadEncryptedAB function never hooks onto anything, at least up to the log in screen of the game (I cannot go any further than this anyways because the game crashes afterwards). I assume that, based on the conditional required to hit this function (checking if the file is encrypted in the first place), none of the files are labelled as encrypted for whatever reason, although they clearly cannot be de-compiled by standard tools. This already deviates from the tutorial pretty heavily since I can't go any farther when looking for UnityFS strings.

Instead of the LoadEncryptedAB function, the other side of the conditional instead calls a UnityEngine.AssetBundle$$LoadFromFile function. However, not much is delved from this either since this also receives the file similar to the LoadAssetBundle function, and returns "gibberish". I have looked around for any other functions of relevance, but since LoadEncryptedAB is never hit, none of the subsequent functions are ever reached as well.

Post Reply