在二进制数据序列中解码日期和时间

逆向工程 文件格式
2021-06-10 10:29:52

介绍

我正在尝试对包含 sms 消息的二进制数据文件进行逆向工程。
该文件名为 ems.idx4,大约在 5 年前使用名为 LG PhoneManager 的软件创建,作为 LG 手机短信的备份存档。
我不知道用哪种语言编写 LG PhoneManager,但在二进制文件中我读取了诸如“CObTree”、“CFolder”、“CMessage”之类的字符串:也许这条线索没有任何意义,也许它表明 Cobol/.net/无论使用什么语言。

问题

我解码了二进制文件的整个结构,这很简单。
我唯一无法解码的部分是单个消息的日期和时间。
我确定了日期和时间编码的二进制部分,并得到了一些解码示例(感谢消息的内容)。
十六进制二进制数据:

[0x10] D0 74 C4 FE 3F 42 E3 40 F1 64 [0x7] 2 [0x13] 1 [0x6] 6C [0x2] is 2007/12/25 some time after 23:58 GMT+1
[0x10] 2B 25 CA 19 2F 43 E3 40 F1 64 [0x7] 2 [0x13] 1 [0x6] 6C [0x2] is 2008/01/02 some time after 10:48 GMT+1
[0x10] AA C0 2C 6E 35 43 E3 40 F1 64 [0x7] 2 [0x13] 1 [0x6] 6C [0x2] is 2008/01/02 some time after 16:03 GMT+1
[0x10] EE 04 71 F2 B6 43 E3 40 F1 64 [0x7] 2 [0x13] 1 [0x6] 6C [0x2] is 2008/01/06 some time after 14:31 GMT+1
[0x10] 60 2C F9 45 4E 4F E3 40 F1 64 [0x7] 2 [0x13] 1 [0x6] 6C [0x2] is 2008/04/08 some time after 10:32 GMT+1
[0x10] 5D 84 01 14 74 64 E3 40 F1 64 [0x7] 2 [0x13] 1 [0x6] 6C [0x2] is 2008/11/11 some time after 14:53 GMT+1

其中 [0xN] 表示 N 个零的序列。

任何的想法?

更新

使用此工具:http : //www.digital-detective.co.uk/freetools/decode.asp
我意识到它是 Windows 64 位 OLE 日期/时间格式。
根据该工具:

D0 74 C4 FE 3F 42 E3 40 means exactly 26/12/2007 00:59

知道这个 Windows 64 位 OLE 日期/时间格式背后的数学原理是什么吗?

2个回答

显然,OLE 日期时间基于双精度值,其中整个部分是自纪元以来的天数,而小数部分是一天的一小部分。时间格式转换变得容易找到了一些信息,在适当命名的部分OLE 日期的特殊性

OLE 日期 (VT_DATE) 可能很棒:它们指定自纪元(1899 年 12 月 30 日)以来的天数,小数部分给出一天的分数(例如,中午为 0.5)。浮点允许在纪元附近交易分辨率以进行长期计算。

负值需要分成整数部分和小数部分:例如-2.5 表示从纪元开始前两天和半天(即符号应用于整数部分,而不是小数部分)。这使得数字错误特别麻烦,-2 表示“从纪元回溯两天”,在 1899 年 12 月 28 日结束。-1.9999999 表示返回一天并再次向前几乎一整天,在 12 月之前结束您30, 1899 - 几乎相隔两天。

选择该纪元是为了使 Excel 与 Lotus 1-2-3 中的错误兼容,导致 1900 年 1 月和 2 月的一些转换不准确。有关详细信息,请参阅下面的链接列表。

我不知道这一点,谢谢你的帮助 :)

好的,我找到了我的方法!
[0x10] 之后的前 8 个字节是小端十六进制的 OLE 日期。
我将它们转换为 python 中的常规日期时间:

import datetime
import math
from struct import unpack


def ole_date_bin_to_datetime(ole_date_bin):
    """
        Converts a OLE date from a binary 8 bytes little endian hex form to a datetime
    """
    #Conversion to OLE date float, where:
    # - integer part: days from epoch (1899/12/30 00:00) 
    # - decimal part: percentage of the day, where 0,5 is midday
    date_float = unpack('<d', ole_date_bin)[0]
    date_decimal, date_integer = math.modf(date_float)
    date_decimal = abs(date_decimal) 
    date_integer = int(date_integer)

    #Calculate the result
    res = datetime.datetime(1899, 12, 30) + datetime.timedelta(days=date_integer) #adding days to epoch
    res = res + datetime.timedelta(seconds = 86400*date_decimal) #adding percentage of the day
    return res


if __name__ == "__main__":
    print ole_date_bin_to_datetime('\xd0\x74\xc4\xfe\x3f\x42\xe3\x40')