- Architecture overview, BLE and WebSocket protocols - All 19 modules with command IDs validated against smali source - BLE packet format with CRC-16/MODBUS pseudocode - Complete WsCmd index (~300 commands) - Connection flow with pseudocode examples - Methodology section explaining APK decompilation process
97 lines
5.6 KiB
Markdown
97 lines
5.6 KiB
Markdown
# Methodology & Sources
|
|
|
|
## How This Documentation Was Obtained
|
|
|
|
All information in this documentation was extracted through **static analysis of the decompiled DWARFLAB Android APK** (v3.4.0, build 629, package `com.convergence.dwarflab`). No device was needed — the entire protocol is defined in the app's code.
|
|
|
|
### Decompilation
|
|
|
|
The APK was decompiled using **apktool v3.4.0**, which produced:
|
|
|
|
- `AndroidManifest.xml` — permissions, activities, services
|
|
- `smali/` through `smali_classes7/` — 7 DEX files of dalvik bytecode
|
|
- `lib/` — native `.so` libraries (arm64, armeabi-v7a, x86_64)
|
|
- `assets/` — voice JSON, country JSON, keystores
|
|
- `res/` — layouts, drawables, Lottie animations
|
|
|
|
### Key Smali Files Mapped to Protocol Concepts
|
|
|
|
| Protocol Concept | Smali File | Location |
|
|
|-----------------|------------|----------|
|
|
| BLE UUIDs | `cg1.smali` | `smali_classes4/` |
|
|
| BLE commands | `j80.smali` | `smali_classes4/` |
|
|
| BLE packet format | `l80.smali` | `smali_classes4/` |
|
|
| BLE CRC-16 | `vc0.smali` | `smali_classes4/` |
|
|
| WebSocket URL | `v55.smali` | `smali_classes4/` |
|
|
| WsPacket fields | `BaseProto$WsPacket.smali` | `smali_classes5/` |
|
|
| WsModuleId | `WsModuleId.smali` | `smali_classes4/` |
|
|
| WsCmd (all commands) | `WsCmd.smali` | `smali_classes4/` |
|
|
| WsMessageType | `WsMessageType.smali` | `smali_classes4/` |
|
|
| WsRespCode | `WsRespCode.smali` | `smali_classes4/` |
|
|
| DeviceType | `DeviceType.smali` | `smali_classes4/` |
|
|
| BluetoothPacketSender | `BluetoothPacketSender.smali` | `smali_classes4/` |
|
|
| ConnectionManager | `ConnectionManager.smali` | `smali_classes4/` |
|
|
| Proto messages | `AstroProto*.smali`, `CameraProto*.smali`, etc. | `smali_classes5/` |
|
|
|
|
### Extraction Methods
|
|
|
|
#### 1. UUID Discovery (`cg1.smali`)
|
|
The `cg1` class contains 8 static UUID strings. Read directly from the `<clinit>` method — the values are string constants embedded in the bytecode.
|
|
|
|
#### 2. Command IDs (`WsCmd.smali`)
|
|
The `WsCmd` enum contains ~300 entries. Each entry is initialized in `<clinit>` via `<init>(String name, int ordinal, int cmd)`. The third parameter (`cmd`) is the numeric command ID. Extracted by tracing register values through the constructor calls.
|
|
|
|
**Important**: Kotlin enum ordinals and explicit `cmd` IDs are different numbers. The `cmd` value is what goes on the wire.
|
|
|
|
#### 3. Module IDs (`WsModuleId.smali`)
|
|
The `WsModuleId` enum uses **ordinal values only** (no custom id field). Module ID = ordinal position in the enum (0-18).
|
|
|
|
#### 4. BLE Packet Format (`l80.smali`)
|
|
The `l80` class (obfuscated name for `BluetoothPacket`) encodes packets in method `j()`:
|
|
- Magic byte `0xAA` at position 0
|
|
- 9-byte header: protocolVersion, cmdInstruction, packageSequence, totalPackages, extendedProtocol (2B), validDataLength (2B)
|
|
- Payload: protobuf data
|
|
- CRC-16 computed by class `vc0` over header+payload
|
|
- End marker `0x0D`
|
|
|
|
The CRC lookup table in `vc0.smali` starts with `{0x0000, 0xC0C1, 0xC181, 0x0140, ...}` which identifies it as CRC-16/MODBUS (reflected polynomial 0xA001 = 0x8005 reflected, init 0xFFFF).
|
|
|
|
#### 5. WebSocket URL (`v55.smali`)
|
|
The URL is assembled by concatenating: `"ws://"` + `yd3.b()` (host IP) + `":9900/?client_id="` + `y32.c()` (client ID). Two additional constants: `0x1139` (4409) and `0x113A` (4410) for secondary ports.
|
|
|
|
#### 6. DeviceType IDs (`DeviceType.smali`)
|
|
The constructor signature is `<init>(String name, int ordinal, int deviceId, int nameResId)`. The `deviceId` parameter is the on-wire device identifier. Careful register tracing is required because smali reuses registers:
|
|
- Unknown: deviceId=0
|
|
- DWARF_2: deviceId=1
|
|
- DWARF_3: deviceId=2
|
|
- DWARF_mini: deviceId=4 (ordinal=3, **gap at deviceId=3**)
|
|
- DWARF_4: deviceId=5
|
|
- DWARF_DRAGON: deviceId=6
|
|
|
|
#### 7. Proto Message Fields (`smali_classes5/com/convergence/dwarflab/proto/`)
|
|
Each `.smali` file in the proto package corresponds to a protobuf message. Field numbers are embedded as constants in the `writeTo()` method (serialized using `writeString(fieldNumber, value)`, `writeInt32(fieldNumber, value)`, etc.). Field names are preserved in the obfuscated class names via Kotlin metadata annotations.
|
|
|
|
### Limitations
|
|
|
|
- **Obfuscated names**: Most class names are obfuscated (e.g., `l80`, `cg1`, `j80`). Kotlin metadata annotations help recover some names.
|
|
- **No `.proto` files**: The original `.proto` source files are not included in the APK. Field names and numbers are inferred from the generated Java/Kotlin code.
|
|
- **String literals**: Some strings (UUIDs, URLs, keys) are embedded directly and can be extracted with certainty. Others require contextual inference.
|
|
- **Behavioral details**: Timing, retry logic, and UI flow are inferred from the code but not directly observable without a device.
|
|
- **Version-specific**: This documentation corresponds to APK v3.4.0. Newer or older versions may differ.
|
|
|
|
### Verification
|
|
|
|
All data points were cross-validated in two passes:
|
|
1. **First pass**: Initial extraction from smali source code
|
|
2. **Second pass**: Independent re-reading of each smali file to confirm register values, field numbers, and constants
|
|
|
|
Key verifications:
|
|
- All 8 BLE UUIDs confirmed from `cg1.smali`
|
|
- All 19 module IDs confirmed from `WsModuleId.smali` (ordinals)
|
|
- All ~300 WsCmd command IDs confirmed from `WsCmd.smali` (hex → decimal conversions)
|
|
- All 8 WsPacket field numbers confirmed from `BaseProto$WsPacket.smali`
|
|
- DeviceType IDs confirmed with register tracing (including the gap at deviceId=3)
|
|
- BLE command bytes (0-7) confirmed from `j80.smali`
|
|
- BLE packet format confirmed from `l80.smali` (header layout, CRC, end marker)
|
|
- WebSocket URL and ports confirmed from `v55.smali`
|
|
- CRC-16/MODBUS confirmed from `vc0.smali` lookup table |