USB audio interface #
US-2x2HR and US-4x4HR models should be very similar. But probably multiple changes over the last generation (US-2x2). Let’s see if we can look at the firmware updater and fw image.
initial poking #
The ‘settings’ program requests a json, https://teac-global.com/download/fw/us-hr/US-HR_UpdateInformation.json
, but the links contained there are broken ? Or I am missing some request magic and get punished with a 404.
Downloading a fw updater from the european website works better. The .exe clearly contains the firmware image.
Using Resource Hacker: finds only icons
Looking around in the disasm, it’s probably some Qt resource format. One tool found, https://github.com/axstin/qtextract , not tested.
Running fw updater, see hint about version ‘110’ and ‘build 16’. In About screen, see large License text file that I recall seeing in disasm. In ghidra, that chunk is easily found, as well as its length. Just nearby, clearly some kind of resource section:
004119c4 78 ?? 78h x
004119c5 c3 ?? C3h
004119c6 00 ?? 00h
004119c7 72 ?? 72h r
004119c8 00 ?? 00h
004119c9 65 ?? 65h e
004119ca 00 ?? 00h
004119cb 73 ?? 73h s
004119cc 00 ?? 00h
004119cd 0b ?? 0Bh len(filename?)
004119ce 03 ?? 03h
004119cf d9 ?? D9h
004119d0 f4 ?? F4h
004119d1 b4 ?? B4h
004119d2 00 ?? 00h
004119d3 4c 00 49 unicode u"LICENSE.txt"
00 43 00
45 00 4e
004119e9 0c db Ch len(filename) ?
004119ea 07 ?? 07h
004119eb fa ?? FAh
004119ec 19 ?? 19h
004119ed be ?? BEh
004119ee 00 ?? 00h
004119ef 75 00 70 unicode u"update44.bin"
00 64 00
61 00 74
followed by the contents of those 2 resources:
lic_txt_content XREF[2]: 0040c953(*), 0040eeb3(*)
00411a40 00 00 76 a4 ddw 76A4h sizeof content (bigendian)
00411a44 3d 3d 3d char[303 "=============================================
3d 3d 3d
3d 3d 3d
004190e8 00 02 30 20 ddw 23020h length of blob
update44_bin_blob
004190ec 55 53 2d db[143392]
34 78 34
48 52 00
fw blob parsing #
ok, found some error messages relating to checksum errors which lead to:
bVar4 = parse_fw_blob?((int)(param_1 + 0x53d),(int)param_1[0x4053d]);
not sure how the blob data ends up in those args. Was not successful in navigating Qt/C++ mess, but ‘param_1’ would be a large class, holding a static buffer where the file would be copied.
parse_fw_blob is just a wrapper around parse_fw_blob2 (my excellent nomenclature…). In there, some important information.
//extract blob size
uVar3 = (uint)param_1[0x15] << 0x10 | (uint)param_1[0x14] << 0x18 | (uint)param_1[0x17] |
(uint)param_1[0x16] << 0x8;
if (uVar3 == 0x0) {
printf("%s:%d:ERROR\n","../../ustest/prgdecode.c",0x9d);
return 0x1;
}
Ah, we’re reconstructing a big-endian u32; if I look at those offsets in the extracted blob, I find the value 0x23020 which matches its filesize and resource size. Good.
More hints around there indicate that the blob has a 0x20 byte header. My best guess currently:
struct {
char[8] devicename; // "US-4x4HR"
u16_be version; //0x6E = 110
u16_be build; //0x10 = 16
u32_be unknown_field; //0x7e50c15 ; not clear what that refers to.
u32_be filesize; // big-endian
u8 padding[];
} //sizeof = 0x20
possible ‘decryption’ #
In parse_fw_blob2()
:
copy_junk((int)_Memory + 0x20,(int)(param_1 + 0x20),file_size - 0x20);
// what's that ?
void __cdecl copy_junk(byte *dest,byte *src,int len) {
int idx;
idx = 0x0;
if (0x0 < len) {
do {
dest[idx] = (&DAT_00411680)[src[idx]];
idx = idx + 0x1;
} while (idx != len);
}
A look-up table ? how quaint. Let’s see what’s at 411680
BYTE_ARRAY_00411680 XREF[1]: copy_junk:0040b8a8(*)
00411680 00 cc c1 db[256]
c2 c3 cd
ce cf c4
00411680 [0] 0h, CCh, C1h, C2h,
00411684 [4] C3h, CDh, CEh, CFh,
00411688 [8] C4h, C5h, C6h, C7h,
0041168c [12] C8h, C9h, CAh, CBh,
00411690 [16] 20h, 2Ah, 2Bh, 2Ch,
.....
Hmm, I don’t recognize that pattern, but it doesn’t really matter. Cook one small python script, essentially:
decrypt_lut = b'\x00\xcc\xc1 .....
decrypted = bytes(map(lambda x:decrypt_lut[x], fw_blob))
the firmware is now “decrypted”, as confirmed by low entropy, as well as the presence of many promising strings :
..\src\device\cs4272.c:%d:ERROR
-- Runtime Assertion
..\src\device\usbaudio.c:1705 dsp->desc_pos == dspin->put_pos
... etc
My brain doesn’t recognize the instruction set, but cpu_rec claims ‘Blackfin’. This is believable since there is some online mentions of other tascam models (US-16x08, many DR recorders etc) using blackfin DSP / mcu. This is in contrast to the previous-generation model US-2x2 which was based on a LPC1820, ARM cortex-m3.
Anyway I have no business with the firmware itself at the moment, and ghidra doesn’t have native support for blackfin. There is one independant implementation here : https://github.com/sualk/ghidra-blackfin (haven’t tested)
fw blob checksum(s) ? #
Also in parse_fw_blob2()
:
iVar3 = 0x0;
sum = 0x0;
do {
ofs = iVar3 + 0x20;
iVar3 = iVar3 + 0x1;
sum = sum + *(byte *)((int)_Memory + ofs);
} while (fw_actual_size != iVar3);
simple sum of all bytes, skipping the 0x20-byte header.