复杂的未知日期/时间表示法

4

我因为日期/时间格式很奇怪的日志文件而失眠。
我没有成功地逆向工程使用的算法。从www.digital-detective.co.uk使用DCode也无效。 我所知道的是:它是一个64位值,起始于1900年1月1日。 下面是一些例子:

日期/时间: 十六进制表示:
1900-01-01 00:00:00 > 0000000000000000
2006-07-19 00:00:00 > 0000000000A000E3
2008-04-14 00:00:00 > 00000000000050E3
2008-04-15 11:04:32 > 00D6CF74C42E50E3
2008-04-15 11:04:46 > 00CEA0C8C52E50E3
2008-04-15 11:08:32 > 00EC3B36DB2E50E3
2008-04-16 11:08:43 > 008B3B41DC4E50E3
2008-04-16 11:21:02 > 00B3AD52224F50E3
2012-02-21 00:00:00 > 00000000000000E4
2012-03-13 13:37:54 > 007A35F12CB202E4
2012-10-22 16:27:13 > 001F7A2AF0951EE4

有什么想法可以将给定的值转换为日期/时间以恢复我的睡眠吗?


这是一个有趣的谜题,但我无法解决它(除了基本的反向阅读)。我建议您在http://reverseengineering.stackexchange.com/上提问。并在解决方案后保持更新(当然,在您好好休息一晚之后!)。 - Déjà vu
2个回答

2

在Nick Cano的答案基础上,似乎需要从右到左读取十六进制对。您可以通过以下步骤将十六进制值转换为日期:

  1. 反转十六进制值
  2. 将十六进制值转换为字节
  3. 字节交换:将字节作为大端解包,然后重新打包为小端字节
  4. 将十六进制值转换为整数Int
  5. 计算Timestamp = A*Int + B,其中A = 2.45563569478691e-09B = -39014179200.000061
  6. Timestamp(自1970-01-01时代以来的秒数)转换为Date

当这些步骤应用于发布的数据时,结果如下:

              Datetime               Hex              RHex              Flip  \
0  1900-01-01 00:00:00  0000000000000000  0000000000000000  0000000000000000   
1  2006-07-19 00:00:00  0000000000A000E3  3E000A0000000000  E300A00000000000   
2  2008-04-14 00:00:00  00000000000050E3  3E05000000000000  E350000000000000   
3  2008-04-15 11:04:32  00D6CF74C42E50E3  3E05E24C47FC6D00  E3502EC474CFD600   
4  2008-04-15 11:04:46  00CEA0C8C52E50E3  3E05E25C8C0AEC00  E3502EC5C8A0CE00   
5  2008-04-15 11:08:32  00EC3B36DB2E50E3  3E05E2BD63B3CE00  E3502EDB363BEC00   
6  2008-04-16 11:08:43  008B3B41DC4E50E3  3E05E4CD14B3B800  E3504EDC413B8B00   
7  2008-04-16 11:21:02  00B3AD52224F50E3  3E05F42225DA3B00  E3504F2252ADB300   
8  2012-02-21 00:00:00  00000000000000E4  4E00000000000000  E400000000000000   
9  2012-03-13 13:37:54  007A35F12CB202E4  4E202BC21F53A700  E402B22CF1357A00   
10 2012-10-22 16:27:13  001F7A2AF0951EE4  4EE1590FA2A7F100  E41E95F02A7A1F00   

                     Int    Timestamp                 Date  
0                      0 -39014179200  0733-09-10 00:00:00  
1   16357249768470085632   1153267200  2006-07-19 00:00:00  
2   16379591844746493952   1208131200  2008-04-14 00:00:00  
3   16379643266054739456   1208257472  2008-04-15 11:04:32  
4   16379643271755910656   1208257486  2008-04-15 11:04:46  
5   16379643363789106176   1208257712  2008-04-15 11:08:32  
6   16379678552640686848   1208344123  2008-04-16 11:08:43  
7   16379678853581091584   1208344862  2008-04-16 11:21:02  
8   16429131440647569408   1329782400  2012-02-21 00:00:00  
9   16429890296696109568   1331645874  2012-03-13 13:37:54  
10  16437740548686225152   1350923233  2012-10-22 16:27:13  

请注意,计算出的(最后一个)Date列与给定的(第一个)Datetime列除了1900-01-01 00:00:00以外完全匹配。我猜测MySQL将1900-01-01 00:00:00插入作为无效日期的默认值。
通过对数据应用线性回归找到魔数A和B。给定Datetime,可以计算相应的Timestamp。然后通过将TimestampInt拟合最佳拟合线来找到A和B。
以下是我用于探索问题并生成上面表格的Python代码:
import pandas as pd
import numpy as np
import struct
import binascii

df = pd.read_table('data', sep='\s{2,}', parse_dates=[0])

df['RHex'] = df['Hex'].str[::-1]

def flip_endian(x):
    xbytes = binascii.unhexlify(x)
    swapped = struct.pack('<8h', *struct.unpack('>8h', x))
    return swapped
df['Flip'] = df['RHex'].apply(flip_endian)

df['Int'] = df['Flip'].apply(lambda x: int(x, 16))

# The constants were found by linear regression:
# import scipy.stats as stats
# df['Timestamp'] = (df['Datetime'] - pd.Timestamp('1970-1-1')).dt.total_seconds()
# A, B, rval, pval, stderr = stats.linregress(df['Int'], df['Timestamp'])
A, B = 2.45563569478691e-09, -39014179200.000061

df['Timestamp'] = (A*df['Int'] + B).astype(int)
df['Date'] = (np.array(['1970-01-01'], dtype='datetime64[D]') 
              + np.array(df['Timestamp'], dtype='timedelta64[s]')).tolist()

print(df)

事实上,字节序是答案,使用它可以将最右边的字节分成两个部分。使用以下方法来隔离这个乘数:set @a=conv(LEFT(HEX(substring(@RuweString,8,1)),1), 16,10),其中RuweString是数据源中的8字节单词。 - PetervanderKemp

2
我可以确定的是,该值需要交换字节序或翻转。你可以看到除了EPOCH结束时的E3E4之外,其他大部分数字都会发生变化。而且当时间为00:00:00时,左边的数位都是0,这进一步证明了这个说法。
我进行了一些快速计算,但似乎不是以秒、纳秒、微秒或其他任何形式表示的。但这些值之间肯定有线性关系。从这里开始,我会生成一批相隔几秒钟的时间,并观察值的变化情况。这将有助于确认是否需要翻转数字或交换字节序,同时也可能提示该值与秒的关系。
编辑:肯定是要交换字节序,而不是字符串反转。如果是反转,应该是E3->F3,而不是E3->E4。唉。
从这里开始,我会生成EPOCH后100秒、1000秒和10000秒的时间,这可能会给你一个额外的提示。

当 00000000000050E3 < 0000000000A000E3 时,如何表达存在“线性”相关性? - nehem
我尝试使用位置方法进行解码,而不是将它们视为数字。我的上面的比较实际上意味着通过剥离尾数,"00000000000050" < "0000000000A000"。但它们所指的日期分别是2008年和2006年。 - nehem
我第一次回复你的时候是不正确的,你在我的理论中扔了一个扳手,但并没有完全打乱。顺便说一下,我认为你不知道什么是字节序。交换这两个数字的字节序会得到 E300A00000000000E350000000000000。你基本上是在2位数对上颠倒它。https://en.wikipedia.org/wiki/Endianness - Nick Cano

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接