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.
Zero Tolerance for Disrespect

[PC] Asphalt Legends UNITE unknown file

Featured Replies

  • Localization

I really need help with Asphalt Legends UNITE PC version unknown files because I really wanted to dump the game files using BigChillGhost's python script and manifest.map but this script only supports v3.6.3a Android version and my sample file is v24.5.130.0 PC version (the latest version) because there's even more unicorn cars i wanted to rip. Is there anyone who can help me with it?

 

The process on how to rip all assets from separate apks using both manifest.map and the python script (For Android version of Asphalt 9 Legends Unite) was:

 

I) put both manifest.map and the python file in the dump folder with encrypted files

 

II) run the python script. It'll rename all the filenames contained in the manifest.map

manifest.7z restoreFileHierarchy.py Asphalt 9 PC sample.7z

In the meantime, I'll also link my other topic relating to Asphalt 9/Legends Unite jmodel: 

Edited by UndercoverBoy833
Linking my other link related to it + the steps of extracting unknown files

  • Supporter
On 2025/4/12 at PM4点55分, UndercoverBoy833 said:

我急需《狂野飙车:联合》PC 版未知文件的帮助,因为我真的很想用 BigChillGhost 的 Python 脚本和 manifest.map 转储游戏文件,但这个脚本只支持 v3.6.3a 安卓版本,而我的示例文件是 v24.5.130.0 PC 版(最新版本),因为里面还有更多独角兽车我想提取。有谁能帮我吗?

 

使用 manifest.map 和 python 脚本(针对 Android 版 Asphalt 9 Legends Unite)从单独的 apk 中提取所有资产的过程如下:

 

I) 将 manifest.map 和 python 文件放入包含加密文件的 dump 文件夹中

 

II) 运行 python 脚本。它将重命名 manifest.map 中包含的所有文件名

清单.7z 207.24 千字节 · 1 次下载 恢复文件层次结构.py 796 B · 1 次下载 狂野飙车9 PC 样本.7z 1.89 MB · 2 次下载

与此同时,我还将链接与 Asphalt 9/Legends Unite jmodel 相关的其他主题: 

Some of the files you provide contain zstd compression

File Type 1:89 6A 74 65 78 20 78 0D

Compression position is 0x5B

But there are 22 bytes of additional data before this

These additional data need to be added to the compressed file at the same time and skipped when decompressed

4 bytes - extra data + total compressed data size

4 bytes - unknown, very close to the size of the compressed data

4 bytes - Decompressed size (correct)

File Type 2:89 6A 6D 6F 78 0D 0A 01

The example of this file starts after 510 bytes

Because two unknowns need to be read, four compression sizes and four decompressed sizes

File Type 3:02 AF EA 61 6E 67 69 65

79 EC DC 47

The verification is too small, and I haven't seen whether there is compression for the time being, I'm not sure

For the first two data, I wrote a script to decompress the compressed data inside and directly extract binary data of unknown structures.

All research is based on guessing from existing files, if a more complete script is needed, you may need to add features based on more files, because I can't guarantee that the offsets displayed by each file are the same

import os
import struct
import pyzstd
import random
import string
from pathlib import Path

def random_filename(length=16, extension='.bin'):
    chars = string.ascii_letters + string.digits
    return ''.join(random.choice(chars) for _ in range(length)) + extension

def process_first_format(f):
    extracted_data = []
    f.seek(69)
    
    while True:
        position = f.tell()
        size_bytes = f.read(4)
        if len(size_bytes) < 4: break
        
        data_size = struct.unpack('<I', size_bytes)[0]
        remaining_size = data_size - 4
        data = f.read(remaining_size)
        if len(data) < remaining_size:
            print(f"Insufficient data @ {position}")
            break
        
        full_data = size_bytes + data
        processed_data = full_data[22:] if len(full_data) > 22 else full_data
        
        if len(processed_data) >= 4 and processed_data[:4] == bytes.fromhex('28 B5 2F FD'):
            try:
                extracted_data.append(pyzstd.decompress(processed_data))
            except Exception as e:
                print(f"Decompression failed: {e}")
                extracted_data.append(processed_data)
        else:
            extracted_data.append(processed_data)
    
    return extracted_data

