求助大佬,Megaha:Re 异世界实干记,解包

搞不懂,这游戏策划和其他ero不一样,咋一直换加密,也没几个角色:downcast_face_with_sweat:,前前后后换了有3次了,防谁啊:roll_eyes:

好家伙又换了,我说怎么解不出来

有大佬能教一下怎么调图层吗?有的眼皮没了 有的JJ穿模了

他live2d不是隐藏了吗,你解出来了?

全部换成Spine了,图还是原来live2d的图,另外之前也说过了,只有在游戏中访问HCG才会下载对应的HCG文件

我还以为有办法直接下载hcg的资源包了呢,谢谢解惑


global-metadata.dat没加密
这应该是个资源清单看样子和本地清单的头部几个字节差不多感觉可能和xor有关
如果可以解开这个加密应该就能获取所有资源清单

清单可能就是bin明码那些,关键是下载地址是经过处理的,同一份文件的清单、下载、本地保存名称均不一致

看了一下有些可读的ASCII
但是Bson解析也是失败或许又是哪个没见过的压缩格式

这不一眼二进制catalog吗,直接AddressablestoolsPy之类的解析啊。

catalog_1.16.002.bin这文件没啥用, 里面不是资产的下载清单,单纯就是unity文件的引用id


感觉应该是资产清单

解析后可以看到一些包名类似

from pathlib import Path
from AddressablesToolsPy.src.AddressablesTools import parse_binary
from AddressablesToolsPy.src.AddressablesTools.Catalog.SerializedObjectDecoder import SerializedObjectDecoder


CATALOG_PATH = r"C:\Users\1\Downloads\catalog_1.16.002.bin"


def create_patcher():
    def patcher(match_name: str) -> str:
        if "EncryptedAssetBundleRequestOptions" in match_name:
            return SerializedObjectDecoder.ABRO_MATCHNAME
        elif "AssetBundleRequestOptions" in match_name:
            return SerializedObjectDecoder.ABRO_MATCHNAME
        return match_name
    return patcher


def load_catalog(path: str):
    data = Path(path).read_bytes()
    patcher = create_patcher()
    catalog = parse_binary(data, patcher=patcher)
    return catalog


def dump_bundles(catalog):
    print(f"资源总数: {len(catalog.Resources)}")
    print("-" * 60)
    # 打开文件 a.xtx,模式为写入('w'),会覆盖已有内容
    with open("a.xtx", "w", encoding="utf-8") as f:
        for name_key, infos in catalog.Resources.items():
            if isinstance(name_key, str):
                f.write(f"{name_key}\n")  # 写入文件并换行



if __name__ == "__main__":
    catalog = load_catalog(CATALOG_PATH)
    dump_bundles(catalog)

晚点再研究AddressablesToolsPy吧在给python3.14造轮子
看文件url长度像是sha256的结果交叉引用没发现啥东西可能是自定义的算法
3.14运行速度提升挺大的在把3.9的环境升级上去就是折磨…

这个id不对,应该是通过加密获得的最终下载链接,只能反编译看源码

对比了下之前和现在的包,libil2cpp.so变化比较大,加密函数应该在里面

我也是这么认为的,只不过反编译我实在是不怎么擅长

找了一圈估计这个函数就是

