mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-28 08:20:54 +01:00
Improve HCA key tester
This commit is contained in:
parent
79ca4f76eb
commit
99eb1c328f
@ -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 reset_hca(hca_codec_data* data);
|
||||||
void loop_hca(hca_codec_data* data, int32_t num_sample);
|
void loop_hca(hca_codec_data* data, int32_t num_sample);
|
||||||
void free_hca(hca_codec_data* data);
|
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);
|
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);
|
STREAMFILE* hca_get_streamfile(hca_codec_data* data);
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
|
|
||||||
struct hca_codec_data {
|
struct hca_codec_data {
|
||||||
STREAMFILE* streamfile;
|
STREAMFILE* sf;
|
||||||
clHCA_stInfo info;
|
clHCA_stInfo info;
|
||||||
|
|
||||||
signed short* sample_buffer;
|
signed short* sample_buffer;
|
||||||
@ -58,8 +58,8 @@ hca_codec_data* init_hca(STREAMFILE* sf) {
|
|||||||
if (!data->sample_buffer) goto fail;
|
if (!data->sample_buffer) goto fail;
|
||||||
|
|
||||||
/* load streamfile for reads */
|
/* load streamfile for reads */
|
||||||
data->streamfile = reopen_streamfile(sf, 0);
|
data->sf = reopen_streamfile(sf, 0);
|
||||||
if (!data->streamfile) goto fail;
|
if (!data->sf) goto fail;
|
||||||
|
|
||||||
/* set initial values */
|
/* set initial values */
|
||||||
reset_hca(data);
|
reset_hca(data);
|
||||||
@ -115,7 +115,7 @@ void decode_hca(hca_codec_data* data, sample_t* outbuf, int32_t samples_to_do) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* read frame */
|
/* 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) {
|
if (bytes != blockSize) {
|
||||||
VGM_LOG("HCA: read %x vs expected %x bytes at %x\n", bytes, blockSize, (uint32_t)offset);
|
VGM_LOG("HCA: read %x vs expected %x bytes at %x\n", bytes, blockSize, (uint32_t)offset);
|
||||||
break;
|
break;
|
||||||
@ -171,7 +171,7 @@ void loop_hca(hca_codec_data* data, int32_t num_sample) {
|
|||||||
void free_hca(hca_codec_data* data) {
|
void free_hca(hca_codec_data* data) {
|
||||||
if (!data) return;
|
if (!data) return;
|
||||||
|
|
||||||
close_streamfile(data->streamfile);
|
close_streamfile(data->sf);
|
||||||
clHCA_done(data->handle);
|
clHCA_done(data->handle);
|
||||||
free(data->handle);
|
free(data->handle);
|
||||||
free(data->data_buffer);
|
free(data->data_buffer);
|
||||||
@ -179,6 +179,14 @@ void free_hca(hca_codec_data* data) {
|
|||||||
free(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) */
|
/* ignores beginning frames (~10 is not uncommon, Dragalia Lost vocal layers have lots) */
|
||||||
#define HCA_KEY_MAX_SKIP_BLANKS 1200
|
#define HCA_KEY_MAX_SKIP_BLANKS 1200
|
||||||
/* 5~15 should be enough, but almost silent or badly mastered files may need tweaks
|
/* 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) */
|
* (ex. newer Tales of the Rays files clip a lot) */
|
||||||
#define HCA_KEY_MIN_TEST_FRAMES 7
|
#define HCA_KEY_MIN_TEST_FRAMES 3 //7
|
||||||
#define HCA_KEY_MAX_TEST_FRAMES 12
|
#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 */
|
/* 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_FRAME_SCORE 150
|
||||||
#define HCA_KEY_MAX_TOTAL_SCORE (HCA_KEY_MAX_TEST_FRAMES * 50*HCA_KEY_SCORE_SCALE)
|
#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.
|
/* 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). */
|
* 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;
|
size_t test_frames = 0, current_frame = 0, blank_frames = 0;
|
||||||
int total_score = 0, found_regular_frame = 0;
|
int total_score = 0;
|
||||||
const unsigned int blockSize = data->info.blockSize;
|
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.
|
/* 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).
|
* 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 */
|
/* 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) {
|
while (test_frames < HCA_KEY_MAX_TEST_FRAMES && current_frame < data->info.blockCount) {
|
||||||
off_t offset = data->info.headerSize + current_frame * blockSize;
|
|
||||||
int score;
|
int score;
|
||||||
size_t bytes;
|
size_t bytes;
|
||||||
|
//VGM_LOG(" *frame\n");
|
||||||
/* read and test frame */
|
/* read and test frame */
|
||||||
bytes = read_streamfile(data->data_buffer, offset, blockSize, data->streamfile);
|
bytes = read_streamfile(data->data_buffer, offset, block_size, data->sf);
|
||||||
if (bytes != blockSize) {
|
if (bytes != block_size) {
|
||||||
/* normally this shouldn't happen, but pre-fetch ACB stop with frames in half, so just keep score */
|
/* normally this shouldn't happen, but pre-fetch ACB stop with frames in half, so just keep score */
|
||||||
//total_score = -1;
|
//total_score = -1;
|
||||||
break;
|
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) {
|
if (score < 0 || score > HCA_KEY_MAX_FRAME_SCORE) {
|
||||||
total_score = -1;
|
total_score = -1;
|
||||||
break;
|
break;
|
||||||
@ -236,13 +256,12 @@ int test_hca_key(hca_codec_data* data, unsigned long long keycode) {
|
|||||||
|
|
||||||
current_frame++;
|
current_frame++;
|
||||||
|
|
||||||
/* ignore silent frames at the beginning, up to a point */
|
/* ignore silent frames at the beginning, up to a point and first non-blank */
|
||||||
if (score == 0 && blank_frames < HCA_KEY_MAX_SKIP_BLANKS && !found_regular_frame) {
|
if (score == 0 && blank_frames < HCA_KEY_MAX_SKIP_BLANKS && !hk->start_offset) {
|
||||||
blank_frames++;
|
blank_frames++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
found_regular_frame = 1;
|
|
||||||
test_frames++;
|
test_frames++;
|
||||||
|
|
||||||
/* scale values to make scores of perfect frames more detectable */
|
/* 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;
|
total_score += score;
|
||||||
|
|
||||||
|
|
||||||
/* don't bother checking more frames, other keys will get better scores */
|
/* don't bother checking more frames, other keys will get better scores */
|
||||||
if (total_score > HCA_KEY_MAX_TOTAL_SCORE)
|
if (total_score > HCA_KEY_MAX_TOTAL_SCORE)
|
||||||
break;
|
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) {
|
if (test_frames > HCA_KEY_MIN_TEST_FRAMES && total_score > 0 && total_score <= test_frames) {
|
||||||
total_score = 1;
|
total_score = 1;
|
||||||
}
|
}
|
||||||
|
//VGM_LOG("test=%i\n", total_score);
|
||||||
clHCA_DecodeReset(data->handle);
|
clHCA_DecodeReset(data->handle);
|
||||||
return total_score;
|
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) {
|
void hca_set_encryption_key(hca_codec_data* data, uint64_t keycode) {
|
||||||
clHCA_SetKey(data->handle, (unsigned long long)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;
|
|
||||||
}
|
|
||||||
|
215
src/meta/hca.c
215
src/meta/hca.c
@ -5,11 +5,11 @@
|
|||||||
|
|
||||||
#ifdef VGM_DEBUG_OUTPUT
|
#ifdef VGM_DEBUG_OUTPUT
|
||||||
//#define HCA_BRUTEFORCE
|
//#define HCA_BRUTEFORCE
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HCA_BRUTEFORCE
|
#ifdef HCA_BRUTEFORCE
|
||||||
static void bruteforce_hca_key(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey);
|
static void bruteforce_hca_key(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey);
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
static int find_hca_key(hca_codec_data* hca_data, uint64_t* p_keycode, uint16_t subkey);
|
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) {
|
/* try to find the decryption key from a list */
|
||||||
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. */
|
|
||||||
static int find_hca_key(hca_codec_data* hca_data, uint64_t* p_keycode, uint16_t subkey) {
|
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);
|
const size_t keys_length = sizeof(hcakey_list) / sizeof(hcakey_list[0]);
|
||||||
int best_score = -1;
|
|
||||||
int i;
|
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++) {
|
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);
|
test_hca_key(hca_data, &hk);
|
||||||
if (best_score == 1)
|
if (hk.best_score == 1)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
{
|
{
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
size_t subkeys_size = hcakey_list[i].subkeys_size;
|
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) {
|
if (subkeys_size > 0 && subkey == 0) {
|
||||||
for (j = 0; j < subkeys_size; j++) {
|
for (j = 0; j < subkeys_size; j++) {
|
||||||
test_key(hca_data, key, subkeys[j], &best_score, p_keycode);
|
hk.subkey = subkeys[j];
|
||||||
if (best_score == 1)
|
test_hca_key(hca_data, &hk);
|
||||||
|
if (hk.best_score == 1)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -190,10 +162,24 @@ static int find_hca_key(hca_codec_data* hca_data, uint64_t* p_keycode, uint16_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
VGM_ASSERT(best_score > 1, "HCA: best key=%08x%08x (score=%i)\n",
|
*p_keycode = hk.best_key;
|
||||||
(uint32_t)((*p_keycode >> 32) & 0xFFFFFFFF), (uint32_t)(*p_keycode & 0xFFFFFFFF), best_score);
|
VGM_ASSERT(hk.best_score > 1, "HCA: best key=%08x%08x (score=%i)\n",
|
||||||
vgm_asserti(best_score < 0, "HCA: decryption key not found\n");
|
(uint32_t)((*p_keycode >> 32) & 0xFFFFFFFF), (uint32_t)(*p_keycode & 0xFFFFFFFF), hk.best_score);
|
||||||
return best_score > 0;
|
vgm_asserti(hk.best_score <= 0, "HCA: decryption key not found\n");
|
||||||
|
return hk.best_score > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************* */
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HCA_BRUTEFORCE
|
#ifdef HCA_BRUTEFORCE
|
||||||
@ -209,17 +195,17 @@ typedef enum {
|
|||||||
} HBF_type_t;
|
} HBF_type_t;
|
||||||
|
|
||||||
/* Bruteforce binary keys in executables and similar files, mainly for some mobile games.
|
/* 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
|
* Kinda slow but acceptable for ~100MB exes, not very optimized. Unity usually has keys
|
||||||
* in plaintext (inside levelX or other base files) instead though. */
|
* 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) {
|
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;
|
STREAMFILE* sf_keys = NULL;
|
||||||
uint8_t* buf = NULL;
|
uint8_t* buf = NULL;
|
||||||
int best_score = 0xFFFFFF, cur_score;
|
uint32_t keys_size, bytes;
|
||||||
off_t keys_size, bytes;
|
|
||||||
int pos, step;
|
int pos, step;
|
||||||
uint64_t old_key = 0;
|
uint64_t key = 0, old_key = 0;
|
||||||
uint64_t key = 0;
|
hca_keytest_t hk = {0};
|
||||||
uint64_t best_key = 0;
|
|
||||||
|
hk.subkey = subkey;
|
||||||
|
|
||||||
|
|
||||||
/* load whole file in memory for performance (exes with keys shouldn't be too big) */
|
/* load whole file in memory for performance (exes with keys shouldn't be too big) */
|
||||||
@ -232,7 +218,10 @@ static void bruteforce_hca_key_bin_type(STREAMFILE* sf, hca_codec_data* hca_data
|
|||||||
keys_size = get_streamfile_size(sf_keys);
|
keys_size = get_streamfile_size(sf_keys);
|
||||||
|
|
||||||
buf = malloc(keys_size);
|
buf = malloc(keys_size);
|
||||||
if (!buf) goto done;
|
if (!buf) {
|
||||||
|
VGM_LOG("HCA BF: key file too big!\n");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
bytes = read_streamfile(buf, 0, keys_size, sf_keys);
|
bytes = read_streamfile(buf, 0, keys_size, sf_keys);
|
||||||
if (bytes != keys_size) goto done;
|
if (bytes != keys_size) goto done;
|
||||||
@ -273,35 +262,14 @@ static void bruteforce_hca_key_bin_type(STREAMFILE* sf, hca_codec_data* hca_data
|
|||||||
continue;
|
continue;
|
||||||
old_key = key;
|
old_key = key;
|
||||||
|
|
||||||
cur_score = 0;
|
hk.key = key;
|
||||||
test_key(hca_data, key, subkey, &cur_score, p_keycode);
|
test_hca_key(hca_data, &hk);
|
||||||
if (cur_score == 1) {
|
if (hk.best_score == 1)
|
||||||
best_key = key;
|
|
||||||
best_score = cur_score;
|
|
||||||
goto done;
|
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:
|
done:
|
||||||
if (best_score < 0 || best_score > 10000) {
|
bruteforce_process_result(&hk, p_keycode);
|
||||||
*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);
|
close_streamfile(sf_keys);
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
@ -328,11 +296,13 @@ static void bruteforce_hca_key_bin(STREAMFILE* sf, hca_codec_data* hca_data, uns
|
|||||||
static void bruteforce_hca_key_txt(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey) {
|
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;
|
STREAMFILE* sf_keys = NULL;
|
||||||
uint8_t* buf = NULL;
|
uint8_t* buf = NULL;
|
||||||
int best_score = 0xFFFFFF, cur_score;
|
uint32_t keys_size, bytes;
|
||||||
off_t keys_size, bytes;
|
|
||||||
int i = 0, pos;
|
|
||||||
char line[1024];
|
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) */
|
/* load whole file in memory for performance (exes with keys shouldn't be too big) */
|
||||||
@ -345,7 +315,10 @@ static void bruteforce_hca_key_txt(STREAMFILE* sf, hca_codec_data* hca_data, uns
|
|||||||
keys_size = get_streamfile_size(sf_keys);
|
keys_size = get_streamfile_size(sf_keys);
|
||||||
|
|
||||||
buf = malloc(keys_size);
|
buf = malloc(keys_size);
|
||||||
if (!buf) goto done;
|
if (!buf) {
|
||||||
|
VGM_LOG("HCA BF: key file too big!\n");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
bytes = read_streamfile(buf, 0, keys_size, sf_keys);
|
bytes = read_streamfile(buf, 0, keys_size, sf_keys);
|
||||||
if (bytes != keys_size) goto done;
|
if (bytes != keys_size) goto done;
|
||||||
@ -355,7 +328,7 @@ static void bruteforce_hca_key_txt(STREAMFILE* sf, hca_codec_data* hca_data, uns
|
|||||||
pos = 0;
|
pos = 0;
|
||||||
while (pos < keys_size) {
|
while (pos < keys_size) {
|
||||||
int bytes_read, line_ok, count;
|
int bytes_read, line_ok, count;
|
||||||
uint64_t key = 0;
|
key = 0;
|
||||||
|
|
||||||
bytes_read = read_line(line, sizeof(line), pos, sf_keys, &line_ok);
|
bytes_read = read_line(line, sizeof(line), pos, sf_keys, &line_ok);
|
||||||
pos += bytes_read;
|
pos += bytes_read;
|
||||||
@ -370,31 +343,67 @@ static void bruteforce_hca_key_txt(STREAMFILE* sf, hca_codec_data* hca_data, uns
|
|||||||
continue;
|
continue;
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
cur_score = 0;
|
hk.key = key;
|
||||||
test_key(hca_data, key, subkey, &cur_score, p_keycode);
|
test_hca_key(hca_data, &hk);
|
||||||
if (cur_score == 1)
|
if (hk.best_score == 1)
|
||||||
goto done;
|
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:
|
done:
|
||||||
VGM_LOG("HCA BF: done %i keys.txt\n", i);
|
bruteforce_process_result(&hk, p_keycode);
|
||||||
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);
|
close_streamfile(sf_keys);
|
||||||
free(buf);
|
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) {
|
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);
|
bruteforce_hca_key_bin(sf, hca_data, p_keycode, subkey);
|
||||||
if (*p_keycode != 0)
|
if (*p_keycode != 0)
|
||||||
@ -403,6 +412,10 @@ static void bruteforce_hca_key(STREAMFILE* sf, hca_codec_data* hca_data, unsigne
|
|||||||
bruteforce_hca_key_txt(sf, hca_data, p_keycode, subkey);
|
bruteforce_hca_key_txt(sf, hca_data, p_keycode, subkey);
|
||||||
if (*p_keycode != 0)
|
if (*p_keycode != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
bruteforce_hca_key_num(sf, hca_data, p_keycode, subkey);
|
||||||
|
if (*p_keycode != 0)
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user