5

I have an existing software, with no source and possible editing. It contains a grid (looks like an old DevExpress one, the software itself is created in Delphi 7). Grid content is stored in the memory, which I have to read and modify externally.

I've successfully decoded the structure, except for date+time fields. It's stored in 8 bytes. I've checked all common structures, such as TDateTime as a double variable, TTimeStamp as two integers, TFileTime, Windows OLE, MySQL timestamp, other timestamps, but found nothing closely relative.

I can input any data and check the result in the table, so I am sure data is correct.

I've provided examples of data times in bytes and the result in grid. Can test any other, if it helps.

00 00 00 00 00 00 00 43 - 04.03.17840 11:03:41
00 00 00 00 00 00 00 41 - "0.131072 is not a valid timestamp"
00 00 00 00 00 00 00 42 - 09.04.001 10:05:34
00 00 00 00 00 00 67 42 - 15.01.0026 16:33:02
00 00 00 00 00 00 CB 42 - 22.06.1882 18:24:59
00 00 00 00 00 00 CC 42 - 28.02.1952 10:12:35
00 00 00 00 00 E4 CC 42 - 22.03.2014 07:24:02
00 00 00 00 00 E5 CC 42 - 29.06.2014 17:29:37
00 00 00 00 3D E5 CC 42 - 23.07.2014 10:03:17
00 95 1E 7E 3D E5 CC 42 - 23.07.2014 14:38:48
00 87 F9 7C 3D E5 CC 42 - 23.07.2014 14:36:18
00 4C 99 57 38 E5 CC 42 - 21.07.2014 14:38:26
80 55 0C 2E 3E E4 CC 42 - 15.04.2014 10:57:32

UPDATE 1: Weird differnce in the years mentioned in the comment lead to a discovery, that date is not strictly linear to the elder bytes. I've tested this:

00 00 00 00   00 00 CA 42 - 16.10.1812
00 00 00 00   00 00 CB 42 - 22.06.1882
00 00 00 00   00 00 CC 42 - 28.02.1952

The difference between values is ~70 years (~25452 days)

And now this:

00 00 00 00   00 00 BA 42 - 23.11.0906
00 00 00 00   00 00 BB 42 - 26.09.0941
00 00 00 00   00 00 BC 42 - 30.07.0976

The difference is actually ~35 years (~12726 days)

To sum it up, here's the breakdown:

00 00 00 00   00 00 BD 42 - 04.06.1011
00 00 00 00   00 00 BE 42 - 06.04.1046 (+35 years)
00 00 00 00   00 00 BF 42 - 07.02.1081 (+35 years)
...
00 00 00 00   00 00 C0 42 - 13.12.1115 (+35 years)
00 00 00 00   00 00 C1 42 - 19.08.1185 (+70 years)
00 00 00 00   00 00 C2 42 - 25.04.1255 (+70 years)
...
00 00 00 00   00 00 C8 42 - 02.06.1673 (+70 years)
00 00 00 00   00 00 C9 42 - 08.02.1743 (+70 years)
00 00 00 00   00 00 CA 42 - 16.10.1812 (+70 years)
...
00 00 00 00   00 00 CE 42 - 11.07.2091 (+70 years)
00 00 00 00   00 00 CF 42 - 18.03.2161 (+70 years)
...
00 00 00 00   00 00 D0 42 - 24.11.2230 (+70 years)
00 00 00 00   00 00 D1 42 - 07.04.2370 (+140 years)
00 00 00 00   00 00 D2 42 - 19.08.2509 (+140 years)

So it looks like the elder bits is rather some coeff, not the date directly

I've tested lesser bits, they seem to behave more logically:

00 00 00 00   00 00 CC 42 - 28.02.1952
00 00 00 00   00 01 CC 42 - 06.06.1952
00 00 00 00   00 02 CC 42 - 14.09.1952

~100 days

00 00 00 00   00 CC CC 42 - 09.09.2007
00 00 00 00   00 CD CC 42 - 17.12.2007
00 00 00 00   00 CE CC 42 - 26.03.2008

~100 days

00 00 00 00   00 FC CC 42 - 02.10.2020
00 00 00 00   00 FD CC 42 - 09.01.2021
00 00 00 00   00 FE CC 42 - 19.04.2021

~100 days

And for the fourth byte:

