Search code examples
datedelphitime64-bit

Strange 64-bit time format from game, you can recognize it?


i capture this 64-bit time format from a game and trying to understand it. I can not use a date delta because every now and then the value totally changes and even becomes negative as seen below.

v1:int64=-5990085973098618987;   //2021-01-25 13:30:00
v2:int64=-5990085973321147595;   //4 mins later
v3:int64=6140958949625363349;    //7 mins later
v4:int64=6140958948894898101;    //11 mins later
v5:int64=-174740204032730139;    //16 mins later
v6:int64=-174740204054383467;    //18 mins later
v7:int64=-6490439358095090795;   //23 mins later

I tried to split the 64-bit into two 32-bit containers to get low and high part. still strange values. I also tried using pdouble(@value)^ to get float value of the 64-bit data, still strange values. So kind of running out of ideas, maybe some kind of bitfield data or something else going on.

hipart: -1394675573 | lopart: 1466441621  | hex: acdef08b|57681f95 | swap: -7701322112560996692
hipart: -1394675573 | lopart: 1243913013  | hex: acdef08b|4a249b35 | swap: 3862721007994330796
hipart: 1429803424  | lopart: -458425451  | hex: 553911a0|e4acfb95 | swap: -7639322244965910187
hipart: 1429803424  | lopart: -1188890699 | hex: 553911a0|b922f7b5 | swap: -5334757052947285675
hipart: -40684875   | lopart: -760849435  | hex: fd9332b5|d2a65be5 | swap: -1919757392230050819
hipart: -40684875   | lopart: -782502763  | hex: fd9332b5|d15bf495 | swap: -7641381711494605827
hipart: -1511173174 | lopart: -1467540587 | hex: a5ed53ca|a8871b95 | swap: -7702413578668347995

Any ideas welcomed, thanks in advance //mbs

--EDIT: So far, thanks to Martin Rosenau we are able to encode like this:

func mulproc_nfsw(i:int64;key:uint32):int64;
begin
 if (blnk i) or (blnk key) then exit;
 p:pointer=@i;
 hi:uint32=uint32(p+4)^; //30864159 (hex: 01d6f31f)
 lo:uint32=uint32(p)^; //748455936 (hex: 2c9c8800)
 hi64:int64=hi*key; //0135b55a acdef08b <-- keep
 lo64:int64=lo*key; //1d566e0b a65f2800 <-- keep
 q:pointer=@result; //-5990085971773806592
 uint32(q+4)^:=hi64; //acdef08b
 uint32(q)^:=lo64; //a65f2800
end;
func encode_time_nfsw(j:juncture):int64;
begin
 if blnk j then exit; //input: '2021-01-25 13:37:07'
 key:uint32=$A85A2115; //encode key
 ft:int64=j.filetime; //hex: 01d6f31f 2c9c8800
 result:=mulproc_nfsw(ft,key);
end;

--EDIT2: Finally, thanks to fpiette we are able to decode also:

func decode_time_nfsw(i:int64):juncture;
begin
 if blnk i then exit; //input: -5990085971773806592
 key:uint32=$3069263D; //decode key
 ft:int64=mulproc_nfsw(i,key);
 result.setfiletime(ft);
end;

Solution

  • I checked my suspicion that the high and the low 32 bits are simply multiplied by A85A2115 (hex):

    We get a FILETIME structure. Then we perform a 32x32->32 bit multiplication (this means we throw away the high 32 bits of the 64 bits result) of the high and the low word independently.

    Example:

    25 Jan 2021 13:37:07 (and some milliseconds)
    

    Unencrypted FILETIME:

    High dword = 1D6F31F (hex)
    Low dword  = 2C9CA481 (hex)
    

    Multiplication

    High dword: 1D6F31F * A85A2115  = 135B55AACDEF08B (hex)
    Low dword:  2C9CA481 * A85A2115 = 1D5680CA57681F95 (hex)
    

    Now only take the low 32 bits of the results:

    High dword: ACDEF08B (hex)
    Low dword:  57681F95 (hex)
    

    Unfortunately, I don't know how to do the the "reverse operation"; I did it by searching for the result in a loop with the following pseudo-code:

    encryptedValue = 57681F95 (hex)
    originalValue = 0
    product = 0
    while product not equal to encryptedValue
        // 32-bit addition discarding carry:
        product = product + A85A2115 (hex) 
        originalValue = originalValue + 1
    end_of_while_loop
    

    We get the following results:

    25 Jan 2021 13:37:07 => acdef08b|57681f95
    25 Jan 2021 13:40:51 => acdef08b|4a249b35
    25 Jan 2021 13:45:07 => 553911a0|e4acfb95
    25 Jan 2021 13:49:03 => 553911a0|b922f7b5
    25 Jan 2021 13:53:53 => fd9332b5|d2a65be5
    25 Jan 2021 13:55:50 => fd9332b5|d15bf495
    25 Jan 2021 14:00:39 => a5ed53ca|a8871b95
    

    Addendum

    The reverse operation seems to be done by multiplying with 3069263D (hex) (and only using the low 32 bits).

    Encrypting:

    2C9CA481 * A85A2115 = 1D5680CA57681F95
    => Result: 57681F95
    

    Decrypting:

    57681F95 * 3069263D = 10876CAF2C9CA481
    => Result: 2C9CA481