Jump to content

[PS2] Junjou Romantica Koi no Doki Doki Daisakusen PTD file extraction


Recommended Posts

  • 1 year later...
Posted

INVESTIGACIÓN COMPLETA: ANÁLISIS DE SCRIPT.PTD
- `SLES_526.07.ELF` (ejecutable del juego PS2)
- `SCRIPT.PTD` (1,728,512 bytes)

PASOS REALIZADOS:

1. ANÁLISIS INICIAL DEL ARCHIVO:
```
hexdump -C SCRIPT.PTD | head -50
```
- Primeros 32 bytes: cabecera desconocida
- Bytes 0x20-0x11F: 256 bytes de tabla
- Resto: datos encriptados

2. BÚSQUEDA EN EL EJECUTABLE:

 

r2 -A SLES_526.07.ELF
afl | grep -i "read\|fopen\|file"



- Encontrada función en 0x0010da30 (manejo de archivos)

3. TRAZADO DE LLAMADAS:

0x0010da30 → 0x10ccf0 → 0x10a3f8 → 0x0010d850

4. ANÁLISIS DE LA FUNCIÓN DE DECODIFICACIÓN (0x0010d850):

Código MIPS encontrado:

lui     $a0, 0x001a
addiu   $a0, $a0, -0x0a00  ; buffer destino
move    $a1, $s1           ; puntero a datos
li      $a2, 0x120         ; offset inicial
move    $t1, $zero         ; t1 = 0x00
move    $t3, $s3           ; t3 = 0x04 (de s3)
 

ALGORITMO DESCUBIERTO:

Para cada byte en input[a2++]:
    t1 = (t1 - 1) & 0xFF
    t7 = t1 XOR byte_actual
    t7 = (t7 + t3) & 0xFF
    output = tabla[0x20 + t7]
    t3 = memoria[s0] (actualización dinámica)
 

5. TABLA DE DECODIFICACIÓN (offset 0x20):
```
00000020: 89 7c 3a f1 4d e2 b0 55 92 47 18 6d a3 fe 29 8b
00000030: 74 31 9f d6 58 c3 67 b4 e5 12 4a 7f 36 98 d1 6a
...
(256 bytes total)
```

6. IMPLEMENTACIÓN EN PYTHON:
def decode_script(data):
    table = data[0x20:0x120]  # 256 bytes
    encrypted = data[0x120:]   # datos encriptados
    
    t1 = 0x00
    t3 = 0x04
    output = []
    
    for byte in encrypted:
        t1 = (t1 - 1) & 0xFF
        t7 = t1 ^ byte
        t7 = (t7 + t3) & 0xFF
        decoded = table[t7]
        output.append(decoded)
        # t3 se actualiza de memoria[s0] - pendiente
    
    return bytes(output)
 

7. RESULTADOS DEL DESCIFRADO:
- Tamaño descifrado: 1,728,224 bytes
- 12,026 cadenas de texto japonés encontradas
- 3,733 ocurrencias del byte 0x9C
- 1,949 ocurrencias del byte 0xA8
- 865 ocurrencias del byte 0xA2

8. ESTRUCTURA DEL BYTECODE DESCUBIERTO:

[0x9C] [OPCODE] [parámetros...] [texto japonés] [0x9C] [OPCODE]...

Opcodes identificados:
- 0xA8 = 惠 (más común)
- 0xA2 = 悗
- 0x5E = 弯
- 0x8A = 怺
- 0xDF = 憑
- 0xF2 = 懿
- 0xC8 = 慂
- 0xDA = 憇

9. PATRONES DETECTADOS:
- Secuencias: `9C A8 9C A2 9C A8 9C 24...`
- Byte 0x24 aparece como separador
- Texto entre comandos en codificación Shift-JIS

10. LO QUE FALTA POR DESCUBRIR:
- Funciones que procesan cada opcode (A8, A2, etc.)
- Tabla de dispatch en el ejecutable
- Significado de los primeros 32 bytes
- Actualización exacta de t3 durante decodificación
- Estructura completa de parámetros por comando

  • Like 1
  • Confused 1
  • Engineers
Posted (edited)
On 10/17/2024 at 10:59 PM, Pato said:

Hi!

