求助:e服深渊征途解包

文件打开明显加密,没有固定标识头。

资源文件图片



尝试Il2CppDumper了一下能出来,ida分析了一下。
跟UnityEngine_AssetBundle__LoadFromMemory交叉引用跟到UnityEngine_ResourceManagement_ResourceProviders_AddressableEncryptHelp__Decrypt中

相关函数

总的解密函数

__int64 __fastcall UnityEngine_ResourceManagement_ResourceProviders_AddressableEncryptHelp__Decrypt(
        __int64 a1,
        __int64 a2,
        int *a3)
{
  int v6; // w21
  __int64 UTF8; // x0
  unsigned int v8; // w8
  unsigned __int64 v9; // x8
  unsigned __int64 v10; // x9
  __int64 v11; // x12
  unsigned int v12; // w8
  __int64 v13; // x22
  int v14; // w3
  int v15; // w4
  int v16; // w5
  int v17; // w6
  int v18; // w7
  unsigned __int64 v19; // x8
  unsigned __int64 v20; // x9
  __int64 v21; // x12
  __int64 v23; // x0

  if ( (byte_44503C1 & 1) == 0 )
  {
    sub_128CFD8();
    byte_44503C1 = 1;
  }
  v6 = UnityEngine_ResourceManagement_ResourceProviders_AddressableEncryptHelp__FormatStrHash(a2);
  UTF8 = sub_128CFE8(byte___TypeInfo, 4u);
  if ( !UTF8 )
    goto LABEL_28;
  v8 = *(_DWORD *)(UTF8 + 24);
  if ( !v8 )
    goto LABEL_27;
  *(_BYTE *)(UTF8 + 32) = HIBYTE(v6);
  if ( v8 == 1 )
    goto LABEL_27;
  *(_BYTE *)(UTF8 + 33) = BYTE2(v6);
  if ( v8 <= 2 )
    goto LABEL_27;
  *(_BYTE *)(UTF8 + 34) = BYTE1(v6);
  if ( v8 == 3 )
    goto LABEL_27;
  *(_BYTE *)(UTF8 + 35) = v6;
  if ( !a1 )
    goto LABEL_28;
  v9 = *(unsigned int *)(a1 + 24);
  if ( (__int64)(v9 << 32) >= 1 )
  {
    v10 = 0LL;
    while ( v10 < v9 )
    {
      v11 = v10 & 3;
      if ( (unsigned int)v11 >= *(_DWORD *)(UTF8 + 24) )
        break;
      *(_BYTE *)(a1 + 32 + v10++) ^= *(_BYTE *)(UTF8 + v11 + 32);
      if ( (__int64)v10 >= (int)v9 )
        goto LABEL_14;
    }
LABEL_27:
    v23 = sub_128D0EC(UTF8);
    sub_128D074(v23, 0LL);
  }
LABEL_14:
  UTF8 = sub_128CFE8(byte___TypeInfo, 4u);
  if ( !UTF8 )
    goto LABEL_28;
  v12 = *(_DWORD *)(UTF8 + 24);
  v13 = UTF8;
  if ( !v12 )
    goto LABEL_27;
  *(_BYTE *)(UTF8 + 32) = v6;
  if ( v12 == 1 )
    goto LABEL_27;
  *(_BYTE *)(UTF8 + 33) = BYTE1(v6);
  if ( v12 <= 2 )
    goto LABEL_27;
  *(_BYTE *)(UTF8 + 34) = BYTE2(v6);
  if ( v12 == 3 )
    goto LABEL_27;
  *(_BYTE *)(UTF8 + 35) = HIBYTE(v6);
  UTF8 = System_Text_Encoding__get_UTF8(0LL);
  if ( !UTF8
    || (UTF8 = (*(__int64 (__fastcall **)(__int64, __int64, _QWORD))(*(_QWORD *)UTF8 + 720LL))(
                 UTF8,
                 StringLiteral_7933,
                 *(_QWORD *)(*(_QWORD *)UTF8 + 728LL))) == 0 )
  {
LABEL_28:
    sub_128D0C4(UTF8);
  }
  v19 = *(unsigned int *)(UTF8 + 24);
  if ( (__int64)(v19 << 32) >= 1 )
  {
    v20 = 0LL;
    while ( v20 < v19 )
    {
      v21 = v20 & 3;
      if ( (unsigned int)v21 >= *(_DWORD *)(v13 + 24) )
        break;
      *(_BYTE *)(UTF8 + 32 + v20++) ^= *(_BYTE *)(v13 + v21 + 32);
      if ( (__int64)v20 >= (int)v19 )
        return UnityEngine_ResourceManagement_ResourceProviders_AddressableEncryptHelp__DecryptXXTea(
                 a1,
                 UTF8,
                 a3,
                 v14,
                 v15,
                 v16,
                 v17,
                 v18);
    }
    goto LABEL_27;
  }
  return UnityEngine_ResourceManagement_ResourceProviders_AddressableEncryptHelp__DecryptXXTea(
           a1,
           UTF8,
           a3,
           v14,
           v15,
           v16,
           v17,
           v18);
}
__int64 __fastcall UnityEngine_ResourceManagement_ResourceProviders_AddressableEncryptHelp__FormatStrHash(__int64 a1)
{
  __int64 IsNullOrEmpty; // x0
  __int64 v4; // x19
  int IndexOf; // w0

  IsNullOrEmpty = System_String__IsNullOrEmpty(a1, 0LL);
  if ( (IsNullOrEmpty & 1) != 0 )
    return 0LL;
  if ( !a1
    || (IsNullOrEmpty = System_String__ToLower(a1, 0LL)) == 0
    || (IsNullOrEmpty = System_String__Replace(IsNullOrEmpty, 92LL, 47LL, 0LL)) == 0 )
  {
    sub_128D0C4(IsNullOrEmpty);
  }
  v4 = IsNullOrEmpty;
  IndexOf = System_String__LastIndexOf(IsNullOrEmpty, 47LL, 0LL);
  if ( (IndexOf & 0x80000000) == 0 )
    v4 = System_String__Substring_43148328(
           v4,
           (unsigned int)(IndexOf + 1),
           (unsigned int)(*(_DWORD *)(v4 + 16) + ~IndexOf),
           0LL);
  return UnityEngine_ResourceManagement_ResourceProviders_AddressableEncryptHelp__GetStringHash(v4);
}
__int64 __fastcall UnityEngine_ResourceManagement_ResourceProviders_AddressableEncryptHelp__DecryptXXTea(
        __int64 a1,
        __int64 a2,
        int *a3,
        int a4,
        int a5,
        int a6,
        int a7,
        int a8)
{
  __int64 v9; // x20
  __int64 v11; // x8
  __int64 result; // x0
  __int64 v13; // x8
  __int64 v14; // x21
  __int64 v15; // x0
  int v16; // w8
  __int64 v17; // x9
  __int64 v18; // x10
  int ChunkInt; // w0
  int v20; // w22
  int v21; // w8
  unsigned int v22; // w27
  int v23; // w25
  unsigned int v24; // w23
  int v25; // w28
  int v26; // w22
  unsigned int v27; // w24
  unsigned int v28; // w26
  int v29; // w0
  bool v30; // vf
  unsigned int v31; // w24
  int v32; // w0
  __int64 v33; // x8
  unsigned int v34; // w11
  __int64 v35; // x9
  __int64 v36; // x10
  __int64 v37; // x0
  int v38; // [xsp+0h] [xbp-70h]
  char v39; // [xsp+8h] [xbp-68h]
  int v40; // [xsp+8h] [xbp-68h]
  int v41; // [xsp+10h] [xbp-60h]
  __int64 v42; // [xsp+18h] [xbp-58h]
  int v43; // [xsp+18h] [xbp-58h]
  unsigned int v44; // [xsp+1Ch] [xbp-54h]
  char v45; // [xsp+20h] [xbp-50h]
  int v46; // [xsp+28h] [xbp-48h]
  void *v47; // [xsp+30h] [xbp-40h]

  v9 = a2;
  if ( (byte_44503C2 & 1) == 0 )
  {
    sub_128CFD8();
    byte_44503C2 = 1;
  }
  *a3 = 0;
  if ( !a1 )
    return 0LL;
  v11 = *(_QWORD *)(a1 + 24);
  result = 0LL;
  if ( (int)v11 < 8 || (v11 & 3) != 0 )
    return result;
  if ( !v9 || (v13 = *(_QWORD *)(v9 + 24)) == 0 )
  {
    if ( (*(_BYTE *)(UnityEngine_Debug_TypeInfo + 303) & 2) != 0 && !*(_DWORD *)(UnityEngine_Debug_TypeInfo + 224) )
      j_il2cpp_runtime_class_init_0(
        UnityEngine_Debug_TypeInfo,
        a2,
        (int)a3,
        a4,
        a5,
        a6,
        a7,
        a8,
        v38,
        v39,
        v41,
        v42,
        v45,
        v46,
        v47);
    UnityEngine_Debug__LogError(StringLiteral_7934, 0LL);
    return 0LL;
  }
  if ( (int)v13 <= 15 )
  {
    v14 = sub_128CFE8(byte___TypeInfo, 0x10u);
    v15 = System_Array__CopyTo(v9, v14, 0LL, 0LL);
    v16 = *(_DWORD *)(v9 + 24);
    v9 = v14;
    if ( v16 <= 15 )
    {
      if ( !v14 )
        sub_128D0C4(v15);
      v17 = v16 + 32LL;
      do
      {
        if ( (unsigned int)v16 >= *(_DWORD *)(v14 + 24) )
          goto LABEL_34;
        v18 = v17 - 32;
        *(_BYTE *)(v14 + v17++) = 0;
        ++v16;
      }
      while ( v18 < 15 );
      v9 = v14;
    }
  }
  ChunkInt = UnityEngine_ResourceManagement_ResourceProviders_AddressableEncryptHelp__GetChunkInt(
               a1,
               *(_DWORD *)(a1 + 24) - 4);
  *a3 = ChunkInt;
  v20 = *(_DWORD *)(a1 + 24);
  v40 = ChunkInt;
  v15 = UnityEngine_ResourceManagement_ResourceProviders_AddressableEncryptHelp__GetChunkInt(a1, 0);
  v21 = 208 / (v20 - 4);
  v22 = -1640531527 * v21 - 1253254570;
  if ( -1640531527 * v21 != 1253254570 )
  {
    v23 = v20 - 8;
    v24 = v15;
    v43 = (v20 - 8) >> 2;
    v44 = v20 - 8;
    do
    {
      v25 = (v22 >> 2) & 3;
      if ( v23 >= 4 )
      {
        v27 = 4 * v43;
        v26 = v43;
        do
        {
          v28 = UnityEngine_ResourceManagement_ResourceProviders_AddressableEncryptHelp__GetChunkInt(a1, v27 - 4);
          v29 = UnityEngine_ResourceManagement_ResourceProviders_AddressableEncryptHelp__GetChunkInt(
                  v9,
                  4 * (v26 & 3 ^ (unsigned int)v25));
          v24 = UnityEngine_ResourceManagement_ResourceProviders_AddressableEncryptHelp__DecChunkInt(
                  a1,
                  v27,
                  (((16 * v28) ^ (v24 >> 3)) + ((v28 >> 5) ^ (4 * v24))) ^ ((v29 ^ v28) + (v24 ^ v22)));
          v30 = __OFSUB__(v26--, 1);
          v27 -= 4;
        }
        while ( !((v26 < 0) ^ v30 | (v26 == 0)) );
      }
      else
      {
        LOBYTE(v26) = v43;
      }
      v23 = v44;
      v31 = UnityEngine_ResourceManagement_ResourceProviders_AddressableEncryptHelp__GetChunkInt(a1, v44);
      v32 = UnityEngine_ResourceManagement_ResourceProviders_AddressableEncryptHelp__GetChunkInt(
              v9,
              4 * (v26 & 3 ^ (unsigned int)v25));
      v15 = UnityEngine_ResourceManagement_ResourceProviders_AddressableEncryptHelp__DecChunkInt(
              a1,
              0,
              (((16 * v31) ^ (v24 >> 3)) + ((v31 >> 5) ^ (4 * v24))) ^ ((v32 ^ v31) + (v24 ^ v22)));
      v22 += 1640531527;
      v24 = v15;
    }
    while ( v22 );
  }
  LODWORD(v33) = *(_DWORD *)(a1 + 24);
  v34 = v40;
  if ( v40 < (int)v33 )
  {
    v35 = v40 + 32LL;
    while ( (unsigned int)v33 > v34 )
    {
      *(_BYTE *)(a1 + v35) = 0;
      v33 = *(_QWORD *)(a1 + 24);
      v36 = v35 - 31;
      ++v35;
      ++v34;
      if ( v36 >= (int)v33 )
        return a1;
    }
LABEL_34:
    v37 = sub_128D0EC(v15);
    sub_128D074(v37, 0LL);
  }
  return a1;
}

