Pato Posted October 18, 2024 Posted October 18, 2024 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!
ninoochan Posted Monday at 03:27 AM Posted Monday at 03:27 AM 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 1
Engineers Rabatini Posted Monday at 06:51 AM Engineers Posted Monday at 06:51 AM (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. Edited Monday at 01:40 PM by Rabatini
Engineers Rabatini Posted Tuesday at 05:25 PM Engineers Posted Tuesday at 05:25 PM (edited) There is the tool PS2JunjouUnpacker-decompressor.zip Edited Tuesday at 05:26 PM by Rabatini 2
ninoochan Posted 16 hours ago Posted 16 hours ago (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: 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 8 hours ago by ninoochan 1
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now