This is going to be a huge post... Sorry about that.
Okay, so I spent an afternoon trying to get a grip on how this device communicates with the software. My idea was to copy the USB commands that the software sent with wireshark and usbmon and replicate them using libusb to try and get some info. What I gathered was the following:
I wrote a small python script based on the files in Hantek60022API to test my findings.
import libusb1
device_handle = self.context.getByVendorIDAndProductID(
0x04B4,
self.MODEL_ID,
skip_on_error=True,
skip_on_access_error=True
).open()
As with the 6022, the software has direct access to the scope's EEPROM, and reads and writes to it during normal operation. This is why many people have reported that crashing software destroys their scope.
However, as previously stated, there's no need to upload any firmware to the EEPROM on boot.
The sequence to read from the EEPROM is:
print('EEPROM Response', device_handle.controlRead(0xC0, 162, MEM_OFFSET, 0, 8, timeout=0))
and to write:
bytes_written = device_handle.controlWrite(0xc0, 162, MEM_OFFSET, 0, BYTES_TO_WRITE, timeout=timeout)
However, this can corrupt the contents of the EEPROM and the device may not work anymore. So only test this if you already have a copy of some working firmware.
This allows us to extract the entire contents and flash whatever we want. Previously, when bricking my scope, I had to ask Hantek for a file (
DSO6106BD20160601.iic), but I'm unable to redistribute it since I haven't got permission. They sent me a copy of Cypress's CyConsole (win only) to upload this, but with this info, we can dump the entire contents of the memory of a working scope ourselves, save it to a file and later upload it, thus replicating its functionality with ~10 lines of python code and the ability to run it in *NIX OSs. I'll post my tool when I get some more free time.
I've yet to see if the calibration values are 32 bytes sored in offset 0x08, as is the case in the 6022.
When active, the software sets and reads a couple of commands and then begins polling the scope's buffer.
There's a recurring loop that does the following:
controlWrite(0x40, 179, 0, 0, WEIRD_BYTE_ARRAY) always followed by controlRead(0xC0, 178, 0, 0, 10)
And then, the software asks for the data buffer:
device_handle.bulkRead(0x86, 10, timeout=100)
If polling when the LED is supposed to blink, the scope blinks green, and if the polling rate is fast enough (I've tested 10Hz), it only blinks this color, indicating a 'succesful' connection to the software.
My initial attempt, after repeating the commands the software sends when booted, was to create a loop that sent the 179, 178 and 0x86 commands and read the buffer. Here, I've substituted
WEIRD_BYTE_ARRAY by the first value the program sent.
while(1):
device_handle.controlWrite(0x40, 179, 0, 0, b'\x0f\x03\x03\x03\xd9\x10\x1d\x00\x90\xfe', timeout=timeout)
print('Response', device_handle.controlRead(0xC0, 178, 0x00, 0, 10, timeout=0))
try:
data = device_handle.bulkRead(0x86, 10, timeout=100)
except Exception as e:
print('couldn\'t read')
else:
print('received', data)
time.sleep(0.1)
What's interesting here is the
WEIRD_BYTE_ARRAY value. This is a repeating (I think I've found 20-30 different values in an unknown order) value which initially made no sense to me. It isn't sequential, so clearly it isn't a frame number and doesn't seem to be any kind of setting.
Even though when capturing the commands my program sends they are equal to my previous capture of the Windows software, the scope doesn't return anything. I can't seem to get a single value out of it.
Okay, so here comes the interesting part. It's my suspicion that the software sends a sort of token before reading. If it corresponds to what the scope expects, it'll dump the buffer and won't otherwise. I ignore its purpose. It may be to authenticate to the device and prevent this sort of reverse engineering.
In the official Windows SDK (
HT6004BX_Software.zip/SDK), the
QTDSO demo imports the
HTHardDll library, which is stored in some parent folder. I disassembled it using IDA-free and a ton of functions were listed. Logically, I peeked into the one responsible to read the scope's value (
dsoGetInBuffer), and check out what I found:
in function dsoGetInBuffer
mov rax, cs:__security_cookie
call __security_check_cookie
If you follow this reference, you'll see:
uintptr_t _security_cookie
.data:000000018006E000 __security_cookie dq 2B992DDFA232h
I've got 0 clue about assembly and may be 100% wrong, but this seems to be the token that I see, and what prevents me from reading the DSO's buffer even when copying the commands the program sent previously verbatim. More research needs to be made in order to find how it works.
Regarding the USB protocol, I'm wondering whether it is rather high-level (with commands like "set V/div", "set timebase", "set trigger"), or whether is is low-level (with commands like "send byte sequence x to SPI device #y on SPI bus #z").
There's one last type of command that I seldom find:
device_handle.bulkWrite(0x02, b'\x04\x00\xd4\x70', timeout=0)
I don't know what these payload bytes mean yet. I've found different values and they also seem to be sent when not changing any setting.
In the 6022, the command:
device_handle.controlWrite(0x40, 224+chNumber, 0, 0, VOLTAGE_RANGE_ID)
sets the scope's voltage range. I haven't found this to be the case in my 6204BD.
Maybe this link: Android APK for Hantek 6004 series
can help you..
I found this Android app last November and I'm wondering that it seems still unknown
I was too lazy to create a thread for it 'cause it's not my stuff..
Wow, good find! Yeah, unfortunately the cool stuff is hidden in that ht6000api.aar file. I've decompiled the java files in: JD-GUI and, while all the names are unobfuscated and are quite easy to understand, everything useful seems to be inside
ht6000api.aar/jni/x86-64/libhantek-native-lib.so. I've also opened it and it also seems to corroborate the polling-nature of the software. It shines some light on some aspects, however:
In function ht_measure_update
mov rax, cs:g_channelsInfo_ptr
There you go, (some) channel info appears to be sent every time the buffer is polled.
It was announced here in the Forum.
Unfortunately it contains a binary-only library "ht6000api.aar" with unclear origin and copyright.
The "interesting" part is hidden in this library, while the open sourced components are just the GUI stuff.
This is a really weird project. Almost nobody knows about it, the source includes dependencies from unknown originsm the github user has no other projects and the EEVblog account seemed to be created for that only purpose. Again, I'm not going to complaint since I've also created my account to discuss this project
Clearly, the ht6000api resource file comes from Hantek themselves, and it contains quite interesting file:
In ht6000api.aar/assets/autowave
.amr files, which start with the ASCII chars:
H.T.K.-.D.S.O.-.A.M.
And are named like car diagnostics events. Are they recordings?
And also, in ht6000api.aar/assets/autowave/settings
.set which start with the hex values:
H.T.K.-.D.S.O.
They are very short, are mostly the same and contain mainly 0s. This could shed some light into this, since they clearly specify the scope's configuration. They may be directly written on the EEPROM of the device, and (if these settings are directly stored in this memory) we could deduce the offsets of each config. If the official Hantek software supports these automotive files, it'd great to see how they are sent via USB.
It'd be great if user
hackscope from the Hantek60x4 android APP could chime in on this. Then again, the git repo was abandoned last December, so who knows.
When I get some more free time, I'll continue investigating and will keep you up to date (even if I spend another 2h organizing my findings and writing this post lol). With some luck, I'll clean up the mess of code I've written and will publish it.
This is my first time working with USB, attempting to do something useful with wireshark and reverse engineering anything, so mind that I may be wrong on tons of stuff. I'm a total noob on all of these fields and still have got tons to learn. Any input is much appreciated.