def process_second_format(f):
    extracted_data = []
    f.seek(510)
    
    while True:
        position = f.tell()
        unknown = f.read(2)
        if len(unknown) < 2: break
        
        compression_info = f.read(8)
        if len(compression_info) < 8: break
        
        compressed_size = struct.unpack('<I', compression_info[:4])[0]
        compressed_data = f.read(compressed_size)
        if len(compressed_data) < compressed_size:
            print(f"Insufficient data @ {position}")
            break
        
        if len(compressed_data) >= 4 and compressed_data[:4] == bytes.fromhex('28 B5 2F FD'):
            try:
                extracted_data.append(pyzstd.decompress(compressed_data))
            except Exception as e:
                print(f"Decompression failed: {e}")
                extracted_data.append(compressed_data)
        else:
            extracted_data.append(compressed_data)
    
    return extracted_data

def process_single_file(input_file, output_dir):
    try:
        with open(input_file, 'rb') as f:
            header = f.read(8)
            
            if header == bytes.fromhex('89 6A 74 65 78 20 78 0D'):
                print(f"Processing {input_file} (Format 1)")
                results = process_first_format(f)
            elif header == bytes.fromhex('89 6A 6D 6F 78 0D 0A 01'):
                print(f"Processing {input_file} (Format 2)")
                results = process_second_format(f)
            else:
                print(f"Skipping {input_file} (Unknown format)")
                return
            
            for i, data in enumerate(results, 1):
                output_path = Path(output_dir) / random_filename()
                with open(output_path, 'wb') as out_file:
                    out_file.write(data)
                print(f"Saved block {i} from {input_file}")
    
    except Exception as e:
        print(f"Error processing {input_file}: {e}")

def process_directory(input_dir, output_dir):
    Path(output_dir).mkdir(parents=True, exist_ok=True)
    
    for entry in os.scandir(input_dir):
        if entry.is_file():
            process_single_file(entry.path, output_dir)

if __name__ == '__main__':
    import sys
    if len(sys.argv) != 3:
        print("Usage: python asphalt.py <input_directory> <output_directory>")
        sys.exit(1)
    
    process_directory(sys.argv[1], sys.argv[2])

 

  • Supporter

Skipping this additional data may do the trick.

A9tool (which comes with libzstd.dll, btw, if user cared for BigChillghosts post more carefully) gives me this:

a9tool c.jtex
Error: missing configuration file! Default settings have been used!
Processing c.jtex...     1048576, 262144, 65536, 16384, 4096, 1024, 256,finished
 

(Where c.jtex is renamed 000C022A608FF242 for easier handling on command line.)

The resulting c.jtex.pvr doesn't show a valid tex, so I'll recompile libzstd asap, with taking the additional data into acount.

Thanks for the hint.

(I'd like to check your python code, but module pyzstd is not standard (haha) on Windows systems.)

 

 

Edited by shak-otay

  • Supporter

This work is done on other systems, because I can't install pyzstd on Windows system, it may be a problem with my python version, maybe some alternatives can be used

Edited by wq223

  • Supporter

I got your script running under windows after

python -m pip install pyzstd==0.15.3

and 11 bins where created from the c.jtex mentioned here.

I compared the biggest bin file (1 MB) to the c.jtex.pvr (from offset 0x34) created by A9tool and the data is identical (apart from the fact that c.jtex.pvr is bigger).

So far so good. But why then doesn't the pvr contain a valid texture?

 

 

Edited by shak-otay

  • Author
  • Localization
34 minutes ago, shak-otay said:

I got your script running under windows after

python -m pip install pyzstd==0.15.3

and 11 bins where created from the c.jtex mentioned here.

I compared the biggest bin file (1 MB) to the c.jtex.pvr (from offset 0x34) created by A9tool and the data is identical (apart from the fact that c.jtex.pvr is bigger).

So far so good. But why then doesn't the pvr contain a valid texture?

 

 

probably different format, also have you tried getting into game memory for any file format type in the PC version (Windows Store) of this game? If not, then it's probably that.

  • Supporter

How should "getting into game memory" help? I guess it's another problem because the biggest decompressed block has some structures:

texAssumed.png

edit: I have a working file, car_Lamborghini_Terzo_Millennio_details_mk.tga.jtex, which provides a valid pvr, so I think I need to understand the .jtex headers.

What I found is that the above shown pvr picture has the pixelformat ASTC_5x5x5, while the valid pvr has ETC2 RGB.

Edited by shak-otay

  • 6 months later...

Create an account or sign in to comment

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.