fix(official): 修正官方 hash 校验算法

This commit is contained in:
2026-07-15 22:30:33 +08:00
parent 9e83bbea11
commit 60b8339ecb
3 changed files with 39 additions and 14 deletions
+27 -4
View File
@@ -77,8 +77,12 @@ fn parse_legacy_game_main_config(bytes: &[u8]) -> Result<YostarJpGameMainConfig,
}
fn parse_game_main_config_json(value: &str) -> Result<YostarJpGameMainConfig, String> {
serde_json::from_str(value)
.map_err(|error| format!("Failed to parse decrypted GameMainConfig JSON: {error}"))
let config: YostarJpGameMainConfig = serde_json::from_str(value)
.map_err(|error| format!("Failed to parse decrypted GameMainConfig JSON: {error}"))?;
if !game_main_config_has_known_field(&config) {
return Err("Decrypted GameMainConfig JSON did not contain any known fields".to_string());
}
Ok(config)
}
fn parse_obfuscated_game_main_config(bytes: &[u8]) -> Result<YostarJpGameMainConfig, String> {
@@ -113,6 +117,13 @@ fn parse_obfuscated_game_main_config(bytes: &[u8]) -> Result<YostarJpGameMainCon
})
}
fn game_main_config_has_known_field(config: &YostarJpGameMainConfig) -> bool {
config.skip_tutorial.is_some()
|| config.language.is_some()
|| config.default_connection_group.is_some()
|| config.server_info_data_url.is_some()
}
fn decrypt_inferred_ascii_json(bytes: &[u8]) -> Result<String, String> {
if !bytes.len().is_multiple_of(2) {
return Err("Obfuscated GameMainConfig byte length is not UTF-16LE aligned".to_string());
@@ -362,9 +373,9 @@ fn round(acc: u32, input: u32) -> u32 {
fn avalanche(mut hash: u32) -> u32 {
hash ^= hash >> 15;
hash = hash.wrapping_mul(0x85EB_CA6B);
hash = hash.wrapping_mul(0x85EB_CA77);
hash ^= hash >> 13;
hash = hash.wrapping_mul(0xC2B2_AE35);
hash = hash.wrapping_mul(0xC2B2_AE3D);
hash ^= hash >> 16;
hash
}
@@ -616,6 +627,18 @@ mod tests {
);
}
#[test]
fn rejects_legacy_json_without_known_fields() {
let error = parse_game_main_config_json(r#"{"unknown":"value"}"#).unwrap_err();
assert!(error.contains("did not contain any known fields"));
}
#[test]
fn uses_standard_xxhash32_seed_for_game_main_config_key() {
assert_eq!(xxhash32(b"GameMainConfig"), 2131083068);
}
#[test]
#[ignore]
fn extracts_game_main_config_bytes_from_serialized_assets() {