System_String_o *BCUL_AddressablesManager_ResourceProviders_EncryptedAssetBundleResource__CalcHashName(
        System_String_o *baseFileName,
        UnityEngine_ResourceManagement_ResourceProviders_AssetBundleRequestOptions_o *options,
        const MethodInfo *method)
{
  uint32_t m_Crc; // w9
  const MethodInfo *v6; // x4
  UnityEngine_Hash128_o v7; // kr00_16
  BCUL_AddressablesManager_CachingBundle_c *v8; // x0
  uint32_t val; // [xsp+Ch] [xbp-24h] BYREF

  if ( (byte_96CE867 & 1) == 0 )
  {
    sub_3D6561C();
    sub_3D6561C();
    byte_96CE867 = 1;
  }
  if ( options )
    m_Crc = options->fields.m_Crc;
  else
    m_Crc = 0;
  val = m_Crc;
  v7 = UnityEngine_Hash128__Compute_uint_(&val, (const MethodInfo_522E5FC *)Method_UnityEngine_Hash128_Compute_uint___);
  v8 = BCUL_AddressablesManager_CachingBundle_TypeInfo;
  if ( !BCUL_AddressablesManager_CachingBundle_TypeInfo->_2.cctor_finished )
  {
    j_il2cpp_runtime_class_init_0(BCUL_AddressablesManager_CachingBundle_TypeInfo, v7.fields.u64_1);
    v8 = BCUL_AddressablesManager_CachingBundle_TypeInfo;
  }
  return BCUL_AddressablesManager_AssetBundleUtils__GetHashName(baseFileName, v8->static_fields->AbHashKey, v7, v6);
}
System_String_o *BCUL_AddressablesManager_AssetBundleUtils__GetHashName(
        System_String_o *assetBundleName,
        System_String_o *hashKey,
        UnityEngine_Hash128_o assetBundleHash,
        const MethodInfo *method)
{
  Il2CppObject *v6; // x0
  System_String_o *v7; // x0
  System_String_o *v8; // x19
  System_Text_Encoding_o *UTF8; // x0
  System_Byte_array *v10; // x0
  const MethodInfo *v11; // x1
  System_Byte_array *v12; // x20
  System_Text_StringBuilder_o *v13; // x19
  il2cpp_array_size_t max_length; // x8
  unsigned __int64 v15; // x21
  System_String_o *v16; // x0
  UnityEngine_Hash128_o v18; // [xsp+0h] [xbp-60h] BYREF
  uint8_t v19; // [xsp+1Ch] [xbp-44h] BYREF
  UnityEngine_Hash128_o v20; // [xsp+20h] [xbp-40h] BYREF
  UnityEngine_Hash128_o v21; // 0:x0.16

  v20 = assetBundleHash;
  if ( (byte_96CE828 & 1) == 0 )
  {
    sub_3D6561C();
    sub_3D6561C();
    sub_3D6561C();
    sub_3D6561C();
    sub_3D6561C();
    byte_96CE828 = 1;
  }
  v21.fields.u64_0 = (uint64_t)&v20;
  v21.fields.u64_1 = 0LL;
  v19 = 0;
  if ( UnityEngine_Hash128__get_isValid(v21, (const MethodInfo *)assetBundleHash.fields.u64_0) )
  {
    v18 = v20;
    v6 = (Il2CppObject *)j_il2cpp_value_box_0(UnityEngine_Hash128_TypeInfo, &v18);
    v7 = System_String__Format_130277216(
           (System_String_o *)StringLiteral_17126,
           (Il2CppObject *)assetBundleName,
           v6,
           (Il2CppObject *)hashKey,
           0LL);
  }
  else
  {
    v7 = System_String__Concat_130275884(assetBundleName, (System_String_o *)StringLiteral_868, hashKey, 0LL);
  }
  v8 = v7;
  UTF8 = System_Text_Encoding__get_UTF8(0LL);
  if ( !UTF8 )
    goto LABEL_15;
  v10 = (System_Byte_array *)((__int64 (__fastcall *)(System_Text_Encoding_o *, System_String_o *, const MethodInfo *))UTF8->klass->vtable._18_GetBytes.methodPtr)(
                               UTF8,
                               v8,
                               UTF8->klass->vtable._18_GetBytes.method);
  v12 = BCUL_AddressablesManager_AssetBundleUtils__ComputeHash(v10, v11);
  v13 = (System_Text_StringBuilder_o *)sub_3D658A4(System_Text_StringBuilder_TypeInfo);
  System_Text_StringBuilder___ctor(v13, 0LL);
  if ( !v12 )
    goto LABEL_15;
  max_length = v12->max_length;
  if ( (int)max_length >= 1 )
  {
    v15 = 0LL;
    while ( 1 )
    {
      if ( v15 >= (unsigned int)max_length )
        sub_3D658B0();
      v19 = v12->m_Items[v15];
      v16 = System_Byte__ToString_131272268((uint8_t)&v19, (System_String_o *)StringLiteral_16888, 0LL);
      if ( !v13 )
        break;
      System_Text_StringBuilder__Append_130329112(v13, v16, 0LL);
      LODWORD(max_length) = v12->max_length;
      if ( (__int64)++v15 >= (int)max_length )
        goto LABEL_13;
    }
LABEL_15:
    sub_3D658A8();
  }
LABEL_13:
  if ( !v13 )
    goto LABEL_15;
  return (System_String_o *)((__int64 (__fastcall *)(System_Text_StringBuilder_o *, const MethodInfo *))v13->klass->vtable._3_ToString.methodPtr)(
                              v13,
                              v13->klass->vtable._3_ToString.method);
}
System_Byte_array *BCUL_AddressablesManager_AssetBundleUtils__ComputeHash(
        System_Byte_array *buffer,
        const MethodInfo *method)
{
  System_Security_Cryptography_SHA256CryptoServiceProvider_o *v3; // x19
  __int64 v4; // x3
  System_Byte_array *v5; // x21
  System_Security_Cryptography_SHA256CryptoServiceProvider_c *klass; // x8
  __int64 v7; // x9
  int32_t *p_offset; // x10
  __int64 v9; // x0

  if ( (byte_96CE825 & 1) == 0 )
  {
    sub_3D6561C();
    sub_3D6561C();
    byte_96CE825 = 1;
  }
  v3 = (System_Security_Cryptography_SHA256CryptoServiceProvider_o *)sub_3D658A4(System_Security_Cryptography_SHA256CryptoServiceProvider_TypeInfo);
  System_Security_Cryptography_SHA256CryptoServiceProvider___ctor(v3, 0LL);
  if ( !v3 )
    sub_3D658A8();
  v5 = System_Security_Cryptography_HashAlgorithm__ComputeHash(
         (System_Security_Cryptography_HashAlgorithm_o *)v3,
         buffer,
         0LL);
  klass = v3->klass;
  v7 = *(unsigned __int16 *)&v3->klass->_2.rank;
  if ( *(_WORD *)&v3->klass->_2.rank )
  {
    p_offset = &klass->_1.interfaceOffsets->offset;
    while ( *((System_IDisposable_c **)p_offset - 1) != System_IDisposable_TypeInfo )
    {
      --v7;
      p_offset += 4;
      if ( !v7 )
        goto LABEL_8;
    }
    v9 = (__int64)&klass->vtable + 16 * *p_offset;
  }
  else
  {
LABEL_8:
    v9 = sub_3D24214(v3, System_IDisposable_TypeInfo, 0LL, v4);
  }
  (*(void (__fastcall **)(System_Security_Cryptography_SHA256CryptoServiceProvider_o *, _QWORD))v9)(
    v3,
    *(_QWORD *)(v9 + 8));
  return v5;
}

