From d8e13f6d298ae4200e612287e80d12836c707bdc Mon Sep 17 00:00:00 2001 From: halleyscometsw Date: Thu, 15 Dec 2011 08:00:47 +0000 Subject: [PATCH] SCD Ogg Vorbis with obfuscated header triad (FFXIII-2) git-svn-id: https://vgmstream.svn.sourceforge.net/svnroot/vgmstream@970 51a99a44-fe44-0410-b1ba-c3e57ba2b86b --- src/meta/meta.h | 4 ++++ src/meta/ogg_vorbis_file.c | 47 ++++++++++++++++++++++++++++++++++---- src/meta/sqex_scd.c | 38 +++++++++++++++++++++++++++++- src/vgmstream.h | 4 ++++ 4 files changed, 87 insertions(+), 6 deletions(-) diff --git a/src/meta/meta.h b/src/meta/meta.h index 4a99f72d..bcf00361 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -97,6 +97,10 @@ typedef struct { int32_t loop_end; meta_t meta_type; layout_t layout_type; + + // XOR setup with a single byte (SCD) + unsigned char scd_xor; + off_t scd_xor_len; } vgm_vorbis_info_t; VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, const char * filename, ov_callbacks *callbacks, off_t other_header_bytes, const vgm_vorbis_info_t *vgm_inf); diff --git a/src/meta/ogg_vorbis_file.c b/src/meta/ogg_vorbis_file.c index fb93d2cb..db2cc1b7 100644 --- a/src/meta/ogg_vorbis_file.c +++ b/src/meta/ogg_vorbis_file.c @@ -80,6 +80,32 @@ static size_t read_func_kovs(void *ptr, size_t size, size_t nmemb, void * dataso return items_read; } +static size_t read_func_scd(void *ptr, size_t size, size_t nmemb, void * datasource) +{ + ogg_vorbis_streamfile * const ov_streamfile = datasource; + size_t items_read; + + size_t bytes_read; + + bytes_read = read_streamfile(ptr, ov_streamfile->offset + ov_streamfile->other_header_bytes, size * nmemb, + ov_streamfile->streamfile); + + items_read = bytes_read / size; + + /* first bytes are xor'd with a constant byte */ + if (ov_streamfile->offset < ov_streamfile->scd_xor_len) { + int num_crypt = ov_streamfile->scd_xor_len-ov_streamfile->offset; + int i; + + if (num_crypt > bytes_read) num_crypt=bytes_read; + for (i=0;iscd_xor; + } + + ov_streamfile->offset += items_read * size; + + return items_read; +} static int seek_func(void *datasource, ogg_int64_t offset, int whence) { ogg_vorbis_streamfile * const ov_streamfile = datasource; ogg_int64_t base_offset; @@ -130,7 +156,8 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) { int um3_ogg = 0; int kovs_ogg = 0; - vgm_vorbis_info_t inf = {0,0,0,0,0,0,0,0}; + vgm_vorbis_info_t inf; + memset(&inf, 0, sizeof(inf)); /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); @@ -214,12 +241,17 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, const ch int32_t loop_end = vgm_inf->loop_end; ov_callbacks default_callbacks; - default_callbacks.read_func = read_func; - default_callbacks.seek_func = seek_func; - default_callbacks.close_func = close_func; - default_callbacks.tell_func = tell_func; if (!callbacks_p) { + default_callbacks.read_func = read_func; + default_callbacks.seek_func = seek_func; + default_callbacks.close_func = close_func; + default_callbacks.tell_func = tell_func; + + if (vgm_inf->scd_xor != 0) { + default_callbacks.read_func = read_func_scd; + } + callbacks_p = &default_callbacks; } @@ -227,11 +259,14 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, const ch temp_streamfile.offset = 0; temp_streamfile.size = get_streamfile_size(temp_streamfile.streamfile); temp_streamfile.other_header_bytes = other_header_bytes; + temp_streamfile.scd_xor = vgm_inf->scd_xor; + temp_streamfile.scd_xor_len = vgm_inf->scd_xor_len; /* can we open this as a proper ogg vorbis file? */ memset(&temp_ovf, 0, sizeof(temp_ovf)); if (ov_test_callbacks(&temp_streamfile, &temp_ovf, NULL, 0, *callbacks_p)) goto fail; + /* we have to close this as it has the init_vgmstream meta-reading STREAMFILE */ ov_clear(&temp_ovf); @@ -246,6 +281,8 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, const ch data->ov_streamfile.offset = 0; data->ov_streamfile.size = get_streamfile_size(data->ov_streamfile.streamfile); data->ov_streamfile.other_header_bytes = other_header_bytes; + data->ov_streamfile.scd_xor = vgm_inf->scd_xor; + data->ov_streamfile.scd_xor_len = vgm_inf->scd_xor_len; /* open the ogg vorbis file for real */ if (ov_open_callbacks(&data->ov_streamfile, &data->ogg_vorbis_file, NULL, diff --git a/src/meta/sqex_scd.c b/src/meta/sqex_scd.c index 5565b4b3..4ca5447f 100644 --- a/src/meta/sqex_scd.c +++ b/src/meta/sqex_scd.c @@ -64,6 +64,10 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) { if (codec_id == 0x6) { vgm_vorbis_info_t inf; + uint32_t seek_table_size = read_32bit(meta_offset+0x30, streamFile); + uint32_t vorb_header_size = read_32bit(meta_offset+0x34, streamFile); + + memset(&inf, 0, sizeof(inf)); inf.loop_start = loop_start; inf.loop_end = loop_end; inf.loop_flag = loop_flag; @@ -72,7 +76,39 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) { inf.layout_type = layout_ogg_vorbis; inf.meta_type = meta_SQEX_SCD; - return init_vgmstream_ogg_vorbis_callbacks(streamFile, filename, NULL, start_offset, &inf); + VGMSTREAM * result = init_vgmstream_ogg_vorbis_callbacks(streamFile, filename, NULL, start_offset, &inf); + + if (result != NULL) { + return result; + } + + // try skipping seek table + { + if (0x20 + seek_table_size + vorb_header_size != read_32bit(meta_offset+0x18, streamFile)) { + return NULL; + } + + start_offset = meta_offset + 0x40 + seek_table_size; + result = init_vgmstream_ogg_vorbis_callbacks(streamFile, filename, NULL, start_offset, &inf); + if (result != NULL) { + return result; + } + } + + // try deobfuscating header (assume skipping seek table) + { + unsigned char xor_byte = read_8bit(meta_offset+0x22, streamFile); + + if (xor_byte == 0) { + return NULL; + } + + inf.scd_xor = xor_byte; + inf.scd_xor_len = vorb_header_size; + + VGMSTREAM * result = init_vgmstream_ogg_vorbis_callbacks(streamFile, filename, NULL, start_offset, &inf); + return result; + } } #endif diff --git a/src/vgmstream.h b/src/vgmstream.h index fdfe076f..ce9382a8 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -659,6 +659,10 @@ typedef struct { ogg_int64_t offset; ogg_int64_t size; ogg_int64_t other_header_bytes; + + // XOR setup with a single byte (SCD) + unsigned char scd_xor; + ogg_int64_t scd_xor_len; } ogg_vorbis_streamfile; typedef struct {