document challenge mode time encoding
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <phosg/Encoding.hh>
|
||||
#include <phosg/Random.hh>
|
||||
#include <phosg/Strings.hh>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
@@ -886,6 +887,38 @@ void decrypt_trivial_gci_data(void* data, size_t size, uint8_t basis) {
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t count_one_bits(uint16_t v) {
|
||||
uint8_t ret = 0;
|
||||
while (v) {
|
||||
v &= (v - 1);
|
||||
ret++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t encrypt_challenge_time(uint16_t value) {
|
||||
vector<uint8_t> available_bits({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15});
|
||||
|
||||
uint16_t mask = 0;
|
||||
uint8_t num_one_bits = (random_object<uint8_t>() % 9) + 4; // Range [4, 12]
|
||||
for (; num_one_bits; num_one_bits--) {
|
||||
uint8_t index = random_object<uint8_t>() % available_bits.size();
|
||||
auto it = available_bits.begin() + index;
|
||||
mask |= (1 << *it);
|
||||
available_bits.erase(it);
|
||||
}
|
||||
|
||||
return (mask << 16) | (value ^ mask);
|
||||
}
|
||||
|
||||
uint16_t decrypt_challenge_time(uint32_t value) {
|
||||
uint16_t mask = (value >> 0x10);
|
||||
uint8_t mask_one_bits = count_one_bits(mask);
|
||||
return ((mask_one_bits < 4) || (mask_one_bits > 12))
|
||||
? 0xFFFF
|
||||
: ((mask ^ value) & 0xFFFF);
|
||||
}
|
||||
|
||||
template <typename StringT, bool IsEncrypt>
|
||||
StringT crypt_challenge_rank_text(const void* src, size_t count) {
|
||||
if (count == 0) {
|
||||
|
||||
@@ -241,6 +241,9 @@ private:
|
||||
|
||||
void decrypt_trivial_gci_data(void* data, size_t size, uint8_t basis);
|
||||
|
||||
uint32_t encrypt_challenge_time(uint16_t value);
|
||||
uint16_t decrypt_challenge_time(uint32_t value);
|
||||
|
||||
std::string decrypt_challenge_rank_text(const char* data, size_t count);
|
||||
std::string decrypt_challenge_rank_text(const std::string& data);
|
||||
std::string encrypt_challenge_rank_text(const char* data, size_t count);
|
||||
|
||||
+8
-8
@@ -333,13 +333,13 @@ struct PlayerRecordsDCPC_Challenge {
|
||||
/* 00 */ le_uint16_t title_color = 0x7FFF;
|
||||
/* 02 */ parray<uint8_t, 2> unknown_u0;
|
||||
/* 04 */ ptext<CharT, 0x0C> rank_title; // Encrypted; see decrypt_challenge_rank_text
|
||||
/* 10 */ parray<le_uint32_t, 9> times_ep1_online; // TODO: This might be offline times
|
||||
/* 10 */ parray<le_uint32_t, 9> times_ep1_online; // Encrypted; see decrypt_challenge_time. TODO: This might be offline times
|
||||
/* 34 */ le_uint16_t unknown_g3 = 0;
|
||||
/* 36 */ le_uint16_t grave_deaths = 0;
|
||||
/* 38 */ parray<le_uint32_t, 5> grave_coords_time;
|
||||
/* 4C */ ptext<CharT, 0x14> grave_team;
|
||||
/* 60 */ ptext<CharT, 0x18> grave_message;
|
||||
/* 78 */ parray<le_uint32_t, 9> times_ep1_offline; // TODO: This might be online times
|
||||
/* 78 */ parray<le_uint32_t, 9> times_ep1_offline; // Encrypted; see decrypt_challenge_time. TODO: This might be online times
|
||||
/* 9C */ parray<uint8_t, 4> unknown_l4;
|
||||
/* A0 */
|
||||
} __attribute__((packed));
|
||||
@@ -359,9 +359,9 @@ struct PlayerRecordsV3_Challenge {
|
||||
// of save file structure
|
||||
/* 0000:001C */ U16T title_color = 0x7FFF; // XRGB1555
|
||||
/* 0002:001E */ parray<uint8_t, 2> unknown_u0;
|
||||
/* 0004:0020 */ parray<U32T, 9> times_ep1_online;
|
||||
/* 0028:0044 */ parray<U32T, 5> times_ep2_online;
|
||||
/* 003C:0058 */ parray<U32T, 9> times_ep1_offline;
|
||||
/* 0004:0020 */ parray<U32T, 9> times_ep1_online; // Encrypted; see decrypt_challenge_time
|
||||
/* 0028:0044 */ parray<U32T, 5> times_ep2_online; // Encrypted; see decrypt_challenge_time
|
||||
/* 003C:0058 */ parray<U32T, 9> times_ep1_offline; // Encrypted; see decrypt_challenge_time
|
||||
/* 0060:007C */ parray<uint8_t, 4> unknown_g3;
|
||||
/* 0064:0080 */ U16T grave_deaths = 0;
|
||||
/* 0066:0082 */ parray<uint8_t, 2> unknown_u4;
|
||||
@@ -378,9 +378,9 @@ struct PlayerRecordsV3_Challenge {
|
||||
struct PlayerRecordsBB_Challenge {
|
||||
/* 0000 */ le_uint16_t title_color = 0x7FFF; // XRGB1555
|
||||
/* 0002 */ parray<uint8_t, 2> unknown_u0;
|
||||
/* 0004 */ parray<le_uint32_t, 9> times_ep1_online;
|
||||
/* 0028 */ parray<le_uint32_t, 5> times_ep2_online;
|
||||
/* 003C */ parray<le_uint32_t, 9> times_ep1_offline;
|
||||
/* 0004 */ parray<le_uint32_t, 9> times_ep1_online; // Encrypted; see decrypt_challenge_time
|
||||
/* 0028 */ parray<le_uint32_t, 5> times_ep2_online; // Encrypted; see decrypt_challenge_time
|
||||
/* 003C */ parray<le_uint32_t, 9> times_ep1_offline; // Encrypted; see decrypt_challenge_time
|
||||
/* 0060 */ parray<uint8_t, 4> unknown_g3;
|
||||
/* 0064 */ le_uint16_t grave_deaths = 0;
|
||||
/* 0066 */ parray<uint8_t, 2> unknown_u4;
|
||||
|
||||
+1
-1
@@ -725,7 +725,7 @@ static const QuestScriptOpcodeDefinition opcode_defs[] = {
|
||||
{0xF8B5, "write4", {REG, REG}, {}, V2, V2},
|
||||
{0xF8B5, "write4", {}, {INT32, REG}, V3, V4},
|
||||
{0xF8B6, "check_for_hacking", {REG}, {}, V2, V2}, // Returns a bitmask of 5 different types of detectable hacking. But it only works on DCv2 - it crashes on all other versions.
|
||||
{0xF8B7, nullptr, {REG}, {}, V2, V4}, // TODO (DX) - Challenge mode. Appears to be timing-related; regA is expected to be in [60, 3600]. Encodes the value with some strange masking key, even though it's never sent over the network and is only decoded locally.
|
||||
{0xF8B7, nullptr, {REG}, {}, V2, V4}, // TODO (DX) - Challenge mode. Appears to be timing-related; regA is expected to be in [60, 3600]. Encodes the value with encrypt_challenge_time even though it's never sent over the network and is only decrypted locally.
|
||||
{0xF8B8, "disable_retry_menu", {}, {}, V2, V4},
|
||||
{0xF8B9, "chl_recovery", {}, {}, V2, V4},
|
||||
{0xF8BA, "load_guild_card_file_creation_time_to_flag_buf", {}, {}, V2, V4},
|
||||
|
||||
Reference in New Issue
Block a user