00 00 00 00   00 CC CC 42 - 09.09.2007 05:10:12
00 00 00 00   01 CC CC 42 - 09.09.2007 14:29:26
00 00 00 00   02 CC CC 42 - 09.09.2007 23:48:26

~9 hours

00 00 00 00   CC CC CC 42 - 27.11.2007 10:35:16
00 00 00 00   CD CC CC 42 - 27.11.2007 19:54:30
00 00 00 00   CE CC CC 42 - 28.11.2007 05:13:45

~9 hours

For the question on the breakdown of +1m, +1h, etc. It's much harder to test, since I cannot input the random date and get its code, only the opposite. But I can add the value manually, and test its internal structure. Here's what I managed to grab today:

00 90 D2 80   4A E5 CC 42 - 28.07.2014 15:54:50
00 E3 D4 80   4A E5 CC 42 - 28.07.2014 15:54:51

80 5D 48 81   4A E5 CC 42 - 28.07.2014 15:55:50
80 5A 4B 81   4A E5 CC 42 - 28.07.2014 15:55:51

80 D4 49 9C   4A E5 CC 42 - 28.07.2014 16:54:50
00 8C 4C 9C   4A E5 CC 42 - 28.07.2014 16:54:51
  • 1
    Can you show the data where just one second/minute/day/month/year changed at a time? – user1814 Jul 28 '14 at 8:41
  • I suspect there is a typo in at least some of your values. The difference between CB 42 and CC 42 is about 70 years, which would mean the difference between 67 42 and CB 42 (CBh-67h=64h=100d) should be around 7000 years, which is not the case. – Guntram Blohm supports Monica Jul 28 '14 at 9:13
  • @m0nhawk It's a bit hard, but I've added the info at the bottom of the edited post. – AlexeiD Jul 28 '14 at 11:05
  • @GuntramBlohm I've made an update, seems like elder bytes are not linear to the date. – AlexeiD Jul 28 '14 at 11:05
7

The non-linearity is a clue that it's a floating-point encoding. If you are familiar with looking at floating point values in memory dumps, the most significant byte is often in the 0x3f-0x4f range, representing values from 3e-5 to 2e77 for doubles. In this case, it's little-endian.

e.g. 00 4C 99 57 38 E5 CC 42 - 21.07.2014 14:38:26 -> unpacks to -> 63541636706968.0

Working the other direction, let's examine the standard encoding for that date. UNIX time_t (seconds since 1970 epoch) = 1405949906.

That's four orders of magnitude too small. Not good; perhaps we could try seconds since 1 AD. Assuming 365.2425 days per year for now, and remembering day, month and year numbering starting at 1:

(21-1 + 181 days before July + (2014-1AD)*365.2425)*86400 sec/day + 14*3600 + 38*60 + 26 = 63541563483.0
63541563483.0 * 1000 = 63541563483000.0

That's similar to the decoded number, but it's off by ~1000x; the encoded value must be in milliseconds. The prediction is not precise, we are off by approximately 1 day. We should still test if it continues to work on other values.

00 00 00 00 00 00 CB 42 - 22.06.1882 18:24:59
decoding: 59373627899904.0
prediction: 59373553811000.0

00 00 00 00 00 00 67 42 - 15.01.0026 16:33:02
decoding: 790273982464.0
prediction: 790192982000.0

Close, but again off by approximately 1 day. We have to examine our assumptions. The Gregorian calendar system we use with its leap years only extends back to 1582, but this system has a zero point before that. We have to guess what the programmer did to extend this backwards to 1AD.

You can find the zero point by running floating-point zero (all zeros) through the program; it should show the exact date-time origin the programmer chose. If the program doesn't accept zero, you can use a very small double value like DBL_MIN. You also have to examine exactly how leap days are handled by the program, if it correctly considers the 400 year rule, and any implementation bugs.

| improve this answer | |
1

Not looking at the first three plus 28.02.1952 10:12:35, 29.06.2014 17:29:37, 15.04.2014 10:57:32 lines, I get the following:

The value on the right is in 1/128000 seconds, with an offset to UNIX timestamps of 4805619185047532800 seconds. So, we have:

yourtime =  4805619185047532800 +128000 * unixtime

It does not look familiar though, that would mean t=0 -> 1187749 BC.

If you leave off the 0x42 then t=0 would be 10363 BC, still not a familiar number.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.