[TOOL][WIN] Offline TXT FlightRecord to CSV Converter

Anouncement / current status:
As some of you noticed, the tool doesn't work with newest TXT logs (2.8.4 and newer), because DJI GO is now encrypting them

I am cooperating with BudWalker (creator of DatCon and CsvView) and msinger (he is behind www.phantomhelp.com)
but so far, we haven't succeeded and we are running out of options

guys from paid services (HealthyDrones and djilogs) are ignoring us (that I'm not surprised)
developers from DJI won't help us either (actually they say they are gonna change the encryption system again)

some of you contacted me and offered help
that's very kind of you, but I honestly don't know, how you could help
maybe if you are some very smart programmer or you know some DJI GO developer who would help us or I don't know, you have some special power that you look into logs and solve the puzzle :)

so unless some miracle happens, it's your choice of what is important to you - to have readable logs with older app or to have new app and no readable logs (so you must rely on those paid online services)
 
Normally logs are available without any encryption. I don't understand why DJI encrypted logs along with communication signals. And how other apps like djilogs and healthy drones have access to a decryptor?


Sent from my iPhone using PhantomPilots
 
we are also working on a solution to decrypt log file and we put some of where we are so far here:
Help me reverse this

Fell free to read and help!
The decompiled .SO that I have is slightly different than yours. One cosmetic, two semantically different. I've noticed in both versions that there must be an error in the decompilation of getKey(). a4 is unused in the body of getKey(). I think it is a5 that should be unused and the references to a5 changed to a4. a4 is a uint64 and that's what is expected in the 2nd arg to crc64. Clearly crc64 needs a 8 byte vector to work - otherwise it's just using bytes from nowhere in particular.

I had already renamed the variables in getKey() before I saw your post yesterday. I added some comments based on the discussion in your post. Here is the code I have currently.

int getKey(void *retKeyArray, uint length, uint8 keyChar, uint64 seed,
char a5) {
void * keyVector; // r8@1 ==v5
//unsigned int v6; // r7@1 ==v6
unsigned int num64BitSegs; // r10@1 ==v7
void *keyVectorOffset; // r5@1 ==v8
uint64 segment; // r0@1 ==v9
unsigned int currentSeg; // r6@1 ==v10
uint64 initialSegment; // [sp+8h] [bp-30h]@1 ==v12
unsigned int v13; // [sp+14h] [bp-24h]@1

keyVector = retKeyArray;
num64BitSegs = length >> 3;
keyVectorOffset = retKeyArray;
v13 = stack_chk_guard;
segment = 0;
//LODWORD(segment) = crc64(keyChar, (unsigned char*) &seed, 8);
segment = crc64(keyChar, (unsigned char*) &seed, 8);
currentSeg = 0;
initialSegment = segment;
// Loop on segments
do {
// increase the counter for the current segment
//++current8ByteChunk; //not sure about this
// If current segment exceeds the required length
if (8 * ++currentSeg > length) {

// If some bytes of the 8byte chunks are needed
if (length >= 8 * currentSeg - 8)
// Copy portion of initialSegment needed to fill the buffer
LODWORD(segment) = (unsigned int) (memcpy(keyVectorOffset,
&initialSegment,
(size_t) ((keyVector + length)
- (_DWORD) keyVectorOffset)));
//segment = (long long) (memcpy(keyVectorOffset, &initialSegment, (size_t)((keyVector + length) - (_DWORD) keyVectorOffset)));
} else {
// Set segment to the initialSegment
segment = initialSegment;
*(_QWORD *) keyVectorOffset = initialSegment;
}
keyVectorOffset = (char *) keyVectorOffset + 8;
} while (currentSeg <= num64BitSegs);
if (v13 != stack_chk_guard) {
//_stack_chk_fail(v9);
}
return segment;
}
 
Last edited:
  • Like
Reactions: TecHunter
The decompiled .SO that I have is slightly different than yours. One cosmetic, two semantically different. I've noticed in both versions that there must be an error in the decompilation of getKey(). a4 is unused in the body of getKey(). I think it is a5 that should be unused and the references to a5 changed to a4. a4 is a uint64 and that's what is expected in the 2nd arg to crc64. Clearly crc64 needs a 8 byte vector to work - otherwise it's just using bytes from nowhere in particular.

I had already renamed the variables in getKey() before I saw your post yesterday. I added some comments based on the discussion in your post. Here is the code I have currently.

int getKey(void *retKeyArray, uint length, uint8 keyChar, uint64 seed,
char a5) {
void * keyVector; // r8@1 ==v5
//unsigned int v6; // r7@1 ==v6
unsigned int num64BitSegs; // r10@1 ==v7
void *keyVectorOffset; // r5@1 ==v8
uint64 segment; // r0@1 ==v9
unsigned int currentSeg; // r6@1 ==v10
uint64 initialSegment; // [sp+8h] [bp-30h]@1 ==v12
unsigned int v13; // [sp+14h] [bp-24h]@1...

interesting...seems this difference, can help to move forward...
 
Hi there,

I'm the one one RE post, thanks for the input that helps a lot!!!
Seems like the seed used is a 64bit key

From DecryptData function we have the 4th arg of getKey as :
(2596069104u * (unsigned __int64)v8 >> 32) + 305419896 * v8

v8 seems to be the first byte of the data field. This explains why we have redundant keys accross the file.

To check if I get the correct key I use the GPS coordinates which are something around this ones :
46.1474762999586 and 6.16260780798589

So if I convert these to radians with their float representations then XOR these with the first 2 chunks of 8 bytes from my data I get an almost common key that ends with 6399 (I say almost because due to float approximation accross languages I don't know the exact value and the 2 last bytes of the float is the integer part.) So now I need to run the crc64 function with the correct parameters and check if it corresponds with the end of the key. that's my primary check. if it matches then I try to run the key for the whole set of data.

I'm here for now, I will try with the seed instead of the data as 2nd argument for crc64 function!
will keep you in touch.

PS: if you have the whole C file from your decompiler I'm interested!
 
  • Like
Reactions: BudWalker
Hi there,

I'm the one one RE post, thanks for the input that helps a lot!!!
Seems like the seed used is a 64bit key

From DecryptData function we have the 4th arg of getKey as :
(2596069104u * (unsigned __int64)v8 >> 32) + 305419896 * v8

v8 seems to be the first byte of the data field. This explains why we have redundant keys accross the file.

To check if I get the correct key I use the GPS coordinates which are something around this ones :
46.1474762999586 and 6.16260780798589

So if I convert these to radians with their float representations then XOR these with the first 2 chunks of 8 bytes from my data I get an almost common key that ends with 6399 (I say almost because due to float approximation accross languages I don't know the exact value and the 2 last bytes of the float is the integer part.) So now I need to run the crc64 function with the correct parameters and check if it corresponds with the end of the key. that's my primary check. if it matches then I try to run the key for the whole set of data.

I'm here for now, I will try with the seed instead of the data as 2nd argument for crc64 function!
will keep you in touch.

PS: if you have the whole C file from your decompiler I'm interested!
The decompiler we used is the same one you used. So you already have the .c. There is a minor difference though having to do with how a loop is initialized in getKey(). Ours doesn't have this
// increase the counter for the current 8byte chunk we're using
++v10_NI_current_8byte_chunk; <<<=======================

I think I understand in the paragraph "So if I convert these....." If so, I've tried that and it didn't work. Maybe you'll have better luck. The basic problem is given RecID and the 1 byte key then how is the 8 byte key generated. The way the code is decompiled the 8 byte key is dependent on random parts of memory. That's why I started trying with the change I described. (and you're trying).

BTW
(2596069104u * (unsigned __int64)v8 >> 32) + 305419896 * v8
can be rewritten as
(0x9ABCDEF0 * (unsigned __int64) v8 >> 32) + 0x12345678 * v8;
When I saw that I figured it just has to be involved in the computation of the 8 byte key.
 
  • Like
Reactions: TecHunter
yes basically the getKey does this :

  1. compute crc from a seed
  2. malloc an array with length matching the data.
  3. fill crc in this array by repeating it + some byte at the end to check consistency(??)
  4. return key array
As for the conversion, it did work. just dont use the first byte.
 
BTW
(2596069104u * (unsigned __int64)v8 >> 32) + 305419896 * v8
can be rewritten as
(0x9ABCDEF0 * (unsigned __int64) v8 >> 32) + 0x12345678 * v8;
When I saw that I figured it just has to be involved in the computation of the 8 byte key.

OMG I just saw the hex code lol. nice finding
 
I'm glad to announce, that thanks to BIG help from BudWalker, my tool is working again, with newest log version too

so enjoy it (while it lasts - who knows, when DJI changes the logging structure or encryption again - maybe with DJI GO 3.0...)
 
Last edited:
My log viewer will be updated too sometime this week. Thank you for your help @BudWalker.
 
I guarantee nobody is more appreciative about this then I am. I'm so happy about this I doubt I will even fall asleep tonight. I don't know what it was, but for some odd reason I thought I would message you guys earlier this evening and ask how things were coming...... Enough with this...I have some new files to look at now!

Thank You BudWalker!!!
 
Last edited:
  • Like
Reactions: Hans 75 and Oso
I'm glad to announce, that thanks to BIG help from BudWalker, my tool is working again, with newest log version too

so enjoy it (while it lasts - who knows, when DJI changes the logging structure or encryption again - maybe with DJI GO 3.0...)
This was a team effort with contributions from @msinger, and @TecHunter. And, especially @ferraript who provided some crucial observations and other contributions.
 
It means, that I have to say:
Thank you to you all!
H.


And sorry for my question, the .dat-file has the same procedure and the same key for encryption?
 

Recent Posts

Members online

No members online now.

Forum statistics

Threads
143,096
Messages
1,467,615
Members
104,981
Latest member
brianklenhart