如何编写脚本解码WebService返回的二进制数据文件?
Alright, let's break this down to decode that binary data you're getting from the WebService. From the hex snippet you shared, there's already clear ASCII content, which gives us a great starting point to reverse-engineer the format.
First, Spot the Pattern in the Hex Data
Looking at your hex string:
0a39 0a06 3939 3831 3438 1206 4467 616d 6178 1a0b 6361 7264 6963 6f6e 5f33 3222 0d54 6865 204f 6c64 2047 7561 7264 2a02 ...
Let's map the chunks to the ASCII values you recognized:
0a(hex = newline) followed by39= ASCII '9'0a 06(newline + length byte06= 6 characters) → next 6 bytes393938313438= "998148" (perfect match for the length)12 06(type marker0x12+ length 6) →4467616d6178= "Dgamax"1a 0b(type marker0x1a+ length 11) →6361726469636f6e5f3332= "cardicon_32"22 0d(type marker0x22+ length 13) →546865204f6c64204775617264= "The Old Guard"
This is classic TLV (Type-Length-Value) structure—each field starts with a type identifier byte, a length byte, then the actual value (either human-readable ASCII or binary numbers).
Next, Decode the Numeric Fields (Kills/Wins/Battles/XP/Currency)
The trailing 2a02 ... is almost certainly your numeric stats. These are usually encoded in one of two ways:
- Variable-length integers (varints) (super common in formats like Protobuf, since they save space for small numbers)
- Fixed-size little-endian integers (16-bit or 32-bit, straightforward for consistent value ranges)
Let's Write a Quick Script to Test Both
Here's a Python script that parses the TLV structure and tries both decoding methods. I included comments so you can tweak it if needed:
import struct # We'll use Protobuf's varint decoder since it's widely used from google.protobuf.internal.decoder import _DecodeVarint def parse_binary_response(hex_data): # Convert hex string to raw bytes binary = bytes.fromhex(hex_data.replace(' ', '')) offset = 0 decoded_fields = {} while offset < len(binary): # Grab the field type byte field_type = binary[offset] offset += 1 # Grab the length of the value value_length = binary[offset] offset += 1 # Extract the value chunk value = binary[offset:offset + value_length] offset += value_length # First check if it's printable ASCII try: ascii_str = value.decode('ascii') if all(32 <= ord(c) <= 126 for c in ascii_str): decoded_fields[f"0x{field_type:02X}"] = ascii_str continue except UnicodeDecodeError: pass # Try decoding as a varint (Protobuf-style) try: varint_val, used_length = _DecodeVarint(value, 0) if used_length == value_length: decoded_fields[f"0x{field_type:02X}"] = varint_val continue except: pass # Try fixed-size integers (little-endian) if value_length == 2: decoded_fields[f"0x{field_type:02X}"] = struct.unpack('<H', value)[0] elif value_length == 4: decoded_fields[f"0x{field_type:02X}"] = struct.unpack('<I', value)[0] # Fallback to hex if nothing else works else: decoded_fields[f"0x{field_type:02X}"] = value.hex() return decoded_fields # Replace this with your full hex data your_hex_data = "0a390a0639393831343812064467616d61781a0b6361726469636f6e5f3332220d546865204f6c642047756172642a02..." results = parse_binary_response(your_hex_data) # Print out all decoded fields for field_id, value in results.items(): print(f"Field {field_id}: {value}")
Validate with Your Known Results
Since you know what the end values should be (e.g., "this vehicle has 150 kills"), run the script and cross-reference the numeric outputs against your expected stats. If you see a number that matches, you'll know which decoding method works for that field.
Pro Tips for Troubleshooting
- If the numbers don't make sense, check if the length is a 2-byte value instead of 1 (some TLV formats use longer length fields for larger values)
- Test with multiple WebService calls: play a battle, then call the service again—look for which bytes change. Those are definitely your dynamic stats (kills, battle count, etc.)
- If varints don't work, try big-endian integers (replace
<Hwith>Hin thestruct.unpackcalls)
内容的提问来源于stack exchange,提问作者Maxence