感觉应该是xor加xxtea,但是由于实力有限,不会调试,没找到xxtea_key,甚至都不确定过程是否正确。
希望有大佬可以救一下QAQ。

网址

深渊征途 | 立即游玩最色色的无码成人游戏| EROLABS 工口实验室

部分资源文件

Android.zip (38.0 KB)

安装包及反编译的一些垃圾

通过网盘分享的文件:output等2个文件
链接: https://pan.baidu.com/s/11QJUpqf4WsA6ijiRdcO9LQ?pwd=0721 提取码: 0721

我擦我刚尝试重新分析就有人发了

看代码像是文件名-hash-4字节xor密钥解密-xxtea

xxtea_key不知道怎么来的。

from pathlib import Path
from xxtea import decrypt as xxtea
from numpy import frombuffer as npfb
from ctypes import c_int32 as i32, c_uint32 as u32

class AbyssExpedition:
    BaseKey = npfb(b'fc($.)<!@man+abc', dtype='>u4')

    @classmethod
    def DJB2(cls, string: bytes|str) -> int:
        strb = string.encode() if isinstance(string, str) else string
        h = 0
        for i in strb:
            h = (h * 33) + i
        return u32(i32(h).value).value
    
    @classmethod
    def Decrypt(cls, data: bytes, name: bytes|str) -> bytes|None:
        dataLen = len(data)
        if dataLen % 4 != 0 or dataLen <= 0:
            return None
        xorKey = npfb(bytearray(int.to_bytes(cls.DJB2(name), 4, 'big')), dtype='>u4')
        dArr = npfb(data, dtype='>u4') ^ xorKey
        cutSize = int(dArr[-1])
        xData = dArr[:-1].tobytes()
        if cutSize <= 0 or cutSize > dataLen - 4:
            return None
        xKey = (cls.BaseKey ^ xorKey.byteswap(True)).tobytes()
        decData = npfb(bytearray(xxtea(xData, xKey, padding=False)), dtype='<u4').byteswap(True).tobytes()
        if not decData.startswith(b'UnityFS\x00'):
            return None
        return decData[:cutSize]

def batch(datPath: str = '', ext: str = '*.bundle', subfolder: bool = False):
    path = Path(datPath) if datPath else Path.cwd()
    need = [i for i in (path.rglob(ext) if subfolder else path.glob(ext)) if i.is_file()]
    for i in need:
        with open(i, 'rb') as f:
            data = f.read()
        decData = AbyssExpedition.Decrypt(data, i.name)
        if decData is None:
            print(f'解密错误 --- {i.as_posix()}')
            continue
        with open(i, 'wb') as w:
            w.write(decData)

if __name__ == '__main__':
    path = r'' # 游戏文件所在的路径
    ext = '*.bundle' # 要解密的文件后缀
    subfolder = False # 是否查找字文件夹内的文件
    batch(path, ext, subfolder)

它使用的hash类型是 DJBX33A(djb2)
解密流程:
1 - 将文件名(包括后缀)转hash
2 - 将数据和hash异或
3 - 提取xor后的数据最后一个uint32 它是解密后的文件大小 - CutLen
4 - 去掉xor后的最后一个uint32
5 - 将BaseKey 和 hash(反转端序) 进行xor 得到 xxtea key
6 - 将xor后的数据和xxtea key 进行 xxtea 解密, 解密后将端序反转
7 - 剪切数据根据CutLen
8 - 解密完成

1 个赞

大佬,这回能分享一下思路了吧。这总不能又说是“瞪眼法”瞪出来的吧!

…这个人不是已经贴了代码出来了吗…照着c的思路转python代码不就行了吗…

我是说找到解密的方法,正常流程不是走libxxx.so,找到解密函数,再根据解密算法用python写批量解密嘛。想知道大概流程,比如从哪个函数入手一步一步追踪到解密函数的。

解密呢先dump so, 然后找解密函数, 然后用frida hook住解密的函数, 检查下它传递的值和返回的值, 接着就用python写解密就完事了, 真不难…

这个得它有没有标识, 有的话, 大概率一搜就找到, 没有的话, 只能用 frida hook io的read的函数, 追踪异常, 找到它的解密函数

不过是 unity的话 大概率解密函数名字有Encrypt/Decrypt

基于unity,il2cpp打包方式,il2cppdumper出能看的函数名(前提是那两个文件没加密),丢ida分析,然后经验搜索loadfrom、assetbundle或者decrypt,跟下交叉引用就跟到解密函数了。也可以dump.cs看函数名。找到解密函数基本上简单的可以直接解出来,不确定传参就frida hook一下(可惜我不会),想尝试ida下断点调试不知道行不行,还没试。