Dealing with data obfuscation in some Chinese dash cameras

This is post relates to the extracting GPS coordinates form Novatek based dash cameras.

About an year ago I was contacted by someone who tried to use my script on MP4 files generated by their camera, only to get garbage data out. It appeared that the camera was obfuscating the coordinates stored in MP4 (the speed and heading was recorded correctly). It was not a bug because provided player was decoding them correctly.

I have spent few hours on this problem and given up as I could not see the pattern in the coordinates. As far as I was concerned it was one off and obscure enough not to worry about it.

Recently I got contacted by George G. with exactly same problem. This time I decided to really look into it.

Again, I hit a brick wall by just looking at the floats that the camera recorded, as they absolutely made no sense as coordinates in any known coordinate systems.

So the answer must be in the player. The player is called JMS GPS DVR Player.

Because I have no Windows machines I got friend to decompile the .exe file with jetbrains decompiler. That did an awesome job and I got fully readable C# code out if. At first I though I hit a jackpot when I saw some de-obfuscation going on but that turned out to be Chinese standard obfuscation and not the one I was looking for.

The jetbrains decompiler could not handle the GPSDataPraser.dll (not my typo ;)). Fortunately, previously I got it decompiled on Linux with retdec.

Having both, clear C# sources and messy retdec generated C code for the DLL I worked my way backwards from C#, on how it was calling the DLL. What initially prompt me to look into C# code for the algorithm is that on glance the DLL had no float/double arithmetic going on.

Working backwards allowed me to see this two pieces of code being executed on chunks of MP4 read by the DLL:

int128_t v20 = __asm_movss(*(int32_t *)(g9 + 72)); // 0x100023f5
int128_t v21 = __asm_subsd(__asm_cvtps2pd(v20), 0x40a12e65c3dee782); // 0x100023fe
int128_t v22 = __asm_cvtpd2ps(__asm_mulsd(v21, 0x3fe0000000000000)); // 0x1000240e

and

int128_t v23 = __asm_movss(*(int32_t *)(g9 + 68)); // 0x1000241d
int128_t v24 = __asm_subsd(__asm_cvtps2pd(v23), 0x40677f6defc7a398); // 0x10002426
int128_t v25 = __asm_cvtpd2ps(__asm_divsd(v24, 0x4008000000000000)); // 0x10002436

This was found on line 1064 of the decompiled C “code”. I found it by looking for decimal values (ASCII) of ‘A’ and ‘V’, after the point the file was read. And there it was:

if (v72 != 86) {

It was looking if the value of char of not being ‘V’, as the GPS provides the valid data as ‘A’ and invalid data as ‘V’ I suspected I was in the right place.

When I saw that the value was converted into double precision float (aka double) and subdivision was done to it I knew I struck gold.

These bastards were doing basic arithmetic to obfuscate the coordinates so their end users are forced to use their crappy JMS GPS DVR player. I consider that a dick move.

Here is the translation the assembly/c into human readable presentation of the crappy obfuscation.

For longitude they use following two constants:

0x40a12e65c3dee782 -> 2199.19876 and 0x3fe0000000000000 -> 0.5.

To get longitude:
longitude = (obfuscated_longitude - 2199.19876) * 0.5

For latitude they use following two constants:

0x40677f6defc7a398 -> 187.98217 and 0x4008000000000000 -> 3.

To get latitude:
latitude = (obfuscated_latitude - 187.98217) / 3