Reverse Engineering for WITRN products binary firmware
For WITRNUP.exe, WITRN uses commercial grade ".NET Reactor" for obfuscation. We may never know correct symbol names nor be able to debug. All results are based on static analysis.
This repository contains only the analysis of binary file headers, as all WITRN products use a custom 2nd bootloader rather than a generic format for any microcontroller, binwalk helps nothing and so am I :(
WITRN uses a fixed mapping table to encrypt the firmware binary file.
MAPPING_TABLE = [26, 182, 183, 241, 123, 140, 213, 60, 124, 144, 210, 244, 53, 242, 27, 233, 219, 18, 119, 91, 61, 127, 63, 189, 45, 71, 42, 80, 220, 195, 255, 87, 130, 131, 96, 252, 155, 78, 136, 208, 0, 95, 46, 89, 43, 249, 198, 56, 240, 200, 142, 128, 68, 253, 115, 126, 11, 41, 25, 175, 216, 150, 113, 179, 98, 230, 229, 17, 145, 156, 70, 21, 196, 194, 165, 82, 185, 102, 172, 178, 34, 83, 238, 84, 170, 180, 116, 207, 176, 108, 114, 167, 146, 90, 86, 231, 133, 236, 193, 159, 206, 110, 174, 59, 120, 143, 93, 75, 226, 100, 12, 76, 19, 99, 192, 65, 79, 186, 228, 16, 4, 166, 62, 49, 225, 184, 72, 103, 5, 211, 152, 105, 191, 54, 101, 190, 6, 81, 92, 199, 139, 9, 55, 197, 169, 168, 112, 212, 135, 29, 218, 13, 243, 118, 48, 173, 23, 148, 224, 177, 20, 237, 14, 8, 66, 154, 51, 181, 85, 217, 69, 57, 227, 125, 77, 1, 203, 39, 239, 37, 106, 58, 122, 121, 109, 22, 64, 97, 164, 2, 171, 134, 15, 52, 111, 235, 107, 247, 40, 222, 163, 204, 117, 44, 202, 94, 129, 10, 250, 104, 248, 7, 3, 36, 205, 31, 162, 47, 50, 67, 157, 245, 215, 188, 158, 187, 73, 74, 214, 138, 132, 161, 33, 223, 151, 254, 32, 209, 30, 147, 28, 141, 251, 38, 24, 149, 246, 201, 221, 234, 153, 35, 232, 160, 88, 137]
data_array = bytearray(data)
data_length = len(data_array)
decrypted_array = bytearray(data_length)
for i in range(data_length):
decrypted_array[i] = MAPPING_TABLE[data_array[i]][StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct Header
{
[FixedBuffer(typeof(byte), 7)]
public Header.MagicFixedBuffer magic;
public ushort year;
public byte month;
public byte day;
[FixedBuffer(typeof(byte), 9)]
public Header.ReversedFixedBuffer reversed;
public UUID uuid;
public uint size;
public uint xor_checksum;
public uint add_checksum;
[CompilerGenerated]
[UnsafeValueType]
[StructLayout(LayoutKind.Sequential, Size = 7)]
internal struct MagicFixedBuffer
{
public byte FixedElementField;
}
[UnsafeValueType]
[CompilerGenerated]
[StructLayout(LayoutKind.Sequential, Size = 9)]
internal struct ReversedFixedBuffer
{
public byte FixedElementField;
}
}-
magic
Length: 7 bytes
Value:
- Hex:
67 7A 75 74 61 70 70 - ASCII:
gzutapp
Note: "GZUT", "Guangzhou Youshuo Microelectronics Technology Co., Ltd.", "广州市优硕微电子科技有限公司", has close ties with WITRN, and GZUT holds partial of the “WITRN” trademark.
- Hex:
-
year
Length: 2 bytes
Value: The year of the date when this firmware was built (or packaged). Example:
- Hex:
E9 07 - ASCII:
2025
- Hex:
-
month
Length: 1 byte
Value: The month of the date when this firmware was built (or packaged). Example:
- Hex:
08 - ASCII:
08
- Hex:
-
day
Length: 1 byte
Value: The day of the date when this firmware was built (or packaged). Example:
- Hex:
15 - ASCII:
15
- Hex:
-
reversed
Length: 9 bytes
Value: Filled with
7F -
uuid
Length: 16 bytes
Value: Struct. Contains a UUID, where each UUID refers to a WITRN product. See below.
-
size
Length: 2 bytes
Value: Size of the firmware body (excluding header size (48 bytes))
-
xor_checksum
Length: 2 bytes
Value: Firmware body (excluding header) XOR checksum
-
add_checksum
Length: 2 bytes
Value: Firmware body (excluding header) ADD checksum
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct UUID
{
public uint uuid_1;
public ushort uuid_2;
public ushort uuid_3;
[FixedBuffer(typeof(byte), 8)]
public UUID.uuid_4FixedBuffer uuid_4;
[UnsafeValueType]
[CompilerGenerated]
[StructLayout(LayoutKind.Sequential, Size = 8)]
internal struct uuid_4FixedBuffer
{
public byte FixedElementField;
}
}UUID is a mapping list. Each UUID corresponds to a WITRN product. For example
KNOWN_MODELS = {
"A3DC1BC1-8FD1-4374-85B9-FC9A2650FDDA": "WITRN W96D",
"B793053A-236B-4F99-A6E1-5A48A08B86D1": "WITRN U3"
}Can find UUID in MeterUP.exe. There's no chaos there :D
WITRN does not define Version in header, but some place within the firmware.
VERSION_OFFSET = 48 + 2048The upper 4 bits of this byte (8 bit) value is major version, lower 4 bits is minor version.
Of course there's a Python demo :D (demo.py)