Last active
November 12, 2025 02:53
-
-
Save Airtnp/ca3831f5269fefc7e8416b56c0e1d1ac to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import hashlib | |
| import mst_card_text_pb2 | |
| import json | |
| from Crypto.Cipher import AES | |
| from Crypto.Util.Padding import unpad, pad | |
| from protodeep.lib import guess_schema | |
| from Crypto.Protocol.KDF import PBKDF2 # From PyCryptodome | |
| from Crypto.Hash import HMAC, SHA1 # PBKDF2 default hash = HMAC-SHA1 | |
| from collections import OrderedDict | |
| from pathlib import Path | |
| from typing import Dict | |
| # Dumped from Memory | |
| KEY = bytes.fromhex("C5 C5 15 6C 00 03 AD EE 8C 17 AE 24 92 94 2D 5A 1A 77 E7 EF 46 8D 77 7D FA B8 88 4A 4E 08 76 E6") | |
| IV = bytes.fromhex("84 E7 6B 8C 7C 40 5C 6E 96 68 CB CB A3 F8 05 08") | |
| # Also in stringliterals.json | |
| PASSWORD = "sbiVmG&$P0qDu1$sqT$4r+T96lSFEpDD" | |
| ITERATION_COUNT = 0x3e8 # 1000 | |
| # PrivateImplementationDetails | |
| SALT = bytes.fromhex("00 01 03 02 07 05 06 F1 F0 EE 21 22 46") | |
| def decrypt(data): | |
| return unpad(AES.new(KEY, AES.MODE_CBC, IV).decrypt(data), 16) | |
| def encrypt(data): | |
| return AES.new(KEY, AES.MODE_CBC, IV).encrypt(pad(data, 16)) | |
| def generate_key(): | |
| KEY_LEN = 0x20 | |
| IV_LEN = 0x10 | |
| total_size = KEY_LEN + IV_LEN | |
| derived = PBKDF2(PASSWORD.encode('utf-8'), SALT, dkLen=total_size, count=ITERATION_COUNT, hmac_hash_module=SHA1) | |
| key = derived[:KEY_LEN] | |
| iv = derived[KEY_LEN:] | |
| return key, iv | |
| def serialize_card_text_file(src: Path, dst_folder: Path, translation_map: Dict[str, str]): | |
| with open(src,"rb") as f: | |
| ct = f.read() | |
| pt = decrypt(ct) | |
| card_text_data = mst_card_text_pb2.Schema() | |
| card_text_data.ParseFromString(pt) | |
| for e in card_text_data.entries: | |
| if e.text.value in translation_map and translation_map[e.text.value] != "": | |
| e.text.value = translation_map[e.text.value] | |
| # md5('mst_card_text') | |
| with open(dst_folder / '870e4daec54c1d63dee345925f4378fc.dat', 'wb') as f: | |
| f.write(encrypt(card_text_data.SerializeToString())) | |
| def write_translation_template(src: Path, dst: Path, translation_map: Dict[str, str]): | |
| with open(src,"rb") as f: | |
| ct = f.read() | |
| pt = decrypt(ct) | |
| card_text_data = mst_card_text_pb2.Schema() | |
| card_text_data.ParseFromString(pt) | |
| text_lines = OrderedDict() | |
| for e in card_text_data.entries: | |
| if e.text.value in translation_map and translation_map[e.text.value] != "": | |
| text_lines[e.text.value] = translation_map[e.text.value] | |
| else: | |
| text_lines[e.text.value] = "" | |
| # md5('mst_card_text') | |
| with open(dst, 'w', encoding='utf-8') as f: | |
| f.write(json.dumps(text_lines, indent=2, ensure_ascii=False)) | |
| if __name__ == '__main__': | |
| with open('./zh/translation.json', 'r', encoding='utf-8') as f: | |
| translation_map = json.loads(f.read()) | |
| serialize_card_text_file(Path('./mst_card_text.dat'), Path('./zh/'), translation_map) | |
| # write_translation_template(Path('./mst_card_text.dat'), Path('./translation.json'), {}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import hashlib | |
| import json | |
| from Crypto.Cipher import AES | |
| from Crypto.Util.Padding import unpad, pad | |
| from protodeep.lib import guess_schema | |
| from Crypto.Protocol.KDF import PBKDF2 # From PyCryptodome | |
| from Crypto.Hash import HMAC, SHA1 # PBKDF2 default hash = HMAC-SHA1 | |
| from tqdm import tqdm | |
| # Dumped from Memory | |
| KEY = bytes.fromhex("C5 C5 15 6C 00 03 AD EE 8C 17 AE 24 92 94 2D 5A 1A 77 E7 EF 46 8D 77 7D FA B8 88 4A 4E 08 76 E6") | |
| IV = bytes.fromhex("84 E7 6B 8C 7C 40 5C 6E 96 68 CB CB A3 F8 05 08") | |
| # Also in stringliterals.json | |
| PASSWORD = "sbiVmG&$P0qDu1$sqT$4r+T96lSFEpDD" | |
| ITERATION_COUNT = 0x3e8 # 1000 | |
| # PrivateImplementationDetails | |
| SALT = bytes.fromhex("00 01 03 02 07 05 06 F1 F0 EE 21 22 46") | |
| def decrypt(data): | |
| return unpad(AES.new(KEY, AES.MODE_CBC, IV).decrypt(data), 16) | |
| def encrypt(data): | |
| return AES.new(KEY, AES.MODE_CBC, IV).encrypt(pad(data, 16)) | |
| def generate_key(): | |
| KEY_LEN = 0x20 | |
| IV_LEN = 0x10 | |
| total_size = KEY_LEN + IV_LEN | |
| derived = PBKDF2(PASSWORD.encode('utf-8'), SALT, dkLen=total_size, count=ITERATION_COUNT, hmac_hash_module=SHA1) | |
| key = derived[:KEY_LEN] | |
| iv = derived[KEY_LEN:] | |
| return key, iv | |
| if __name__ == '__main__': | |
| # https://master-dmplays-jp.cdn-dena.com/latest_Win.dat | |
| with open("latest_Win.dat","rb") as f: | |
| ct = f.read() | |
| pt = decrypt(ct) | |
| with open("Test.dat", 'wb') as f: | |
| f.write(encrypt(pt)) | |
| schema = guess_schema(pt) | |
| md5_mapping = {} | |
| for v in schema.values['2']: | |
| md5_mapping[v['1']['1']] = hashlib.md5(v['1']['1'].encode("utf-8")).hexdigest() | |
| for name, m in tqdm(md5_mapping.items()): | |
| with open(f'C:\\Users\\<your_pc>\\AppData\\Roaming\\AndApp\\GameData\\<>\\<>\\data\\a7843688bc3abfa77b4331970f135680\\{m}.dat', 'rb') as f: | |
| schema = guess_schema(decrypt(f.read())) | |
| schema.export_protofile(f"./Proto/proto/{name}.proto") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| syntax = "proto3"; | |
| message Schema { | |
| message HashStr { | |
| string value = 1; | |
| } | |
| HashStr hash = 1; | |
| message Data { | |
| message CardTextId { | |
| int64 value = 1; | |
| } | |
| CardTextId id = 1; | |
| message CardTextStr { | |
| string value = 1; | |
| } | |
| CardTextStr text = 2; | |
| message LineFeedDecision { | |
| int64 value = 1; | |
| } | |
| LineFeedDecision line_feed_decision = 3; | |
| } | |
| repeated Data entries = 2; | |
| } | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # -*- coding: utf-8 -*- | |
| # Generated by the protocol buffer compiler. DO NOT EDIT! | |
| # NO CHECKED-IN PROTOBUF GENCODE | |
| # source: mst_card_text.proto | |
| # Protobuf Python Version: 6.32.1 | |
| """Generated protocol buffer code.""" | |
| from google.protobuf import descriptor as _descriptor | |
| from google.protobuf import descriptor_pool as _descriptor_pool | |
| from google.protobuf import runtime_version as _runtime_version | |
| from google.protobuf import symbol_database as _symbol_database | |
| from google.protobuf.internal import builder as _builder | |
| _runtime_version.ValidateProtobufRuntimeVersion( | |
| _runtime_version.Domain.PUBLIC, | |
| 6, | |
| 32, | |
| 1, | |
| '', | |
| 'mst_card_text.proto' | |
| ) | |
| # @@protoc_insertion_point(imports) | |
| _sym_db = _symbol_database.Default() | |
| DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x13mst_card_text.proto\"\xcf\x02\n\x06Schema\x12\x1d\n\x04hash\x18\x01 \x01(\x0b\x32\x0f.Schema.HashStr\x12\x1d\n\x07\x65ntries\x18\x02 \x03(\x0b\x32\x0c.Schema.Data\x1a\x18\n\x07HashStr\x12\r\n\x05value\x18\x01 \x01(\t\x1a\xec\x01\n\x04\x44\x61ta\x12#\n\x02id\x18\x01 \x01(\x0b\x32\x17.Schema.Data.CardTextId\x12&\n\x04text\x18\x02 \x01(\x0b\x32\x18.Schema.Data.CardTextStr\x12\x39\n\x12line_feed_decision\x18\x03 \x01(\x0b\x32\x1d.Schema.Data.LineFeedDecision\x1a\x1b\n\nCardTextId\x12\r\n\x05value\x18\x01 \x01(\x03\x1a\x1c\n\x0b\x43\x61rdTextStr\x12\r\n\x05value\x18\x01 \x01(\t\x1a!\n\x10LineFeedDecision\x12\r\n\x05value\x18\x01 \x01(\x03\x62\x06proto3') | |
| _globals = globals() | |
| _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) | |
| _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'mst_card_text_pb2', _globals) | |
| if not _descriptor._USE_C_DESCRIPTORS: | |
| DESCRIPTOR._loaded_options = None | |
| _globals['_SCHEMA']._serialized_start=24 | |
| _globals['_SCHEMA']._serialized_end=359 | |
| _globals['_SCHEMA_HASHSTR']._serialized_start=96 | |
| _globals['_SCHEMA_HASHSTR']._serialized_end=120 | |
| _globals['_SCHEMA_DATA']._serialized_start=123 | |
| _globals['_SCHEMA_DATA']._serialized_end=359 | |
| _globals['_SCHEMA_DATA_CARDTEXTID']._serialized_start=267 | |
| _globals['_SCHEMA_DATA_CARDTEXTID']._serialized_end=294 | |
| _globals['_SCHEMA_DATA_CARDTEXTSTR']._serialized_start=296 | |
| _globals['_SCHEMA_DATA_CARDTEXTSTR']._serialized_end=324 | |
| _globals['_SCHEMA_DATA_LINEFEEDDECISION']._serialized_start=326 | |
| _globals['_SCHEMA_DATA_LINEFEEDDECISION']._serialized_end=359 | |
| # @@protoc_insertion_point(module_scope) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment