Wire messenger is secure messenger similar to Signal and Telegram. It has been downloaded over 1 million in Google Playstore, and supports various platforms such as Android, iOS, Windows, macOS.
This posts cover local artifacts, data reading from IndexedDB, decryption of encrypted attachements in Windows OS.
Wire's local artifacts store in %AppData%\Wire
.
\IndexedDB\https_app.wire.com_0.indexeddb.leveldb
(IndexedDB)\Service Worker\CacheStorage
Wire's database has IndexedDB format as below.
We use ccl_chrome_indexeddb
(link) to parse IndexedDB to JSON. Specifically, I modify some point of dump_indexeddb_details.py
so that it can print all values in the IndexedDB.
(...)
for obj_store_name in db.object_store_names:
obj_store = db[obj_store_name]
print(f"\tobject_store_id={obj_store.object_store_id}; name={obj_store.name}")
try:
for message in obj_store.iterate_records():
print(message.value)
except StopIteration:
pass
IndexedDB can be printed like this.
// User access information
{
"capabilities":{
"capabilities":[
]
},
"class":"desktop",
"id":"17bcfe3e104e158f",
"label":"Windows 10 64-bit 10",
"location":{
"lat":37.5841,
"lon":127.0616
},
"mls_public_keys":{
},
"model":"Wire Windows",
"time":"2023-07-19T08:51:56.773Z",
"type":"permanent",
"domain":"wire.com",
"meta":{
"is_verified":true,
"primary_key":"local_identity"
}
}
// Chat Logs
{
"conversation":"f3455ff3-21ee-419e-8a3b-28709518745c",
"from":"464da264-7518-4b38-b60f-391f8d46e257",
"from_client_id":"<Undefined>",
"id":"32f51913-9ba3-44fe-a1a9-40830060a314",
"qualified_conversation":{
"domain":"wire.com",
"id":"f3455ff3-21ee-419e-8a3b-28709518745c"
},
"qualified_from":"<Undefined>",
"status":1,
"time":"2023-07-19T08:54:00.002Z",
"data":{
"content":"hello?",
"mentions":[
],
"previews":[
],
"expects_read_confirmation":false,
"legal_hold_status":1
},
"type":"conversation.message-add",
"category":16
}
Wire's attachments are all encrypted and stored in Service Worker\CacheStorage
. They cached request and response packets when I uploaded a picture on Wire.
Cache files are Chromium Simple Cache
(For detailed information, see this). An encrypted image is on the request packet, so I can parse it as below.
0x18
)0x156
)0x18 + 0x156 = 0x16E
D8 41 0D 97
, choose the first one because it indicate the request packet.0x3AA6E - 1 = 0x3AA6D
Ctrl+E
in HxD)In the IndexedDB logs, encryption key named otr_key
can be found.
// Attachment
{'conversation': 'f3455ff3-21ee-419e-8a3b-28709518745c',
// ...
'otr_key': (12, 104, 172, 189, 164, 135, 145, 145, 20, 65, 54, 158, 191, 53, 24, 191, 93, 220, 61, 164, 1, 218, 182, 98, 224, 212, 188, 228, 36, 236, 88, 253)
}
Because otr_key
is decimal format, It needs to be converted to hex. I use Cyberchef to convert the format.
All right, now we can decrypt the image.
otr_key
, which is converted to hex.0x10
bytes at the beginning of encrypted binary.0x10
.