看样子确实最后是sha256
最后还是挺烦人的感觉很多参数不确定得动态调试
catalog完全解析出来差不多如

{
  "EntryCount": 139056,
  "Resources": {
    "00033a27790b90e88dd5ba3e653f1f3c.bundle": [
      {
        "__type__": "ResourceLocation",
        "Data": {
          "__type__": "WrappedSerializedObject",
          "Object": {
            "__type__": "AssetBundleRequestOptions",
            "BundleName": "4694165b0206bf77910ebd6a1191b9e3",
            "BundleSize": 90362,
            "ComInfo": {
              "__type__": "CommonInfo",
              "AssetLoadMode": {
                "__type__": "AssetLoadMode",
                "_value_": 0,
                "_name_": "RequestedAssetAndDependencies",
                "__objclass__": {
                  "__type__": "EnumType",
                  "_generate_next_value_": "<max_depth:staticmethod>",
                  "__module__": "AddressablesTools.Classes.AssetBundleRequestOptions",
                  "__firstlineno__": 10,
                  "__static_attributes__": "<max_depth:tuple>",
                  "_new_member_": "<max_depth:builtin_function_or_method>",
                  "_use_args_": false,
                  "_member_names_": "<max_depth:list>",
                  "_member_map_": "<max_depth:dict>",
                  "_value2member_map_": "<max_depth:dict>",
                  "_hashable_values_": "<max_depth:list>",
                  "_unhashable_values_": "<max_depth:list>",
                  "_unhashable_values_map_": "<max_depth:dict>",
                  "_member_type_": "<max_depth:type>",
                  "_value_repr_": null,
                  "__doc__": null,
                  "RequestedAssetAndDependencies": "<cycle:AssetLoadMode>",
                  "AllPackedAssetsAndDependencies": "<max_depth:AssetLoadMode>",
                  "__new__": "<max_depth:function>"
                },
                "_sort_order_": 0
              },
              "ChunkedTransfer": false,
              "ClearOtherCachedVersionsWhenLoaded": false,
              "RedirectLimit": 32,
              "RetryCount": 0,
              "Timeout": 0,
              "UseCrcForCachedBundle": true,
              "UseUnityWebRequestForLocalBundles": false,
              "Version": 3
            },
            "Crc": 3583767260,
            "Hash": "00033a27790b90e88dd5ba3e653f1f3c"
          },
          "Type": {
            "__type__": "SerializedType",
            "AssemblyName": "Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
            "ClassName": "BCUL.AddressablesManager.ResourceProviders.EncryptedAssetBundleRequestOptions"
          }
        },
        "Dependencies": [],
        "DependencyHashCode": 0,
        "DependencyKey": null,
        "HashCode": 0,
        "InternalId": "{AM.RemoteAssetRootURL}/00033a27790b90e88dd5ba3e653f1f3c.bundle",
        "PrimaryKey": "00033a27790b90e88dd5ba3e653f1f3c.bundle",
        "ProviderId": "BCUL.AddressablesManager.ResourceProviders.EncryptedAssetBundleProvider",
        "Type": {
          "__type__": "SerializedType",
          "AssemblyName": "Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
          "ClassName": "UnityEngine.ResourceManagement.ResourceProviders.IAssetBundleResource"
        }
      }
    ],
    "000b49d70268e5ab9e28dbeb5c56bade.bundle": [
      {
        "__type__": "ResourceLocation",
        "Data": {
          "__type__": "WrappedSerializedObject",
          "Object": {
            "__type__": "AssetBundleRequestOptions",
            "BundleName": "7696b61c32022de421b8b69b8b6643ac",
            "BundleSize": 14353,
            "ComInfo": {
              "__type__": "CommonInfo",
              "AssetLoadMode": {
                "__type__": "AssetLoadMode",
                "_value_": 0,
                "_name_": "RequestedAssetAndDependencies",
                "__objclass__": {
                  "__type__": "EnumType",
                  "_generate_next_value_": "<max_depth:staticmethod>",
                  "__module__": "AddressablesTools.Classes.AssetBundleRequestOptions",
                  "__firstlineno__": 10,
                  "__static_attributes__": "<max_depth:tuple>",
                  "_new_member_": "<max_depth:builtin_function_or_method>",
                  "_use_args_": false,
                  "_member_names_": "<max_depth:list>",
                  "_member_map_": "<max_depth:dict>",
                  "_value2member_map_": "<max_depth:dict>",
                  "_hashable_values_": "<max_depth:list>",
                  "_unhashable_values_": "<max_depth:list>",
                  "_unhashable_values_map_": "<max_depth:dict>",
                  "_member_type_": "<max_depth:type>",
                  "_value_repr_": null,
                  "__doc__": null,
                  "RequestedAssetAndDependencies": "<cycle:AssetLoadMode>",
                  "AllPackedAssetsAndDependencies": "<max_depth:AssetLoadMode>",
                  "__new__": "<max_depth:function>"
                },
                "_sort_order_": 0
              },
              "ChunkedTransfer": false,
              "ClearOtherCachedVersionsWhenLoaded": false,
              "RedirectLimit": 32,
              "RetryCount": 0,
              "Timeout": 0,
              "UseCrcForCachedBundle": true,
              "UseUnityWebRequestForLocalBundles": false,
              "Version": 3
            },
            "Crc": 1295375149,
            "Hash": "000b49d70268e5ab9e28dbeb5c56bade"
          },
          "Type": {
            "__type__": "SerializedType",
            "AssemblyName": "Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
            "ClassName": "BCUL.AddressablesManager.ResourceProviders.EncryptedAssetBundleRequestOptions"
          }
        },
        "Dependencies": [],
        "DependencyHashCode": 0,
        "DependencyKey": null,
        "HashCode": 0,
        "InternalId": "{AM.RemoteAssetRootURL}/000b49d70268e5ab9e28dbeb5c56bade.bundle",
        "PrimaryKey": "000b49d70268e5ab9e28dbeb5c56bade.bundle",
        "ProviderId": "BCUL.AddressablesManager.ResourceProviders.EncryptedAssetBundleProvider",
        "Type": {
          "__type__": "SerializedType",
          "AssemblyName": "Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
          "ClassName": "UnityEngine.ResourceManagement.ResourceProviders.IAssetBundleResource"
        }
      }
    ],
    "00109695489693987c9d5757005e1dec.bundle": [
      {
        "__type__": "ResourceLocation",
        "Data": {
          "__type__": "WrappedSerializedObject",
          "Object": {
            "__type__": "AssetBundleRequestOptions",
            "BundleName": "6105ff46aa23fdfc1804a9619d1d4343",
            "BundleSize": 6270,
            "ComInfo": {
              "__type__": "CommonInfo",
              "AssetLoadMode": {
                "__type__": "AssetLoadMode",
                "_value_": 0,
                "_name_": "RequestedAssetAndDependencies",
                "__objclass__": {
                  "__type__": "EnumType",
                  "_generate_next_value_": "<max_depth:staticmethod>",
                  "__module__": "AddressablesTools.Classes.AssetBundleRequestOptions",
                  "__firstlineno__": 10,
                  "__static_attributes__": "<max_depth:tuple>",
                  "_new_member_": "<max_depth:builtin_function_or_method>",
                  "_use_args_": false,
                  "_member_names_": "<max_depth:list>",
                  "_member_map_": "<max_depth:dict>",
                  "_value2member_map_": "<max_depth:dict>",
                  "_hashable_values_": "<max_depth:list>",
                  "_unhashable_values_": "<max_depth:list>",
                  "_unhashable_values_map_": "<max_depth:dict>",
                  "_member_type_": "<max_depth:type>",
                  "_value_repr_": null,
                  "__doc__": null,
                  "RequestedAssetAndDependencies": "<cycle:AssetLoadMode>",
                  "AllPackedAssetsAndDependencies": "<max_depth:AssetLoadMode>",
                  "__new__": "<max_depth:function>"
                },
                "_sort_order_": 0
              },
              "ChunkedTransfer": false,
              "ClearOtherCachedVersionsWhenLoaded": false,
              "RedirectLimit": 32,
              "RetryCount": 0,
              "Timeout": 0,
              "UseCrcForCachedBundle": true,
              "UseUnityWebRequestForLocalBundles": false,
              "Version": 3
            },
            "Crc": 949661317,
            "Hash": "00109695489693987c9d5757005e1dec"
          },
          "Type": {
            "__type__": "SerializedType",
            "AssemblyName": "Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
            "ClassName": "BCUL.AddressablesManager.ResourceProviders.EncryptedAssetBundleRequestOptions"
          }
        },
        "Dependencies": [],
        "DependencyHashCode": 0,
        "DependencyKey": null,
        "HashCode": 0,
        "InternalId": "{AM.RemoteAssetRootURL}/00109695489693987c9d5757005e1dec.bundle",
        "PrimaryKey": "00109695489693987c9d5757005e1dec.bundle",
        "ProviderId": "BCUL.AddressablesManager.ResourceProviders.EncryptedAssetBundleProvider",
        "Type": {
          "__type__": "SerializedType",
          "AssemblyName": "Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
          "ClassName": "UnityEngine.ResourceManagement.ResourceProviders.IAssetBundleResource"
        }
      }
    ],...
}

BCUL_AddressablesManager_AssetBundleUtils__GetHashName(baseFileName, v8->static_fields->AbHashKey, v7, v6);


得知道这个AbHashKey怎么得到的



也不知道是对的还是错的…

纯静态分析的了。。。不会动态调试没用过安卓的hook模拟器一hook就炸
25a1351ae117a5072392cb67e26bb27d




其中有大量不确定的变量比如 StringLiteral_868 StringLiteral_17126 AbHashKey

import requests
import json
import msgpack
from Crypto.Cipher import AES
import base64
from Crypto.Util.Padding import unpad, pad


def xor(enc, k):
    return "".join(chr(ord(c) ^ k) for c in enc)


def parse(data):
    return msgpack.unpackb(
        unpad(
            AES.new(
                base64.b64decode(
                    xor("ypqoI-OwPJmPI.uTO.OuKpm,JsSGSJGoDvekGHejNpH ", 29).replace(
                        "\\", "/"
                    )
                ),
                AES.MODE_CBC,
                base64.b64decode(xor("O,dsS/(2+OGqs%2+jd[PL\\  ", 29)),
            ).decrypt(base64.b64decode(msgpack.unpackb(data, raw=False)["p"])),
            AES.block_size,
        ),
        raw=False,
    )


def encrypt(data: dict) -> str:
    return base64.b64encode(
        AES.new(
            base64.b64decode(
                xor("ypqoI-OwPJmPI.uTO.OuKpm,JsSGSJGoDvekGHejNpH ", 29).replace(
                    "\\", "/"
                )
            ),
            AES.MODE_CBC,
            base64.b64decode(xor("O,dsS/(2+OGqs%2+jd[PL\\  ", 29)),
        ).encrypt(pad(msgpack.packb(data, use_bin_type=True), AES.block_size))
    ).decode("utf-8")


headers = {
    "User-Agent": "UnityPlayer/2022.3.62f2 (UnityWebRequest/1.0, libcurl/8.10.1-DEV)",
    "Accept-Encoding": "deflate, gzip",
    "Accept-ViewType": "7",
    "X-Unity-Version": "2022.3.62f2",
}

payload = {
    "c": "Index",
    "dgs_adult": 1,
    "app_vc": {
        "os": 1,
        "catalog": "",
        "use_cdn": "https://gina.sangduoan.com/prod",
        "app_ver": "1.13.000",
        "app_type": 1,
    },
}


response = requests.post(
    "https://prod.karen-megahare.com/i.php",
    data={"p": encrypt(payload)},
    headers=headers,
)
print(json.dumps(parse(response.content), indent=4))

变更:突然发现下发的json里面没有hash key了,应该是他们又改了啥,也可能少参数了,以前是能获取到的

2 个赞