diff --git a/src/coding/coding.h b/src/coding/coding.h index 3d05f987..32fea8f3 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -324,9 +324,21 @@ void decode_hca(hca_codec_data* data, sample_t* outbuf, int32_t samples_to_do); void reset_hca(hca_codec_data* data); void loop_hca(hca_codec_data* data, int32_t num_sample); void free_hca(hca_codec_data* data); -int test_hca_key(hca_codec_data* data, unsigned long long keycode); -void hca_set_encryption_key(hca_codec_data* data, uint64_t keycode); clHCA_stInfo* hca_get_info(hca_codec_data* data); + +typedef struct { + /* config + output */ + uint64_t key; + uint16_t subkey; + uint64_t best_key; + int best_score; + /* internals */ + uint32_t start_offset; +} hca_keytest_t; + +void test_hca_key(hca_codec_data* data, hca_keytest_t* hk); +void hca_set_encryption_key(hca_codec_data* data, uint64_t keycode); + STREAMFILE* hca_get_streamfile(hca_codec_data* data); diff --git a/src/coding/hca_decoder.c b/src/coding/hca_decoder.c index d4183b62..1f1de3a5 100644 --- a/src/coding/hca_decoder.c +++ b/src/coding/hca_decoder.c @@ -3,7 +3,7 @@ struct hca_codec_data { - STREAMFILE* streamfile; + STREAMFILE* sf; clHCA_stInfo info; signed short* sample_buffer; @@ -58,8 +58,8 @@ hca_codec_data* init_hca(STREAMFILE* sf) { if (!data->sample_buffer) goto fail; /* load streamfile for reads */ - data->streamfile = reopen_streamfile(sf, 0); - if (!data->streamfile) goto fail; + data->sf = reopen_streamfile(sf, 0); + if (!data->sf) goto fail; /* set initial values */ reset_hca(data); @@ -115,7 +115,7 @@ void decode_hca(hca_codec_data* data, sample_t* outbuf, int32_t samples_to_do) { } /* read frame */ - bytes = read_streamfile(data->data_buffer, offset, blockSize, data->streamfile); + bytes = read_streamfile(data->data_buffer, offset, blockSize, data->sf); if (bytes != blockSize) { VGM_LOG("HCA: read %x vs expected %x bytes at %x\n", bytes, blockSize, (uint32_t)offset); break; @@ -171,7 +171,7 @@ void loop_hca(hca_codec_data* data, int32_t num_sample) { void free_hca(hca_codec_data* data) { if (!data) return; - close_streamfile(data->streamfile); + close_streamfile(data->sf); clHCA_done(data->handle); free(data->handle); free(data->data_buffer); @@ -179,6 +179,14 @@ void free_hca(hca_codec_data* data) { free(data); } +clHCA_stInfo* hca_get_info(hca_codec_data* data) { + return &data->info; +} + +STREAMFILE* hca_get_streamfile(hca_codec_data* data) { + if (!data) return NULL; + return data->sf; +} /* ************************************************************************* */ @@ -192,19 +200,25 @@ void free_hca(hca_codec_data* data) { /* ignores beginning frames (~10 is not uncommon, Dragalia Lost vocal layers have lots) */ #define HCA_KEY_MAX_SKIP_BLANKS 1200 /* 5~15 should be enough, but almost silent or badly mastered files may need tweaks - * (ex. newer Tales of the Rays files clip a lot and need +6 as some keys give almost-ok results) */ -#define HCA_KEY_MIN_TEST_FRAMES 7 -#define HCA_KEY_MAX_TEST_FRAMES 12 + * (ex. newer Tales of the Rays files clip a lot) */ +#define HCA_KEY_MIN_TEST_FRAMES 3 //7 +#define HCA_KEY_MAX_TEST_FRAMES 7 //12 /* score of 10~30 isn't uncommon in a single frame, too many frames over that is unlikely */ #define HCA_KEY_MAX_FRAME_SCORE 150 #define HCA_KEY_MAX_TOTAL_SCORE (HCA_KEY_MAX_TEST_FRAMES * 50*HCA_KEY_SCORE_SCALE) /* Test a number of frames if key decrypts correctly. * Returns score: <0: error/wrong, 0: unknown/silent file, >0: good (the closest to 1 the better). */ -int test_hca_key(hca_codec_data* data, unsigned long long keycode) { +static int test_hca_score(hca_codec_data* data, hca_keytest_t* hk, unsigned long long keycode) { size_t test_frames = 0, current_frame = 0, blank_frames = 0; - int total_score = 0, found_regular_frame = 0; - const unsigned int blockSize = data->info.blockSize; + int total_score = 0; + const unsigned int block_size = data->info.blockSize; + uint32_t offset = hk->start_offset; + + if (!offset) + offset = data->info.headerSize; + +//VGM_LOG("test=k\n"); /* Due to the potentially large number of keys this must be tuned for speed. * Buffered IO seems fast enough (not very different reading a large block once vs frame by frame). @@ -216,19 +230,25 @@ int test_hca_key(hca_codec_data* data, unsigned long long keycode) { /* A final score of 0 (=silent) is only possible for short files with all blank frames */ while (test_frames < HCA_KEY_MAX_TEST_FRAMES && current_frame < data->info.blockCount) { - off_t offset = data->info.headerSize + current_frame * blockSize; int score; size_t bytes; - +//VGM_LOG(" *frame\n"); /* read and test frame */ - bytes = read_streamfile(data->data_buffer, offset, blockSize, data->streamfile); - if (bytes != blockSize) { + bytes = read_streamfile(data->data_buffer, offset, block_size, data->sf); + if (bytes != block_size) { /* normally this shouldn't happen, but pre-fetch ACB stop with frames in half, so just keep score */ //total_score = -1; break; } - score = clHCA_TestBlock(data->handle, (void*)(data->data_buffer), blockSize); + score = clHCA_TestBlock(data->handle, data->data_buffer, block_size); + + /* get first non-blank frame */ + if (!hk->start_offset && score != 0) { + hk->start_offset = offset; + } + offset += bytes; + if (score < 0 || score > HCA_KEY_MAX_FRAME_SCORE) { total_score = -1; break; @@ -236,13 +256,12 @@ int test_hca_key(hca_codec_data* data, unsigned long long keycode) { current_frame++; - /* ignore silent frames at the beginning, up to a point */ - if (score == 0 && blank_frames < HCA_KEY_MAX_SKIP_BLANKS && !found_regular_frame) { + /* ignore silent frames at the beginning, up to a point and first non-blank */ + if (score == 0 && blank_frames < HCA_KEY_MAX_SKIP_BLANKS && !hk->start_offset) { blank_frames++; continue; } - found_regular_frame = 1; test_frames++; /* scale values to make scores of perfect frames more detectable */ @@ -254,7 +273,6 @@ int test_hca_key(hca_codec_data* data, unsigned long long keycode) { total_score += score; - /* don't bother checking more frames, other keys will get better scores */ if (total_score > HCA_KEY_MAX_TOTAL_SCORE) break; @@ -265,20 +283,42 @@ int test_hca_key(hca_codec_data* data, unsigned long long keycode) { if (test_frames > HCA_KEY_MIN_TEST_FRAMES && total_score > 0 && total_score <= test_frames) { total_score = 1; } - +//VGM_LOG("test=%i\n", total_score); clHCA_DecodeReset(data->handle); return total_score; } +void test_hca_key(hca_codec_data* data, hca_keytest_t* hk) { + int score; + uint64_t key = hk->key; + uint16_t subkey = hk->subkey; + + //;VGM_LOG("HCA: test key=%08x%08x, subkey=%04x\n", + // (uint32_t)((key >> 32) & 0xFFFFFFFF), (uint32_t)(key & 0xFFFFFFFF), subkey); + + if (subkey) { + key = key * ( ((uint64_t)subkey << 16u) | ((uint16_t)~subkey + 2u) ); + } + + score = test_hca_score(data, hk, (unsigned long long)key); + + //;VGM_LOG("HCA: test key=%08x%08x, subkey=%04x, score=%i\n", + // (uint32_t)((key >> 32) & 0xFFFFFFFF), (uint32_t)(key & 0xFFFFFFFF), subkey, score); + + /* wrong key */ + if (score < 0) + return; + + //;VGM_LOG("HCA: ok key=%08x%08x, subkey=%04x, score=%i\n", + // (uint32_t)((key >> 32) & 0xFFFFFFFF), (uint32_t)(key & 0xFFFFFFFF), subkey, score); + + /* update if something better is found */ + if (hk->best_score <= 0 || (score < hk->best_score && score > 0)) { + hk->best_score = score; + hk->best_key = key; + } +} + void hca_set_encryption_key(hca_codec_data* data, uint64_t keycode) { clHCA_SetKey(data->handle, (unsigned long long)keycode); } - -clHCA_stInfo* hca_get_info(hca_codec_data* data) { - return &data->info; -} - -STREAMFILE* hca_get_streamfile(hca_codec_data* data) { - if (!data) return NULL; - return data->streamfile; -} diff --git a/src/coding/hca_decoder_clhca.c b/src/coding/hca_decoder_clhca.c index 09294066..4a999979 100644 --- a/src/coding/hca_decoder_clhca.c +++ b/src/coding/hca_decoder_clhca.c @@ -57,9 +57,9 @@ #define HCA_MAX_FRAME_SIZE 0xFFFF /* lib max */ #define HCA_MASK 0x7F7F7F7F /* chunk obfuscation when the HCA is encrypted with key */ -#define HCA_SUBFRAMES_PER_FRAME 8 +#define HCA_SUBFRAMES 8 #define HCA_SAMPLES_PER_SUBFRAME 128 /* also spectrum points/etc */ -#define HCA_SAMPLES_PER_FRAME (HCA_SUBFRAMES_PER_FRAME*HCA_SAMPLES_PER_SUBFRAME) +#define HCA_SAMPLES_PER_FRAME (HCA_SUBFRAMES*HCA_SAMPLES_PER_SUBFRAME) #define HCA_MDCT_BITS 7 /* (1<<7) = 128 */ #define HCA_MIN_CHANNELS 1 @@ -88,7 +88,7 @@ typedef struct stChannel { unsigned int coded_count; /* encoded scales/resolutions/coefs */ /* subframe state */ - unsigned char intensity[HCA_SUBFRAMES_PER_FRAME]; /* intensity indexes for joins stereo (value max: 15 / 4b) */ + unsigned char intensity[HCA_SUBFRAMES]; /* intensity indexes for joins stereo (value max: 15 / 4b) */ unsigned char scalefactors[HCA_SAMPLES_PER_SUBFRAME]; /* scale indexes (value max: 64 / 6b)*/ unsigned char resolution[HCA_SAMPLES_PER_SUBFRAME]; /* resolution indexes (value max: 15 / 4b) */ unsigned char noises[HCA_SAMPLES_PER_SUBFRAME]; /* indexes to coefs that need noise fill + coefs that don't (value max: 128 / 8b) */ @@ -96,13 +96,14 @@ typedef struct stChannel { unsigned int valid_count; /* resolutions with valid values saved in 'noises' */ float gain[HCA_SAMPLES_PER_SUBFRAME]; /* gain to apply to quantized spectral data */ - float spectra[HCA_SAMPLES_PER_SUBFRAME]; /* resulting dequantized data */ + float spectra[HCA_SUBFRAMES][HCA_SAMPLES_PER_SUBFRAME]; /* resulting dequantized data */ + float temp[HCA_SAMPLES_PER_SUBFRAME]; /* temp for DCT-IV */ float dct[HCA_SAMPLES_PER_SUBFRAME]; /* result of DCT-IV */ float imdct_previous[HCA_SAMPLES_PER_SUBFRAME]; /* IMDCT */ /* frame state */ - float wave[HCA_SUBFRAMES_PER_FRAME][HCA_SAMPLES_PER_SUBFRAME]; /* resulting samples */ + float wave[HCA_SUBFRAMES][HCA_SAMPLES_PER_SUBFRAME]; /* resulting samples */ } stChannel; typedef struct clHCA { @@ -333,7 +334,7 @@ void clHCA_ReadSamples16(clHCA* hca, signed short *samples) { unsigned int i, j, k; /* PCM output is generally unused, but lib functions seem to use SIMD for f32 to s32 + round to zero */ - for (i = 0; i < HCA_SUBFRAMES_PER_FRAME; i++) { + for (i = 0; i < HCA_SUBFRAMES; i++) { for (j = 0; j < HCA_SAMPLES_PER_SUBFRAME; j++) { for (k = 0; k < hca->channels; k++) { f = hca->channel[k].wave[i][j]; @@ -989,8 +990,12 @@ void clHCA_SetKey(clHCA* hca, unsigned long long keycode) { } } +static int clHCA_DecodeBlock_unpack(clHCA* hca, void *data, unsigned int size); +static void clHCA_DecodeBlock_transform(clHCA* hca); + + int clHCA_TestBlock(clHCA* hca, void *data, unsigned int size) { - const int frame_samples = HCA_SUBFRAMES_PER_FRAME * HCA_SAMPLES_PER_SUBFRAME; + const int frame_samples = HCA_SUBFRAMES * HCA_SAMPLES_PER_SUBFRAME; const float scale = 32768.0f; unsigned int i, ch, sf, s; int status; @@ -1014,7 +1019,7 @@ int clHCA_TestBlock(clHCA* hca, void *data, unsigned int size) { } /* return if decode fails (happens often with wrong keys due to bad bitstream values) */ - status = clHCA_DecodeBlock(hca, data, size); + status = clHCA_DecodeBlock_unpack(hca, data, size); if (status < 0) return -1; @@ -1042,8 +1047,9 @@ int clHCA_TestBlock(clHCA* hca, void *data, unsigned int size) { } /* check decode results as (rarely) bad keys may still get here */ + clHCA_DecodeBlock_transform(hca); for (ch = 0; ch < hca->channels; ch++) { - for (sf = 0; sf < HCA_SUBFRAMES_PER_FRAME; sf++) { + for (sf = 0; sf < HCA_SUBFRAMES; sf++) { for (s = 0; s < HCA_SAMPLES_PER_SUBFRAME; s++) { float fsample = hca->channel[ch].wave[sf][s]; @@ -1095,15 +1101,15 @@ void clHCA_DecodeReset(clHCA * hca) { stChannel* ch = &hca->channel[i]; /* most values get overwritten during decode */ - //memset(ch->intensity, 0, sizeof(ch->intensity[0]) * HCA_SUBFRAMES_PER_FRAME); + //memset(ch->intensity, 0, sizeof(ch->intensity[0]) * HCA_SUBFRAMES); //memset(ch->scalefactors, 0, sizeof(ch->scalefactors[0]) * HCA_SAMPLES_PER_SUBFRAME); //memset(ch->resolution, 0, sizeof(ch->resolution[0]) * HCA_SAMPLES_PER_SUBFRAME); //memset(ch->gain, 0, sizeof(ch->gain[0]) * HCA_SAMPLES_PER_SUBFRAME); - //memset(ch->spectra, 0, sizeof(ch->spectra[0]) * HCA_SAMPLES_PER_SUBFRAME); + //memset(ch->spectra, 0, sizeof(ch->spectra[0]) * HCA_SUBFRAMES * HCA_SAMPLES_PER_SUBFRAME); //memset(ch->temp, 0, sizeof(ch->temp[0]) * HCA_SAMPLES_PER_SUBFRAME); //memset(ch->dct, 0, sizeof(ch->dct[0]) * HCA_SAMPLES_PER_SUBFRAME); memset(ch->imdct_previous, 0, sizeof(ch->imdct_previous[0]) * HCA_SAMPLES_PER_SUBFRAME); - //memset(ch->wave, 0, sizeof(ch->wave[0][0]) * HCA_SUBFRAMES_PER_FRAME * HCA_SUBFRAMES_PER_FRAME); + //memset(ch->wave, 0, sizeof(ch->wave[0][0]) * HCA_SUBFRAMES * HCA_SUBFRAMES); } } @@ -1119,23 +1125,21 @@ static void calculate_resolution(stChannel* ch, unsigned int packed_noise_level, static void calculate_gain(stChannel* ch); -static void dequantize_coefficients(stChannel* ch, clData* br); +static void dequantize_coefficients(stChannel* ch, clData* br, int subframe); -static void reconstruct_noise(stChannel* ch, unsigned int min_resolution, unsigned int ms_stereo, unsigned int* random_p); +static void reconstruct_noise(stChannel* ch, unsigned int min_resolution, unsigned int ms_stereo, unsigned int* random_p, int subframe); static void reconstruct_high_frequency(stChannel* ch, unsigned int hfr_group_count, unsigned int bands_per_hfr_group, - unsigned int stereo_band_count, unsigned int base_band_count, unsigned int total_band_count, unsigned int version); + unsigned int stereo_band_count, unsigned int base_band_count, unsigned int total_band_count, unsigned int version, int subframe); static void apply_intensity_stereo(stChannel* ch_pair, int subframe, unsigned int base_band_count, unsigned int total_band_count); -static void apply_ms_stereo(stChannel* ch_pair, unsigned int ms_stereo, unsigned int base_band_count, unsigned int total_band_count); +static void apply_ms_stereo(stChannel* ch_pair, unsigned int ms_stereo, unsigned int base_band_count, unsigned int total_band_count, int subframe); static void imdct_transform(stChannel* ch, int subframe); -/* takes HCA data and decodes all of a frame's samples */ -//hcadecoder_decode_block -int clHCA_DecodeBlock(clHCA* hca, void *data, unsigned int size) { +static int clHCA_DecodeBlock_unpack(clHCA* hca, void *data, unsigned int size) { clData br; unsigned short sync; unsigned int subframe, ch; @@ -1180,19 +1184,29 @@ int clHCA_DecodeBlock(clHCA* hca, void *data, unsigned int size) { } /* lib seems to use a state value to skip parts (unpacking/subframe N/etc) as needed */ - for (subframe = 0; subframe < HCA_SUBFRAMES_PER_FRAME; subframe++) { + for (subframe = 0; subframe < HCA_SUBFRAMES; subframe++) { /* unpack channel data and get dequantized spectra */ for (ch = 0; ch < hca->channels; ch++){ - dequantize_coefficients(&hca->channel[ch], &br); + dequantize_coefficients(&hca->channel[ch], &br, subframe); } + /* original code transforms subframe here, but we have it for later */ + } + + return br.bit; /* numbers of read bits for validations */ +} + +static void clHCA_DecodeBlock_transform(clHCA* hca) { + unsigned int subframe, ch; + + for (subframe = 0; subframe < HCA_SUBFRAMES; subframe++) { /* restore missing bands from spectra */ for (ch = 0; ch < hca->channels; ch++) { - reconstruct_noise(&hca->channel[ch], hca->min_resolution, hca->ms_stereo, &hca->random); + reconstruct_noise(&hca->channel[ch], hca->min_resolution, hca->ms_stereo, &hca->random, subframe); reconstruct_high_frequency(&hca->channel[ch], hca->hfr_group_count, hca->bands_per_hfr_group, - hca->stereo_band_count, hca->base_band_count, hca->total_band_count, hca->version); + hca->stereo_band_count, hca->base_band_count, hca->total_band_count, hca->version, subframe); } /* restore missing joint stereo bands */ @@ -1200,7 +1214,7 @@ int clHCA_DecodeBlock(clHCA* hca, void *data, unsigned int size) { for (ch = 0; ch < hca->channels - 1; ch++) { apply_intensity_stereo(&hca->channel[ch], subframe, hca->base_band_count, hca->total_band_count); - apply_ms_stereo(&hca->channel[ch], hca->ms_stereo, hca->base_band_count, hca->total_band_count); + apply_ms_stereo(&hca->channel[ch], hca->ms_stereo, hca->base_band_count, hca->total_band_count, subframe); } } @@ -1209,9 +1223,27 @@ int clHCA_DecodeBlock(clHCA* hca, void *data, unsigned int size) { imdct_transform(&hca->channel[ch], subframe); } } +} - return br.bit; /* numbers of read bits for validations */ +/* takes HCA data and decodes all of a frame's samples */ +//hcadecoder_decode_block +int clHCA_DecodeBlock(clHCA* hca, void *data, unsigned int size) { + int res; + + /* Original HCA code doesn't separate unpack + transform (unpacks most data, + * reads a subframe's spectra, transforms that subframe. + * + * Unpacking first takes a bit more memory (1 spectra per subframe) but test keys faster + * (since unpack may fail with bad keys we can skip transform). For regular decoding, this + * way somehow is slightly faster? (~3-5%, extra compiler optimizations with reduced scope?) */ + + res = clHCA_DecodeBlock_unpack(hca, data, size); + if (res < 0) + return res; + clHCA_DecodeBlock_transform(hca); + + return res; } //-------------------------------------------------- @@ -1330,7 +1362,7 @@ static int unpack_intensity(stChannel* ch, clData* br, unsigned int hfr_group_co ch->intensity[0] = value; if (value < 15) { bitreader_skip(br, 4); - for (i = 1; i < HCA_SUBFRAMES_PER_FRAME; i++) { + for (i = 1; i < HCA_SUBFRAMES; i++) { ch->intensity[i] = bitreader_read(br, 4); } } @@ -1352,7 +1384,7 @@ static int unpack_intensity(stChannel* ch, clData* br, unsigned int hfr_group_co ch->intensity[0] = value; if (delta_bits == 3) { /* 3+1 = 4b */ /* fixed intensities */ - for (i = 1; i < HCA_SUBFRAMES_PER_FRAME; i++) { + for (i = 1; i < HCA_SUBFRAMES; i++) { ch->intensity[i] = bitreader_read(br, 4); } } @@ -1361,7 +1393,7 @@ static int unpack_intensity(stChannel* ch, clData* br, unsigned int hfr_group_co unsigned char bmax = (2 << delta_bits) - 1; unsigned char bits = delta_bits + 1; - for (i = 1; i < HCA_SUBFRAMES_PER_FRAME; i++) { + for (i = 1; i < HCA_SUBFRAMES; i++) { unsigned char delta = bitreader_read(br, bits); if (delta == bmax) { value = bitreader_read(br, 4); /* encoded */ @@ -1378,7 +1410,7 @@ static int unpack_intensity(stChannel* ch, clData* br, unsigned int hfr_group_co } else { bitreader_skip(br, 4); - for (i = 0; i < HCA_SUBFRAMES_PER_FRAME; i++) { + for (i = 0; i < HCA_SUBFRAMES; i++) { ch->intensity[i] = 7; } } @@ -1498,7 +1530,7 @@ static const float hcatbdecoder_read_val_table[128] = { }; /* read spectral coefficients in the bitstream */ -static void dequantize_coefficients(stChannel* ch, clData* br) { +static void dequantize_coefficients(stChannel* ch, clData* br, int subframe) { int i; unsigned int cc_count = ch->coded_count; @@ -1524,11 +1556,11 @@ static void dequantize_coefficients(stChannel* ch, clData* br) { } /* dequantize coef with gain */ - ch->spectra[i] = ch->gain[i] * qc; + ch->spectra[subframe][i] = ch->gain[i] * qc; } /* clean rest of spectra */ - memset(&ch->spectra[cc_count], 0, sizeof(ch->spectra[0]) * (HCA_SAMPLES_PER_SUBFRAME - cc_count)); + memset(&ch->spectra[subframe][cc_count], 0, sizeof(ch->spectra[subframe][0]) * (HCA_SAMPLES_PER_SUBFRAME - cc_count)); } @@ -1560,7 +1592,7 @@ static const float* hcadecoder_scale_conversion_table = (const float*)hcadecoder /* recreate resolution 0 coefs (not encoded) with pseudo-random noise based on * other coefs/scales (probably similar to AAC's perceptual noise substitution) */ -static void reconstruct_noise(stChannel* ch, unsigned int min_resolution, unsigned int ms_stereo, unsigned int* random_p) { +static void reconstruct_noise(stChannel* ch, unsigned int min_resolution, unsigned int ms_stereo, unsigned int* random_p, int subframe) { if (min_resolution > 0) /* added in v3.0 */ return; if (ch->valid_count <= 0 || ch->noise_count <= 0) @@ -1587,7 +1619,8 @@ static void reconstruct_noise(stChannel* ch, unsigned int min_resolution, unsign sf_valid = ch->scalefactors[valid_index]; sc_index = (sf_noise - sf_valid + 62) & ~((sf_noise - sf_valid + 62) >> 31); - ch->spectra[noise_index] = hcadecoder_scale_conversion_table[sc_index] * ch->spectra[valid_index]; + ch->spectra[subframe][noise_index] = + hcadecoder_scale_conversion_table[sc_index] * ch->spectra[subframe][valid_index]; } *random_p = random; /* lib saves this in the bitreader, maybe for simplified passing around */ @@ -1596,7 +1629,7 @@ static void reconstruct_noise(stChannel* ch, unsigned int min_resolution, unsign /* recreate missing coefs in high bands based on lower bands (probably similar to AAC's spectral band replication) */ static void reconstruct_high_frequency(stChannel* ch, unsigned int hfr_group_count, unsigned int bands_per_hfr_group, - unsigned int stereo_band_count, unsigned int base_band_count, unsigned int total_band_count, unsigned int version) { + unsigned int stereo_band_count, unsigned int base_band_count, unsigned int total_band_count, unsigned int version, int subframe) { if (bands_per_hfr_group == 0) /* added in v2.0, skipped in v2.0 files with 0 bands too */ return; if (ch->type == STEREO_SECONDARY) @@ -1630,7 +1663,7 @@ static void reconstruct_high_frequency(stChannel* ch, unsigned int hfr_group_cou sc_index = hfr_scales[group] - ch->scalefactors[lowband] + 63; sc_index = sc_index & ~(sc_index >> 31); /* clamped in v3.0 lib (in theory 6b sf are 0..128) */ - ch->spectra[highband] = hcadecoder_scale_conversion_table[sc_index] * ch->spectra[lowband]; + ch->spectra[subframe][highband] = hcadecoder_scale_conversion_table[sc_index] * ch->spectra[subframe][lowband]; highband += 1; lowband -= lowband_sub; @@ -1638,7 +1671,7 @@ static void reconstruct_high_frequency(stChannel* ch, unsigned int hfr_group_cou } /* last spectrum coefficient is 0 (normally highband = 128, but perhaps could 'break' before) */ - ch->spectra[highband - 1] = 0.0f; + ch->spectra[subframe][highband - 1] = 0.0f; } } @@ -1661,8 +1694,8 @@ static void apply_intensity_stereo(stChannel* ch_pair, int subframe, unsigned in int band; float ratio_l = hcadecoder_intensity_ratio_table[ ch_pair[1].intensity[subframe] ]; float ratio_r = 2.0f - ratio_l; /* correct, though other decoders substract 2.0 (it does use 'fsubr 2.0' and such) */ - float* sp_l = ch_pair[0].spectra; - float* sp_r = ch_pair[1].spectra; + float* sp_l = &ch_pair[0].spectra[subframe][0]; + float* sp_r = &ch_pair[1].spectra[subframe][0]; for (band = base_band_count; band < total_band_count; band++) { float coef_l = sp_l[band] * ratio_l; @@ -1674,7 +1707,7 @@ static void apply_intensity_stereo(stChannel* ch_pair, int subframe, unsigned in } /* restore L/R bands based on mid channel + side differences */ -static void apply_ms_stereo(stChannel* ch_pair, unsigned int ms_stereo, unsigned int base_band_count, unsigned int total_band_count) { +static void apply_ms_stereo(stChannel* ch_pair, unsigned int ms_stereo, unsigned int base_band_count, unsigned int total_band_count, int subframe) { if (!ms_stereo) /* added in v3.0 */ return; if (ch_pair[0].type != STEREO_PRIMARY) @@ -1683,8 +1716,8 @@ static void apply_ms_stereo(stChannel* ch_pair, unsigned int ms_stereo, unsigned { int band; const float ratio = 0.70710676908493; /* 0x3F3504F3 */ - float* sp_l = ch_pair[0].spectra; - float* sp_r = ch_pair[1].spectra; + float* sp_l = &ch_pair[0].spectra[subframe][0]; + float* sp_r = &ch_pair[1].spectra[subframe][0]; for (band = base_band_count; band < total_band_count; band++) { float coef_l = (sp_l[band] + sp_r[band]) * ratio; @@ -1867,8 +1900,8 @@ static void imdct_transform(stChannel* ch, int subframe) { { unsigned int count1 = 1; unsigned int count2 = half; - float* temp1 = ch->spectra; - float* temp2 = ch->temp; + float* temp1 = &ch->spectra[subframe][0]; + float* temp2 = &ch->temp[0]; for (i = 0; i < mdct_bits; i++) { float* swap; @@ -1897,8 +1930,8 @@ static void imdct_transform(stChannel* ch, int subframe) { { unsigned int count1 = half; unsigned int count2 = 1; - float* temp1 = ch->temp; - float* temp2 = ch->spectra; + float* temp1 = &ch->temp[0]; + float* temp2 = &ch->spectra[subframe][0]; for (i = 0; i < mdct_bits; i++) { const float* sin_table = (const float*) sin_tables_hex[i];//todo cleanup @@ -1934,15 +1967,15 @@ static void imdct_transform(stChannel* ch, int subframe) { /* copy dct */ /* (with the above optimization spectra is already modified, so this is redundant) */ for (i = 0; i < size; i++) { - ch->dct[i] = ch->spectra[i]; + ch->dct[i] = ch->spectra[subframe][i]; } #endif } /* update output/imdct with overlapped window (lib fuses this with the above) */ { - const float* dct = ch->spectra; //ch->dct; - const float* prev = ch->imdct_previous; + const float* dct = &ch->spectra[subframe][0]; //ch->dct; + const float* prev = &ch->imdct_previous[0]; for (i = 0; i < half; i++) { ch->wave[subframe][i] = hcaimdct_window_float[i] * dct[i + half] + prev[i]; diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index 93e46652..0ed715e9 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -145,6 +145,7 @@ + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 65f965fb..89389ef0 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -197,6 +197,9 @@ meta\Header Files + + meta\Header Files + meta\Header Files diff --git a/src/meta/hca.c b/src/meta/hca.c index 9e176525..37e58d29 100644 --- a/src/meta/hca.c +++ b/src/meta/hca.c @@ -4,12 +4,12 @@ #include "../coding/hca_decoder_clhca.h" #ifdef VGM_DEBUG_OUTPUT -//#define HCA_BRUTEFORCE + //#define HCA_BRUTEFORCE + #ifdef HCA_BRUTEFORCE + #include "hca_bf.h" + #endif #endif -#ifdef HCA_BRUTEFORCE -static void bruteforce_hca_key(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey); -#endif static int find_hca_key(hca_codec_data* hca_data, uint64_t* p_keycode, uint16_t subkey); @@ -128,60 +128,32 @@ fail: } -static inline void test_key(hca_codec_data* hca_data, uint64_t key, uint16_t subkey, int* best_score, uint64_t* best_keycode) { - int score; - - //;VGM_LOG("HCA: test key=%08x%08x, subkey=%04x\n", - // (uint32_t)((key >> 32) & 0xFFFFFFFF), (uint32_t)(key & 0xFFFFFFFF), subkey); - - if (subkey) { - key = key * ( ((uint64_t)subkey << 16u) | ((uint16_t)~subkey + 2u) ); - } - - score = test_hca_key(hca_data, (unsigned long long)key); - - //;VGM_LOG("HCA: test key=%08x%08x, subkey=%04x, score=%i\n", - // (uint32_t)((key >> 32) & 0xFFFFFFFF), (uint32_t)(key & 0xFFFFFFFF), subkey, score); - - /* wrong key */ - if (score < 0) - return; - - //;VGM_LOG("HCA: ok key=%08x%08x, subkey=%04x, score=%i\n", - // (uint32_t)((key >> 32) & 0xFFFFFFFF), (uint32_t)(key & 0xFFFFFFFF), subkey, score); - - /* update if something better is found */ - if (*best_score <= 0 || (score < *best_score && score > 0)) { - *best_score = score; - *best_keycode = key; - } -} - -/* try to find the decryption key from a list. */ +/* try to find the decryption key from a list */ static int find_hca_key(hca_codec_data* hca_data, uint64_t* p_keycode, uint16_t subkey) { - const size_t keys_length = sizeof(hcakey_list) / sizeof(hcakey_info); - int best_score = -1; + const size_t keys_length = sizeof(hcakey_list) / sizeof(hcakey_list[0]); int i; + hca_keytest_t hk = {0}; - *p_keycode = 0xCC55463930DBE1AB; /* defaults to PSO2 key, most common */ + hk.best_key = 0xCC55463930DBE1AB; /* defaults to PSO2 key, most common */ + hk.subkey = subkey; for (i = 0; i < keys_length; i++) { - uint64_t key = hcakey_list[i].key; + hk.key = hcakey_list[i].key; - test_key(hca_data, key, subkey, &best_score, p_keycode); - if (best_score == 1) + test_hca_key(hca_data, &hk); + if (hk.best_score == 1) goto done; #if 0 { int j; - size_t subkeys_size = hcakey_list[i].subkeys_size; - const uint16_t *subkeys = hcakey_list[i].subkeys; + const uint16_t* subkeys = hcakey_list[i].subkeys; if (subkeys_size > 0 && subkey == 0) { for (j = 0; j < subkeys_size; j++) { - test_key(hca_data, key, subkeys[j], &best_score, p_keycode); - if (best_score == 1) + hk.subkey = subkeys[j]; + test_hca_key(hca_data, &hk); + if (hk.best_score == 1) goto done; } } @@ -190,219 +162,9 @@ static int find_hca_key(hca_codec_data* hca_data, uint64_t* p_keycode, uint16_t } done: - VGM_ASSERT(best_score > 1, "HCA: best key=%08x%08x (score=%i)\n", - (uint32_t)((*p_keycode >> 32) & 0xFFFFFFFF), (uint32_t)(*p_keycode & 0xFFFFFFFF), best_score); - vgm_asserti(best_score < 0, "HCA: decryption key not found\n"); - return best_score > 0; + *p_keycode = hk.best_key; + VGM_ASSERT(hk.best_score > 1, "HCA: best key=%08x%08x (score=%i)\n", + (uint32_t)((*p_keycode >> 32) & 0xFFFFFFFF), (uint32_t)(*p_keycode & 0xFFFFFFFF), hk.best_score); + vgm_asserti(hk.best_score <= 0, "HCA: decryption key not found\n"); + return hk.best_score > 0; } - -#ifdef HCA_BRUTEFORCE -typedef enum { - HBF_TYPE_64LE_1, - HBF_TYPE_64BE_1, - HBF_TYPE_32LE_1, - HBF_TYPE_32BE_1, - HBF_TYPE_64LE_4, - HBF_TYPE_64BE_4, - HBF_TYPE_32LE_4, - HBF_TYPE_32BE_4, -} HBF_type_t; - -/* Bruteforce binary keys in executables and similar files, mainly for some mobile games. - * Kinda slow but acceptable for ~20MB exes, not very optimized. Unity usually has keys - * in plaintext (inside levelX or other base files) instead though. */ -static void bruteforce_hca_key_bin_type(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey, HBF_type_t type) { - STREAMFILE* sf_keys = NULL; - uint8_t* buf = NULL; - int best_score = 0xFFFFFF, cur_score; - off_t keys_size, bytes; - int pos, step; - uint64_t old_key = 0; - uint64_t key = 0; - uint64_t best_key = 0; - - - /* load whole file in memory for performance (exes with keys shouldn't be too big) */ - sf_keys = open_streamfile_by_filename(sf, "keys.bin"); - if (!sf_keys) return; - - VGM_LOG("HCA BF: test keys.bin (type %i)\n", type); - *p_keycode = 0; - - keys_size = get_streamfile_size(sf_keys); - - buf = malloc(keys_size); - if (!buf) goto done; - - bytes = read_streamfile(buf, 0, keys_size, sf_keys); - if (bytes != keys_size) goto done; - - VGM_LOG("HCA BF: start .bin\n"); - - switch(type) { - case HBF_TYPE_64LE_1: - case HBF_TYPE_64BE_1: - case HBF_TYPE_32LE_1: - case HBF_TYPE_32BE_1: step = 0x01; break; - case HBF_TYPE_64LE_4: - case HBF_TYPE_64BE_4: - case HBF_TYPE_32LE_4: - case HBF_TYPE_32BE_4: step = 0x04; break; - default: goto done; - } - - pos = 0; - while (pos < keys_size - 8) { - VGM_ASSERT(pos % 0x1000000 == 0, "HCA: pos %x...\n", pos); - - /* keys are usually u64le but other orders may exist */ - switch(type) { - case HBF_TYPE_64LE_1: key = get_u64le(buf + pos); break; - case HBF_TYPE_64BE_1: key = get_u64be(buf + pos); break; - case HBF_TYPE_32LE_1: key = get_u32le(buf + pos); break; - case HBF_TYPE_32BE_1: key = get_u32be(buf + pos); break; - case HBF_TYPE_64LE_4: key = get_u64le(buf + pos); break; - case HBF_TYPE_64BE_4: key = get_u64be(buf + pos); break; - case HBF_TYPE_32LE_4: key = get_u32le(buf + pos); break; - case HBF_TYPE_32BE_4: key = get_u32be(buf + pos); break; - default: goto done; - } - pos += step; - - if (key == 0 || key == old_key) - continue; - old_key = key; - - cur_score = 0; - test_key(hca_data, key, subkey, &cur_score, p_keycode); - if (cur_score == 1) { - best_key = key; - best_score = cur_score; - goto done; - } - - if (cur_score > 0 && cur_score <= 500) { - VGM_LOG("HCA BF: possible key=%08x%08x (score=%i) at offset %x\n", - (uint32_t)((key >> 32) & 0xFFFFFFFF), (uint32_t)(key & 0xFFFFFFFF), cur_score, pos - step); - if (best_score > cur_score) { - best_key = key; - best_score = cur_score; - } - } - } - -done: - if (best_score < 0 || best_score > 10000) { - *p_keycode = 0; - VGM_LOG("HCA BF: no good key found\n"); - } - else { - /* print best_key as p_keycode includes subkey */ - VGM_LOG("HCA BF: best key=%08x%08x (score=%i)\n", - (uint32_t)((best_key >> 32) & 0xFFFFFFFF), (uint32_t)(best_key & 0xFFFFFFFF), best_score); - } - - close_streamfile(sf_keys); - free(buf); -} - -static void bruteforce_hca_key_bin(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey) { - bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64LE_1); -/* - bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32LE_1); - bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64BE_1); - bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32BE_1); - - bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64LE_4); - bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32LE_4); - bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64BE_4); - bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32BE_4); -*/ -} - - -#include -//#include - -/* same as the above but for txt lines. */ -static void bruteforce_hca_key_txt(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey) { - STREAMFILE* sf_keys = NULL; - uint8_t* buf = NULL; - int best_score = 0xFFFFFF, cur_score; - off_t keys_size, bytes; - int i = 0, pos; - char line[1024]; - - - - /* load whole file in memory for performance (exes with keys shouldn't be too big) */ - sf_keys = open_streamfile_by_filename(sf, "keys.txt"); - if (!sf_keys) return; - - VGM_LOG("HCA BF: test keys.txt\n"); - *p_keycode = 0; - - keys_size = get_streamfile_size(sf_keys); - - buf = malloc(keys_size); - if (!buf) goto done; - - bytes = read_streamfile(buf, 0, keys_size, sf_keys); - if (bytes != keys_size) goto done; - - VGM_LOG("HCA BF: start .txt\n"); - - pos = 0; - while (pos < keys_size) { - int bytes_read, line_ok, count; - uint64_t key = 0; - - bytes_read = read_line(line, sizeof(line), pos, sf_keys, &line_ok); - pos += bytes_read; - if (!line_ok) continue; /* line too long */ - - count = sscanf(line, "%" SCNd64, &key); - if (count != 1) continue; - - VGM_ASSERT(pos % 10000 == 0, "HCA: count %i...\n", i); - - if (key == 0) - continue; - i++; - - cur_score = 0; - test_key(hca_data, key, subkey, &cur_score, p_keycode); - if (cur_score == 1) - goto done; - - if (cur_score > 0 && cur_score <= 500) { - VGM_LOG("HCA BF: possible key=%08x%08x (score=%i) at %x\n", - (uint32_t)((key >> 32) & 0xFFFFFFFF), (uint32_t)(key & 0xFFFFFFFF), cur_score, pos - bytes_read); - if (best_score > cur_score) - best_score = cur_score; - } - } - -done: - VGM_LOG("HCA BF: done %i keys.txt\n", i); - VGM_ASSERT(best_score > 0, "HCA BF: best key=%08x%08x (score=%i)\n", - (uint32_t)((*p_keycode >> 32) & 0xFFFFFFFF), (uint32_t)(*p_keycode & 0xFFFFFFFF), best_score); - VGM_ASSERT(best_score < 0, "HCA BF: no good key found\n"); - if (best_score < 0 || best_score > 10000) - *p_keycode = 0; - - close_streamfile(sf_keys); - free(buf); -} - -static void bruteforce_hca_key(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey) { - bruteforce_hca_key_bin(sf, hca_data, p_keycode, subkey); - if (*p_keycode != 0) - return; - - bruteforce_hca_key_txt(sf, hca_data, p_keycode, subkey); - if (*p_keycode != 0) - return; -} - -#endif diff --git a/src/meta/hca_bf.h b/src/meta/hca_bf.h new file mode 100644 index 00000000..8d43460a --- /dev/null +++ b/src/meta/hca_bf.h @@ -0,0 +1,257 @@ +#ifndef _HCA_BF_ +#define _HCA_BF_ + +#include "meta.h" +#include "../coding/coding.h" + +#ifdef HCA_BRUTEFORCE + +static void bruteforce_process_result(hca_keytest_t* hk, unsigned long long* p_keycode) { + *p_keycode = hk->best_key; + if (hk->best_score < 0 || hk->best_score > 10000) { + VGM_LOG("HCA BF: no good key found\n"); + } + else { + VGM_LOG("HCA BF: best key=%08x%08x (score=%i)\n", + (uint32_t)((*p_keycode >> 32) & 0xFFFFFFFF), (uint32_t)(*p_keycode & 0xFFFFFFFF), hk->best_score); + } +} + +typedef enum { + HBF_TYPE_64LE_1, + HBF_TYPE_64BE_1, + HBF_TYPE_32LE_1, + HBF_TYPE_32BE_1, + HBF_TYPE_64LE_4, + HBF_TYPE_64BE_4, + HBF_TYPE_32LE_4, + HBF_TYPE_32BE_4, +} HBF_type_t; + +/* Bruteforce binary keys in executables and similar files, mainly for some mobile games. + * Kinda slow but acceptable for ~100MB exes, not very optimized. Unity usually has keys + * in plaintext (inside levelX or other base files) instead though, use test below. */ +static void bruteforce_hca_key_bin_type(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey, HBF_type_t type) { + STREAMFILE* sf_keys = NULL; + uint8_t* buf = NULL; + uint32_t keys_size, bytes; + int pos, step; + uint64_t key = 0, old_key = 0; + hca_keytest_t hk = {0}; + + hk.subkey = subkey; + + + /* load whole file in memory for performance (exes with keys shouldn't be too big) */ + sf_keys = open_streamfile_by_filename(sf, "keys.bin"); + if (!sf_keys) return; + + VGM_LOG("HCA BF: test keys.bin (type %i)\n", type); + *p_keycode = 0; + + keys_size = get_streamfile_size(sf_keys); + + buf = malloc(keys_size); + if (!buf) { + VGM_LOG("HCA BF: key file too big!\n"); + goto done; + } + + bytes = read_streamfile(buf, 0, keys_size, sf_keys); + if (bytes != keys_size) goto done; + + VGM_LOG("HCA BF: start .bin\n"); + + switch(type) { + case HBF_TYPE_64LE_1: + case HBF_TYPE_64BE_1: + case HBF_TYPE_32LE_1: + case HBF_TYPE_32BE_1: step = 0x01; break; + case HBF_TYPE_64LE_4: + case HBF_TYPE_64BE_4: + case HBF_TYPE_32LE_4: + case HBF_TYPE_32BE_4: step = 0x04; break; + default: goto done; + } + + pos = 0; + while (pos < keys_size - 8) { + VGM_ASSERT(pos % 0x1000000 == 0, "HCA: pos %x...\n", pos); + + /* keys are usually u64le but other orders may exist */ + switch(type) { + case HBF_TYPE_64LE_1: key = get_u64le(buf + pos); break; + case HBF_TYPE_64BE_1: key = get_u64be(buf + pos); break; + case HBF_TYPE_32LE_1: key = get_u32le(buf + pos); break; + case HBF_TYPE_32BE_1: key = get_u32be(buf + pos); break; + case HBF_TYPE_64LE_4: key = get_u64le(buf + pos); break; + case HBF_TYPE_64BE_4: key = get_u64be(buf + pos); break; + case HBF_TYPE_32LE_4: key = get_u32le(buf + pos); break; + case HBF_TYPE_32BE_4: key = get_u32be(buf + pos); break; + default: goto done; + } + pos += step; + + if (key == 0 || key == old_key) + continue; + old_key = key; + + hk.key = key; + test_hca_key(hca_data, &hk); + if (hk.best_score == 1) + goto done; + } + +done: + bruteforce_process_result(&hk, p_keycode); + close_streamfile(sf_keys); + free(buf); +} + +static void bruteforce_hca_key_bin(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey) { + bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64LE_1); +/* + bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32LE_1); + bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64BE_1); + bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32BE_1); + + bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64LE_4); + bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32LE_4); + bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64BE_4); + bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32BE_4); +*/ +} + + +#include +//#include + +/* same as the above but for txt lines. */ +static void bruteforce_hca_key_txt(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey) { + STREAMFILE* sf_keys = NULL; + uint8_t* buf = NULL; + uint32_t keys_size, bytes; + char line[1024]; + int i = 0, pos; + uint64_t key = 0; + hca_keytest_t hk = {0}; + + hk.subkey = subkey; + + + /* load whole file in memory for performance (exes with keys shouldn't be too big) */ + sf_keys = open_streamfile_by_filename(sf, "keys.txt"); + if (!sf_keys) return; + + VGM_LOG("HCA BF: test keys.txt\n"); + *p_keycode = 0; + + keys_size = get_streamfile_size(sf_keys); + + buf = malloc(keys_size); + if (!buf) { + VGM_LOG("HCA BF: key file too big!\n"); + goto done; + } + + bytes = read_streamfile(buf, 0, keys_size, sf_keys); + if (bytes != keys_size) goto done; + + VGM_LOG("HCA BF: start .txt\n"); + + pos = 0; + while (pos < keys_size) { + int bytes_read, line_ok, count; + key = 0; + + bytes_read = read_line(line, sizeof(line), pos, sf_keys, &line_ok); + pos += bytes_read; + if (!line_ok) continue; /* line too long */ + + count = sscanf(line, "%" SCNd64, &key); + if (count != 1) continue; + + VGM_ASSERT(pos % 10000 == 0, "HCA: count %i...\n", i); + + if (key == 0) + continue; + i++; + + hk.key = key; + test_hca_key(hca_data, &hk); + if (hk.best_score == 1) + goto done; + } + +done: + bruteforce_process_result(&hk, p_keycode); + close_streamfile(sf_keys); + free(buf); +} + +/* same as the above but good ol' bruteforce numbers (useful for games with keys that are dates) */ +static void bruteforce_hca_key_num(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey) { + STREAMFILE* sf_keys = NULL; + uint32_t keys_size; + uint64_t min, max; + uint64_t key = 0; + hca_keytest_t hk = {0}; + + hk.subkey = subkey; + + + /* load whole file in memory for performance (exes with keys shouldn't be too big) */ + sf_keys = open_streamfile_by_filename(sf, "keys.num"); + if (!sf_keys) return; + + VGM_LOG("HCA BF: test keys.num\n"); + *p_keycode = 0; + + keys_size = get_streamfile_size(sf_keys); + + /* don't set too high as it does ~70000 keys per second, do the math */ + if (keys_size < 0x10) { + min = 0; + max = 0xFFFFFFFF; + } + else { + min = read_u64be(0x00, sf_keys); + max = read_u64be(0x08, sf_keys); + } + + VGM_LOG("HCA BF: start .num\n"); + + while (min < max) { + key = min; + + min++; + VGM_ASSERT(min % 0x100000 == 0, "HCA: count %x...\n", (uint32_t)min); + + hk.key = key; + test_hca_key(hca_data, &hk); + if (hk.best_score == 1) + goto done; + } + +done: + bruteforce_process_result(&hk, p_keycode); + close_streamfile(sf_keys); +} + +static void bruteforce_hca_key(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey) { + bruteforce_hca_key_bin(sf, hca_data, p_keycode, subkey); + if (*p_keycode != 0) + return; + + bruteforce_hca_key_txt(sf, hca_data, p_keycode, subkey); + if (*p_keycode != 0) + return; + + bruteforce_hca_key_num(sf, hca_data, p_keycode, subkey); + if (*p_keycode != 0) + return; +} + +#endif + +#endif /*_HCA_BF_*/ diff --git a/src/meta/hca_keys.h b/src/meta/hca_keys.h index 54aacc39..7f3a1ed6 100644 --- a/src/meta/hca_keys.h +++ b/src/meta/hca_keys.h @@ -67,11 +67,9 @@ static const hcakey_info hcakey_list[] = { // Sonic Runners (iOS/Android) {19910623}, // 00000000012FCFDF - // Fate/Grand Order (iOS/Android) base assets - {12345}, // 0000000000003039 - - // Fate/Grand Order (iOS/Android) download assets *unconfirmed - {9117927877783581796}, // 7E89631892EBF464 + // Fate/Grand Order (iOS/Android) + {12345}, // 0000000000003039 - base assets + {9117927877783581796}, // 7E89631892EBF464 - downloaded assets *unconfirmed // Raramagi (iOS/Android) {45719322}, // 0000000002B99F1A @@ -809,6 +807,12 @@ static const hcakey_info hcakey_list[] = { {0x178a76b6436d20f0}, // Sng028 {0x3ff99f2fed65a1ed}, // Sng030 + // Ulala: Idle Adventure (Android) + {20191022}, // 000000000134172E + + // Girls' Frontline: Project Neural Cloud (Android) + {210222522032314}, // 0000BF323EBFE0BA + }; #endif/*_HCA_KEYS_H_*/ diff --git a/src/meta/str_wav.c b/src/meta/str_wav.c index 6c32cbaa..7706927b 100644 --- a/src/meta/str_wav.c +++ b/src/meta/str_wav.c @@ -612,7 +612,7 @@ static int parse_header(STREAMFILE* sf_h, STREAMFILE* sf_b, strwav_header* strwa strwav->codec = DSP; strwav->dsps_table = 0xf0; - strwav->interleave = strwav->tracks > 2 ? 0x8000 : 0x10000; + strwav->interleave = strwav->tracks >= 2 ? 0x8000 : 0x10000; ;VGM_LOG("STR+WAV: header SBCKK (GC)\n"); return 1; }