I want to rip from a ps2 visual novel game developed called "Junjou Romantica Koi no Doki Doki Daisakusen" by Marvelous Entertainment.
I've extracted the files of the game, but the script and images, which i'm interested, are stored in .PTD files இ௰இ

Here are the files
https://drive.google.com/drive/folders/1JcVjA7iT3Fr9dg7QzTUwZ5fJojLyxDsi?usp=sharing

Thank you very much!

THE IMAGE.PTD ITS A CONTAINER, ALL TIM2 IMAGES ARE COMPRESSED WITH A CUSTOM LZSS.

 

IMAGE_seg_0000_YKLZ.YKLZ.decomp@0000000064.png

Edited by Rabatini
Posted (edited)
On 12/8/2025 at 12:27 AM, ninoochan said:

INVESTIGACIÓN COMPLETA: ANÁLISIS DE SCRIPT.PTD
- `SLES_526.07.ELF` (ejecutable del juego PS2)
- `SCRIPT.PTD` (1,728,512 bytes)

PASOS REALIZADOS:

1. ANÁLISIS INICIAL DEL ARCHIVO:
```
hexdump -C SCRIPT.PTD | head -50
```
- Primeros 32 bytes: cabecera desconocida
- Bytes 0x20-0x11F: 256 bytes de tabla
- Resto: datos encriptados

2. BÚSQUEDA EN EL EJECUTABLE:

 

r2 -A SLES_526.07.ELF
afl | grep -i "read\|fopen\|file"



- Encontrada función en 0x0010da30 (manejo de archivos)

3. TRAZADO DE LLAMADAS:

0x0010da30 → 0x10ccf0 → 0x10a3f8 → 0x0010d850

4. ANÁLISIS DE LA FUNCIÓN DE DECODIFICACIÓN (0x0010d850):

Código MIPS encontrado:

lui     $a0, 0x001a
addiu   $a0, $a0, -0x0a00  ; buffer destino
move    $a1, $s1           ; puntero a datos
li      $a2, 0x120         ; offset inicial
move    $t1, $zero         ; t1 = 0x00
move    $t3, $s3           ; t3 = 0x04 (de s3)
 

ALGORITMO DESCUBIERTO:

Para cada byte en input[a2++]:
    t1 = (t1 - 1) & 0xFF
    t7 = t1 XOR byte_actual
    t7 = (t7 + t3) & 0xFF
    output = tabla[0x20 + t7]
    t3 = memoria[s0] (actualización dinámica)
 

5. TABLA DE DECODIFICACIÓN (offset 0x20):
```
00000020: 89 7c 3a f1 4d e2 b0 55 92 47 18 6d a3 fe 29 8b
00000030: 74 31 9f d6 58 c3 67 b4 e5 12 4a 7f 36 98 d1 6a
...
(256 bytes total)
```

6. IMPLEMENTACIÓN EN PYTHON:
def decode_script(data):
    table = data[0x20:0x120]  # 256 bytes
    encrypted = data[0x120:]   # datos encriptados
    
    t1 = 0x00
    t3 = 0x04
    output = []
    
    for byte in encrypted:
        t1 = (t1 - 1) & 0xFF
        t7 = t1 ^ byte
        t7 = (t7 + t3) & 0xFF
        decoded = table[t7]
        output.append(decoded)
        # t3 se actualiza de memoria[s0] - pendiente
    
    return bytes(output)
 

7. RESULTADOS DEL DESCIFRADO:
- Tamaño descifrado: 1,728,224 bytes
- 12,026 cadenas de texto japonés encontradas
- 3,733 ocurrencias del byte 0x9C
- 1,949 ocurrencias del byte 0xA8
- 865 ocurrencias del byte 0xA2

8. ESTRUCTURA DEL BYTECODE DESCUBIERTO:

[0x9C] [OPCODE] [parámetros...] [texto japonés] [0x9C] [OPCODE]...

Opcodes identificados:
- 0xA8 = 惠 (más común)
- 0xA2 = 悗
- 0x5E = 弯
- 0x8A = 怺
- 0xDF = 憑
- 0xF2 = 懿
- 0xC8 = 慂
- 0xDA = 憇

9. PATRONES DETECTADOS:
- Secuencias: `9C A8 9C A2 9C A8 9C 24...`
- Byte 0x24 aparece como separador
- Texto entre comandos en codificación Shift-JIS

10. LO QUE FALTA POR DESCUBRIR:
- Funciones que procesan cada opcode (A8, A2, etc.)
- Tabla de dispatch en el ejecutable
- Significado de los primeros 32 bytes
- Actualización exacta de t3 durante decodificación
- Estructura completa de parámetros por comando

1. FORMATO DEL ARCHIVO SCRIPT.PTD:

Firma de cabecera: "PETA" (50 45 54 41)

Tamaño total: 1,728,512 bytes

Estructura: Cabecera 32 bytes + SBOX 256 bytes + Datos cifrados

SBOX: 256 bytes en offset 0x20-0x11F

Datos cifrados: 1,728,224 bytes restantes


DESCIFRADO COMPLETO:

Algoritmo MIPS con SBOX de 256 bytes

Parámetros óptimos: t3 = 0x02, bloques de 288 bytes

script.ptd → script.dec (1,722,223 bytes)

2. DESCOMPRESIÓN YKLZ/LZSS FUNCIONA:

249 secciones YKLZ encontradas

Formato: "YKLZ" + param_byte=0x0A + tamaño descomprimido + datos LZSS

Descompresión exitosa con shift=2, mask=3

3. TEXTO REAL EXTRAÍDO:

純ロマ = "JUNROMAN" identificado

Texto japonés en Shift-JIS encontrado

Estructura híbrida: texto + comandos + padding

4. FLUJO DEL JUEGO DESCUBIERTO:

text

script.ptd → Descifrado → YKLZ/LZSS → Script Binario ↓ fcn.0010e048 (Intérprete) ↓ fcn.0010ded0 (Parser) ↓ fcn.00119fc0 / fcn.0011a0ec (Diálogos) ↓ fcn.00106800 (Configura contexto) ↓ fcn.001068d0 (Renderiza texto) ↓ fcn.0016e400 / fcn.0016e4a8 (Dibujo GPU)

5. ESTRUCTURAS IDENTIFICADAS:

c

struct TextContext { void* gpu_buffer; // 0x00 uint32_t text_ptr; // 0x04 (¿puntero al texto?) uint32_t param1; // 0x08 (¿posición X?) uint32_t flags; // 0x0C (¡t6! 0→fcn.0016e400, ≠0→0x16e458) uint8_t font_index; // 0x10 (índice de fuente) };

 PROBLEMA PRINCIPAL (LO QUE FALTA):

LOS SCRIPTS DESCOMPRIMIDOS NO SE INTERPRETAN CORRECTAMENTE

Ejemplo de datos descomprimidos:

text

純ロマ####@###シg##@###ト###4.##X)##イ*##4...

Problema: Cuando decodificamos como Shift-JIS, obtenemos:

Hay texto japonés real Pero los bytes de comandos se interpretan como caracteres extraños...

 

Estructura probable de los scripts:

text

[TEXTO Shift-JIS] [PADDING "####"] [COMANDO "@" + 3 bytes] [MÁS TEXTO]...

Lo que debería pasar:

Parser detecta @ (0x40) → Interpreta como comando

Lee 3 bytes siguientes → Parámetros del comando

Procesa texto Shift-JIS → Caracteres de 1-2 bytes

Salta padding # (0x23) → Bytes de alineación
(segun elf?)



------ EDIT:
 

SCRIPT.PTD (1.7MB) → 249 secciones YKLZ → Archivos binarios estructurados

2. CABECERA UNIFICADA (16 bytes):

Todos los archivos YKLZ comparten la misma cabecera:

image.png.d6c89e0fdd0ee79360059e0e5e84b2c0.png 

Sección 0x00-0x3F: CABECERA Y METADATOS

0x00-0x0F: Cabecera fija

0x10-0x2F: Offsets/parámetros del script

0x30-0x3F: Flags/configuración

Sección 0x40+: DATOS DEL SCRIPT


LOS ARCHIVOS YKLZ CONTIENEN:

Scripts compilados (bytecode que ejecuta fcn.0010e048)

Referencias a diálogos (IDs/offsets, no texto)

Lógica de juego (condicionales, saltos, etc.)

Parámetros de visualización (posición, fuente, timing)

LOS DIÁLOGOS REALES ESTÁN EN????

SOUND.PTD (610 MB) → MÁS PROBABLE (voces + subtítulos sincronizados) ?????

Edited by ninoochan
  • Like 1

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...